From a1c2d5797313c2ef13a8c3b0ae2539577785eba1 Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Wed, 26 Nov 2025 20:19:21 +0900 Subject: [PATCH] Fix row-identity handling for dummy partitioned resultrels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop adding tableoid for child relations that do not have any row-identity columns. In cases where all partitions are excluded by pruning or constraint exclusion, this allows distribute_row_identity_vars() to detect the empty state (root->row_identity_vars == NIL) and add the appropriate ctid column for the dummy partitioned result relation, satisfying the executor’s requirement that a resultrel always have a row identity. As part of this, make add_row_identity_columns() return a boolean to report whether any row-identity columns were added, and skip FDW children that cannot support the current command. Adjust expected EXPLAIN output accordingly and extend file_fdw tests to cover dummy-root plans with and without pruning. --- contrib/file_fdw/expected/file_fdw.out | 75 +++++++++++++++++++ contrib/file_fdw/sql/file_fdw.sql | 34 +++++++++ src/backend/optimizer/prep/preptlist.c | 4 +- src/backend/optimizer/util/appendinfo.c | 18 ++++- src/backend/optimizer/util/inherit.c | 6 +- src/include/optimizer/appendinfo.h | 2 +- src/test/regress/expected/inherit.out | 14 ++-- src/test/regress/expected/merge.out | 6 +- src/test/regress/expected/partition_prune.out | 4 +- src/test/regress/expected/returning.out | 24 +++--- src/test/regress/expected/updatable_views.out | 20 ++--- src/test/regress/expected/with.out | 14 ++-- 12 files changed, 171 insertions(+), 50 deletions(-) diff --git a/contrib/file_fdw/expected/file_fdw.out b/contrib/file_fdw/expected/file_fdw.out index 5121e27dce5..e60177af8c8 100644 --- a/contrib/file_fdw/expected/file_fdw.out +++ b/contrib/file_fdw/expected/file_fdw.out @@ -457,6 +457,81 @@ SELECT tableoid::regclass, * FROM p2; p2 | 2 | xyzzy (3 rows) +-- Verify that a dummy root partitioned-table result relation works without +-- error when all child partitions are excluded from the plan (for example, +-- by constraint exclusion or pruning). In this case, the executor accepts +-- a missing ctid for the root result relation since no rows can be produced. +-- When a foreign-table child is processed before exclusion, a tableoid junk +-- column may still appear in the targetlist and also wholerow for update. +-- Dummy-root cases where all children are excluded. +-- With pruning off, the foreign child is processed first, then excluded +-- by constraint exclusion. EXPLAIN shows tableoid (rewritten to NULL), +-- and for UPDATE also wholerow as NULL::record. No ctid. +DROP TABLE p2; +SET enable_partition_pruning TO off; +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE false; + QUERY PLAN +-------------------------------- + Delete on public.pt + -> Result + Output: pt.ctid + Replaces: Scan on pt + One-Time Filter: false +(5 rows) + +-- also cover wholerow for UPDATE; expect NULL::oid and NULL::record +EXPLAIN (COSTS OFF, VERBOSE) UPDATE pt SET b = 'x' WHERE false; + QUERY PLAN +------------------------------------ + Update on public.pt + -> Result + Output: 'x'::text, pt.ctid + Replaces: Scan on pt + One-Time Filter: false +(5 rows) + +-- MERGE behaves the same here; expect NULL::oid +EXPLAIN (COSTS OFF, VERBOSE) MERGE INTO pt t USING (VALUES (1, 'x'::text)) AS s(a, b) + ON false WHEN MATCHED THEN UPDATE SET b = s.b; + QUERY PLAN +-------------------------------- + Merge on public.pt t + -> Result + Output: t.ctid + Replaces: Scan on t + One-Time Filter: false +(5 rows) + +-- With pruning on, the foreign child is pruned entirely. The plan has only +-- the dummy root, and EXPLAIN shows ctid (and for UPDATE, ctid plus target). +SET enable_partition_pruning TO on; +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE false; + QUERY PLAN +-------------------------------- + Delete on public.pt + -> Result + Output: ctid + Replaces: Scan on pt + One-Time Filter: false +(5 rows) + +EXPLAIN (COSTS OFF, VERBOSE) UPDATE pt SET b = 'x' WHERE false; + QUERY PLAN +--------------------------------- + Update on public.pt + -> Result + Output: 'x'::text, ctid + Replaces: Scan on pt + One-Time Filter: false +(5 rows) + +-- Foreign child not pruned and it does not support DELETE: error. +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE a = 1; +ERROR: cannot delete from foreign table "p1" +-- Runtime pruning includes the foreign child in the plan; executor errors +-- since the foreign child does not support the command. +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE (SELECT false); +ERROR: cannot delete from foreign table "p1" DROP TABLE pt; -- generated column tests \set filename :abs_srcdir '/data/list1.csv' diff --git a/contrib/file_fdw/sql/file_fdw.sql b/contrib/file_fdw/sql/file_fdw.sql index 1a397ad4bd1..25658b1f2dc 100644 --- a/contrib/file_fdw/sql/file_fdw.sql +++ b/contrib/file_fdw/sql/file_fdw.sql @@ -242,6 +242,40 @@ UPDATE pt set a = 1 where a = 2; -- ERROR SELECT tableoid::regclass, * FROM pt; SELECT tableoid::regclass, * FROM p1; SELECT tableoid::regclass, * FROM p2; + +-- Verify that a dummy root partitioned-table result relation works without +-- error when all child partitions are excluded from the plan (for example, +-- by constraint exclusion or pruning). In this case, the executor accepts +-- a missing ctid for the root result relation since no rows can be produced. +-- When a foreign-table child is processed before exclusion, a tableoid junk +-- column may still appear in the targetlist and also wholerow for update. + +-- Dummy-root cases where all children are excluded. +-- With pruning off, the foreign child is processed first, then excluded +-- by constraint exclusion. EXPLAIN shows tableoid (rewritten to NULL), +-- and for UPDATE also wholerow as NULL::record. No ctid. +DROP TABLE p2; +SET enable_partition_pruning TO off; +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE false; +-- also cover wholerow for UPDATE; expect NULL::oid and NULL::record +EXPLAIN (COSTS OFF, VERBOSE) UPDATE pt SET b = 'x' WHERE false; +-- MERGE behaves the same here; expect NULL::oid +EXPLAIN (COSTS OFF, VERBOSE) MERGE INTO pt t USING (VALUES (1, 'x'::text)) AS s(a, b) + ON false WHEN MATCHED THEN UPDATE SET b = s.b; + +-- With pruning on, the foreign child is pruned entirely. The plan has only +-- the dummy root, and EXPLAIN shows ctid (and for UPDATE, ctid plus target). +SET enable_partition_pruning TO on; +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE false; +EXPLAIN (COSTS OFF, VERBOSE) UPDATE pt SET b = 'x' WHERE false; + +-- Foreign child not pruned and it does not support DELETE: error. +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE a = 1; + +-- Runtime pruning includes the foreign child in the plan; executor errors +-- since the foreign child does not support the command. +EXPLAIN (COSTS OFF, VERBOSE) DELETE FROM pt WHERE (SELECT false); + DROP TABLE pt; -- generated column tests diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index ffc9d6c3f30..26090d71dfd 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -122,8 +122,8 @@ preprocess_targetlist(PlannerInfo *root) { /* row-identity logic expects to add stuff to processed_tlist */ root->processed_tlist = tlist; - add_row_identity_columns(root, result_relation, - target_rte, target_relation); + (void) add_row_identity_columns(root, result_relation, + target_rte, target_relation); tlist = root->processed_tlist; } diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c index 69b8b0c2ae0..f977dfda208 100644 --- a/src/backend/optimizer/util/appendinfo.c +++ b/src/backend/optimizer/util/appendinfo.c @@ -951,7 +951,7 @@ add_row_identity_var(PlannerInfo *root, Var *orig_var, * FDWs might call add_row_identity_var() for themselves to add nonstandard * columns. (Duplicate requests are fine.) */ -void +bool add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation) @@ -977,6 +977,7 @@ add_row_identity_columns(PlannerInfo *root, Index rtindex, InvalidOid, 0); add_row_identity_var(root, var, rtindex, "ctid"); + return true; } else if (relkind == RELKIND_FOREIGN_TABLE) { @@ -987,6 +988,13 @@ add_row_identity_columns(PlannerInfo *root, Index rtindex, fdwroutine = GetFdwRoutineForRelation(target_relation, false); + if (commandType == CMD_MERGE || + (commandType == CMD_UPDATE && + fdwroutine->ExecForeignUpdate == NULL) || + (commandType == CMD_DELETE && + fdwroutine->ExecForeignDelete == NULL)) + return false; + if (fdwroutine->AddForeignUpdateTargets != NULL) fdwroutine->AddForeignUpdateTargets(root, rtindex, target_rte, target_relation); @@ -1017,7 +1025,11 @@ add_row_identity_columns(PlannerInfo *root, Index rtindex, 0); add_row_identity_var(root, var, rtindex, "wholerow"); } + + return true; } + + return false; } /* @@ -1075,8 +1087,8 @@ distribute_row_identity_vars(PlannerInfo *root) Relation target_relation; target_relation = table_open(target_rte->relid, NoLock); - add_row_identity_columns(root, result_relation, - target_rte, target_relation); + (void) add_row_identity_columns(root, result_relation, + target_rte, target_relation); table_close(target_relation, NoLock); build_base_rel_tlists(root, root->processed_tlist); /* There are no ROWID_VAR Vars in this case, so we're done. */ diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 6d5225079f8..96c24a8a552 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -634,11 +634,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, -1, InvalidOid, 0); - add_row_identity_var(root, rrvar, childRTindex, "tableoid"); /* Register any row-identity columns needed by this child. */ - add_row_identity_columns(root, childRTindex, - childrte, childrel); + if (add_row_identity_columns(root, childRTindex, + childrte, childrel)) + add_row_identity_var(root, rrvar, childRTindex, "tableoid"); } } } diff --git a/src/include/optimizer/appendinfo.h b/src/include/optimizer/appendinfo.h index d06f93b7266..5f3168d612f 100644 --- a/src/include/optimizer/appendinfo.h +++ b/src/include/optimizer/appendinfo.h @@ -42,7 +42,7 @@ extern AppendRelInfo **find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos); extern void add_row_identity_var(PlannerInfo *root, Var *orig_var, Index rtindex, const char *rowid_name); -extern void add_row_identity_columns(PlannerInfo *root, Index rtindex, +extern bool add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation); extern void distribute_row_identity_vars(PlannerInfo *root); diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index 0490a746555..e8fcae6514f 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -579,7 +579,7 @@ update some_tab set a = a + 1 where false; -------------------------------------------------------- Update on public.some_tab -> Result - Output: (some_tab.a + 1), NULL::oid, NULL::tid + Output: (some_tab.a + 1), NULL::tid, NULL::oid Replaces: Scan on some_tab One-Time Filter: false (5 rows) @@ -592,7 +592,7 @@ update some_tab set a = a + 1 where false returning b, a; Update on public.some_tab Output: some_tab.b, some_tab.a -> Result - Output: (some_tab.a + 1), NULL::oid, NULL::tid + Output: (some_tab.a + 1), NULL::tid, NULL::oid Replaces: Scan on some_tab One-Time Filter: false (6 rows) @@ -2054,12 +2054,12 @@ update inhpar i set (f1, f2) = (select i.f1, i.f2 || '-' from int4_tbl limit 1); Update on public.inhpar i_1 Update on public.inhcld i_2 -> Result - Output: (SubPlan multiexpr_1).col1, (SubPlan multiexpr_1).col2, (rescan SubPlan multiexpr_1), i.tableoid, i.ctid + Output: (SubPlan multiexpr_1).col1, (SubPlan multiexpr_1).col2, (rescan SubPlan multiexpr_1), i.ctid, i.tableoid -> Append -> Seq Scan on public.inhpar i_1 - Output: i_1.f1, i_1.f2, i_1.tableoid, i_1.ctid + Output: i_1.f1, i_1.f2, i_1.ctid, i_1.tableoid -> Seq Scan on public.inhcld i_2 - Output: i_2.f1, i_2.f2, i_2.tableoid, i_2.ctid + Output: i_2.f1, i_2.f2, i_2.ctid, i_2.tableoid SubPlan multiexpr_1 -> Limit Output: (i.f1), (((i.f2)::text || '-'::text)) @@ -2103,14 +2103,14 @@ update inhpar i set (f1, f2) = (select i.f1, i.f2 || '-' from int4_tbl limit 1); Update on public.inhcld2 i_2 -> Append -> Seq Scan on public.inhcld1 i_1 - Output: (SubPlan multiexpr_1).col1, (SubPlan multiexpr_1).col2, (rescan SubPlan multiexpr_1), i_1.tableoid, i_1.ctid + Output: (SubPlan multiexpr_1).col1, (SubPlan multiexpr_1).col2, (rescan SubPlan multiexpr_1), i_1.ctid, i_1.tableoid SubPlan multiexpr_1 -> Limit Output: (i_1.f1), (((i_1.f2)::text || '-'::text)) -> Seq Scan on public.int4_tbl Output: i_1.f1, ((i_1.f2)::text || '-'::text) -> Seq Scan on public.inhcld2 i_2 - Output: (SubPlan multiexpr_1).col1, (SubPlan multiexpr_1).col2, (rescan SubPlan multiexpr_1), i_2.tableoid, i_2.ctid + Output: (SubPlan multiexpr_1).col1, (SubPlan multiexpr_1).col2, (rescan SubPlan multiexpr_1), i_2.ctid, i_2.tableoid (13 rows) update inhpar i set (f1, f2) = (select i.f1, i.f2 || '-' from int4_tbl limit 1); diff --git a/src/test/regress/expected/merge.out b/src/test/regress/expected/merge.out index 9cb1d87066a..10b27b01532 100644 --- a/src/test/regress/expected/merge.out +++ b/src/test/regress/expected/merge.out @@ -2387,15 +2387,15 @@ MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid Merge on public.pa_target t Merge on public.pa_targetp t_1 -> Hash Left Join - Output: s.sid, s.ctid, t_1.tableoid, t_1.ctid + Output: s.sid, s.ctid, t_1.ctid, t_1.tableoid Inner Unique: true Hash Cond: (s.sid = t_1.tid) -> Seq Scan on public.pa_source s Output: s.sid, s.ctid -> Hash - Output: t_1.tid, t_1.tableoid, t_1.ctid + Output: t_1.tid, t_1.ctid, t_1.tableoid -> Seq Scan on public.pa_targetp t_1 - Output: t_1.tid, t_1.tableoid, t_1.ctid + Output: t_1.tid, t_1.ctid, t_1.tableoid (12 rows) MERGE INTO pa_target t USING pa_source s ON t.tid = s.sid diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index deacdd75807..24c6ac408f3 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -4585,7 +4585,7 @@ explain (verbose, costs off) execute update_part_abc_view (1, 'd'); -> Append Subplans Removed: 1 -> Seq Scan on public.part_abc_1 - Output: $2, part_abc_1.tableoid, part_abc_1.ctid + Output: $2, part_abc_1.ctid, part_abc_1.tableoid Filter: ((part_abc_1.b <> 'a'::text) AND (part_abc_1.a = $1)) (8 rows) @@ -4604,7 +4604,7 @@ explain (verbose, costs off) execute update_part_abc_view (2, 'a'); -> Append Subplans Removed: 1 -> Seq Scan on public.part_abc_2 - Output: $2, part_abc_2.tableoid, part_abc_2.ctid + Output: $2, part_abc_2.ctid, part_abc_2.tableoid Filter: ((part_abc_2.b <> 'a'::text) AND (part_abc_2.a = $1)) (8 rows) diff --git a/src/test/regress/expected/returning.out b/src/test/regress/expected/returning.out index cfaaf015bb3..2b2161f245c 100644 --- a/src/test/regress/expected/returning.out +++ b/src/test/regress/expected/returning.out @@ -504,9 +504,9 @@ UPDATE foo SET f4 = 100 WHERE f1 = 5 Output: (old.tableoid)::regclass, old.ctid, old.f1, old.f2, old.f3, old.f4, old.*, (new.tableoid)::regclass, new.ctid, new.f1, new.f2, new.f3, new.f4, new.*, (((old.f4)::text || '->'::text) || (new.f4)::text) Update on pg_temp.foo foo_1 -> Result - Output: '100'::bigint, foo_1.tableoid, foo_1.ctid + Output: '100'::bigint, foo_1.ctid, foo_1.tableoid -> Seq Scan on pg_temp.foo foo_1 - Output: foo_1.tableoid, foo_1.ctid + Output: foo_1.ctid, foo_1.tableoid Filter: (foo_1.f1 = 5) (8 rows) @@ -530,7 +530,7 @@ DELETE FROM foo WHERE f1 = 5 Output: (old.tableoid)::regclass, old.ctid, old.f1, old.f2, old.f3, old.f4, (new.tableoid)::regclass, new.ctid, new.f1, new.f2, new.f3, new.f4, foo_1.f1, foo_1.f2, foo_1.f3, foo_1.f4 Delete on pg_temp.foo foo_1 -> Seq Scan on pg_temp.foo foo_1 - Output: foo_1.tableoid, foo_1.ctid + Output: foo_1.ctid, foo_1.tableoid Filter: (foo_1.f1 = 5) (6 rows) @@ -586,9 +586,9 @@ UPDATE foo SET f4 = 100 WHERE f1 = 5 Output: (SubPlan expr_1), (SubPlan expr_2), (SubPlan expr_3) Update on pg_temp.foo foo_1 -> Result - Output: '100'::bigint, foo_1.tableoid, foo_1.ctid + Output: '100'::bigint, foo_1.ctid, foo_1.tableoid -> Seq Scan on pg_temp.foo foo_1 - Output: foo_1.tableoid, foo_1.ctid + Output: foo_1.ctid, foo_1.tableoid Filter: (foo_1.f1 = 5) SubPlan expr_1 -> Result @@ -626,7 +626,7 @@ DELETE FROM foo WHERE f1 = 5 Output: (SubPlan expr_1), (SubPlan expr_2) Delete on pg_temp.foo foo_1 -> Seq Scan on pg_temp.foo foo_1 - Output: foo_1.tableoid, foo_1.ctid + Output: foo_1.ctid, foo_1.tableoid Filter: (foo_1.f1 = 5) SubPlan expr_1 -> Aggregate @@ -662,9 +662,9 @@ DELETE FROM foo WHERE f1 = 4 RETURNING old.*,new.*, *; Output: old.f1, old.f2, old.f3, old.f4, new.f1, new.f2, new.f3, new.f4, foo_2.f1, foo_2.f2, foo_2.f3, foo_2.f4 Update on pg_temp.foo foo_2 -> Nested Loop - Output: (foo_2.f2 || ' (deleted)'::text), '-1'::integer, '-1'::bigint, foo_1.ctid, foo_1.tableoid, foo_2.tableoid, foo_2.ctid + Output: (foo_2.f2 || ' (deleted)'::text), '-1'::integer, '-1'::bigint, foo_1.ctid, foo_1.tableoid, foo_2.ctid, foo_2.tableoid -> Seq Scan on pg_temp.foo foo_2 - Output: foo_2.f2, foo_2.f1, foo_2.tableoid, foo_2.ctid + Output: foo_2.f2, foo_2.f1, foo_2.ctid, foo_2.tableoid Filter: (foo_2.f1 = 4) -> Seq Scan on pg_temp.foo foo_1 Output: foo_1.ctid, foo_1.f1, foo_1.tableoid @@ -687,17 +687,17 @@ UPDATE joinview SET f3 = f3 + 1 WHERE f3 = 57 Output: old.f1, old.f2, old.f3, old.f4, joinme.other, new.f1, new.f2, new.f3, new.f4, joinme.other, foo_1.f1, foo_1.f2, foo_1.f3, foo_1.f4, joinme.other, (new.f3 - old.f3) Update on pg_temp.foo foo_1 -> Hash Join - Output: foo_2.f1, (foo_2.f3 + 1), joinme.ctid, foo_2.ctid, joinme_1.ctid, joinme.other, foo_1.tableoid, foo_1.ctid, foo_2.tableoid + Output: foo_2.f1, (foo_2.f3 + 1), joinme.ctid, foo_2.ctid, joinme_1.ctid, joinme.other, foo_1.ctid, foo_1.tableoid, foo_2.tableoid Hash Cond: (foo_1.f2 = joinme.f2j) -> Hash Join - Output: foo_1.f2, foo_1.tableoid, foo_1.ctid, joinme_1.ctid, joinme_1.f2j + Output: foo_1.f2, foo_1.ctid, foo_1.tableoid, joinme_1.ctid, joinme_1.f2j Hash Cond: (joinme_1.f2j = foo_1.f2) -> Seq Scan on pg_temp.joinme joinme_1 Output: joinme_1.ctid, joinme_1.f2j -> Hash - Output: foo_1.f2, foo_1.tableoid, foo_1.ctid + Output: foo_1.f2, foo_1.ctid, foo_1.tableoid -> Seq Scan on pg_temp.foo foo_1 - Output: foo_1.f2, foo_1.tableoid, foo_1.ctid + Output: foo_1.f2, foo_1.ctid, foo_1.tableoid -> Hash Output: joinme.ctid, joinme.other, joinme.f2j, foo_2.f1, foo_2.f3, foo_2.ctid, foo_2.f2, foo_2.tableoid -> Hash Join diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index 03df7e75b7b..d059e70e0c5 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -3248,10 +3248,10 @@ UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; Update on public.t12 t1_3 Update on public.t111 t1_4 -> Result - Output: 100, t1.tableoid, t1.ctid + Output: 100, t1.ctid, t1.tableoid -> Append -> Index Scan using t1_a_idx on public.t1 t1_1 - Output: t1_1.tableoid, t1_1.ctid + Output: t1_1.ctid, t1_1.tableoid Index Cond: ((t1_1.a > 5) AND (t1_1.a < 7)) Filter: ((t1_1.a <> 6) AND EXISTS(SubPlan exists_1) AND snoop(t1_1.a) AND leakproof(t1_1.a)) SubPlan exists_1 @@ -3261,15 +3261,15 @@ UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; -> Seq Scan on public.t111 t12_2 Filter: (t12_2.a = t1_1.a) -> Index Scan using t11_a_idx on public.t11 t1_2 - Output: t1_2.tableoid, t1_2.ctid + Output: t1_2.ctid, t1_2.tableoid Index Cond: ((t1_2.a > 5) AND (t1_2.a < 7)) Filter: ((t1_2.a <> 6) AND EXISTS(SubPlan exists_1) AND snoop(t1_2.a) AND leakproof(t1_2.a)) -> Index Scan using t12_a_idx on public.t12 t1_3 - Output: t1_3.tableoid, t1_3.ctid + Output: t1_3.ctid, t1_3.tableoid Index Cond: ((t1_3.a > 5) AND (t1_3.a < 7)) Filter: ((t1_3.a <> 6) AND EXISTS(SubPlan exists_1) AND snoop(t1_3.a) AND leakproof(t1_3.a)) -> Index Scan using t111_a_idx on public.t111 t1_4 - Output: t1_4.tableoid, t1_4.ctid + Output: t1_4.ctid, t1_4.tableoid Index Cond: ((t1_4.a > 5) AND (t1_4.a < 7)) Filter: ((t1_4.a <> 6) AND EXISTS(SubPlan exists_1) AND snoop(t1_4.a) AND leakproof(t1_4.a)) (30 rows) @@ -3295,10 +3295,10 @@ UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; Update on public.t12 t1_3 Update on public.t111 t1_4 -> Result - Output: (t1.a + 1), t1.tableoid, t1.ctid + Output: (t1.a + 1), t1.ctid, t1.tableoid -> Append -> Index Scan using t1_a_idx on public.t1 t1_1 - Output: t1_1.a, t1_1.tableoid, t1_1.ctid + Output: t1_1.a, t1_1.ctid, t1_1.tableoid Index Cond: ((t1_1.a > 5) AND (t1_1.a = 8)) Filter: (EXISTS(SubPlan exists_1) AND snoop(t1_1.a) AND leakproof(t1_1.a)) SubPlan exists_1 @@ -3308,15 +3308,15 @@ UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; -> Seq Scan on public.t111 t12_2 Filter: (t12_2.a = t1_1.a) -> Index Scan using t11_a_idx on public.t11 t1_2 - Output: t1_2.a, t1_2.tableoid, t1_2.ctid + Output: t1_2.a, t1_2.ctid, t1_2.tableoid Index Cond: ((t1_2.a > 5) AND (t1_2.a = 8)) Filter: (EXISTS(SubPlan exists_1) AND snoop(t1_2.a) AND leakproof(t1_2.a)) -> Index Scan using t12_a_idx on public.t12 t1_3 - Output: t1_3.a, t1_3.tableoid, t1_3.ctid + Output: t1_3.a, t1_3.ctid, t1_3.tableoid Index Cond: ((t1_3.a > 5) AND (t1_3.a = 8)) Filter: (EXISTS(SubPlan exists_1) AND snoop(t1_3.a) AND leakproof(t1_3.a)) -> Index Scan using t111_a_idx on public.t111 t1_4 - Output: t1_4.a, t1_4.tableoid, t1_4.ctid + Output: t1_4.a, t1_4.ctid, t1_4.tableoid Index Cond: ((t1_4.a > 5) AND (t1_4.a = 8)) Filter: (EXISTS(SubPlan exists_1) AND snoop(t1_4.a) AND leakproof(t1_4.a)) (30 rows) diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index f4caedf272f..b949c95ae58 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -3597,21 +3597,21 @@ DELETE FROM a_star USING wcte WHERE aa = q2; -> Result Output: '42'::bigint, '47'::bigint -> Hash Join - Output: wcte.*, a_star.tableoid, a_star.ctid + Output: wcte.*, a_star.ctid, a_star.tableoid Hash Cond: (a_star.aa = wcte.q2) -> Append -> Seq Scan on public.a_star a_star_1 - Output: a_star_1.aa, a_star_1.tableoid, a_star_1.ctid + Output: a_star_1.aa, a_star_1.ctid, a_star_1.tableoid -> Seq Scan on public.b_star a_star_2 - Output: a_star_2.aa, a_star_2.tableoid, a_star_2.ctid + Output: a_star_2.aa, a_star_2.ctid, a_star_2.tableoid -> Seq Scan on public.c_star a_star_3 - Output: a_star_3.aa, a_star_3.tableoid, a_star_3.ctid + Output: a_star_3.aa, a_star_3.ctid, a_star_3.tableoid -> Seq Scan on public.d_star a_star_4 - Output: a_star_4.aa, a_star_4.tableoid, a_star_4.ctid + Output: a_star_4.aa, a_star_4.ctid, a_star_4.tableoid -> Seq Scan on public.e_star a_star_5 - Output: a_star_5.aa, a_star_5.tableoid, a_star_5.ctid + Output: a_star_5.aa, a_star_5.ctid, a_star_5.tableoid -> Seq Scan on public.f_star a_star_6 - Output: a_star_6.aa, a_star_6.tableoid, a_star_6.ctid + Output: a_star_6.aa, a_star_6.ctid, a_star_6.tableoid -> Hash Output: wcte.*, wcte.q2 -> CTE Scan on wcte -- 2.47.3