Re: Implementing SELECT FOR UPDATE [NOWAIT] - Mailing list pgsql-patches

From Hans-Juergen Schoenig
Subject Re: Implementing SELECT FOR UPDATE [NOWAIT]
Date
Msg-id 42BCFC6D.9000905@cybertec.at
Whole thread Raw
In response to Re: Implementing SELECT FOR UPDATE [NOWAIT]  (Bruce Momjian <pgman@candle.pha.pa.us>)
Responses Re: Implementing SELECT FOR UPDATE [NOWAIT]
List pgsql-patches
yes, i think we can do it in time.

    regards,

       hans



Bruce Momjian wrote:

>Are you working on a updated version of this?
>
>---------------------------------------------------------------------------
>
>Bruce Momjian wrote:
>
>
>>Uh, seems the code has drifted too much and now I can't apply this.
>>Would you redo this against current CVS?  Thanks.
>>
>>---------------------------------------------------------------------------
>>
>>Hans-Juergen Schoenig wrote:
>>
>>
>>>Folks,
>>>
>>>We have implemented SELECT FOR UPDATE NOWAIT for PostgreSQL.
>>>The patch attached to this email contains all the required code
>>>including ECPG updates and some documentation.
>>>It would be nice if this patch would be included in PostgreSQL 8.1
>>>
>>>    Best regards,
>>>
>>>        Ewald Geschwinde & Hans-Juergen Schoenig
>>>
>>>--
>>>Cybertec Geschwinde u Schoenig GmbH.
>>>Schoengrabern 134, A-2020 Hollabrunn, Austria
>>>Tel: +43/660/816 40 77
>>>www.cybertec.at, www.postgresql.at
>>>
>>>
>>[ text/x-patch is unsupported, treating like TEXT/PLAIN ]
>>
>>
>>
>>>diff -r -c postgresql-8.0.0rc2.orig/doc/src/sgml/ref/select.sgml postgresql-8.0.0rc2/doc/src/sgml/ref/select.sgml
>>>*** postgresql-8.0.0rc2.orig/doc/src/sgml/ref/select.sgml    Sat Nov 27 22:27:07 2004
>>>--- postgresql-8.0.0rc2/doc/src/sgml/ref/select.sgml    Mon Dec 27 10:57:05 2004
>>>***************
>>>*** 30,36 ****
>>>      [ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable
class="parameter">operator</replaceable>] [, ...] ] 
>>>      [ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
>>>      [ OFFSET <replaceable class="parameter">start</replaceable> ]
>>>!     [ FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ]
>>>
>>>  where <replaceable class="parameter">from_item</replaceable> can be one of:
>>>
>>>--- 30,36 ----
>>>      [ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable
class="parameter">operator</replaceable>] [, ...] ] 
>>>      [ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
>>>      [ OFFSET <replaceable class="parameter">start</replaceable> ]
>>>!     [ FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [NOWAIT] ]
>>>
>>>  where <replaceable class="parameter">from_item</replaceable> can be one of:
>>>
>>>***************
>>>*** 772,778 ****
>>>     <para>
>>>      The <literal>FOR UPDATE</literal> clause has this form:
>>>  <synopsis>
>>>! FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
>>>  </synopsis>
>>>     </para>
>>>
>>>--- 772,778 ----
>>>     <para>
>>>      The <literal>FOR UPDATE</literal> clause has this form:
>>>  <synopsis>
>>>! FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [NOWAIT]
>>>  </synopsis>
>>>     </para>
>>>
>>>***************
>>>*** 789,796 ****
>>>      has already locked a selected row or rows, <command>SELECT FOR
>>>      UPDATE</command> will wait for the other transaction to complete,
>>>      and will then lock and return the updated row (or no row, if the
>>>!     row was deleted).  For further discussion see <xref
>>>!     linkend="mvcc">.
>>>     </para>
>>>
>>>     <para>
>>>--- 789,802 ----
>>>      has already locked a selected row or rows, <command>SELECT FOR
>>>      UPDATE</command> will wait for the other transaction to complete,
>>>      and will then lock and return the updated row (or no row, if the
>>>!     row was deleted).  If the current transaction is not supposed to
>>>!     wait on other transactions to commit the NOWAIT option can be
>>>!     used.  If <command>SELECT FOR UPDATE NOWAIT</command> finds out
>>>!     that somebody else is holding a lock an error will be thrown.
>>>!     This will only happen in case of row level locks - if somebody
>>>!     holds a table lock <command>SELECT FOR UPDATE NOWAIT</command>
>>>!     will still wait for concurrent transactions.  For further
>>>!     discussion see <xref linkend="mvcc">.
>>>     </para>
>>>
>>>     <para>
>>>diff -r -c postgresql-8.0.0rc2.orig/doc/src/sgml/sql.sgml postgresql-8.0.0rc2/doc/src/sgml/sql.sgml
>>>*** postgresql-8.0.0rc2.orig/doc/src/sgml/sql.sgml    Mon Nov 15 07:32:14 2004
>>>--- postgresql-8.0.0rc2/doc/src/sgml/sql.sgml    Mon Dec 27 10:57:05 2004
>>>***************
>>>*** 866,872 ****
>>>      [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable
class="PARAMETER">operator</replaceable>] [, ...] ] 
>>>      [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
>>>      [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
>>>!     [ FOR UPDATE [ OF <replaceable class="PARAMETER">class_name</replaceable> [, ...] ] ]
>>>       </synopsis>
>>>      </para>
>>>
>>>--- 866,872 ----
>>>      [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable
class="PARAMETER">operator</replaceable>] [, ...] ] 
>>>      [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
>>>      [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
>>>!     [ FOR UPDATE [ OF <replaceable class="PARAMETER">class_name</replaceable> [, ...] ] [NOWAIT] ]
>>>       </synopsis>
>>>      </para>
>>>
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/access/heap/heapam.c
postgresql-8.0.0rc2/src/backend/access/heap/heapam.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/access/heap/heapam.c    Sun Nov 14 03:04:12 2004
>>>--- postgresql-8.0.0rc2/src/backend/access/heap/heapam.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 16,21 ****
>>>--- 16,22 ----
>>>   *        relation_openrv - open any relation specified by a RangeVar
>>>   *        relation_openr    - open a system relation by name
>>>   *        relation_close    - close any relation
>>>+  *        conditional_relation_open - open with option not to wait
>>>   *        heap_open        - open a heap relation by relation OID
>>>   *        heap_openrv        - open a heap relation specified by a RangeVar
>>>   *        heap_openr        - open a system heap relation by name
>>>***************
>>>*** 1828,1834 ****
>>>   */
>>>  int
>>>  heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer,
>>>!                  CommandId cid)
>>>  {
>>>      TransactionId xid = GetCurrentTransactionId();
>>>      ItemPointer tid = &(tuple->t_self);
>>>--- 1829,1835 ----
>>>   */
>>>  int
>>>  heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer,
>>>!                  CommandId cid, bool nowait)
>>>  {
>>>      TransactionId xid = GetCurrentTransactionId();
>>>      ItemPointer tid = &(tuple->t_self);
>>>***************
>>>*** 1858,1866 ****
>>>      {
>>>          TransactionId xwait = HeapTupleHeaderGetXmax(tuple->t_data);
>>>
>>>-         /* sleep until concurrent transaction ends */
>>>          LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
>>>!         XactLockTableWait(xwait);
>>>
>>>          LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
>>>          if (!TransactionIdDidCommit(xwait))
>>>--- 1859,1881 ----
>>>      {
>>>          TransactionId xwait = HeapTupleHeaderGetXmax(tuple->t_data);
>>>
>>>          LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
>>>!
>>>!         if (nowait)
>>>!         {
>>>!             /* rather error than sleep until concurrent transaction ends */
>>>!             if (!ConditionalXactLockTableWait(xwait))
>>>!             {
>>>!                 ReleaseBuffer(*buffer);
>>>!                 ereport(ERROR,
>>>!                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
>>>!                      errmsg("data in table \"%s\" was modify by concurrent trasaction.",
>>>!                          RelationGetRelationName(relation))));
>>>!             }
>>>!         }
>>>!         else
>>>!             /* sleep until concurrent transaction ends */
>>>!             XactLockTableWait(xwait);
>>>
>>>          LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
>>>          if (!TransactionIdDidCommit(xwait))
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/commands/trigger.c
postgresql-8.0.0rc2/src/backend/commands/trigger.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/commands/trigger.c    Tue Dec  7 00:57:17 2004
>>>--- postgresql-8.0.0rc2/src/backend/commands/trigger.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 1574,1580 ****
>>>          *newSlot = NULL;
>>>          tuple.t_self = *tid;
>>>  ltrmark:;
>>>!         test = heap_mark4update(relation, &tuple, &buffer, cid);
>>>          switch (test)
>>>          {
>>>              case HeapTupleSelfUpdated:
>>>--- 1574,1580 ----
>>>          *newSlot = NULL;
>>>          tuple.t_self = *tid;
>>>  ltrmark:;
>>>!         test = heap_mark4update(relation, &tuple, &buffer, cid, estate->es_nowait);
>>>          switch (test)
>>>          {
>>>              case HeapTupleSelfUpdated:
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/executor/execMain.c
postgresql-8.0.0rc2/src/backend/executor/execMain.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/executor/execMain.c    Thu Oct  7 20:38:49 2004
>>>--- postgresql-8.0.0rc2/src/backend/executor/execMain.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 558,563 ****
>>>--- 558,564 ----
>>>      /*
>>>       * Have to lock relations selected for update
>>>       */
>>>+     estate->es_nowait = parseTree->nowait;
>>>      estate->es_rowMark = NIL;
>>>      if (parseTree->rowMarks != NIL)
>>>      {
>>>***************
>>>*** 1133,1139 ****
>>>
>>>                      tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
>>>                      test = heap_mark4update(erm->relation, &tuple, &buffer,
>>>!                                             estate->es_snapshot->curcid);
>>>                      ReleaseBuffer(buffer);
>>>                      switch (test)
>>>                      {
>>>--- 1134,1140 ----
>>>
>>>                      tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
>>>                      test = heap_mark4update(erm->relation, &tuple, &buffer,
>>>!                             estate->es_snapshot->curcid, estate->es_nowait);
>>>                      ReleaseBuffer(buffer);
>>>                      switch (test)
>>>                      {
>>>***************
>>>*** 2082,2087 ****
>>>--- 2083,2089 ----
>>>      epqstate->es_instrument = estate->es_instrument;
>>>      epqstate->es_select_into = estate->es_select_into;
>>>      epqstate->es_into_oids = estate->es_into_oids;
>>>+     epqstate->es_nowait = estate->es_nowait;
>>>      epqstate->es_topPlan = estate->es_topPlan;
>>>
>>>      /*
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/executor/execUtils.c
postgresql-8.0.0rc2/src/backend/executor/execUtils.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/executor/execUtils.c    Fri Oct  1 01:21:23 2004
>>>--- postgresql-8.0.0rc2/src/backend/executor/execUtils.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 203,209 ****
>>>      estate->es_instrument = false;
>>>      estate->es_select_into = false;
>>>      estate->es_into_oids = false;
>>>!
>>>      estate->es_exprcontexts = NIL;
>>>
>>>      estate->es_per_tuple_exprcontext = NULL;
>>>--- 203,210 ----
>>>      estate->es_instrument = false;
>>>      estate->es_select_into = false;
>>>      estate->es_into_oids = false;
>>>!     estate->es_nowait = false;
>>>!
>>>      estate->es_exprcontexts = NIL;
>>>
>>>      estate->es_per_tuple_exprcontext = NULL;
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/copyfuncs.c postgresql-8.0.0rc2/src/backend/nodes/copyfuncs.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/nodes/copyfuncs.c    Sun Dec 12 00:26:33 2004
>>>--- postgresql-8.0.0rc2/src/backend/nodes/copyfuncs.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 1426,1431 ****
>>>--- 1426,1442 ----
>>>      return newnode;
>>>  }
>>>
>>>+ static ForUpdate *
>>>+ _copyForUpdate(ForUpdate *from)
>>>+ {
>>>+     ForUpdate *newnode = makeNode(ForUpdate);
>>>+
>>>+     COPY_NODE_FIELD(update_list);
>>>+     COPY_SCALAR_FIELD(nowait);
>>>+
>>>+     return newnode;
>>>+ }
>>>+
>>>  static RangeSubselect *
>>>  _copyRangeSubselect(RangeSubselect *from)
>>>  {
>>>***************
>>>*** 1537,1542 ****
>>>--- 1548,1554 ----
>>>      COPY_NODE_FIELD(groupClause);
>>>      COPY_NODE_FIELD(havingQual);
>>>      COPY_NODE_FIELD(distinctClause);
>>>+     COPY_SCALAR_FIELD(nowait);
>>>      COPY_NODE_FIELD(sortClause);
>>>      COPY_NODE_FIELD(limitOffset);
>>>      COPY_NODE_FIELD(limitCount);
>>>***************
>>>*** 1611,1617 ****
>>>      COPY_NODE_FIELD(sortClause);
>>>      COPY_NODE_FIELD(limitOffset);
>>>      COPY_NODE_FIELD(limitCount);
>>>!     COPY_NODE_FIELD(forUpdate);
>>>      COPY_SCALAR_FIELD(op);
>>>      COPY_SCALAR_FIELD(all);
>>>      COPY_NODE_FIELD(larg);
>>>--- 1623,1629 ----
>>>      COPY_NODE_FIELD(sortClause);
>>>      COPY_NODE_FIELD(limitOffset);
>>>      COPY_NODE_FIELD(limitCount);
>>>!     COPY_NODE_FIELD(forupdateClause);
>>>      COPY_SCALAR_FIELD(op);
>>>      COPY_SCALAR_FIELD(all);
>>>      COPY_NODE_FIELD(larg);
>>>***************
>>>*** 3065,3070 ****
>>>--- 3077,3085 ----
>>>          case T_SortBy:
>>>              retval = _copySortBy(from);
>>>              break;
>>>+         case T_ForUpdate:
>>>+             retval = _copyForUpdate(from);
>>>+             break;
>>>          case T_RangeSubselect:
>>>              retval = _copyRangeSubselect(from);
>>>              break;
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/equalfuncs.c
postgresql-8.0.0rc2/src/backend/nodes/equalfuncs.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/nodes/equalfuncs.c    Sun Dec 12 00:26:33 2004
>>>--- postgresql-8.0.0rc2/src/backend/nodes/equalfuncs.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 656,661 ****
>>>--- 656,662 ----
>>>      COMPARE_NODE_FIELD(groupClause);
>>>      COMPARE_NODE_FIELD(havingQual);
>>>      COMPARE_NODE_FIELD(distinctClause);
>>>+     COMPARE_SCALAR_FIELD(nowait);
>>>      COMPARE_NODE_FIELD(sortClause);
>>>      COMPARE_NODE_FIELD(limitOffset);
>>>      COMPARE_NODE_FIELD(limitCount);
>>>***************
>>>*** 719,725 ****
>>>      COMPARE_NODE_FIELD(sortClause);
>>>      COMPARE_NODE_FIELD(limitOffset);
>>>      COMPARE_NODE_FIELD(limitCount);
>>>!     COMPARE_NODE_FIELD(forUpdate);
>>>      COMPARE_SCALAR_FIELD(op);
>>>      COMPARE_SCALAR_FIELD(all);
>>>      COMPARE_NODE_FIELD(larg);
>>>--- 720,726 ----
>>>      COMPARE_NODE_FIELD(sortClause);
>>>      COMPARE_NODE_FIELD(limitOffset);
>>>      COMPARE_NODE_FIELD(limitCount);
>>>!     COMPARE_NODE_FIELD(forupdateClause);
>>>      COMPARE_SCALAR_FIELD(op);
>>>      COMPARE_SCALAR_FIELD(all);
>>>      COMPARE_NODE_FIELD(larg);
>>>***************
>>>*** 1577,1582 ****
>>>--- 1578,1592 ----
>>>  }
>>>
>>>  static bool
>>>+ _equalForUpdate(ForUpdate *a, ForUpdate *b)
>>>+ {
>>>+     COMPARE_SCALAR_FIELD(nowait);
>>>+     COMPARE_NODE_FIELD(update_list);
>>>+
>>>+     return true;
>>>+ }
>>>+
>>>+ static bool
>>>  _equalRangeSubselect(RangeSubselect *a, RangeSubselect *b)
>>>  {
>>>      COMPARE_NODE_FIELD(subquery);
>>>***************
>>>*** 2202,2207 ****
>>>--- 2212,2220 ----
>>>          case T_SortBy:
>>>              retval = _equalSortBy(a, b);
>>>              break;
>>>+         case T_ForUpdate:
>>>+             retval = _equalForUpdate(a, b);
>>>+             break;
>>>          case T_RangeSubselect:
>>>              retval = _equalRangeSubselect(a, b);
>>>              break;
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/outfuncs.c postgresql-8.0.0rc2/src/backend/nodes/outfuncs.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/nodes/outfuncs.c    Sun Dec 12 00:26:33 2004
>>>--- postgresql-8.0.0rc2/src/backend/nodes/outfuncs.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 1202,1208 ****
>>>      WRITE_NODE_FIELD(sortClause);
>>>      WRITE_NODE_FIELD(limitOffset);
>>>      WRITE_NODE_FIELD(limitCount);
>>>!     WRITE_NODE_FIELD(forUpdate);
>>>      WRITE_ENUM_FIELD(op, SetOperation);
>>>      WRITE_BOOL_FIELD(all);
>>>      WRITE_NODE_FIELD(larg);
>>>--- 1202,1208 ----
>>>      WRITE_NODE_FIELD(sortClause);
>>>      WRITE_NODE_FIELD(limitOffset);
>>>      WRITE_NODE_FIELD(limitCount);
>>>!     WRITE_NODE_FIELD(forupdateClause);
>>>      WRITE_ENUM_FIELD(op, SetOperation);
>>>      WRITE_BOOL_FIELD(all);
>>>      WRITE_NODE_FIELD(larg);
>>>***************
>>>*** 1323,1328 ****
>>>--- 1323,1329 ----
>>>      WRITE_NODE_FIELD(groupClause);
>>>      WRITE_NODE_FIELD(havingQual);
>>>      WRITE_NODE_FIELD(distinctClause);
>>>+     WRITE_BOOL_FIELD(nowait);
>>>      WRITE_NODE_FIELD(sortClause);
>>>      WRITE_NODE_FIELD(limitOffset);
>>>      WRITE_NODE_FIELD(limitCount);
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/nodes/readfuncs.c postgresql-8.0.0rc2/src/backend/nodes/readfuncs.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/nodes/readfuncs.c    Sun Dec 12 00:26:34 2004
>>>--- postgresql-8.0.0rc2/src/backend/nodes/readfuncs.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 149,154 ****
>>>--- 149,155 ----
>>>      READ_NODE_FIELD(groupClause);
>>>      READ_NODE_FIELD(havingQual);
>>>      READ_NODE_FIELD(distinctClause);
>>>+     READ_BOOL_FIELD(nowait);
>>>      READ_NODE_FIELD(sortClause);
>>>      READ_NODE_FIELD(limitOffset);
>>>      READ_NODE_FIELD(limitCount);
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/analyze.c postgresql-8.0.0rc2/src/backend/parser/analyze.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/parser/analyze.c    Wed Nov 17 00:34:26 2004
>>>--- postgresql-8.0.0rc2/src/backend/parser/analyze.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 135,141 ****
>>>                         bool isAddConstraint);
>>>  static void applyColumnNames(List *dst, List *src);
>>>  static List *getSetColTypes(ParseState *pstate, Node *node);
>>>! static void transformForUpdate(Query *qry, List *forUpdate);
>>>  static void transformConstraintAttrs(List *constraintList);
>>>  static void transformColumnType(ParseState *pstate, ColumnDef *column);
>>>  static void release_pstate_resources(ParseState *pstate);
>>>--- 135,141 ----
>>>                         bool isAddConstraint);
>>>  static void applyColumnNames(List *dst, List *src);
>>>  static List *getSetColTypes(ParseState *pstate, Node *node);
>>>! static void transformForUpdate(Query *qry, Node *forupdateClause);
>>>  static void transformConstraintAttrs(List *constraintList);
>>>  static void transformColumnType(ParseState *pstate, ColumnDef *column);
>>>  static void release_pstate_resources(ParseState *pstate);
>>>***************
>>>*** 1804,1810 ****
>>>      qry->commandType = CMD_SELECT;
>>>
>>>      /* make FOR UPDATE clause available to addRangeTableEntry */
>>>!     pstate->p_forUpdate = stmt->forUpdate;
>>>
>>>      /* process the FROM clause */
>>>      transformFromClause(pstate, stmt->fromClause);
>>>--- 1804,1810 ----
>>>      qry->commandType = CMD_SELECT;
>>>
>>>      /* make FOR UPDATE clause available to addRangeTableEntry */
>>>!     pstate->p_forUpdate = stmt->forupdateClause ? ((ForUpdate *)stmt->forupdateClause)->update_list : NIL;
>>>
>>>      /* process the FROM clause */
>>>      transformFromClause(pstate, stmt->fromClause);
>>>***************
>>>*** 1864,1871 ****
>>>      if (pstate->p_hasAggs || qry->groupClause)
>>>          parseCheckAggregates(pstate, qry);
>>>
>>>!     if (stmt->forUpdate != NIL)
>>>!         transformForUpdate(qry, stmt->forUpdate);
>>>
>>>      return qry;
>>>  }
>>>--- 1864,1871 ----
>>>      if (pstate->p_hasAggs || qry->groupClause)
>>>          parseCheckAggregates(pstate, qry);
>>>
>>>!     if (stmt->forupdateClause)
>>>!         transformForUpdate(qry, stmt->forupdateClause);
>>>
>>>      return qry;
>>>  }
>>>***************
>>>*** 1893,1899 ****
>>>      List       *sortClause;
>>>      Node       *limitOffset;
>>>      Node       *limitCount;
>>>!     List       *forUpdate;
>>>      Node       *node;
>>>      ListCell   *left_tlist,
>>>                 *dtlist;
>>>--- 1893,1899 ----
>>>      List       *sortClause;
>>>      Node       *limitOffset;
>>>      Node       *limitCount;
>>>!     Node       *forUpdate;
>>>      Node       *node;
>>>      ListCell   *left_tlist,
>>>                 *dtlist;
>>>***************
>>>*** 1931,1942 ****
>>>      sortClause = stmt->sortClause;
>>>      limitOffset = stmt->limitOffset;
>>>      limitCount = stmt->limitCount;
>>>!     forUpdate = stmt->forUpdate;
>>>
>>>      stmt->sortClause = NIL;
>>>      stmt->limitOffset = NULL;
>>>      stmt->limitCount = NULL;
>>>!     stmt->forUpdate = NIL;
>>>
>>>      /* We don't support forUpdate with set ops at the moment. */
>>>      if (forUpdate)
>>>--- 1931,1942 ----
>>>      sortClause = stmt->sortClause;
>>>      limitOffset = stmt->limitOffset;
>>>      limitCount = stmt->limitCount;
>>>!     forUpdate = stmt->forupdateClause;
>>>
>>>      stmt->sortClause = NIL;
>>>      stmt->limitOffset = NULL;
>>>      stmt->limitCount = NULL;
>>>!     stmt->forupdateClause = NULL;
>>>
>>>      /* We don't support forUpdate with set ops at the moment. */
>>>      if (forUpdate)
>>>***************
>>>*** 2080,2086 ****
>>>      if (pstate->p_hasAggs || qry->groupClause)
>>>          parseCheckAggregates(pstate, qry);
>>>
>>>!     if (forUpdate != NIL)
>>>          transformForUpdate(qry, forUpdate);
>>>
>>>      return qry;
>>>--- 2080,2086 ----
>>>      if (pstate->p_hasAggs || qry->groupClause)
>>>          parseCheckAggregates(pstate, qry);
>>>
>>>!     if (forUpdate)
>>>          transformForUpdate(qry, forUpdate);
>>>
>>>      return qry;
>>>***************
>>>*** 2105,2111 ****
>>>                  (errcode(ERRCODE_SYNTAX_ERROR),
>>>                   errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
>>>      /* We don't support forUpdate with set ops at the moment. */
>>>!     if (stmt->forUpdate)
>>>          ereport(ERROR,
>>>                  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
>>>                   errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
>>>--- 2105,2111 ----
>>>                  (errcode(ERRCODE_SYNTAX_ERROR),
>>>                   errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
>>>      /* We don't support forUpdate with set ops at the moment. */
>>>!     if (stmt->forupdateClause)
>>>          ereport(ERROR,
>>>                  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
>>>                   errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
>>>***************
>>>*** 2125,2131 ****
>>>      {
>>>          Assert(stmt->larg != NULL && stmt->rarg != NULL);
>>>          if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
>>>!             stmt->forUpdate)
>>>              isLeaf = true;
>>>          else
>>>              isLeaf = false;
>>>--- 2125,2131 ----
>>>      {
>>>          Assert(stmt->larg != NULL && stmt->rarg != NULL);
>>>          if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
>>>!             stmt->forupdateClause)
>>>              isLeaf = true;
>>>          else
>>>              isLeaf = false;
>>>***************
>>>*** 2737,2752 ****
>>>   * in rewriteHandler.c.
>>>   */
>>>  static void
>>>! transformForUpdate(Query *qry, List *forUpdate)
>>>  {
>>>      List       *rowMarks = qry->rowMarks;
>>>      ListCell   *l;
>>>      ListCell   *rt;
>>>!     Index        i;
>>>
>>>      CheckSelectForUpdate(qry);
>>>
>>>!     if (linitial(forUpdate) == NULL)
>>>      {
>>>          /* all regular tables used in query */
>>>          i = 0;
>>>--- 2737,2761 ----
>>>   * in rewriteHandler.c.
>>>   */
>>>  static void
>>>! transformForUpdate(Query *qry, Node *forupdateClause)
>>>  {
>>>      List       *rowMarks = qry->rowMarks;
>>>      ListCell   *l;
>>>      ListCell   *rt;
>>>!     Index       i;
>>>!     ForUpdate  *fu = (ForUpdate *) forupdateClause;
>>>!     ForUpdate  empty;
>>>!     List       *update_list;
>>>
>>>      CheckSelectForUpdate(qry);
>>>
>>>!     update_list = fu->update_list;
>>>!     qry->nowait = fu->nowait;
>>>!
>>>!     memset(&empty, 0, sizeof(ForUpdate));
>>>!     empty.nowait = FALSE;
>>>!
>>>!     if (linitial(update_list) == NULL)
>>>      {
>>>          /* all regular tables used in query */
>>>          i = 0;
>>>***************
>>>*** 2768,2774 ****
>>>                       * FOR UPDATE of subquery is propagated to subquery's
>>>                       * rels
>>>                       */
>>>!                     transformForUpdate(rte->subquery, list_make1(NULL));
>>>                      break;
>>>                  default:
>>>                      /* ignore JOIN, SPECIAL, FUNCTION RTEs */
>>>--- 2777,2785 ----
>>>                       * FOR UPDATE of subquery is propagated to subquery's
>>>                       * rels
>>>                       */
>>>!                     empty.update_list = list_make1(NULL);
>>>!                     transformForUpdate(rte->subquery, (Node *) &empty);
>>>!                     empty.update_list = NIL;
>>>                      break;
>>>                  default:
>>>                      /* ignore JOIN, SPECIAL, FUNCTION RTEs */
>>>***************
>>>*** 2779,2785 ****
>>>      else
>>>      {
>>>          /* just the named tables */
>>>!         foreach(l, forUpdate)
>>>          {
>>>              char       *relname = strVal(lfirst(l));
>>>
>>>--- 2790,2796 ----
>>>      else
>>>      {
>>>          /* just the named tables */
>>>!         foreach(l, update_list)
>>>          {
>>>              char       *relname = strVal(lfirst(l));
>>>
>>>***************
>>>*** 2804,2810 ****
>>>                               * FOR UPDATE of subquery is propagated to
>>>                               * subquery's rels
>>>                               */
>>>!                             transformForUpdate(rte->subquery, list_make1(NULL));
>>>                              break;
>>>                          case RTE_JOIN:
>>>                              ereport(ERROR,
>>>--- 2815,2823 ----
>>>                               * FOR UPDATE of subquery is propagated to
>>>                               * subquery's rels
>>>                               */
>>>!                             empty.update_list = list_make1(NULL);
>>>!                             transformForUpdate(rte->subquery, (Node *) &empty);
>>>!                             empty.update_list = NULL;
>>>                              break;
>>>                          case RTE_JOIN:
>>>                              ereport(ERROR,
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/gram.y postgresql-8.0.0rc2/src/backend/parser/gram.y
>>>*** postgresql-8.0.0rc2.orig/src/backend/parser/gram.y    Mon Nov  8 05:02:20 2004
>>>--- postgresql-8.0.0rc2/src/backend/parser/gram.y    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 87,93 ****
>>>  static List *extractArgTypes(List *parameters);
>>>  static SelectStmt *findLeftmostSelect(SelectStmt *node);
>>>  static void insertSelectOptions(SelectStmt *stmt,
>>>!                                 List *sortClause, List *forUpdate,
>>>                                  Node *limitOffset, Node *limitCount);
>>>  static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
>>>  static Node *doNegate(Node *n);
>>>--- 87,93 ----
>>>  static List *extractArgTypes(List *parameters);
>>>  static SelectStmt *findLeftmostSelect(SelectStmt *node);
>>>  static void insertSelectOptions(SelectStmt *stmt,
>>>!                                 List *sortClause, Node *forUpdate,
>>>                                  Node *limitOffset, Node *limitCount);
>>>  static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
>>>  static Node *doNegate(Node *n);
>>>***************
>>>*** 239,245 ****
>>>  %type <oncommit> OnCommitOption
>>>  %type <withoids> OptWithOids WithOidsAs
>>>
>>>! %type <list>    for_update_clause opt_for_update_clause update_list
>>>  %type <boolean>    opt_all
>>>
>>>  %type <node>    join_outer join_qual
>>>--- 239,247 ----
>>>  %type <oncommit> OnCommitOption
>>>  %type <withoids> OptWithOids WithOidsAs
>>>
>>>! %type <node>    for_update_clause opt_for_update_clause
>>>! %type <list>    update_list
>>>!
>>>  %type <boolean>    opt_all
>>>
>>>  %type <node>    join_outer join_qual
>>>***************
>>>*** 4801,4807 ****
>>>              simple_select                        { $$ = $1; }
>>>              | select_clause sort_clause
>>>                  {
>>>!                     insertSelectOptions((SelectStmt *) $1, $2, NIL,
>>>                                          NULL, NULL);
>>>                      $$ = $1;
>>>                  }
>>>--- 4803,4809 ----
>>>              simple_select                        { $$ = $1; }
>>>              | select_clause sort_clause
>>>                  {
>>>!                     insertSelectOptions((SelectStmt *) $1, $2, NULL,
>>>                                          NULL, NULL);
>>>                      $$ = $1;
>>>                  }
>>>***************
>>>*** 4862,4867 ****
>>>--- 4864,4870 ----
>>>                      n->whereClause = $6;
>>>                      n->groupClause = $7;
>>>                      n->havingClause = $8;
>>>+                     n->forupdateClause = NULL;
>>>                      $$ = (Node *)n;
>>>                  }
>>>              | select_clause UNION opt_all select_clause
>>>***************
>>>*** 5053,5060 ****
>>>          ;
>>>
>>>  for_update_clause:
>>>!             FOR UPDATE update_list                    { $$ = $3; }
>>>!             | FOR READ ONLY                            { $$ = NULL; }
>>>          ;
>>>
>>>  opt_for_update_clause:
>>>--- 5056,5069 ----
>>>          ;
>>>
>>>  for_update_clause:
>>>!             FOR UPDATE update_list opt_nowait
>>>!                 {
>>>!                     ForUpdate *n = makeNode(ForUpdate);
>>>!                     n->update_list = $3;
>>>!                     n->nowait = $4;
>>>!                     $$ = (Node *) n;
>>>!                 }
>>>!             | FOR READ ONLY                            { $$ = NULL; }
>>>          ;
>>>
>>>  opt_for_update_clause:
>>>***************
>>>*** 8284,8290 ****
>>>   */
>>>  static void
>>>  insertSelectOptions(SelectStmt *stmt,
>>>!                     List *sortClause, List *forUpdate,
>>>                      Node *limitOffset, Node *limitCount)
>>>  {
>>>      /*
>>>--- 8293,8299 ----
>>>   */
>>>  static void
>>>  insertSelectOptions(SelectStmt *stmt,
>>>!                     List *sortClause, Node *forUpdate,
>>>                      Node *limitOffset, Node *limitCount)
>>>  {
>>>      /*
>>>***************
>>>*** 8301,8311 ****
>>>      }
>>>      if (forUpdate)
>>>      {
>>>!         if (stmt->forUpdate)
>>>              ereport(ERROR,
>>>                      (errcode(ERRCODE_SYNTAX_ERROR),
>>>                       errmsg("multiple FOR UPDATE clauses not allowed")));
>>>!         stmt->forUpdate = forUpdate;
>>>      }
>>>      if (limitOffset)
>>>      {
>>>--- 8310,8320 ----
>>>      }
>>>      if (forUpdate)
>>>      {
>>>!         if (stmt->forupdateClause)
>>>              ereport(ERROR,
>>>                      (errcode(ERRCODE_SYNTAX_ERROR),
>>>                       errmsg("multiple FOR UPDATE clauses not allowed")));
>>>!         stmt->forupdateClause = forUpdate;
>>>      }
>>>      if (limitOffset)
>>>      {
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/parser/parse_type.c
postgresql-8.0.0rc2/src/backend/parser/parse_type.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/parser/parse_type.c    Wed Dec 15 21:15:17 2004
>>>--- postgresql-8.0.0rc2/src/backend/parser/parse_type.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 432,438 ****
>>>          stmt->sortClause != NIL ||
>>>          stmt->limitOffset != NULL ||
>>>          stmt->limitCount != NULL ||
>>>!         stmt->forUpdate != NIL ||
>>>          stmt->op != SETOP_NONE)
>>>          goto fail;
>>>      if (list_length(stmt->targetList) != 1)
>>>--- 432,438 ----
>>>          stmt->sortClause != NIL ||
>>>          stmt->limitOffset != NULL ||
>>>          stmt->limitCount != NULL ||
>>>!         stmt->forupdateClause != NULL ||
>>>          stmt->op != SETOP_NONE)
>>>          goto fail;
>>>      if (list_length(stmt->targetList) != 1)
>>>diff -r -c postgresql-8.0.0rc2.orig/src/backend/storage/lmgr/lmgr.c
postgresql-8.0.0rc2/src/backend/storage/lmgr/lmgr.c
>>>*** postgresql-8.0.0rc2.orig/src/backend/storage/lmgr/lmgr.c    Thu Sep 16 18:58:33 2004
>>>--- postgresql-8.0.0rc2/src/backend/storage/lmgr/lmgr.c    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 393,395 ****
>>>--- 393,435 ----
>>>      if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
>>>          TransactionIdAbort(xid);
>>>  }
>>>+
>>>+ /*
>>>+  * As above, but only lock if we can get the lock without blocking.
>>>+  * Returns TRUE if the lock was acquired.
>>>+  */
>>>+ bool
>>>+ ConditionalXactLockTableWait(TransactionId xid)
>>>+ {
>>>+     LOCKTAG        tag;
>>>+     TransactionId myxid = GetTopTransactionId();
>>>+
>>>+     for (;;)
>>>+     {
>>>+         Assert(TransactionIdIsValid(xid));
>>>+         Assert(!TransactionIdEquals(xid, myxid));
>>>+
>>>+         MemSet(&tag, 0, sizeof(tag));
>>>+         tag.relId = XactLockTableId;
>>>+         tag.dbId = InvalidOid;
>>>+         tag.objId.xid = xid;
>>>+
>>>+         if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, true))
>>>+             return FALSE;
>>>+         LockRelease(LockTableId, &tag, myxid, ShareLock);
>>>+
>>>+         if (!TransactionIdIsInProgress(xid))
>>>+             break;
>>>+         xid = SubTransGetParent(xid);
>>>+     }
>>>+
>>>+     /*
>>>+      * Transaction was committed/aborted/crashed - we have to update
>>>+      * pg_clog if transaction is still marked as running.
>>>+      */
>>>+     if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
>>>+         TransactionIdAbort(xid);
>>>+
>>>+     return TRUE;
>>>+ }
>>>+
>>>diff -r -c postgresql-8.0.0rc2.orig/src/bin/psql/sql_help.h postgresql-8.0.0rc2/src/bin/psql/sql_help.h
>>>*** postgresql-8.0.0rc2.orig/src/bin/psql/sql_help.h    Tue Dec 21 05:22:44 2004
>>>--- postgresql-8.0.0rc2/src/bin/psql/sql_help.h    Mon Dec 27 10:57:05 2004
>>>***************
>>>*** 383,393 ****
>>>
>>>      { "SELECT",
>>>        N_("retrieve rows from a table or view"),
>>>!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n
  [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP BY expression [, ...] ]\n    [ HAVING condition [,
...]]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [ ORDER BY expression [ ASC | DESC | USING operator ]
[,...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n    [ FOR UPDATE [ OF table_name [, ...] ] ]\n\nwhere
from_itemcan be one of:\n\n    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]\n    ( select )
[AS ] alias [ ( column_alias [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [,
...]| column_definition [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )\n
from_item[ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]") }, 
>>>
>>>      { "SELECT INTO",
>>>        N_("define a new table from the results of a query"),
>>>!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n
  INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table\n    [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP
BYexpression [, ...] ]\n    [ HAVING condition [, ...] ]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [
ORDERBY expression [ ASC | DESC | USING operator ] [, ...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n
[FOR UPDATE [ OF tablename [, ...] ] ]") }, 
>>>
>>>      { "SET",
>>>        N_("change a run-time parameter"),
>>>--- 383,393 ----
>>>
>>>      { "SELECT",
>>>        N_("retrieve rows from a table or view"),
>>>!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n
  [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP BY expression [, ...] ]\n    [ HAVING condition [,
...]]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [ ORDER BY expression [ ASC | DESC | USING operator ]
[,...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n    [ FOR UPDATE [ OF table_name [, ...] ] [NOWAIT]
]\n\nwherefrom_item can be one of:\n\n    [ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]\n
(select ) [ AS ] alias [ ( column_alias [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) [ AS ] alias [ (
column_alias[, ...] | column_definition [, ...] ) ]\n    function_name ( [ argument [, ...] ] ) AS ( column_definition
[,...] )\n    from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]") }, 
>>>
>>>      { "SELECT INTO",
>>>        N_("define a new table from the results of a query"),
>>>!       N_("SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]\n    * | expression [ AS output_name ] [, ...]\n
  INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table\n    [ FROM from_item [, ...] ]\n    [ WHERE condition ]\n    [ GROUP
BYexpression [, ...] ]\n    [ HAVING condition [, ...] ]\n    [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]\n    [
ORDERBY expression [ ASC | DESC | USING operator ] [, ...] ]\n    [ LIMIT { count | ALL } ]\n    [ OFFSET start ]\n
[FOR UPDATE [ OF tablename [, ...] ] [NOWAIT] ]") }, 
>>>
>>>      { "SET",
>>>        N_("change a run-time parameter"),
>>>diff -r -c postgresql-8.0.0rc2.orig/src/include/access/heapam.h postgresql-8.0.0rc2/src/include/access/heapam.h
>>>*** postgresql-8.0.0rc2.orig/src/include/access/heapam.h    Sun Aug 29 07:06:55 2004
>>>--- postgresql-8.0.0rc2/src/include/access/heapam.h    Mon Dec 27 10:57:05 2004
>>>***************
>>>*** 164,170 ****
>>>  extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
>>>          ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool wait);
>>>  extern int heap_mark4update(Relation relation, HeapTuple tup,
>>>!                  Buffer *userbuf, CommandId cid);
>>>
>>>  extern Oid    simple_heap_insert(Relation relation, HeapTuple tup);
>>>  extern void simple_heap_delete(Relation relation, ItemPointer tid);
>>>--- 164,170 ----
>>>  extern int heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
>>>          ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool wait);
>>>  extern int heap_mark4update(Relation relation, HeapTuple tup,
>>>!                  Buffer *userbuf, CommandId cid, bool nowait);
>>>
>>>  extern Oid    simple_heap_insert(Relation relation, HeapTuple tup);
>>>  extern void simple_heap_delete(Relation relation, ItemPointer tid);
>>>diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/execnodes.h postgresql-8.0.0rc2/src/include/nodes/execnodes.h
>>>*** postgresql-8.0.0rc2.orig/src/include/nodes/execnodes.h    Sun Dec 12 00:26:49 2004
>>>--- postgresql-8.0.0rc2/src/include/nodes/execnodes.h    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 308,313 ****
>>>--- 308,314 ----
>>>      bool        es_instrument;    /* true requests runtime instrumentation */
>>>      bool        es_select_into; /* true if doing SELECT INTO */
>>>      bool        es_into_oids;    /* true to generate OIDs in SELECT INTO */
>>>+     bool        es_nowait;    /* SELECT FOR UPDATE NOWAIT */
>>>
>>>      List       *es_exprcontexts;    /* List of ExprContexts within EState */
>>>
>>>diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/nodes.h postgresql-8.0.0rc2/src/include/nodes/nodes.h
>>>*** postgresql-8.0.0rc2.orig/src/include/nodes/nodes.h    Sun Dec 12 00:26:49 2004
>>>--- postgresql-8.0.0rc2/src/include/nodes/nodes.h    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 302,307 ****
>>>--- 302,308 ----
>>>      T_CompositeTypeStmt,
>>>      T_InhRelation,
>>>      T_FunctionParameter,
>>>+     T_ForUpdate,
>>>
>>>      /*
>>>       * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
>>>diff -r -c postgresql-8.0.0rc2.orig/src/include/nodes/parsenodes.h
postgresql-8.0.0rc2/src/include/nodes/parsenodes.h
>>>*** postgresql-8.0.0rc2.orig/src/include/nodes/parsenodes.h    Fri Nov  5 20:16:38 2004
>>>--- postgresql-8.0.0rc2/src/include/nodes/parsenodes.h    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 103,108 ****
>>>--- 103,110 ----
>>>
>>>      List       *sortClause;        /* a list of SortClause's */
>>>
>>>+     bool       nowait;        /* are we in NOWAIT mode? */
>>>+
>>>      Node       *limitOffset;    /* # of result tuples to skip */
>>>      Node       *limitCount;        /* # of result tuples to return */
>>>
>>>***************
>>>*** 422,427 ****
>>>--- 424,439 ----
>>>      Node       *arg;            /* a (Value *) or a (TypeName *) */
>>>  } DefElem;
>>>
>>>+ /*
>>>+  * ForUpdate -
>>>+  *       used in raw parsetrees output only
>>>+  */
>>>+ typedef struct ForUpdate
>>>+ {
>>>+     NodeTag        type;
>>>+     List        *update_list;    /* list of tables */
>>>+     bool        nowait;        /* NOWAIT option */
>>>+ } ForUpdate;
>>>
>>>  /****************************************************************************
>>>   *    Nodes for a Query tree
>>>***************
>>>*** 686,692 ****
>>>      List       *sortClause;        /* sort clause (a list of SortBy's) */
>>>      Node       *limitOffset;    /* # of result tuples to skip */
>>>      Node       *limitCount;        /* # of result tuples to return */
>>>!     List       *forUpdate;        /* FOR UPDATE clause */
>>>
>>>      /*
>>>       * These fields are used only in upper-level SelectStmts.
>>>--- 698,704 ----
>>>      List       *sortClause;        /* sort clause (a list of SortBy's) */
>>>      Node       *limitOffset;    /* # of result tuples to skip */
>>>      Node       *limitCount;        /* # of result tuples to return */
>>>!     Node       *forupdateClause;    /* FOR UPDATE clause (ForUpdate node) */
>>>
>>>      /*
>>>       * These fields are used only in upper-level SelectStmts.
>>>diff -r -c postgresql-8.0.0rc2.orig/src/include/storage/lmgr.h postgresql-8.0.0rc2/src/include/storage/lmgr.h
>>>*** postgresql-8.0.0rc2.orig/src/include/storage/lmgr.h    Thu Sep 16 18:58:42 2004
>>>--- postgresql-8.0.0rc2/src/include/storage/lmgr.h    Mon Dec 27 10:56:52 2004
>>>***************
>>>*** 60,64 ****
>>>--- 60,65 ----
>>>  extern void XactLockTableInsert(TransactionId xid);
>>>  extern void XactLockTableDelete(TransactionId xid);
>>>  extern void XactLockTableWait(TransactionId xid);
>>>+ extern bool ConditionalXactLockTableWait(TransactionId xid);
>>>
>>>  #endif   /* LMGR_H */
>>>
>>>
>>--
>>  Bruce Momjian                        |  http://candle.pha.pa.us
>>  pgman@candle.pha.pa.us               |  (610) 359-1001
>>  +  If your life is a hard drive,     |  13 Roberts Road
>>  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
>>
>>---------------------------(end of broadcast)---------------------------
>>TIP 4: Don't 'kill -9' the postmaster
>>
>>
>>
>
>
>


--
Cybertec Geschwinde u Schoenig
Schoengrabern 134, A-2020 Hollabrunn, Austria
Tel: +43/664/393 39 74
www.cybertec.at, www.postgresql.at




pgsql-patches by date:

Previous
From: Petr Jelínek
Date:
Subject: [PATCH] fix for pg_stat_database (numbackends is always zero)
Next
From: Tom Lane
Date:
Subject: Re: [BUGS] BUG #1707: statistics collector starts with stats_start_collector