diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-08-19 12:12:35 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-08-19 12:12:35 -0400 |
commit | 7fa367d96bb1ae25f422d6c2a78424f0f9227b5a (patch) | |
tree | d27dfe4d020d1521c9af1e862c003273df6c300c /src/backend | |
parent | ecd4dd9f1df00ef9e872a4d13bbbe3f3d8d3f966 (diff) | |
download | postgresql-7fa367d96bb1ae25f422d6c2a78424f0f9227b5a.tar.gz postgresql-7fa367d96bb1ae25f422d6c2a78424f0f9227b5a.zip |
Avoid trying to lock OLD/NEW in a rule with FOR UPDATE.
transformLockingClause neglected to exclude the pseudo-RTEs for
OLD/NEW when processing a rule's query. This led to odd errors
or even crashes later on. This bug is very ancient, but it's
not terribly surprising that nobody noticed, since the use-case
for SELECT FOR UPDATE in a non-view rule is somewhere between
thin and non-existent. Still, crashing is not OK.
Per bug #17151 from Zhiyong Wu. Thanks to Masahiko Sawada
for analysis of the problem.
Discussion: https://postgr.es/m/17151-c03a3e6e4ec9aadb@postgresql.org
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/parser/analyze.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index d09e8ccde4e..8a47b854d40 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -2753,13 +2753,22 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, if (lockedRels == NIL) { - /* all regular tables used in query */ + /* + * Lock all regular tables used in query and its subqueries. We + * examine inFromCl to exclude auto-added RTEs, particularly NEW/OLD + * in rules. This is a bit of an abuse of a mostly-obsolete flag, but + * it's convenient. We can't rely on the namespace mechanism that has + * largely replaced inFromCl, since for example we need to lock + * base-relation RTEs even if they are masked by upper joins. + */ i = 0; foreach(rt, qry->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); ++i; + if (!rte->inFromCl) + continue; switch (rte->rtekind) { case RTE_RELATION: @@ -2789,7 +2798,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, } else { - /* just the named tables */ + /* + * Lock just the named tables. As above, we allow locking any base + * relation regardless of alias-visibility rules, so we need to + * examine inFromCl to exclude OLD/NEW. + */ foreach(l, lockedRels) { RangeVar *thisrel = (RangeVar *) lfirst(l); @@ -2810,6 +2823,8 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); ++i; + if (!rte->inFromCl) + continue; if (strcmp(rte->eref->aliasname, thisrel->relname) == 0) { switch (rte->rtekind) |