Skip to content

Commit 88c5566

Browse files
committed
Fix crash in error report of invalid tuple lock
My tweak of these error messages in commit c359a1b contained the thinko that a query would always have rowMarks set for a query containing a locking clause. Not so: when declaring a cursor, for instance, rowMarks isn't set at the point we're checking, so we'd be dereferencing a NULL pointer. The fix is to pass the lock strength to the function raising the error, instead of trying to reverse-engineer it. The result not only is more robust, but it also seems cleaner overall. Per report from Robert Haas.
1 parent 05ee328 commit 88c5566

File tree

9 files changed

+29
-18
lines changed

9 files changed

+29
-18
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,8 @@ preprocess_rowmarks(PlannerInfo *root)
19621962
* CTIDs invalid. This is also checked at parse time, but that's
19631963
* insufficient because of rule substitution, query pullup, etc.
19641964
*/
1965-
CheckSelectLocking(parse);
1965+
CheckSelectLocking(parse, ((RowMarkClause *)
1966+
linitial(parse->rowMarks))->strength);
19661967
}
19671968
else
19681969
{

src/backend/parser/analyze.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,64 +2243,57 @@ LCS_asString(LockClauseStrength strength)
22432243
* exported so planner can check again after rewriting, query pullup, etc
22442244
*/
22452245
void
2246-
CheckSelectLocking(Query *qry)
2246+
CheckSelectLocking(Query *qry, LockClauseStrength strength)
22472247
{
22482248
if (qry->setOperations)
22492249
ereport(ERROR,
22502250
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22512251
/*------
22522252
translator: %s is a SQL row locking clause such as FOR UPDATE */
22532253
errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
2254-
LCS_asString(((RowMarkClause *)
2255-
linitial(qry->rowMarks))->strength))));
2254+
LCS_asString(strength))));
22562255
if (qry->distinctClause != NIL)
22572256
ereport(ERROR,
22582257
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22592258
/*------
22602259
translator: %s is a SQL row locking clause such as FOR UPDATE */
22612260
errmsg("%s is not allowed with DISTINCT clause",
2262-
LCS_asString(((RowMarkClause *)
2263-
linitial(qry->rowMarks))->strength))));
2261+
LCS_asString(strength))));
22642262
if (qry->groupClause != NIL)
22652263
ereport(ERROR,
22662264
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22672265
/*------
22682266
translator: %s is a SQL row locking clause such as FOR UPDATE */
22692267
errmsg("%s is not allowed with GROUP BY clause",
2270-
LCS_asString(((RowMarkClause *)
2271-
linitial(qry->rowMarks))->strength))));
2268+
LCS_asString(strength))));
22722269
if (qry->havingQual != NULL)
22732270
ereport(ERROR,
22742271
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22752272
/*------
22762273
translator: %s is a SQL row locking clause such as FOR UPDATE */
22772274
errmsg("%s is not allowed with HAVING clause",
2278-
LCS_asString(((RowMarkClause *)
2279-
linitial(qry->rowMarks))->strength))));
2275+
LCS_asString(strength))));
22802276
if (qry->hasAggs)
22812277
ereport(ERROR,
22822278
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22832279
/*------
22842280
translator: %s is a SQL row locking clause such as FOR UPDATE */
22852281
errmsg("%s is not allowed with aggregate functions",
2286-
LCS_asString(((RowMarkClause *)
2287-
linitial(qry->rowMarks))->strength))));
2282+
LCS_asString(strength))));
22882283
if (qry->hasWindowFuncs)
22892284
ereport(ERROR,
22902285
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22912286
/*------
22922287
translator: %s is a SQL row locking clause such as FOR UPDATE */
22932288
errmsg("%s is not allowed with window functions",
2294-
LCS_asString(((RowMarkClause *)
2295-
linitial(qry->rowMarks))->strength))));
2289+
LCS_asString(strength))));
22962290
if (expression_returns_set((Node *) qry->targetList))
22972291
ereport(ERROR,
22982292
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
22992293
/*------
23002294
translator: %s is a SQL row locking clause such as FOR UPDATE */
23012295
errmsg("%s is not allowed with set-returning functions in the target list",
2302-
LCS_asString(((RowMarkClause *)
2303-
linitial(qry->rowMarks))->strength))));
2296+
LCS_asString(strength))));
23042297
}
23052298

23062299
/*
@@ -2321,7 +2314,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
23212314
Index i;
23222315
LockingClause *allrels;
23232316

2324-
CheckSelectLocking(qry);
2317+
CheckSelectLocking(qry, lc->strength);
23252318

23262319
/* make a clause we can pass down to subqueries to select all rels */
23272320
allrels = makeNode(LockingClause);

src/include/parser/analyze.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ extern Query *transformStmt(ParseState *pstate, Node *parseTree);
3737
extern bool analyze_requires_snapshot(Node *parseTree);
3838

3939
extern char *LCS_asString(LockClauseStrength strength);
40-
extern void CheckSelectLocking(Query *qry);
40+
extern void CheckSelectLocking(Query *qry, LockClauseStrength strength);
4141
extern void applyLockingClause(Query *qry, Index rtindex,
4242
LockClauseStrength strength, bool noWait, bool pushedDown);
4343

src/test/regress/expected/matview.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ NOTICE: materialized view "no_such_mv" does not exist, skipping
292292
-- make sure invalid comination of options is prohibited
293293
REFRESH MATERIALIZED VIEW CONCURRENTLY tvmm WITH NO DATA;
294294
ERROR: CONCURRENTLY and WITH NO DATA options cannot be used together
295+
-- no tuple locks on materialized views
296+
SELECT * FROM tvvm FOR SHARE;
297+
ERROR: cannot lock rows in materialized view "tvvm"
295298
-- test join of mv and view
296299
SELECT type, m.totamt AS mtot, v.totamt AS vtot FROM tm m LEFT JOIN tv v USING (type) ORDER BY type;
297300
type | mtot | vtot

src/test/regress/expected/portals.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,10 @@ DECLARE c1 CURSOR FOR SELECT * FROM uctest;
12261226
DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no current row
12271227
ERROR: cursor "c1" is not positioned on a row
12281228
ROLLBACK;
1229+
BEGIN;
1230+
DECLARE c1 CURSOR FOR SELECT MIN(f1) FROM uctest FOR UPDATE;
1231+
ERROR: FOR UPDATE is not allowed with aggregate functions
1232+
ROLLBACK;
12291233
-- WHERE CURRENT OF may someday work with views, but today is not that day.
12301234
-- For now, just make sure it errors out cleanly.
12311235
CREATE TEMP VIEW ucview AS SELECT * FROM uctest;

src/test/regress/expected/union.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl;
317317
123
318318
(3 rows)
319319

320+
SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE;
321+
ERROR: FOR NO KEY UPDATE is not allowed with UNION/INTERSECT/EXCEPT
320322
--
321323
-- Mixed types
322324
--

src/test/regress/sql/matview.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ DROP MATERIALIZED VIEW IF EXISTS no_such_mv;
9595
-- make sure invalid comination of options is prohibited
9696
REFRESH MATERIALIZED VIEW CONCURRENTLY tvmm WITH NO DATA;
9797

98+
-- no tuple locks on materialized views
99+
SELECT * FROM tvvm FOR SHARE;
100+
98101
-- test join of mv and view
99102
SELECT type, m.totamt AS mtot, v.totamt AS vtot FROM tm m LEFT JOIN tv v USING (type) ORDER BY type;
100103

src/test/regress/sql/portals.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@ BEGIN;
447447
DECLARE c1 CURSOR FOR SELECT * FROM uctest;
448448
DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no current row
449449
ROLLBACK;
450+
BEGIN;
451+
DECLARE c1 CURSOR FOR SELECT MIN(f1) FROM uctest FOR UPDATE;
452+
ROLLBACK;
450453

451454
-- WHERE CURRENT OF may someday work with views, but today is not that day.
452455
-- For now, just make sure it errors out cleanly.

src/test/regress/sql/union.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl;
109109

110110
SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl;
111111

112+
SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE;
113+
112114
--
113115
-- Mixed types
114116
--

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy