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