aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-08-19 12:12:35 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-08-19 12:12:35 -0400
commitfbc1eed8a8dd3178de70de53a0e95786c80f9dbc (patch)
tree7f59fa6ccc3e28019d3f7d950a7c044ea4a32f87 /src/backend/parser/analyze.c
parenta65319f093a61cecda7e27f94521704855861046 (diff)
downloadpostgresql-fbc1eed8a8dd3178de70de53a0e95786c80f9dbc.tar.gz
postgresql-fbc1eed8a8dd3178de70de53a0e95786c80f9dbc.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/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index f491d937397..21d26cf7dbc 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -2758,13 +2758,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:
@@ -2794,7 +2803,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);
@@ -2815,6 +2828,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)