Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2a4fad1

Browse files
committed
Add NOWAIT option to SELECT FOR UPDATE/SHARE.
Original patch by Hans-Juergen Schoenig, revisions by Karel Zak and Tom Lane.
1 parent ca7abcd commit 2a4fad1

File tree

28 files changed

+387
-157
lines changed

28 files changed

+387
-157
lines changed

doc/src/sgml/ref/select.sgml

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.88 2005/07/14 06:17:36 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.89 2005/08/01 20:31:04 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -30,7 +30,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="parameter">expression</replac
3030
[ ORDER BY <replaceable class="parameter">expression</replaceable> [ ASC | DESC | USING <replaceable class="parameter">operator</replaceable> ] [, ...] ]
3131
[ LIMIT { <replaceable class="parameter">count</replaceable> | ALL } ]
3232
[ OFFSET <replaceable class="parameter">start</replaceable> ]
33-
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] ]
33+
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
3434

3535
where <replaceable class="parameter">from_item</replaceable> can be one of:
3636

@@ -151,7 +151,7 @@ where <replaceable class="parameter">from_item</replaceable> can be one of:
151151
</listitem>
152152
</orderedlist>
153153
</para>
154-
154+
155155
<para>
156156
You must have <literal>SELECT</literal> privilege on a table to
157157
read its values. The use of <literal>FOR UPDATE</literal> or
@@ -506,7 +506,7 @@ HAVING <replaceable class="parameter">condition</replaceable>
506506
<replaceable class="parameter">select_statement</replaceable> is
507507
any <command>SELECT</command> statement without an <literal>ORDER
508508
BY</>, <literal>LIMIT</>, <literal>FOR UPDATE</literal>, or
509-
<literal>FOR SHARE</literal> clause.
509+
<literal>FOR SHARE</literal> clause.
510510
(<literal>ORDER BY</> and <literal>LIMIT</> can be attached to a
511511
subexpression if it is enclosed in parentheses. Without
512512
parentheses, these clauses will be taken to apply to the result of
@@ -803,14 +803,14 @@ OFFSET <replaceable class="parameter">start</replaceable>
803803
<para>
804804
The <literal>FOR UPDATE</literal> clause has this form:
805805
<synopsis>
806-
FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
806+
FOR UPDATE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ]
807807
</synopsis>
808808
</para>
809809

810810
<para>
811811
The closely related <literal>FOR SHARE</literal> clause has this form:
812812
<synopsis>
813-
FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
813+
FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ]
814814
</synopsis>
815815
</para>
816816

@@ -831,6 +831,18 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
831831
linkend="mvcc">.
832832
</para>
833833

834+
<para>
835+
To prevent the operation from waiting for other transactions to commit,
836+
use the <literal>NOWAIT</> option. <command>SELECT FOR UPDATE
837+
NOWAIT</command> reports an error, rather than waiting, if a selected row
838+
cannot be locked immediately. Note that <literal>NOWAIT</> applies only
839+
to the row-level lock(s) &mdash; the required <literal>ROW SHARE</literal>
840+
table-level lock is still taken in the ordinary way (see
841+
<xref linkend="mvcc">). You can use the <literal>NOWAIT</> option of
842+
<xref linkend="sql-lock" endterm="sql-lock-title">
843+
if you need to acquire the table-level lock without waiting.
844+
</para>
845+
834846
<para>
835847
<literal>FOR SHARE</literal> behaves similarly, except that it
836848
acquires a shared rather than exclusive lock on each retrieved
@@ -843,7 +855,8 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
843855
<para>
844856
It is currently not allowed for a single <command>SELECT</command>
845857
statement to include both <literal>FOR UPDATE</literal> and
846-
<literal>FOR SHARE</literal>.
858+
<literal>FOR SHARE</literal>, nor can different parts of the statement use
859+
both <literal>NOWAIT</> and normal waiting mode.
847860
</para>
848861

849862
<para>
@@ -861,8 +874,8 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
861874
</para>
862875

863876
<para>
864-
It is possible for a <command>SELECT</> command using both
865-
<literal>LIMIT</literal> and <literal>FOR UPDATE/SHARE</literal>
877+
It is possible for a <command>SELECT</> command using both
878+
<literal>LIMIT</literal> and <literal>FOR UPDATE/SHARE</literal>
866879
clauses to return fewer rows than specified by <literal>LIMIT</literal>.
867880
This is because <literal>LIMIT</> is applied first. The command
868881
selects the specified number of rows,

doc/src/sgml/ref/select_into.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.35 2005/04/28 21:47:10 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/select_into.sgml,v 1.36 2005/08/01 20:31:04 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -31,7 +31,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
3131
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
3232
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
3333
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
34-
[ FOR { UPDATE | SHARE } [ OF <replaceable class="PARAMETER">tablename</replaceable> [, ...] ] ]
34+
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
3535
</synopsis>
3636
</refsynopsisdiv>
3737

doc/src/sgml/sql.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.37 2005/07/14 06:17:35 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/sql.sgml,v 1.38 2005/08/01 20:31:05 tgl Exp $
33
-->
44

55
<chapter id="sql-intro">
@@ -865,7 +865,7 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
865865
[ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
866866
[ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
867867
[ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
868-
[ FOR { UPDATE | SHARE } [ OF <replaceable class="PARAMETER">class_name</replaceable> [, ...] ] ]
868+
[ FOR { UPDATE | SHARE } [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ] [ NOWAIT ] ]
869869
</synopsis>
870870
</para>
871871

src/backend/access/heap/heapam.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.195 2005/06/20 18:37:01 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.196 2005/08/01 20:31:05 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -1945,7 +1945,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
19451945
*/
19461946
HTSU_Result
19471947
heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
1948-
CommandId cid, LockTupleMode mode)
1948+
CommandId cid, LockTupleMode mode, bool nowait)
19491949
{
19501950
HTSU_Result result;
19511951
ItemPointer tid = &(tuple->t_self);
@@ -1998,7 +1998,16 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
19981998
*/
19991999
if (!have_tuple_lock)
20002000
{
2001-
LockTuple(relation, tid, tuple_lock_type);
2001+
if (nowait)
2002+
{
2003+
if (!ConditionalLockTuple(relation, tid, tuple_lock_type))
2004+
ereport(ERROR,
2005+
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
2006+
errmsg("could not obtain lock on row in relation \"%s\"",
2007+
RelationGetRelationName(relation))));
2008+
}
2009+
else
2010+
LockTuple(relation, tid, tuple_lock_type);
20022011
have_tuple_lock = true;
20032012
}
20042013

@@ -2020,7 +2029,17 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
20202029
else if (infomask & HEAP_XMAX_IS_MULTI)
20212030
{
20222031
/* wait for multixact to end */
2023-
MultiXactIdWait((MultiXactId) xwait);
2032+
if (nowait)
2033+
{
2034+
if (!ConditionalMultiXactIdWait((MultiXactId) xwait))
2035+
ereport(ERROR,
2036+
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
2037+
errmsg("could not obtain lock on row in relation \"%s\"",
2038+
RelationGetRelationName(relation))));
2039+
}
2040+
else
2041+
MultiXactIdWait((MultiXactId) xwait);
2042+
20242043
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
20252044

20262045
/*
@@ -2045,7 +2064,17 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
20452064
else
20462065
{
20472066
/* wait for regular transaction to end */
2048-
XactLockTableWait(xwait);
2067+
if (nowait)
2068+
{
2069+
if (!ConditionalXactLockTableWait(xwait))
2070+
ereport(ERROR,
2071+
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
2072+
errmsg("could not obtain lock on row in relation \"%s\"",
2073+
RelationGetRelationName(relation))));
2074+
}
2075+
else
2076+
XactLockTableWait(xwait);
2077+
20492078
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
20502079

20512080
/*

src/backend/access/transam/multixact.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
4343
* Portions Copyright (c) 1994, Regents of the University of California
4444
*
45-
* $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.5 2005/06/08 15:50:25 tgl Exp $
45+
* $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.6 2005/08/01 20:31:06 tgl Exp $
4646
*
4747
*-------------------------------------------------------------------------
4848
*/
@@ -558,6 +558,43 @@ MultiXactIdWait(MultiXactId multi)
558558
}
559559
}
560560

561+
/*
562+
* ConditionalMultiXactIdWait
563+
* As above, but only lock if we can get the lock without blocking.
564+
*/
565+
bool
566+
ConditionalMultiXactIdWait(MultiXactId multi)
567+
{
568+
bool result = true;
569+
TransactionId *members;
570+
int nmembers;
571+
572+
nmembers = GetMultiXactIdMembers(multi, &members);
573+
574+
if (nmembers >= 0)
575+
{
576+
int i;
577+
578+
for (i = 0; i < nmembers; i++)
579+
{
580+
TransactionId member = members[i];
581+
582+
debug_elog4(DEBUG2, "ConditionalMultiXactIdWait: trying %d (%u)",
583+
i, member);
584+
if (!TransactionIdIsCurrentTransactionId(member))
585+
{
586+
result = ConditionalXactLockTableWait(member);
587+
if (!result)
588+
break;
589+
}
590+
}
591+
592+
pfree(members);
593+
}
594+
595+
return result;
596+
}
597+
561598
/*
562599
* CreateMultiXactId
563600
* Make a new MultiXactId
@@ -590,7 +627,7 @@ CreateMultiXactId(int nxids, TransactionId *xids)
590627
*/
591628
multi = mXactCacheGetBySet(nxids, xids);
592629
if (MultiXactIdIsValid(multi))
593-
{
630+
{
594631
debug_elog2(DEBUG2, "Create: in cache!");
595632
return multi;
596633
}

src/backend/commands/trigger.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.189 2005/05/30 07:20:58 neilc Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.190 2005/08/01 20:31:07 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1598,7 +1598,8 @@ GetTupleForTrigger(EState *estate, ResultRelInfo *relinfo,
15981598
*newSlot = NULL;
15991599
tuple.t_self = *tid;
16001600
ltrmark:;
1601-
test = heap_lock_tuple(relation, &tuple, &buffer, cid, LockTupleExclusive);
1601+
test = heap_lock_tuple(relation, &tuple, &buffer, cid,
1602+
LockTupleExclusive, false);
16021603
switch (test)
16031604
{
16041605
case HeapTupleSelfUpdated:

src/backend/executor/execMain.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.251 2005/06/28 05:08:55 tgl Exp $
29+
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.252 2005/08/01 20:31:07 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -559,8 +559,9 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
559559
/*
560560
* Have to lock relations selected FOR UPDATE/FOR SHARE
561561
*/
562-
estate->es_rowMark = NIL;
562+
estate->es_rowMarks = NIL;
563563
estate->es_forUpdate = parseTree->forUpdate;
564+
estate->es_rowNoWait = parseTree->rowNoWait;
564565
if (parseTree->rowMarks != NIL)
565566
{
566567
ListCell *l;
@@ -577,7 +578,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
577578
erm->relation = relation;
578579
erm->rti = rti;
579580
snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti);
580-
estate->es_rowMark = lappend(estate->es_rowMark, erm);
581+
estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
581582
}
582583
}
583584

@@ -1010,12 +1011,12 @@ ExecEndPlan(PlanState *planstate, EState *estate)
10101011
}
10111012

10121013
heap_close(estate->es_into_relation_descriptor, NoLock);
1013-
}
1014+
}
10141015

10151016
/*
10161017
* close any relations selected FOR UPDATE/FOR SHARE, again keeping locks
10171018
*/
1018-
foreach(l, estate->es_rowMark)
1019+
foreach(l, estate->es_rowMarks)
10191020
{
10201021
execRowMark *erm = lfirst(l);
10211022

@@ -1156,12 +1157,12 @@ lnext: ;
11561157
/*
11571158
* Process any FOR UPDATE or FOR SHARE locking requested.
11581159
*/
1159-
else if (estate->es_rowMark != NIL)
1160+
else if (estate->es_rowMarks != NIL)
11601161
{
11611162
ListCell *l;
11621163

11631164
lmark: ;
1164-
foreach(l, estate->es_rowMark)
1165+
foreach(l, estate->es_rowMarks)
11651166
{
11661167
execRowMark *erm = lfirst(l);
11671168
Buffer buffer;
@@ -1190,7 +1191,7 @@ lnext: ;
11901191
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
11911192
test = heap_lock_tuple(erm->relation, &tuple, &buffer,
11921193
estate->es_snapshot->curcid,
1193-
lockmode);
1194+
lockmode, estate->es_rowNoWait);
11941195
ReleaseBuffer(buffer);
11951196
switch (test)
11961197
{
@@ -1823,7 +1824,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
18231824
ListCell *l;
18241825

18251826
relation = NULL;
1826-
foreach(l, estate->es_rowMark)
1827+
foreach(l, estate->es_rowMarks)
18271828
{
18281829
if (((execRowMark *) lfirst(l))->rti == rti)
18291830
{
@@ -2128,8 +2129,9 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
21282129
if (estate->es_topPlan->nParamExec > 0)
21292130
epqstate->es_param_exec_vals = (ParamExecData *)
21302131
palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
2131-
epqstate->es_rowMark = estate->es_rowMark;
2132+
epqstate->es_rowMarks = estate->es_rowMarks;
21322133
epqstate->es_forUpdate = estate->es_forUpdate;
2134+
epqstate->es_rowNoWait = estate->es_rowNoWait;
21332135
epqstate->es_instrument = estate->es_instrument;
21342136
epqstate->es_select_into = estate->es_select_into;
21352137
epqstate->es_into_oids = estate->es_into_oids;

src/backend/executor/execUtils.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.124 2005/06/20 18:37:01 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.125 2005/08/01 20:31:07 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -199,8 +199,9 @@ CreateExecutorState(void)
199199

200200
estate->es_processed = 0;
201201
estate->es_lastoid = InvalidOid;
202-
estate->es_rowMark = NIL;
202+
estate->es_rowMarks = NIL;
203203
estate->es_forUpdate = false;
204+
estate->es_rowNoWait = false;
204205

205206
estate->es_instrument = false;
206207
estate->es_select_into = false;

0 commit comments

Comments
 (0)