]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix alias matching in transformLockingClause().
authorDean Rasheed <dean.a.rasheed@gmail.com>
Thu, 7 Jul 2022 12:07:57 +0000 (13:07 +0100)
committerDean Rasheed <dean.a.rasheed@gmail.com>
Thu, 7 Jul 2022 12:07:57 +0000 (13:07 +0100)
When locking a specific named relation for a FOR [KEY] UPDATE/SHARE
clause, transformLockingClause() finds the relation to lock by
scanning the rangetable for an RTE with a matching eref->aliasname.
However, it failed to account for the visibility rules of a join RTE.

If a join RTE doesn't have a user-supplied alias, it will have a
generated eref->aliasname of "unnamed_join" that is not visible as a
relation name in the parse namespace. Such an RTE needs to be skipped,
otherwise it might be found in preference to a regular base relation
with a user-supplied alias of "unnamed_join", preventing it from being
locked.

In addition, if a join RTE doesn't have a user-supplied alias, but
does have a join_using_alias, then the RTE needs to be matched using
that alias rather than the generated eref->aliasname, otherwise a
misleading "relation not found" error will be reported rather than a
"join cannot be locked" error.

Backpatch all the way, except for the second part which only goes back
to 14, where JOIN USING aliases were added.

Dean Rasheed, reviewed by Tom Lane.

Discussion: https://postgr.es/m/CAEZATCUY_KOBnqxbTSPf=7fz9HWPnZ5Xgb9SwYzZ8rFXe7nb=w@mail.gmail.com

src/backend/parser/analyze.c
src/test/regress/expected/join.out
src/test/regress/sql/join.sql

index d243e0284a5ac71a9a52a2cd89cfa11728e28c14..9f59b4af3572103afe68090046f71168db7a1b57 100644 (file)
@@ -2809,6 +2809,15 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
                                ++i;
                                if (!rte->inFromCl)
                                        continue;
+
+                               /*
+                                * A join RTE without an alias is not visible as a relation
+                                * name and needs to be skipped (otherwise it might hide a
+                                * base relation with the same name).
+                                */
+                               if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
+                                       continue;
+
                                if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
                                {
                                        switch (rte->rtekind)
index d2db9804e41f69711f9fc67c66bd33799e716f8f..610e70d1cfdf8ed993101782a3790765600e10b9 100644 (file)
@@ -2449,6 +2449,14 @@ ERROR:  column t1.x does not exist
 LINE 1: select t1.x from t1 join t3 on (t1.a = t3.x);
                ^
 HINT:  Perhaps you meant to reference the column "t3.x".
+-- Test matching of locking clause with wrong alias
+select t1.*, t2.*, unnamed_join.* from
+  t1 join t2 on (t1.a = t2.a), t3 as unnamed_join
+  for update of unnamed_join;
+ a | b | a | b | x | y 
+---+---+---+---+---+---
+(0 rows)
+
 --
 -- regression test for 8.1 merge right join bug
 --
index 16c9b2e4322c33c1371ede3a7e0b041b6fc6bc23..2fff1a882e13d5a698f4483b6be332d2792109a9 100644 (file)
@@ -509,6 +509,12 @@ select * from t1 left join t2 on (t1.a = t2.a);
 
 select t1.x from t1 join t3 on (t1.a = t3.x);
 
+-- Test matching of locking clause with wrong alias
+
+select t1.*, t2.*, unnamed_join.* from
+  t1 join t2 on (t1.a = t2.a), t3 as unnamed_join
+  for update of unnamed_join;
+
 --
 -- regression test for 8.1 merge right join bug
 --