Re: Implementing SELECT FOR UPDATE [NOWAIT]

From: Hans-Juergen Schoenig <hs(at)cybertec(dot)at>
To: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
Cc: pgsql-patches(at)postgresql(dot)org, eg(at)cybertec(dot)at
Subject: Re: Implementing SELECT FOR UPDATE [NOWAIT]
Date: 2005-06-25 06:40:45
Message-ID: 42BCFC6D.9000905@cybertec.at
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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_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(at)candle(dot)pha(dot)pa(dot)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

In response to

Responses

Browse pgsql-patches by date

  From Date Subject
Next Message Luke Lonergan 2005-06-25 08:20:14 Re: COPY FROM performance improvements
Previous Message Luke Lonergan 2005-06-25 05:40:28 Re: COPY FROM performance improvements