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

Commit 46e3a16

Browse files
committed
When FOR UPDATE/SHARE is used with LIMIT, put the LockRows plan node
underneath the Limit node, not atop it. This fixes the old problem that such a query might unexpectedly return fewer rows than the LIMIT says, due to LockRows discarding updated rows. There is a related problem that LockRows might destroy the sort ordering produced by earlier steps; but fixing that by pushing LockRows below Sort would create serious performance problems that are unjustified in many real-world applications, as well as potential deadlock problems from locking many more rows than expected. Instead, keep the present semantics of applying FOR UPDATE after ORDER BY within a single query level; but allow the user to specify the other way by writing FOR UPDATE in a sub-select. To make that work, track whether FOR UPDATE appeared explicitly in sub-selects or got pushed down from the parent, and don't flatten a sub-select that contained an explicit FOR UPDATE.
1 parent 44956c5 commit 46e3a16

File tree

13 files changed

+225
-126
lines changed

13 files changed

+225
-126
lines changed

doc/src/sgml/ref/select.sgml

Lines changed: 83 additions & 41 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.127 2009/10/27 17:11:18 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.128 2009/10/28 14:55:37 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -1092,22 +1092,12 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
10921092
has already locked a selected row or rows, <command>SELECT FOR
10931093
UPDATE</command> will wait for the other transaction to complete,
10941094
and will then lock and return the updated row (or no row, if the
1095-
row was deleted). For further discussion see <xref
1095+
row was deleted). Within a <literal>SERIALIZABLE</> transaction,
1096+
however, an error will be thrown if a row to be locked has changed
1097+
since the transaction started. For further discussion see <xref
10961098
linkend="mvcc">.
10971099
</para>
10981100

1099-
<para>
1100-
To prevent the operation from waiting for other transactions to commit,
1101-
use the <literal>NOWAIT</> option. <command>SELECT FOR UPDATE
1102-
NOWAIT</command> reports an error, rather than waiting, if a selected row
1103-
cannot be locked immediately. Note that <literal>NOWAIT</> applies only
1104-
to the row-level lock(s) &mdash; the required <literal>ROW SHARE</literal>
1105-
table-level lock is still taken in the ordinary way (see
1106-
<xref linkend="mvcc">). You can use the <literal>NOWAIT</> option of
1107-
<xref linkend="sql-lock" endterm="sql-lock-title">
1108-
if you need to acquire the table-level lock without waiting.
1109-
</para>
1110-
11111101
<para>
11121102
<literal>FOR SHARE</literal> behaves similarly, except that it
11131103
acquires a shared rather than exclusive lock on each retrieved
@@ -1117,13 +1107,26 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
11171107
from performing <command>SELECT FOR SHARE</command>.
11181108
</para>
11191109

1110+
<para>
1111+
To prevent the operation from waiting for other transactions to commit,
1112+
use the <literal>NOWAIT</> option. With <literal>NOWAIT</>, the statement
1113+
reports an error, rather than waiting, if a selected row
1114+
cannot be locked immediately. Note that <literal>NOWAIT</> applies only
1115+
to the row-level lock(s) &mdash; the required <literal>ROW SHARE</literal>
1116+
table-level lock is still taken in the ordinary way (see
1117+
<xref linkend="mvcc">). You can use
1118+
<xref linkend="sql-lock" endterm="sql-lock-title">
1119+
with the <literal>NOWAIT</> option first,
1120+
if you need to acquire the table-level lock without waiting.
1121+
</para>
1122+
11201123
<para>
11211124
If specific tables are named in <literal>FOR UPDATE</literal>
11221125
or <literal>FOR SHARE</literal>,
11231126
then only rows coming from those tables are locked; any other
11241127
tables used in the <command>SELECT</command> are simply read as
11251128
usual. A <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
1126-
clause without a table list affects all tables used in the command.
1129+
clause without a table list affects all tables used in the statement.
11271130
If <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal> is
11281131
applied to a view or sub-query, it affects all tables used in
11291132
the view or sub-query.
@@ -1151,6 +1154,36 @@ FOR SHARE [ OF <replaceable class="parameter">table_name</replaceable> [, ...] ]
11511154
individual table rows; for example they cannot be used with aggregation.
11521155
</para>
11531156

1157+
<para>
1158+
When <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
1159+
appears at the top level of a <command>SELECT</> query, the rows that
1160+
are locked are exactly those that are returned by the query; in the
1161+
case of a join query, the rows locked are those that contribute to
1162+
returned join rows. In addition, rows that satisfied the query
1163+
conditions as of the query snapshot will be locked, although they
1164+
will not be returned if they have since been updated to not satisfy
1165+
the query conditions. If a <literal>LIMIT</> is used, locking stops
1166+
once enough rows have been returned to satisfy the limit (but note that
1167+
rows skipped over by <literal>OFFSET</> will get locked). Similarly,
1168+
if <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
1169+
is used in a cursor's query, only rows actually fetched or stepped past
1170+
by the cursor will be locked.
1171+
</para>
1172+
1173+
<para>
1174+
When <literal>FOR UPDATE</literal> or <literal>FOR SHARE</literal>
1175+
appears in a sub-<command>SELECT</>, the rows locked are those
1176+
returned to the outer query by the sub-query. This might involve
1177+
fewer rows than inspection of the sub-query alone would suggest,
1178+
since conditions from the outer query might be used to optimize
1179+
execution of the sub-query. For example,
1180+
<programlisting>
1181+
SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;
1182+
</programlisting>
1183+
will lock only rows having <literal>col1 = 5</>, even though that
1184+
condition is not textually within the sub-query.
1185+
</para>
1186+
11541187
<caution>
11551188
<para>
11561189
Avoid locking a row and then modifying it within a later savepoint or
@@ -1177,30 +1210,26 @@ ROLLBACK TO s;
11771210

11781211
<caution>
11791212
<para>
1180-
It is possible for a <command>SELECT</> command using both
1181-
<literal>LIMIT</literal> and <literal>FOR UPDATE/SHARE</literal>
1182-
clauses to return fewer rows than specified by <literal>LIMIT</literal>.
1183-
This is because <literal>LIMIT</> is applied first. The command
1184-
selects the specified number of rows,
1185-
but might then block trying to obtain a lock on one or more of them.
1186-
Once the <literal>SELECT</> unblocks, the row might have been deleted
1187-
or updated so that it does not meet the query <literal>WHERE</> condition
1188-
anymore, in which case it will not be returned.
1189-
</para>
1190-
</caution>
1191-
1192-
<caution>
1193-
<para>
1194-
Similarly, it is possible for a <command>SELECT</> command
1195-
using <literal>ORDER BY</literal> and <literal>FOR
1196-
UPDATE/SHARE</literal> to return rows out of order. This is
1197-
because <literal>ORDER BY</> is applied first. The command
1198-
orders the result, but might then block trying to obtain a lock
1199-
on one or more of the rows. Once the <literal>SELECT</>
1200-
unblocks, one of the ordered columns might have been modified
1201-
and be returned out of order. A workaround is to perform
1202-
<command>SELECT ... FOR UPDATE/SHARE</> and then <command>SELECT
1203-
... ORDER BY</>.
1213+
It is possible for a <command>SELECT</> command using <literal>ORDER
1214+
BY</literal> and <literal>FOR UPDATE/SHARE</literal> to return rows out of
1215+
order. This is because <literal>ORDER BY</> is applied first.
1216+
The command sorts the result, but might then block trying to obtain a lock
1217+
on one or more of the rows. Once the <literal>SELECT</> unblocks, some
1218+
of the ordering column values might have been modified, leading to those
1219+
rows appearing to be out of order (though they are in order in terms
1220+
of the original column values). This can be worked around at need by
1221+
placing the <literal>FOR UPDATE/SHARE</literal> clause in a sub-query,
1222+
for example
1223+
<programlisting>
1224+
SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;
1225+
</programlisting>
1226+
Note that this will result in locking all rows of <structname>mytable</>,
1227+
whereas <literal>FOR UPDATE</> at the top level would lock only the
1228+
actually returned rows. This can make for a significant performance
1229+
difference, particularly if the <literal>ORDER BY</> is combined with
1230+
<literal>LIMIT</> or other restrictions. So this technique is recommended
1231+
only if concurrent updates of the ordering columns are expected and a
1232+
strictly sorted result is required.
12041233
</para>
12051234
</caution>
12061235
</refsect2>
@@ -1541,15 +1570,28 @@ SELECT distributors.* WHERE distributors.name = 'Westward';
15411570
used by <productname>MySQL</productname>. The SQL:2008 standard
15421571
has introduced the clauses <literal>OFFSET ... FETCH {FIRST|NEXT}
15431572
...</literal> for the same functionality, as shown above
1544-
in <xref linkend="sql-limit" endterm="sql-limit-title">, and this
1573+
in <xref linkend="sql-limit" endterm="sql-limit-title">. This
15451574
syntax is also used by <productname>IBM DB2</productname>.
15461575
(Applications written for <productname>Oracle</productname>
15471576
frequently use a workaround involving the automatically
1548-
generated <literal>rownum</literal> column, not available in
1577+
generated <literal>rownum</literal> column, which is not available in
15491578
PostgreSQL, to implement the effects of these clauses.)
15501579
</para>
15511580
</refsect2>
15521581

1582+
<refsect2>
1583+
<title><literal>FOR UPDATE</> and <literal>FOR SHARE</></title>
1584+
1585+
<para>
1586+
Although <literal>FOR UPDATE</> appears in the SQL standard, the
1587+
standard allows it only as an option of <command>DECLARE CURSOR</>.
1588+
<productname>PostgreSQL</productname> allows it in any <command>SELECT</>
1589+
query as well as in sub-<command>SELECT</>s, but this is an extension.
1590+
The <literal>FOR SHARE</> variant, and the <literal>NOWAIT</> option,
1591+
do not appear in the standard.
1592+
</para>
1593+
</refsect2>
1594+
15531595
<refsect2>
15541596
<title>Nonstandard Clauses</title>
15551597

src/backend/nodes/copyfuncs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.449 2009/10/26 02:26:31 tgl Exp $
18+
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.450 2009/10/28 14:55:38 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -1859,6 +1859,7 @@ _copyRowMarkClause(RowMarkClause *from)
18591859
COPY_SCALAR_FIELD(rti);
18601860
COPY_SCALAR_FIELD(forUpdate);
18611861
COPY_SCALAR_FIELD(noWait);
1862+
COPY_SCALAR_FIELD(pushedDown);
18621863

18631864
return newnode;
18641865
}
@@ -2223,6 +2224,7 @@ _copyQuery(Query *from)
22232224
COPY_SCALAR_FIELD(hasSubLinks);
22242225
COPY_SCALAR_FIELD(hasDistinctOn);
22252226
COPY_SCALAR_FIELD(hasRecursive);
2227+
COPY_SCALAR_FIELD(hasForUpdate);
22262228
COPY_NODE_FIELD(cteList);
22272229
COPY_NODE_FIELD(rtable);
22282230
COPY_NODE_FIELD(jointree);

src/backend/nodes/equalfuncs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* Portions Copyright (c) 1994, Regents of the University of California
2323
*
2424
* IDENTIFICATION
25-
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.371 2009/10/26 02:26:31 tgl Exp $
25+
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.372 2009/10/28 14:55:38 tgl Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -860,6 +860,7 @@ _equalQuery(Query *a, Query *b)
860860
COMPARE_SCALAR_FIELD(hasSubLinks);
861861
COMPARE_SCALAR_FIELD(hasDistinctOn);
862862
COMPARE_SCALAR_FIELD(hasRecursive);
863+
COMPARE_SCALAR_FIELD(hasForUpdate);
863864
COMPARE_NODE_FIELD(cteList);
864865
COMPARE_NODE_FIELD(rtable);
865866
COMPARE_NODE_FIELD(jointree);
@@ -2198,6 +2199,7 @@ _equalRowMarkClause(RowMarkClause *a, RowMarkClause *b)
21982199
COMPARE_SCALAR_FIELD(rti);
21992200
COMPARE_SCALAR_FIELD(forUpdate);
22002201
COMPARE_SCALAR_FIELD(noWait);
2202+
COMPARE_SCALAR_FIELD(pushedDown);
22012203

22022204
return true;
22032205
}

src/backend/nodes/outfuncs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.370 2009/10/26 02:26:31 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.371 2009/10/28 14:55:38 tgl Exp $
1212
*
1313
* NOTES
1414
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1987,6 +1987,7 @@ _outQuery(StringInfo str, Query *node)
19871987
WRITE_BOOL_FIELD(hasSubLinks);
19881988
WRITE_BOOL_FIELD(hasDistinctOn);
19891989
WRITE_BOOL_FIELD(hasRecursive);
1990+
WRITE_BOOL_FIELD(hasForUpdate);
19901991
WRITE_NODE_FIELD(cteList);
19911992
WRITE_NODE_FIELD(rtable);
19921993
WRITE_NODE_FIELD(jointree);
@@ -2036,6 +2037,7 @@ _outRowMarkClause(StringInfo str, RowMarkClause *node)
20362037
WRITE_UINT_FIELD(rti);
20372038
WRITE_BOOL_FIELD(forUpdate);
20382039
WRITE_BOOL_FIELD(noWait);
2040+
WRITE_BOOL_FIELD(pushedDown);
20392041
}
20402042

20412043
static void

src/backend/nodes/readfuncs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.226 2009/10/26 02:26:32 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.227 2009/10/28 14:55:38 tgl Exp $
1212
*
1313
* NOTES
1414
* Path and Plan nodes do not have any readfuncs support, because we
@@ -203,6 +203,7 @@ _readQuery(void)
203203
READ_BOOL_FIELD(hasSubLinks);
204204
READ_BOOL_FIELD(hasDistinctOn);
205205
READ_BOOL_FIELD(hasRecursive);
206+
READ_BOOL_FIELD(hasForUpdate);
206207
READ_NODE_FIELD(cteList);
207208
READ_NODE_FIELD(rtable);
208209
READ_NODE_FIELD(jointree);
@@ -295,6 +296,7 @@ _readRowMarkClause(void)
295296
READ_UINT_FIELD(rti);
296297
READ_BOOL_FIELD(forUpdate);
297298
READ_BOOL_FIELD(noWait);
299+
READ_BOOL_FIELD(pushedDown);
298300

299301
READ_DONE();
300302
}

src/backend/optimizer/plan/planner.c

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.260 2009/10/26 02:26:33 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.261 2009/10/28 14:55:38 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1638,19 +1638,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
16381638
}
16391639

16401640
/*
1641-
* If there is a LIMIT/OFFSET clause, add the LIMIT node.
1642-
*/
1643-
if (parse->limitCount || parse->limitOffset)
1644-
{
1645-
result_plan = (Plan *) make_limit(result_plan,
1646-
parse->limitOffset,
1647-
parse->limitCount,
1648-
offset_est,
1649-
count_est);
1650-
}
1651-
1652-
/*
1653-
* Finally, if there is a FOR UPDATE/SHARE clause, add the LockRows node.
1641+
* If there is a FOR UPDATE/SHARE clause, add the LockRows node.
16541642
* (Note: we intentionally test parse->rowMarks not root->rowMarks here.
16551643
* If there are only non-locking rowmarks, they should be handled by
16561644
* the ModifyTable node instead.)
@@ -1660,6 +1648,23 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
16601648
result_plan = (Plan *) make_lockrows(result_plan,
16611649
root->rowMarks,
16621650
SS_assign_special_param(root));
1651+
/*
1652+
* The result can no longer be assumed sorted, since locking might
1653+
* cause the sort key columns to be replaced with new values.
1654+
*/
1655+
current_pathkeys = NIL;
1656+
}
1657+
1658+
/*
1659+
* Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node.
1660+
*/
1661+
if (parse->limitCount || parse->limitOffset)
1662+
{
1663+
result_plan = (Plan *) make_limit(result_plan,
1664+
parse->limitOffset,
1665+
parse->limitCount,
1666+
offset_est,
1667+
count_est);
16631668
}
16641669

16651670
/* Compute result-relations list if needed */
@@ -1795,20 +1800,33 @@ preprocess_rowmarks(PlannerInfo *root)
17951800

17961801
/*
17971802
* Convert RowMarkClauses to PlanRowMark representation.
1798-
*
1799-
* Note: currently, it is syntactically impossible to have FOR UPDATE
1800-
* applied to an update/delete target rel. If that ever becomes
1801-
* possible, we should drop the target from the PlanRowMark list.
18021803
*/
18031804
prowmarks = NIL;
18041805
foreach(l, parse->rowMarks)
18051806
{
18061807
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
1807-
PlanRowMark *newrc = makeNode(PlanRowMark);
1808+
RangeTblEntry *rte = rt_fetch(rc->rti, parse->rtable);
1809+
PlanRowMark *newrc;
18081810

1811+
/*
1812+
* Currently, it is syntactically impossible to have FOR UPDATE
1813+
* applied to an update/delete target rel. If that ever becomes
1814+
* possible, we should drop the target from the PlanRowMark list.
1815+
*/
18091816
Assert(rc->rti != parse->resultRelation);
1817+
1818+
/*
1819+
* Ignore RowMarkClauses for subqueries; they aren't real tables
1820+
* and can't support true locking. Subqueries that got flattened
1821+
* into the main query should be ignored completely. Any that didn't
1822+
* will get ROW_MARK_COPY items in the next loop.
1823+
*/
1824+
if (rte->rtekind != RTE_RELATION)
1825+
continue;
1826+
18101827
rels = bms_del_member(rels, rc->rti);
18111828

1829+
newrc = makeNode(PlanRowMark);
18121830
newrc->rti = newrc->prti = rc->rti;
18131831
if (rc->forUpdate)
18141832
newrc->markType = ROW_MARK_EXCLUSIVE;
@@ -1838,7 +1856,6 @@ preprocess_rowmarks(PlannerInfo *root)
18381856
continue;
18391857

18401858
newrc = makeNode(PlanRowMark);
1841-
18421859
newrc->rti = newrc->prti = i;
18431860
/* real tables support REFERENCE, anything else needs COPY */
18441861
if (rte->rtekind == RTE_RELATION)

0 commit comments

Comments
 (0)