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_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




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




---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
      choose an index scan if your joining column's datatypes do not
      match

Reply via email to