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_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 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 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\nwhere from_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 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 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

Reply via email to