Re: Implementing SELECT FOR UPDATE [NOWAIT] - Mailing list pgsql-patches
From | Karel Zak |
---|---|
Subject | Re: Implementing SELECT FOR UPDATE [NOWAIT] |
Date | |
Msg-id | 1119880134.3806.72.camel@petra Whole thread Raw |
In response to | Re: Implementing SELECT FOR UPDATE [NOWAIT] (Bruce Momjian <pgman@candle.pha.pa.us>) |
List | pgsql-patches |
On Fri, 2005-06-24 at 22:32 -0400, Bruce Momjian wrote: > Are you working on a updated version of this? I will work on new version during this week. Karel > --------------------------------------------------------------------------- > > 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 | USINGoperator ] [, ...] ]\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 [ GROUPBY 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 | USINGoperator ] [, ...] ]\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 [ GROUPBY 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 > > > > -- > 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 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 -- Karel Zak <zakkr@zf.jcu.cz>
pgsql-patches by date: