Commit 8d846444 authored by Dean Rasheed's avatar Dean Rasheed

Fix alias matching in transformLockingClause().

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
parent 9783413c
......@@ -3245,11 +3245,28 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
foreach(rt, qry->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
char *rtename;
++i;
if (!rte->inFromCl)
continue;
if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
/*
* 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), except if it has a USING
* alias, which *is* visible.
*/
if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
{
if (rte->join_using_alias == NULL)
continue;
rtename = rte->join_using_alias->aliasname;
}
else
rtename = rte->eref->aliasname;
if (strcmp(rtename, thisrel->relname) == 0)
{
switch (rte->rtekind)
{
......
......@@ -2501,6 +2501,39 @@ 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)
select foo.*, unnamed_join.* from
t1 join t2 using (a) as foo, t3 as unnamed_join
for update of unnamed_join;
a | x | y
---+---+---
(0 rows)
select foo.*, unnamed_join.* from
t1 join t2 using (a) as foo, t3 as unnamed_join
for update of foo;
ERROR: FOR UPDATE cannot be applied to a join
LINE 3: for update of foo;
^
select bar.*, unnamed_join.* from
(t1 join t2 using (a) as foo) as bar, t3 as unnamed_join
for update of foo;
ERROR: relation "foo" in FOR UPDATE clause not found in FROM clause
LINE 3: for update of foo;
^
select bar.*, unnamed_join.* from
(t1 join t2 using (a) as foo) as bar, t3 as unnamed_join
for update of bar;
ERROR: FOR UPDATE cannot be applied to a join
LINE 3: for update of bar;
^
--
-- regression test for 8.1 merge right join bug
--
......
......@@ -520,6 +520,28 @@ 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;
select foo.*, unnamed_join.* from
t1 join t2 using (a) as foo, t3 as unnamed_join
for update of unnamed_join;
select foo.*, unnamed_join.* from
t1 join t2 using (a) as foo, t3 as unnamed_join
for update of foo;
select bar.*, unnamed_join.* from
(t1 join t2 using (a) as foo) as bar, t3 as unnamed_join
for update of foo;
select bar.*, unnamed_join.* from
(t1 join t2 using (a) as foo) as bar, t3 as unnamed_join
for update of bar;
--
-- regression test for 8.1 merge right join bug
--
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment