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:
...@@ -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>
......
<!-- <!--
$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,6 +1998,15 @@ l3: ...@@ -1998,6 +1998,15 @@ l3:
*/ */
if (!have_tuple_lock) if (!have_tuple_lock)
{ {
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); 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 */
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); 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 */
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); 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
......
...@@ -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);
} }
} }
...@@ -1015,7 +1016,7 @@ ExecEndPlan(PlanState *planstate, EState *estate) ...@@ -1015,7 +1016,7 @@ ExecEndPlan(PlanState *planstate, EState *estate)
/* /*
* 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) {
if (parse->forUpdate != subquery->forUpdate)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query"))); 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)
{
if (lc->forUpdate != qry->forUpdate)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query"))); errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
qry->forUpdate = forUpdate; 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);
CheckSelectLocking(qry, 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;
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);
...@@ -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
...@@ -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)
{
if (forUpdate != qry->forUpdate)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query"))); 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.
* *
...@@ -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");
} }
} }
......
...@@ -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