diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index ff0e875f..bb254079 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -167,6 +167,7 @@ static void set_param_references(PlannerInfo *root, Plan *plan); static Node *convert_combining_aggrefs(Node *node, void *context); static void set_dummy_tlist_references(Plan *plan, int rtoffset); static indexed_tlist *build_tlist_index(List *tlist); +static indexed_tlist *build_tlist_index_other_vars(List *tlist, int ignore_rel); static Var *search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, int newvarno, @@ -1168,7 +1169,8 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) { indexed_tlist *itlist; - itlist = build_tlist_index(splan->exclRelTlist); + itlist = build_tlist_index_other_vars(splan->exclRelTlist, + 0); splan->onConflictSet = fix_join_expr(root, splan->onConflictSet, diff --git a/src/test/regress/expected/generated_virtual.out b/src/test/regress/expected/generated_virtual.out index fc41c480..8f5ad91b 100644 --- a/src/test/regress/expected/generated_virtual.out +++ b/src/test/regress/expected/generated_virtual.out @@ -1723,3 +1723,55 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; +-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT +-- DO UPDATE is expanded to the generation expression, both for plain and +-- partitioned target relations. Previously, the plan-time setrefs step +-- would re-collapse the expanded expression into a Var referring to the +-- virtual attnum of the EXCLUDED slot, producing either an "unexpected +-- virtual generated column reference" error (plain table) or a silent NULL +-- (partitioned table, via tuple routing's attribute remapping). +create table gtest34 (id int primary key, a int, + c int generated always as (a * 10) virtual); +insert into gtest34 values (1, 5); +insert into gtest34 values (1, 7) + on conflict (id) do update set a = excluded.c returning *; + id | a | c +----+----+----- + 1 | 70 | 700 +(1 row) + +insert into gtest34 values (1, 2) + on conflict (id) do update set a = gtest34.c + excluded.c returning *; + id | a | c +----+-----+------ + 1 | 720 | 7200 +(1 row) + +insert into gtest34 values (1, 3) + on conflict (id) do update set a = 999 where excluded.c > 20 returning *; + id | a | c +----+-----+------ + 1 | 999 | 9990 +(1 row) + +drop table gtest34; +create table gtest34p (id int primary key, a int, + c int generated always as (a * 10) virtual) + partition by range (id); +create table gtest34p_1 partition of gtest34p for values from (1) to (100); +insert into gtest34p values (1, 5); +insert into gtest34p values (1, 7) + on conflict (id) do update set a = excluded.c returning *; + id | a | c +----+----+----- + 1 | 70 | 700 +(1 row) + +insert into gtest34p values (1, 2) + on conflict (id) do update set a = gtest34p.c + excluded.c returning *; + id | a | c +----+-----+------ + 1 | 720 | 7200 +(1 row) + +drop table gtest34p; diff --git a/src/test/regress/sql/generated_virtual.sql b/src/test/regress/sql/generated_virtual.sql index 9b32413e..6e958011 100644 --- a/src/test/regress/sql/generated_virtual.sql +++ b/src/test/regress/sql/generated_virtual.sql @@ -906,3 +906,32 @@ select * from gtest33 where b is null; reset constraint_exclusion; drop table gtest33; + +-- Ensure that EXCLUDED. in INSERT ... ON CONFLICT +-- DO UPDATE is expanded to the generation expression, both for plain and +-- partitioned target relations. Previously, the plan-time setrefs step +-- would re-collapse the expanded expression into a Var referring to the +-- virtual attnum of the EXCLUDED slot, producing either an "unexpected +-- virtual generated column reference" error (plain table) or a silent NULL +-- (partitioned table, via tuple routing's attribute remapping). +create table gtest34 (id int primary key, a int, + c int generated always as (a * 10) virtual); +insert into gtest34 values (1, 5); +insert into gtest34 values (1, 7) + on conflict (id) do update set a = excluded.c returning *; +insert into gtest34 values (1, 2) + on conflict (id) do update set a = gtest34.c + excluded.c returning *; +insert into gtest34 values (1, 3) + on conflict (id) do update set a = 999 where excluded.c > 20 returning *; +drop table gtest34; + +create table gtest34p (id int primary key, a int, + c int generated always as (a * 10) virtual) + partition by range (id); +create table gtest34p_1 partition of gtest34p for values from (1) to (100); +insert into gtest34p values (1, 5); +insert into gtest34p values (1, 7) + on conflict (id) do update set a = excluded.c returning *; +insert into gtest34p values (1, 2) + on conflict (id) do update set a = gtest34p.c + excluded.c returning *; +drop table gtest34p;