Skip to content

Commit 43830ec

Browse files
committed
Fix parsing of qualified relation names in RETURNING.
Given a qualified refname, refnameNamespaceItem() will search for a matching namespace item by relation OID, rather than by name. Commit 80feb72 broke this by adding additional namespace items for OLD and NEW in the RETURNING list, which have the same relation OID, causing ambiguity. Fix this by ignoring these in the search, which is correct since they don't match the qualified relation name, and so there is no real ambiguity. Reported by Richard Guo. Discussion: https://postgr.es/m/CAMbWs49MBjWYWDROJ8MZ%3DY%2B4UgRQa10wzik1tWrD5yto9eoGXg%40mail.gmail.com
1 parent e24d770 commit 43830ec

File tree

3 files changed

+23
-1
lines changed

3 files changed

+23
-1
lines changed

src/backend/parser/parse_relation.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ static bool isQueryUsingTempRelation_walker(Node *node, void *context);
125125
* that (a) has no alias and (b) is for the same relation identified by
126126
* schemaname.refname. In this case we convert schemaname.refname to a
127127
* relation OID and search by relid, rather than by alias name. This is
128-
* peculiar, but it's what SQL says to do.
128+
* peculiar, but it's what SQL says to do. While processing a query's
129+
* RETURNING list, there may be additional namespace items for OLD and NEW,
130+
* with the same relation OID as the target namespace item. These are
131+
* ignored in the search, since they don't match by schemaname.refname.
129132
*/
130133
ParseNamespaceItem *
131134
refnameNamespaceItem(ParseState *pstate,
@@ -255,6 +258,9 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
255258
/* If not inside LATERAL, ignore lateral-only items */
256259
if (nsitem->p_lateral_only && !pstate->p_lateral_active)
257260
continue;
261+
/* Ignore OLD/NEW namespace items that can appear in RETURNING */
262+
if (nsitem->p_returning_type != VAR_RETURNING_DEFAULT)
263+
continue;
258264

259265
/* yes, the test for alias == NULL should be there... */
260266
if (rte->rtekind == RTE_RELATION &&

src/test/regress/expected/returning.out

+10
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,16 @@ DELETE FROM zerocol
766766
(1 row)
767767

768768
DROP TABLE zerocol;
769+
-- Test schema-qualified table name in RETURNING list
770+
CREATE TABLE public.tt(a int, b int);
771+
INSERT INTO public.tt VALUES (1, 10);
772+
UPDATE public.tt SET b = b * 2 RETURNING a, b, old.b, new.b, tt.b, public.tt.b;
773+
a | b | b | b | b | b
774+
---+----+----+----+----+----
775+
1 | 20 | 10 | 20 | 20 | 20
776+
(1 row)
777+
778+
DROP TABLE public.tt;
769779
-- Test cross-partition updates and attribute mapping
770780
CREATE TABLE foo_parted (a int, b float8, c text) PARTITION BY LIST (a);
771781
CREATE TABLE foo_part_s1 PARTITION OF foo_parted FOR VALUES IN (1);

src/test/regress/sql/returning.sql

+6
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,12 @@ DELETE FROM zerocol
312312
new.tableoid::regclass, new.ctid, ctid, *;
313313
DROP TABLE zerocol;
314314

315+
-- Test schema-qualified table name in RETURNING list
316+
CREATE TABLE public.tt(a int, b int);
317+
INSERT INTO public.tt VALUES (1, 10);
318+
UPDATE public.tt SET b = b * 2 RETURNING a, b, old.b, new.b, tt.b, public.tt.b;
319+
DROP TABLE public.tt;
320+
315321
-- Test cross-partition updates and attribute mapping
316322
CREATE TABLE foo_parted (a int, b float8, c text) PARTITION BY LIST (a);
317323
CREATE TABLE foo_part_s1 PARTITION OF foo_parted FOR VALUES IN (1);

0 commit comments

Comments
 (0)