Commit 2a4fad1a authored by Tom Lane's avatar Tom Lane

Add NOWAIT option to SELECT FOR UPDATE/SHARE.

Original patch by Hans-Juergen Schoenig, revisions by Karel Zak
and Tom Lane.
parent ca7abcd8
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.88 2005/07/14 06:17:36 neilc Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.89 2005/08/01 20:31:04 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -30,7 +30,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replac ...@@ -30,7 +30,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replac
[ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ] [ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ] [ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="parameter">start</replaceable> ] [ OFFSET <replaceable class="parameter">start</replaceable> ]
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ] [ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
where <replaceable class="parameter">from_item</replaceable> can be one of: where <replaceable class="parameter">from_item</replaceable> can be one of:
...@@ -151,7 +151,7 @@ where <replaceable class="parameter">from_item</replaceable> can be one of: ...@@ -151,7 +151,7 @@ where <replaceable class="parameter">from_item</replaceable> can be one of:
</listitem> </listitem>
</orderedlist> </orderedlist>
</para> </para>
<para> <para>
You must have <literal>SELECT</literal> privilege on a table to You must have <literal>SELECT</literal> privilege on a table to
read its values. The use of <literal>FOR UPDATE</literal> or read its values. The use of <literal>FOR UPDATE</literal> or
...@@ -506,7 +506,7 @@ HAVING <replaceable class="parameter">condition</replaceable> ...@@ -506,7 +506,7 @@ HAVING <replaceable class="parameter">condition</replaceable>
<replaceable class="parameter">select_statement</replaceable> is <replaceable class="parameter">select_statement</replaceable> is
any <command>SELECT</command> statement without an <literal>ORDER any <command>SELECT</command> statement without an <literal>ORDER
BY</>, <literal>LIMIT</>, <literal>FOR UPDATE</literal>, or BY</>, <literal>LIMIT</>, <literal>FOR UPDATE</literal>, or
<literal>FOR SHARE</literal> clause. <literal>FOR SHARE</literal> clause.
(<literal>ORDER BY</> and <literal>LIMIT</> can be attached to a (<literal>ORDER BY</> and <literal>LIMIT</> can be attached to a
subexpression if it is enclosed in parentheses. Without subexpression if it is enclosed in parentheses. Without
parentheses, these clauses will be taken to apply to the result of parentheses, these clauses will be taken to apply to the result of
...@@ -803,14 +803,14 @@ OFFSET <replaceable class="parameter">start</replaceable> ...@@ -803,14 +803,14 @@ OFFSET <replaceable class="parameter">start</replaceable>
<para> <para>
The <literal>FOR UPDATE</literal> clause has this form: The <literal>FOR UPDATE</literal> clause has this form:
<synopsis> <synopsis>
FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ]
</synopsis> </synopsis>
</para> </para>
<para> <para>
The closely related <literal>FOR SHARE</literal> clause has this form: The closely related <literal>FOR SHARE</literal> clause has this form:
<synopsis> <synopsis>
FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ]
</synopsis> </synopsis>
</para> </para>
...@@ -831,6 +831,18 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ...@@ -831,6 +831,18 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
linkend="mvcc">. linkend="mvcc">.
</para> </para>
<para>
To prevent the operation from waiting for other transactions to commit,
use the <literal>NOWAIT</> option. <command>SELECT FOR UPDATE
NOWAIT</command> reports an error, rather than waiting, if a selected row
cannot be locked immediately. Note that <literal>NOWAIT</> applies only
to the row-level lock(s) &mdash; the required <literal>ROW SHARE</literal>
table-level lock is still taken in the ordinary way (see
<xref linkend="mvcc">). You can use the <literal>NOWAIT</> option of
<xref linkend="sql-lock" endterm="sql-lock-title">
if you need to acquire the table-level lock without waiting.
</para>
<para> <para>
<literal>FOR SHARE</literal> behaves similarly, except that it <literal>FOR SHARE</literal> behaves similarly, except that it
acquires a shared rather than exclusive lock on each retrieved acquires a shared rather than exclusive lock on each retrieved
...@@ -843,7 +855,8 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ...@@ -843,7 +855,8 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
<para> <para>
It is currently not allowed for a single <command>SELECT</command> It is currently not allowed for a single <command>SELECT</command>
statement to include both <literal>FOR UPDATE</literal> and statement to include both <literal>FOR UPDATE</literal> and
<literal>FOR SHARE</literal>. <literal>FOR SHARE</literal>, nor can different parts of the statement use
both <literal>NOWAIT</> and normal waiting mode.
</para> </para>
<para> <para>
...@@ -861,8 +874,8 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ...@@ -861,8 +874,8 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
</para> </para>
<para> <para>
It is possible for a <command>SELECT</> command using both It is possible for a <command>SELECT</> command using both
<literal>LIMIT</literal> and <literal>FOR UPDATE/SHARE</literal> <literal>LIMIT</literal> and <literal>FOR UPDATE/SHARE</literal>
clauses to return fewer rows than specified by <literal>LIMIT</literal>. clauses to return fewer rows than specified by <literal>LIMIT</literal>.
This is because <literal>LIMIT</> is applied first. The command This is because <literal>LIMIT</> is applied first. The command
selects the specified number of rows, selects the specified number of rows,
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.35 2005/04/28 21:47:10 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.36 2005/08/01 20:31:04 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -31,7 +31,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac ...@@ -31,7 +31,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ] [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ] [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ] [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
[ FOR { UPDATE | SHARE } [ OF <replaceable class="PARAMETER">tablename</replaceable> [, ...] ] ] [ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.37 2005/07/14 06:17:35 neilc Exp $ $PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.38 2005/08/01 20:31:05 tgl Exp $
--> -->
<chapter id="sql-intro"> <chapter id="sql-intro">
...@@ -865,7 +865,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac ...@@ -865,7 +865,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ] [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ] [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ] [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
[ FOR { UPDATE | SHARE } [ OF <replaceable class="PARAMETER">class_name</replaceable> [, ...] ] ] [ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
</synopsis> </synopsis>
</para> </para>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.195 2005/06/20 18:37:01 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.196 2005/08/01 20:31:05 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1945,7 +1945,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup) ...@@ -1945,7 +1945,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
*/ */
HTSU_Result HTSU_Result
heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer, heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
CommandId cid, LockTupleMode mode) CommandId cid, LockTupleMode mode, bool nowait)
{ {
HTSU_Result result; HTSU_Result result;
ItemPointer tid = &(tuple->t_self); ItemPointer tid = &(tuple->t_self);
...@@ -1998,7 +1998,16 @@ l3: ...@@ -1998,7 +1998,16 @@ l3:
*/ */
if (!have_tuple_lock) if (!have_tuple_lock)
{ {
LockTuple(relation, tid, tuple_lock_type); if (nowait)
{
if (!ConditionalLockTuple(relation, tid, tuple_lock_type))
ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on row in relation \"%s\"",
RelationGetRelationName(relation))));
}
else
LockTuple(relation, tid, tuple_lock_type);
have_tuple_lock = true; have_tuple_lock = true;
} }
...@@ -2020,7 +2029,17 @@ l3: ...@@ -2020,7 +2029,17 @@ l3:
else if (infomask & HEAP_XMAX_IS_MULTI) else if (infomask & HEAP_XMAX_IS_MULTI)
{ {
/* wait for multixact to end */ /* wait for multixact to end */
MultiXactIdWait((MultiXactId) xwait); if (nowait)
{
if (!ConditionalMultiXactIdWait((MultiXactId) xwait))
ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on row in relation \"%s\"",
RelationGetRelationName(relation))));
}
else
MultiXactIdWait((MultiXactId) xwait);
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
/* /*
...@@ -2045,7 +2064,17 @@ l3: ...@@ -2045,7 +2064,17 @@ l3:
else else
{ {
/* wait for regular transaction to end */ /* wait for regular transaction to end */
XactLockTableWait(xwait); if (nowait)
{
if (!ConditionalXactLockTableWait(xwait))
ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on row in relation \"%s\"",
RelationGetRelationName(relation))));
}
else
XactLockTableWait(xwait);
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
/* /*
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.5 2005/06/08 15:50:25 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.6 2005/08/01 20:31:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -558,6 +558,43 @@ MultiXactIdWait(MultiXactId multi) ...@@ -558,6 +558,43 @@ MultiXactIdWait(MultiXactId multi)
} }
} }
/*
* ConditionalMultiXactIdWait
* As above, but only lock if we can get the lock without blocking.
*/
bool
ConditionalMultiXactIdWait(MultiXactId multi)
{
bool result = true;
TransactionId *members;
int nmembers;
nmembers = GetMultiXactIdMembers(multi, &members);
if (nmembers >= 0)
{
int i;
for (i = 0; i < nmembers; i++)
{
TransactionId member = members[i];
debug_elog4(DEBUG2, "ConditionalMultiXactIdWait: trying %d (%u)",
i, member);
if (!TransactionIdIsCurrentTransactionId(member))
{
result = ConditionalXactLockTableWait(member);
if (!result)
break;
}
}
pfree(members);
}
return result;
}
/* /*
* CreateMultiXactId * CreateMultiXactId
* Make a new MultiXactId * Make a new MultiXactId
...@@ -590,7 +627,7 @@ CreateMultiXactId(int nxids, TransactionId *xids) ...@@ -590,7 +627,7 @@ CreateMultiXactId(int nxids, TransactionId *xids)
*/ */
multi = mXactCacheGetBySet(nxids, xids); multi = mXactCacheGetBySet(nxids, xids);
if (MultiXactIdIsValid(multi)) if (MultiXactIdIsValid(multi))
{ {
debug_elog2(DEBUG2, "Create: in cache!"); debug_elog2(DEBUG2, "Create: in cache!");
return multi; return multi;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.189 2005/05/30 07:20:58 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.190 2005/08/01 20:31:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1598,7 +1598,8 @@ GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo, ...@@ -1598,7 +1598,8 @@ GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
*newSlot = NULL; *newSlot = NULL;
tuple.t_self = *tid; tuple.t_self = *tid;
ltrmark:; ltrmark:;
test = heap_lock_tuple(relation, &tuple, &buffer, cid, LockTupleExclusive); test = heap_lock_tuple(relation, &tuple, &buffer, cid,
LockTupleExclusive, false);
switch (test) switch (test)
{ {
case HeapTupleSelfUpdated: case HeapTupleSelfUpdated:
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.251 2005/06/28 05:08:55 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.252 2005/08/01 20:31:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -559,8 +559,9 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) ...@@ -559,8 +559,9 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
/* /*
* Have to lock relations selected FOR UPDATE/FOR SHARE * Have to lock relations selected FOR UPDATE/FOR SHARE
*/ */
estate->es_rowMark = NIL; estate->es_rowMarks = NIL;
estate->es_forUpdate = parseTree->forUpdate; estate->es_forUpdate = parseTree->forUpdate;
estate->es_rowNoWait = parseTree->rowNoWait;
if (parseTree->rowMarks != NIL) if (parseTree->rowMarks != NIL)
{ {
ListCell *l; ListCell *l;
...@@ -577,7 +578,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) ...@@ -577,7 +578,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
erm->relation = relation; erm->relation = relation;
erm->rti = rti; erm->rti = rti;
snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti); snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti);
estate->es_rowMark = lappend(estate->es_rowMark, erm); estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
} }
} }
...@@ -1010,12 +1011,12 @@ ExecEndPlan(PlanState *planstate, EState *estate) ...@@ -1010,12 +1011,12 @@ ExecEndPlan(PlanState *planstate, EState *estate)
} }
heap_close(estate->es_into_relation_descriptor, NoLock); heap_close(estate->es_into_relation_descriptor, NoLock);
} }
/* /*
* close any relations selected FOR UPDATE/FOR SHARE, again keeping locks * close any relations selected FOR UPDATE/FOR SHARE, again keeping locks
*/ */
foreach(l, estate->es_rowMark) foreach(l, estate->es_rowMarks)
{ {
execRowMark *erm = lfirst(l); execRowMark *erm = lfirst(l);
...@@ -1156,12 +1157,12 @@ lnext: ; ...@@ -1156,12 +1157,12 @@ lnext: ;
/* /*
* Process any FOR UPDATE or FOR SHARE locking requested. * Process any FOR UPDATE or FOR SHARE locking requested.
*/ */
else if (estate->es_rowMark != NIL) else if (estate->es_rowMarks != NIL)
{ {
ListCell *l; ListCell *l;
lmark: ; lmark: ;
foreach(l, estate->es_rowMark) foreach(l, estate->es_rowMarks)
{ {
execRowMark *erm = lfirst(l); execRowMark *erm = lfirst(l);
Buffer buffer; Buffer buffer;
...@@ -1190,7 +1191,7 @@ lnext: ; ...@@ -1190,7 +1191,7 @@ lnext: ;
tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
test = heap_lock_tuple(erm->relation, &tuple, &buffer, test = heap_lock_tuple(erm->relation, &tuple, &buffer,
estate->es_snapshot->curcid, estate->es_snapshot->curcid,
lockmode); lockmode, estate->es_rowNoWait);
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
switch (test) switch (test)
{ {
...@@ -1823,7 +1824,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid) ...@@ -1823,7 +1824,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
ListCell *l; ListCell *l;
relation = NULL; relation = NULL;
foreach(l, estate->es_rowMark) foreach(l, estate->es_rowMarks)
{ {
if (((execRowMark *) lfirst(l))->rti == rti) if (((execRowMark *) lfirst(l))->rti == rti)
{ {
...@@ -2128,8 +2129,9 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq) ...@@ -2128,8 +2129,9 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
if (estate->es_topPlan->nParamExec > 0) if (estate->es_topPlan->nParamExec > 0)
epqstate->es_param_exec_vals = (ParamExecData *) epqstate->es_param_exec_vals = (ParamExecData *)
palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData)); palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
epqstate->es_rowMark = estate->es_rowMark; epqstate->es_rowMarks = estate->es_rowMarks;
epqstate->es_forUpdate = estate->es_forUpdate; epqstate->es_forUpdate = estate->es_forUpdate;
epqstate->es_rowNoWait = estate->es_rowNoWait;
epqstate->es_instrument = estate->es_instrument; epqstate->es_instrument = estate->es_instrument;
epqstate->es_select_into = estate->es_select_into; epqstate->es_select_into = estate->es_select_into;
epqstate->es_into_oids = estate->es_into_oids; epqstate->es_into_oids = estate->es_into_oids;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.124 2005/06/20 18:37:01 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.125 2005/08/01 20:31:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -199,8 +199,9 @@ CreateExecutorState(void) ...@@ -199,8 +199,9 @@ CreateExecutorState(void)
estate->es_processed = 0; estate->es_processed = 0;
estate->es_lastoid = InvalidOid; estate->es_lastoid = InvalidOid;
estate->es_rowMark = NIL; estate->es_rowMarks = NIL;
estate->es_forUpdate = false; estate->es_forUpdate = false;
estate->es_rowNoWait = false;
estate->es_instrument = false; estate->es_instrument = false;
estate->es_select_into = false; estate->es_select_into = false;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.314 2005/08/01 04:03:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.315 2005/08/01 20:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1589,6 +1589,18 @@ _copyDefElem(DefElem *from) ...@@ -1589,6 +1589,18 @@ _copyDefElem(DefElem *from)
return newnode; return newnode;
} }
static LockingClause *
_copyLockingClause(LockingClause *from)
{
LockingClause *newnode = makeNode(LockingClause);
COPY_NODE_FIELD(lockedRels);
COPY_SCALAR_FIELD(forUpdate);
COPY_SCALAR_FIELD(nowait);
return newnode;
}
static Query * static Query *
_copyQuery(Query *from) _copyQuery(Query *from)
{ {
...@@ -1607,6 +1619,7 @@ _copyQuery(Query *from) ...@@ -1607,6 +1619,7 @@ _copyQuery(Query *from)
COPY_NODE_FIELD(jointree); COPY_NODE_FIELD(jointree);
COPY_NODE_FIELD(rowMarks); COPY_NODE_FIELD(rowMarks);
COPY_SCALAR_FIELD(forUpdate); COPY_SCALAR_FIELD(forUpdate);
COPY_SCALAR_FIELD(rowNoWait);
COPY_NODE_FIELD(targetList); COPY_NODE_FIELD(targetList);
COPY_NODE_FIELD(groupClause); COPY_NODE_FIELD(groupClause);
COPY_NODE_FIELD(havingQual); COPY_NODE_FIELD(havingQual);
...@@ -1675,8 +1688,7 @@ _copySelectStmt(SelectStmt *from) ...@@ -1675,8 +1688,7 @@ _copySelectStmt(SelectStmt *from)
COPY_NODE_FIELD(sortClause); COPY_NODE_FIELD(sortClause);
COPY_NODE_FIELD(limitOffset); COPY_NODE_FIELD(limitOffset);
COPY_NODE_FIELD(limitCount); COPY_NODE_FIELD(limitCount);
COPY_NODE_FIELD(lockedRels); COPY_NODE_FIELD(lockingClause);
COPY_SCALAR_FIELD(forUpdate);
COPY_SCALAR_FIELD(op); COPY_SCALAR_FIELD(op);
COPY_SCALAR_FIELD(all); COPY_SCALAR_FIELD(all);
COPY_NODE_FIELD(larg); COPY_NODE_FIELD(larg);
...@@ -3185,6 +3197,9 @@ copyObject(void *from) ...@@ -3185,6 +3197,9 @@ copyObject(void *from)
case T_DefElem: case T_DefElem:
retval = _copyDefElem(from); retval = _copyDefElem(from);
break; break;
case T_LockingClause:
retval = _copyLockingClause(from);
break;
case T_RangeTblEntry: case T_RangeTblEntry:
retval = _copyRangeTblEntry(from); retval = _copyRangeTblEntry(from);
break; break;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.251 2005/08/01 04:03:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.252 2005/08/01 20:31:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -644,6 +644,7 @@ _equalQuery(Query *a, Query *b) ...@@ -644,6 +644,7 @@ _equalQuery(Query *a, Query *b)
COMPARE_NODE_FIELD(jointree); COMPARE_NODE_FIELD(jointree);
COMPARE_NODE_FIELD(rowMarks); COMPARE_NODE_FIELD(rowMarks);
COMPARE_SCALAR_FIELD(forUpdate); COMPARE_SCALAR_FIELD(forUpdate);
COMPARE_SCALAR_FIELD(rowNoWait);
COMPARE_NODE_FIELD(targetList); COMPARE_NODE_FIELD(targetList);
COMPARE_NODE_FIELD(groupClause); COMPARE_NODE_FIELD(groupClause);
COMPARE_NODE_FIELD(havingQual); COMPARE_NODE_FIELD(havingQual);
...@@ -704,8 +705,7 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b) ...@@ -704,8 +705,7 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
COMPARE_NODE_FIELD(sortClause); COMPARE_NODE_FIELD(sortClause);
COMPARE_NODE_FIELD(limitOffset); COMPARE_NODE_FIELD(limitOffset);
COMPARE_NODE_FIELD(limitCount); COMPARE_NODE_FIELD(limitCount);
COMPARE_NODE_FIELD(lockedRels); COMPARE_NODE_FIELD(lockingClause);
COMPARE_SCALAR_FIELD(forUpdate);
COMPARE_SCALAR_FIELD(op); COMPARE_SCALAR_FIELD(op);
COMPARE_SCALAR_FIELD(all); COMPARE_SCALAR_FIELD(all);
COMPARE_NODE_FIELD(larg); COMPARE_NODE_FIELD(larg);
...@@ -1649,6 +1649,16 @@ _equalDefElem(DefElem *a, DefElem *b) ...@@ -1649,6 +1649,16 @@ _equalDefElem(DefElem *a, DefElem *b)
return true; return true;
} }
static bool
_equalLockingClause(LockingClause *a, LockingClause *b)
{
COMPARE_NODE_FIELD(lockedRels);
COMPARE_SCALAR_FIELD(forUpdate);
COMPARE_SCALAR_FIELD(nowait);
return true;
}
static bool static bool
_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
{ {
...@@ -2229,6 +2239,9 @@ equal(void *a, void *b) ...@@ -2229,6 +2239,9 @@ equal(void *a, void *b)
case T_DefElem: case T_DefElem:
retval = _equalDefElem(a, b); retval = _equalDefElem(a, b);
break; break;
case T_LockingClause:
retval = _equalLockingClause(a, b);
break;
case T_RangeTblEntry: case T_RangeTblEntry:
retval = _equalRangeTblEntry(a, b); retval = _equalRangeTblEntry(a, b);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.258 2005/07/02 23:00:39 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.259 2005/08/01 20:31:08 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1343,8 +1343,7 @@ _outSelectStmt(StringInfo str, SelectStmt *node) ...@@ -1343,8 +1343,7 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
WRITE_NODE_FIELD(sortClause); WRITE_NODE_FIELD(sortClause);
WRITE_NODE_FIELD(limitOffset); WRITE_NODE_FIELD(limitOffset);
WRITE_NODE_FIELD(limitCount); WRITE_NODE_FIELD(limitCount);
WRITE_NODE_FIELD(lockedRels); WRITE_NODE_FIELD(lockingClause);
WRITE_BOOL_FIELD(forUpdate);
WRITE_ENUM_FIELD(op, SetOperation); WRITE_ENUM_FIELD(op, SetOperation);
WRITE_BOOL_FIELD(all); WRITE_BOOL_FIELD(all);
WRITE_NODE_FIELD(larg); WRITE_NODE_FIELD(larg);
...@@ -1371,6 +1370,16 @@ _outDefElem(StringInfo str, DefElem *node) ...@@ -1371,6 +1370,16 @@ _outDefElem(StringInfo str, DefElem *node)
WRITE_NODE_FIELD(arg); WRITE_NODE_FIELD(arg);
} }
static void
_outLockingClause(StringInfo str, LockingClause *node)
{
WRITE_NODE_TYPE("LOCKINGCLAUSE");
WRITE_NODE_FIELD(lockedRels);
WRITE_BOOL_FIELD(forUpdate);
WRITE_BOOL_FIELD(nowait);
}
static void static void
_outColumnDef(StringInfo str, ColumnDef *node) _outColumnDef(StringInfo str, ColumnDef *node)
{ {
...@@ -1462,6 +1471,7 @@ _outQuery(StringInfo str, Query *node) ...@@ -1462,6 +1471,7 @@ _outQuery(StringInfo str, Query *node)
WRITE_NODE_FIELD(jointree); WRITE_NODE_FIELD(jointree);
WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(rowMarks);
WRITE_BOOL_FIELD(forUpdate); WRITE_BOOL_FIELD(forUpdate);
WRITE_BOOL_FIELD(rowNoWait);
WRITE_NODE_FIELD(targetList); WRITE_NODE_FIELD(targetList);
WRITE_NODE_FIELD(groupClause); WRITE_NODE_FIELD(groupClause);
WRITE_NODE_FIELD(havingQual); WRITE_NODE_FIELD(havingQual);
...@@ -2079,6 +2089,9 @@ _outNode(StringInfo str, void *obj) ...@@ -2079,6 +2089,9 @@ _outNode(StringInfo str, void *obj)
case T_DefElem: case T_DefElem:
_outDefElem(str, obj); _outDefElem(str, obj);
break; break;
case T_LockingClause:
_outLockingClause(str, obj);
break;
default: default:
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.180 2005/06/28 05:08:57 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.181 2005/08/01 20:31:08 tgl Exp $
* *
* NOTES * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
...@@ -146,6 +146,7 @@ _readQuery(void) ...@@ -146,6 +146,7 @@ _readQuery(void)
READ_NODE_FIELD(jointree); READ_NODE_FIELD(jointree);
READ_NODE_FIELD(rowMarks); READ_NODE_FIELD(rowMarks);
READ_BOOL_FIELD(forUpdate); READ_BOOL_FIELD(forUpdate);
READ_BOOL_FIELD(rowNoWait);
READ_NODE_FIELD(targetList); READ_NODE_FIELD(targetList);
READ_NODE_FIELD(groupClause); READ_NODE_FIELD(groupClause);
READ_NODE_FIELD(havingQual); READ_NODE_FIELD(havingQual);
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.29 2005/06/05 22:32:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.30 2005/08/01 20:31:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -295,18 +295,26 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode, bool below_outer_join) ...@@ -295,18 +295,26 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode, bool below_outer_join)
* already adjusted the marker values, so just list_concat the * already adjusted the marker values, so just list_concat the
* list.) * list.)
* *
* Executor can't handle multiple FOR UPDATE/SHARE flags, so * Executor can't handle multiple FOR UPDATE/SHARE/NOWAIT flags,
* complain if they are valid but different * so complain if they are valid but different
*/ */
if (parse->rowMarks && subquery->rowMarks && if (parse->rowMarks && subquery->rowMarks)
parse->forUpdate != subquery->forUpdate) {
ereport(ERROR, if (parse->forUpdate != subquery->forUpdate)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ereport(ERROR,
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query"))); (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
if (parse->rowNoWait != subquery->rowNoWait)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both wait and NOWAIT in one query")));
}
parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks); parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
if (subquery->rowMarks) if (subquery->rowMarks)
{
parse->forUpdate = subquery->forUpdate; parse->forUpdate = subquery->forUpdate;
parse->rowNoWait = subquery->rowNoWait;
}
/* /*
* We also have to fix the relid sets of any parent * We also have to fix the relid sets of any parent
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.323 2005/07/28 22:27:00 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.324 2005/08/01 20:31:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -134,7 +134,7 @@ static void transformFKConstraints(ParseState *pstate, ...@@ -134,7 +134,7 @@ static void transformFKConstraints(ParseState *pstate,
bool isAddConstraint); bool isAddConstraint);
static void applyColumnNames(List *dst, List *src); static void applyColumnNames(List *dst, List *src);
static List *getSetColTypes(ParseState *pstate, Node *node); static List *getSetColTypes(ParseState *pstate, Node *node);
static void transformLocking(Query *qry, List *lockedRels, bool forUpdate); static void transformLockingClause(Query *qry, LockingClause *lc);
static void transformConstraintAttrs(List *constraintList); static void transformConstraintAttrs(List *constraintList);
static void transformColumnType(ParseState *pstate, ColumnDef *column); static void transformColumnType(ParseState *pstate, ColumnDef *column);
static void release_pstate_resources(ParseState *pstate); static void release_pstate_resources(ParseState *pstate);
...@@ -1812,8 +1812,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1812,8 +1812,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
qry->commandType = CMD_SELECT; qry->commandType = CMD_SELECT;
/* make FOR UPDATE/FOR SHARE list available to addRangeTableEntry */ /* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
pstate->p_lockedRels = stmt->lockedRels; pstate->p_locking_clause = stmt->lockingClause;
/* process the FROM clause */ /* process the FROM clause */
transformFromClause(pstate, stmt->fromClause); transformFromClause(pstate, stmt->fromClause);
...@@ -1872,8 +1872,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1872,8 +1872,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual) if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
parseCheckAggregates(pstate, qry); parseCheckAggregates(pstate, qry);
if (stmt->lockedRels != NIL) if (stmt->lockingClause)
transformLocking(qry, stmt->lockedRels, stmt->forUpdate); transformLockingClause(qry, stmt->lockingClause);
return qry; return qry;
} }
...@@ -1901,8 +1901,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1901,8 +1901,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
List *sortClause; List *sortClause;
Node *limitOffset; Node *limitOffset;
Node *limitCount; Node *limitCount;
List *lockedRels; LockingClause *lockingClause;
bool forUpdate;
Node *node; Node *node;
ListCell *left_tlist, ListCell *left_tlist,
*dtlist; *dtlist;
...@@ -1940,16 +1939,15 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1940,16 +1939,15 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
sortClause = stmt->sortClause; sortClause = stmt->sortClause;
limitOffset = stmt->limitOffset; limitOffset = stmt->limitOffset;
limitCount = stmt->limitCount; limitCount = stmt->limitCount;
lockedRels = stmt->lockedRels; lockingClause = stmt->lockingClause;
forUpdate = stmt->forUpdate;
stmt->sortClause = NIL; stmt->sortClause = NIL;
stmt->limitOffset = NULL; stmt->limitOffset = NULL;
stmt->limitCount = NULL; stmt->limitCount = NULL;
stmt->lockedRels = NIL; stmt->lockingClause = NULL;
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */ /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
if (lockedRels) if (lockingClause)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT"))); errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
...@@ -2089,8 +2087,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -2089,8 +2087,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual) if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
parseCheckAggregates(pstate, qry); parseCheckAggregates(pstate, qry);
if (lockedRels != NIL) if (lockingClause)
transformLocking(qry, lockedRels, forUpdate); transformLockingClause(qry, lockingClause);
return qry; return qry;
} }
...@@ -2114,7 +2112,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt) ...@@ -2114,7 +2112,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"))); errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */ /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
if (stmt->lockedRels) if (stmt->lockingClause)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT"))); errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
...@@ -2134,7 +2132,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt) ...@@ -2134,7 +2132,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
{ {
Assert(stmt->larg != NULL && stmt->rarg != NULL); Assert(stmt->larg != NULL && stmt->rarg != NULL);
if (stmt->sortClause || stmt->limitOffset || stmt->limitCount || if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
stmt->lockedRels) stmt->lockingClause)
isLeaf = true; isLeaf = true;
else else
isLeaf = false; isLeaf = false;
...@@ -2760,24 +2758,40 @@ CheckSelectLocking(Query *qry, bool forUpdate) ...@@ -2760,24 +2758,40 @@ CheckSelectLocking(Query *qry, bool forUpdate)
* in rewriteHandler.c. * in rewriteHandler.c.
*/ */
static void static void
transformLocking(Query *qry, List *lockedRels, bool forUpdate) transformLockingClause(Query *qry, LockingClause *lc)
{ {
List *lockedRels = lc->lockedRels;
List *rowMarks; List *rowMarks;
ListCell *l; ListCell *l;
ListCell *rt; ListCell *rt;
Index i; Index i;
LockingClause *allrels;
if (qry->rowMarks && forUpdate != qry->forUpdate) if (qry->rowMarks)
ereport(ERROR, {
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), if (lc->forUpdate != qry->forUpdate)
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query"))); ereport(ERROR,
qry->forUpdate = forUpdate; (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
if (lc->nowait != qry->rowNoWait)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both wait and NOWAIT in one query")));
}
qry->forUpdate = lc->forUpdate;
qry->rowNoWait = lc->nowait;
CheckSelectLocking(qry, lc->forUpdate);
/* make a clause we can pass down to subqueries to select all rels */
allrels = makeNode(LockingClause);
allrels->lockedRels = NIL; /* indicates all rels */
allrels->forUpdate = lc->forUpdate;
allrels->nowait = lc->nowait;
CheckSelectLocking(qry, forUpdate);
rowMarks = qry->rowMarks; rowMarks = qry->rowMarks;
if (linitial(lockedRels) == NULL) if (lockedRels == NIL)
{ {
/* all regular tables used in query */ /* all regular tables used in query */
i = 0; i = 0;
...@@ -2799,8 +2813,7 @@ transformLocking(Query *qry, List *lockedRels, bool forUpdate) ...@@ -2799,8 +2813,7 @@ transformLocking(Query *qry, List *lockedRels, bool forUpdate)
* FOR UPDATE/SHARE of subquery is propagated to all * FOR UPDATE/SHARE of subquery is propagated to all
* of subquery's rels * of subquery's rels
*/ */
transformLocking(rte->subquery, list_make1(NULL), transformLockingClause(rte->subquery, allrels);
forUpdate);
break; break;
default: default:
/* ignore JOIN, SPECIAL, FUNCTION RTEs */ /* ignore JOIN, SPECIAL, FUNCTION RTEs */
...@@ -2836,8 +2849,7 @@ transformLocking(Query *qry, List *lockedRels, bool forUpdate) ...@@ -2836,8 +2849,7 @@ transformLocking(Query *qry, List *lockedRels, bool forUpdate)
* FOR UPDATE/SHARE of subquery is propagated to * FOR UPDATE/SHARE of subquery is propagated to
* all of subquery's rels * all of subquery's rels
*/ */
transformLocking(rte->subquery, list_make1(NULL), transformLockingClause(rte->subquery, allrels);
forUpdate);
break; break;
case RTE_JOIN: case RTE_JOIN:
ereport(ERROR, ereport(ERROR,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.506 2005/08/01 04:03:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.507 2005/08/01 20:31:09 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -87,7 +87,7 @@ static List *check_func_name(List *names); ...@@ -87,7 +87,7 @@ static List *check_func_name(List *names);
static List *extractArgTypes(List *parameters); static List *extractArgTypes(List *parameters);
static SelectStmt *findLeftmostSelect(SelectStmt *node); static SelectStmt *findLeftmostSelect(SelectStmt *node);
static void insertSelectOptions(SelectStmt *stmt, static void insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *lockingClause, List *sortClause, Node *lockingClause,
Node *limitOffset, Node *limitCount); Node *limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg); static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n); static Node *doNegate(Node *n);
...@@ -132,7 +132,7 @@ static void doNegateFloat(Value *v); ...@@ -132,7 +132,7 @@ static void doNegateFloat(Value *v);
%type <node> stmt schema_stmt %type <node> stmt schema_stmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
...@@ -165,7 +165,7 @@ static void doNegateFloat(Value *v); ...@@ -165,7 +165,7 @@ static void doNegateFloat(Value *v);
%type <dbehavior> opt_drop_behavior %type <dbehavior> opt_drop_behavior
%type <list> createdb_opt_list alterdb_opt_list copy_opt_list %type <list> createdb_opt_list alterdb_opt_list copy_opt_list
transaction_mode_list transaction_mode_list
%type <defelt> createdb_opt_item alterdb_opt_item copy_opt_item %type <defelt> createdb_opt_item alterdb_opt_item copy_opt_item
transaction_mode_item transaction_mode_item
...@@ -240,8 +240,8 @@ static void doNegateFloat(Value *v); ...@@ -240,8 +240,8 @@ static void doNegateFloat(Value *v);
%type <oncommit> OnCommitOption %type <oncommit> OnCommitOption
%type <withoids> OptWithOids WithOidsAs %type <withoids> OptWithOids WithOidsAs
%type <list> for_locking_clause opt_for_locking_clause %type <node> for_locking_clause opt_for_locking_clause
update_list %type <list> locked_rels_list
%type <boolean> opt_all %type <boolean> opt_all
%type <node> join_outer join_qual %type <node> join_outer join_qual
...@@ -4555,7 +4555,7 @@ opt_equal: '=' {} ...@@ -4555,7 +4555,7 @@ opt_equal: '=' {}
*****************************************************************************/ *****************************************************************************/
AlterDatabaseStmt: AlterDatabaseStmt:
ALTER DATABASE database_name opt_with alterdb_opt_list ALTER DATABASE database_name opt_with alterdb_opt_list
{ {
AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
n->dbname = $3; n->dbname = $3;
...@@ -5070,7 +5070,7 @@ lock_type: ACCESS SHARE { $$ = AccessShareLock; } ...@@ -5070,7 +5070,7 @@ lock_type: ACCESS SHARE { $$ = AccessShareLock; }
| ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; } | ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; }
; ;
opt_nowait: NOWAIT { $$ = TRUE; } opt_nowait: NOWAIT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; } | /*EMPTY*/ { $$ = FALSE; }
; ;
...@@ -5191,7 +5191,7 @@ select_no_parens: ...@@ -5191,7 +5191,7 @@ select_no_parens:
simple_select { $$ = $1; } simple_select { $$ = $1; }
| select_clause sort_clause | select_clause sort_clause
{ {
insertSelectOptions((SelectStmt *) $1, $2, NIL, insertSelectOptions((SelectStmt *) $1, $2, NULL,
NULL, NULL); NULL, NULL);
$$ = $1; $$ = $1;
} }
...@@ -5424,14 +5424,6 @@ select_offset_value: ...@@ -5424,14 +5424,6 @@ select_offset_value:
a_expr { $$ = $1; } a_expr { $$ = $1; }
; ;
/*
* jimmy bell-style recursive queries aren't supported in the
* current system.
*
* ...however, recursive addattr and rename supported. make special
* cases for these.
*/
group_clause: group_clause:
GROUP_P BY expr_list { $$ = $3; } GROUP_P BY expr_list { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; }
...@@ -5443,8 +5435,22 @@ having_clause: ...@@ -5443,8 +5435,22 @@ having_clause:
; ;
for_locking_clause: for_locking_clause:
FOR UPDATE update_list { $$ = lcons(makeString("for_update"), $3); } FOR UPDATE locked_rels_list opt_nowait
| FOR SHARE update_list { $$ = lcons(makeString("for_share"), $3); } {
LockingClause *n = makeNode(LockingClause);
n->lockedRels = $3;
n->forUpdate = TRUE;
n->nowait = $4;
$$ = (Node *) n;
}
| FOR SHARE locked_rels_list opt_nowait
{
LockingClause *n = makeNode(LockingClause);
n->lockedRels = $3;
n->forUpdate = FALSE;
n->nowait = $4;
$$ = (Node *) n;
}
| FOR READ ONLY { $$ = NULL; } | FOR READ ONLY { $$ = NULL; }
; ;
...@@ -5453,9 +5459,9 @@ opt_for_locking_clause: ...@@ -5453,9 +5459,9 @@ opt_for_locking_clause:
| /* EMPTY */ { $$ = NULL; } | /* EMPTY */ { $$ = NULL; }
; ;
update_list: locked_rels_list:
OF name_list { $$ = $2; } OF name_list { $$ = $2; }
| /* EMPTY */ { $$ = list_make1(NULL); } | /* EMPTY */ { $$ = NIL; }
; ;
/***************************************************************************** /*****************************************************************************
...@@ -8691,7 +8697,7 @@ findLeftmostSelect(SelectStmt *node) ...@@ -8691,7 +8697,7 @@ findLeftmostSelect(SelectStmt *node)
*/ */
static void static void
insertSelectOptions(SelectStmt *stmt, insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *lockingClause, List *sortClause, Node *lockingClause,
Node *limitOffset, Node *limitCount) Node *limitOffset, Node *limitCount)
{ {
/* /*
...@@ -8708,25 +8714,11 @@ insertSelectOptions(SelectStmt *stmt, ...@@ -8708,25 +8714,11 @@ insertSelectOptions(SelectStmt *stmt,
} }
if (lockingClause) if (lockingClause)
{ {
Value *type; if (stmt->lockingClause)
if (stmt->lockedRels)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple FOR UPDATE/FOR SHARE clauses not allowed"))); errmsg("multiple FOR UPDATE/FOR SHARE clauses not allowed")));
stmt->lockingClause = (LockingClause *) lockingClause;
Assert(list_length(lockingClause) > 1);
/* 1st is Value node containing "for_update" or "for_share" */
type = (Value *) linitial(lockingClause);
Assert(IsA(type, String));
if (strcmp(strVal(type), "for_update") == 0)
stmt->forUpdate = true;
else if (strcmp(strVal(type), "for_share") == 0)
stmt->forUpdate = false;
else
elog(ERROR, "invalid first node in locking clause");
stmt->lockedRels = list_delete_first(lockingClause);
} }
if (limitOffset) if (limitOffset)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.112 2005/06/28 05:08:58 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.113 2005/08/01 20:31:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -903,9 +903,9 @@ isLockedRel(ParseState *pstate, char *refname) ...@@ -903,9 +903,9 @@ isLockedRel(ParseState *pstate, char *refname)
/* Outer loop to check parent query levels as well as this one */ /* Outer loop to check parent query levels as well as this one */
while (pstate != NULL) while (pstate != NULL)
{ {
if (pstate->p_lockedRels != NIL) if (pstate->p_locking_clause)
{ {
if (linitial(pstate->p_lockedRels) == NULL) if (pstate->p_locking_clause->lockedRels == NIL)
{ {
/* all tables used in query */ /* all tables used in query */
return true; return true;
...@@ -915,7 +915,7 @@ isLockedRel(ParseState *pstate, char *refname) ...@@ -915,7 +915,7 @@ isLockedRel(ParseState *pstate, char *refname)
/* just the named tables */ /* just the named tables */
ListCell *l; ListCell *l;
foreach(l, pstate->p_lockedRels) foreach(l, pstate->p_locking_clause->lockedRels)
{ {
char *rname = strVal(lfirst(l)); char *rname = strVal(lfirst(l));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.75 2005/05/29 18:24:13 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.76 2005/08/01 20:31:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -423,7 +423,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod) ...@@ -423,7 +423,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
stmt->sortClause != NIL || stmt->sortClause != NIL ||
stmt->limitOffset != NULL || stmt->limitOffset != NULL ||
stmt->limitCount != NULL || stmt->limitCount != NULL ||
stmt->lockedRels != NIL || stmt->lockingClause != NULL ||
stmt->op != SETOP_NONE) stmt->op != SETOP_NONE)
goto fail; goto fail;
if (list_length(stmt->targetList) != 1) if (list_length(stmt->targetList) != 1)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.156 2005/07/28 22:27:02 tgl Exp $ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.157 2005/08/01 20:31:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -52,7 +52,8 @@ static TargetEntry *process_matched_tle(TargetEntry *src_tle, ...@@ -52,7 +52,8 @@ static TargetEntry *process_matched_tle(TargetEntry *src_tle,
TargetEntry *prior_tle, TargetEntry *prior_tle,
const char *attrName); const char *attrName);
static Node *get_assignment_input(Node *node); static Node *get_assignment_input(Node *node);
static void markQueryForLocking(Query *qry, bool forUpdate, bool skipOldNew); static void markQueryForLocking(Query *qry, bool forUpdate, bool noWait,
bool skipOldNew);
static List *matchLocks(CmdType event, RuleLock *rulelocks, static List *matchLocks(CmdType event, RuleLock *rulelocks,
int varno, Query *parsetree); int varno, Query *parsetree);
static Query *fireRIRrules(Query *parsetree, List *activeRIRs); static Query *fireRIRrules(Query *parsetree, List *activeRIRs);
...@@ -962,7 +963,8 @@ ApplyRetrieveRule(Query *parsetree, ...@@ -962,7 +963,8 @@ ApplyRetrieveRule(Query *parsetree,
/* /*
* Set up the view's referenced tables as if FOR UPDATE/SHARE. * Set up the view's referenced tables as if FOR UPDATE/SHARE.
*/ */
markQueryForLocking(rule_action, parsetree->forUpdate, true); markQueryForLocking(rule_action, parsetree->forUpdate,
parsetree->rowNoWait, true);
} }
return parsetree; return parsetree;
...@@ -977,16 +979,24 @@ ApplyRetrieveRule(Query *parsetree, ...@@ -977,16 +979,24 @@ ApplyRetrieveRule(Query *parsetree,
* NB: this must agree with the parser's transformLocking() routine. * NB: this must agree with the parser's transformLocking() routine.
*/ */
static void static void
markQueryForLocking(Query *qry, bool forUpdate, bool skipOldNew) markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
{ {
Index rti = 0; Index rti = 0;
ListCell *l; ListCell *l;
if (qry->rowMarks && forUpdate != qry->forUpdate) if (qry->rowMarks)
ereport(ERROR, {
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), if (forUpdate != qry->forUpdate)
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query"))); ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
if (noWait != qry->rowNoWait)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both wait and NOWAIT in one query")));
}
qry->forUpdate = forUpdate; qry->forUpdate = forUpdate;
qry->rowNoWait = noWait;
foreach(l, qry->rtable) foreach(l, qry->rtable)
{ {
...@@ -1007,7 +1017,7 @@ markQueryForLocking(Query *qry, bool forUpdate, bool skipOldNew) ...@@ -1007,7 +1017,7 @@ markQueryForLocking(Query *qry, bool forUpdate, bool skipOldNew)
else if (rte->rtekind == RTE_SUBQUERY) else if (rte->rtekind == RTE_SUBQUERY)
{ {
/* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */ /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */
markQueryForLocking(rte->subquery, forUpdate, false); markQueryForLocking(rte->subquery, forUpdate, noWait, false);
} }
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.77 2005/06/17 22:32:45 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.78 2005/08/01 20:31:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -368,6 +368,27 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode) ...@@ -368,6 +368,27 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
lockmode, false, false); lockmode, false, false);
} }
/*
* ConditionalLockTuple
*
* As above, but only lock if we can get the lock without blocking.
* Returns TRUE iff the lock was acquired.
*/
bool
ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_TUPLE(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId,
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
return (LockAcquire(LockTableId, &tag, relation->rd_istemp,
lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
}
/* /*
* UnlockTuple * UnlockTuple
*/ */
...@@ -463,6 +484,44 @@ XactLockTableWait(TransactionId xid) ...@@ -463,6 +484,44 @@ XactLockTableWait(TransactionId xid)
TransactionIdAbort(xid); TransactionIdAbort(xid);
} }
/*
* ConditionalXactLockTableWait
*
* 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;
for (;;)
{
Assert(TransactionIdIsValid(xid));
Assert(!TransactionIdEquals(xid, GetTopTransactionId()));
SET_LOCKTAG_TRANSACTION(tag, xid);
if (LockAcquire(LockTableId, &tag, false,
ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
return false;
LockRelease(LockTableId, &tag, ShareLock, false);
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;
}
/* /*
* LockDatabaseObject * LockDatabaseObject
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.204 2005/07/15 18:39:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.205 2005/08/01 20:31:12 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -201,7 +201,7 @@ static void get_agg_expr(Aggref *aggref, deparse_context *context); ...@@ -201,7 +201,7 @@ static void get_agg_expr(Aggref *aggref, deparse_context *context);
static void get_const_expr(Const *constval, deparse_context *context); static void get_const_expr(Const *constval, deparse_context *context);
static void get_sublink_expr(SubLink *sublink, deparse_context *context); static void get_sublink_expr(SubLink *sublink, deparse_context *context);
static void get_from_clause(Query *query, const char *prefix, static void get_from_clause(Query *query, const char *prefix,
deparse_context *context); deparse_context *context);
static void get_from_clause_item(Node *jtnode, Query *query, static void get_from_clause_item(Node *jtnode, Query *query,
deparse_context *context); deparse_context *context);
static void get_from_clause_alias(Alias *alias, int varno, static void get_from_clause_alias(Alias *alias, int varno,
...@@ -1961,6 +1961,8 @@ get_select_query_def(Query *query, deparse_context *context, ...@@ -1961,6 +1961,8 @@ get_select_query_def(Query *query, deparse_context *context,
quote_identifier(rte->eref->aliasname)); quote_identifier(rte->eref->aliasname));
sep = ", "; sep = ", ";
} }
if (query->rowNoWait)
appendStringInfo(buf, " NOWAIT");
} }
} }
...@@ -2401,8 +2403,8 @@ get_delete_query_def(Query *query, deparse_context *context) ...@@ -2401,8 +2403,8 @@ get_delete_query_def(Query *query, deparse_context *context)
only_marker(rte), only_marker(rte),
generate_relation_name(rte->relid)); generate_relation_name(rte->relid));
/* Add the USING clause if given */ /* Add the USING clause if given */
get_from_clause(query, " USING ", context); get_from_clause(query, " USING ", context);
/* Add a WHERE clause if given */ /* Add a WHERE clause if given */
if (query->jointree->quals != NULL) if (query->jointree->quals != NULL)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.102 2005/06/20 18:37:01 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.103 2005/08/01 20:31:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -163,7 +163,8 @@ extern HTSU_Result heap_delete(Relation relation, ItemPointer tid, ItemPointer c ...@@ -163,7 +163,8 @@ extern HTSU_Result heap_delete(Relation relation, ItemPointer tid, ItemPointer c
extern HTSU_Result heap_update(Relation relation, ItemPointer otid, HeapTuple tup, extern HTSU_Result heap_update(Relation relation, ItemPointer otid, HeapTuple tup,
ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool wait); ItemPointer ctid, CommandId cid, Snapshot crosscheck, bool wait);
extern HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tup, extern HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tup,
Buffer *userbuf, CommandId cid, LockTupleMode mode); Buffer *userbuf, CommandId cid,
LockTupleMode mode, bool nowait);
extern Oid simple_heap_insert(Relation relation, HeapTuple tup); extern Oid simple_heap_insert(Relation relation, HeapTuple tup);
extern void simple_heap_delete(Relation relation, ItemPointer tid); extern void simple_heap_delete(Relation relation, ItemPointer tid);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/multixact.h,v 1.3 2005/06/08 15:50:28 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/multixact.h,v 1.4 2005/08/01 20:31:13 tgl Exp $
*/ */
#ifndef MULTIXACT_H #ifndef MULTIXACT_H
#define MULTIXACT_H #define MULTIXACT_H
...@@ -42,6 +42,7 @@ extern MultiXactId MultiXactIdCreate(TransactionId xid1, TransactionId xid2); ...@@ -42,6 +42,7 @@ extern MultiXactId MultiXactIdCreate(TransactionId xid1, TransactionId xid2);
extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid); extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid);
extern bool MultiXactIdIsRunning(MultiXactId multi); extern bool MultiXactIdIsRunning(MultiXactId multi);
extern void MultiXactIdWait(MultiXactId multi); extern void MultiXactIdWait(MultiXactId multi);
extern bool ConditionalMultiXactIdWait(MultiXactId multi);
extern void MultiXactIdSetOldestMember(void); extern void MultiXactIdSetOldestMember(void);
extern void AtEOXact_MultiXact(void); extern void AtEOXact_MultiXact(void);
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.294 2005/07/31 17:19:20 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.295 2005/08/01 20:31:14 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200507301 #define CATALOG_VERSION_NO 200508011
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.136 2005/06/26 22:05:41 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.137 2005/08/01 20:31:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -319,8 +319,9 @@ typedef struct EState ...@@ -319,8 +319,9 @@ typedef struct EState
uint32 es_processed; /* # of tuples processed */ uint32 es_processed; /* # of tuples processed */
Oid es_lastoid; /* last oid processed (by INSERT) */ Oid es_lastoid; /* last oid processed (by INSERT) */
List *es_rowMark; /* not good place, but there is no other */ List *es_rowMarks; /* not good place, but there is no other */
bool es_forUpdate; /* was it FOR UPDATE or FOR SHARE */ bool es_forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
bool es_rowNoWait; /* FOR UPDATE/SHARE NOWAIT option */
bool es_instrument; /* true requests runtime instrumentation */ bool es_instrument; /* true requests runtime instrumentation */
bool es_select_into; /* true if doing SELECT INTO */ bool es_select_into; /* true if doing SELECT INTO */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.174 2005/08/01 04:03:58 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.175 2005/08/01 20:31:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -315,6 +315,7 @@ typedef enum NodeTag ...@@ -315,6 +315,7 @@ typedef enum NodeTag
T_CompositeTypeStmt, T_CompositeTypeStmt,
T_InhRelation, T_InhRelation,
T_FunctionParameter, T_FunctionParameter,
T_LockingClause,
/* /*
* TAGS FOR RANDOM OTHER STUFF * TAGS FOR RANDOM OTHER STUFF
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.288 2005/08/01 04:03:58 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.289 2005/08/01 20:31:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -95,6 +95,7 @@ typedef struct Query ...@@ -95,6 +95,7 @@ typedef struct Query
bool forUpdate; /* true if rowMarks are FOR UPDATE, bool forUpdate; /* true if rowMarks are FOR UPDATE,
* false if they are FOR SHARE */ * false if they are FOR SHARE */
bool rowNoWait; /* FOR UPDATE/SHARE NOWAIT option */
List *targetList; /* target list (of TargetEntry) */ List *targetList; /* target list (of TargetEntry) */
...@@ -415,6 +416,20 @@ typedef struct DefElem ...@@ -415,6 +416,20 @@ typedef struct DefElem
Node *arg; /* a (Value *) or a (TypeName *) */ Node *arg; /* a (Value *) or a (TypeName *) */
} DefElem; } DefElem;
/*
* LockingClause - raw representation of FOR UPDATE/SHARE options
*
* Note: lockedRels == NIL means "all relations in query". Otherwise it
* is a list of String nodes giving relation eref names.
*/
typedef struct LockingClause
{
NodeTag type;
List *lockedRels; /* FOR UPDATE or FOR SHARE relations */
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
bool nowait; /* NOWAIT option */
} LockingClause;
/**************************************************************************** /****************************************************************************
* Nodes for a Query tree * Nodes for a Query tree
...@@ -686,8 +701,7 @@ typedef struct SelectStmt ...@@ -686,8 +701,7 @@ typedef struct SelectStmt
List *sortClause; /* sort clause (a list of SortBy's) */ List *sortClause; /* sort clause (a list of SortBy's) */
Node *limitOffset; /* # of result tuples to skip */ Node *limitOffset; /* # of result tuples to skip */
Node *limitCount; /* # of result tuples to return */ Node *limitCount; /* # of result tuples to return */
List *lockedRels; /* FOR UPDATE or FOR SHARE relations */ LockingClause *lockingClause; /* FOR UPDATE/FOR SHARE */
bool forUpdate; /* true = FOR UPDATE, false = FOR SHARE */
/* /*
* These fields are used only in upper-level SelectStmts. * These fields are used only in upper-level SelectStmts.
...@@ -699,6 +713,7 @@ typedef struct SelectStmt ...@@ -699,6 +713,7 @@ typedef struct SelectStmt
/* Eventually add fields for CORRESPONDING spec here */ /* Eventually add fields for CORRESPONDING spec here */
} SelectStmt; } SelectStmt;
/* ---------------------- /* ----------------------
* Set Operation node for post-analysis query trees * Set Operation node for post-analysis query trees
* *
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.44 2005/06/05 00:38:11 tgl Exp $ * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.45 2005/08/01 20:31:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,9 +61,9 @@ typedef struct ParseState ...@@ -61,9 +61,9 @@ typedef struct ParseState
Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */ Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */
int p_numparams; /* allocated size of p_paramtypes[] */ int p_numparams; /* allocated size of p_paramtypes[] */
int p_next_resno; /* next targetlist resno to assign */ int p_next_resno; /* next targetlist resno to assign */
List *p_lockedRels; /* FOR UPDATE/SHARE, if any (see gram.y) */ LockingClause *p_locking_clause; /* FOR UPDATE/FOR SHARE info */
Node *p_value_substitute; /* what to replace VALUE with, if Node *p_value_substitute; /* what to replace VALUE with,
* any */ * if any */
bool p_variableparams; bool p_variableparams;
bool p_hasAggs; bool p_hasAggs;
bool p_hasSubLinks; bool p_hasSubLinks;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.50 2005/06/17 22:32:50 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.51 2005/08/01 20:31:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -64,12 +64,15 @@ extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); ...@@ -64,12 +64,15 @@ extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
/* Lock a tuple (see heap_lock_tuple before assuming you understand this) */ /* Lock a tuple (see heap_lock_tuple before assuming you understand this) */
extern void LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode); extern void LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode);
extern bool ConditionalLockTuple(Relation relation, ItemPointer tid,
LOCKMODE lockmode);
extern void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode); extern void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode);
/* Lock an XID (used to wait for a transaction to finish) */ /* Lock an XID (used to wait for a transaction to finish) */
extern void XactLockTableInsert(TransactionId xid); extern void XactLockTableInsert(TransactionId xid);
extern void XactLockTableDelete(TransactionId xid); extern void XactLockTableDelete(TransactionId xid);
extern void XactLockTableWait(TransactionId xid); extern void XactLockTableWait(TransactionId xid);
extern bool ConditionalXactLockTableWait(TransactionId xid);
/* Lock a general object (other than a relation) of the current database */ /* Lock a general object (other than a relation) of the current database */
extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment