Re: Implementing SELECT FOR UPDATE [NOWAIT]

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Hans-Juergen Schoenig <hs(at)cybertec(dot)at>
Cc: pgsql-patches(at)postgresql(dot)org, eg(at)cybertec(dot)at
Subject: Re: Implementing SELECT FOR UPDATE [NOWAIT]
Date: 2005-06-10 16:01:02
Message-ID: 200506101601.j5AG12329341@candle.pha.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches


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

In response to

Responses

Browse pgsql-patches by date

  From Date Subject
Next Message Bruce Momjian 2005-06-10 16:11:33 Re: Grammer Cleanup
Previous Message Alvaro Herrera 2005-06-10 16:00:10 Re: bugfix: character-code conversion of MIC -> EUC_JP.