Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+2-1
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

+9-16
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

+1-1
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

+3
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

+4
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

+2
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

+3
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

+3
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

+2
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)