From 09cae95e24996e34ca12e38133150e71e351edcc Mon Sep 17 00:00:00 2001 From: Tender Wang Date: Sat, 11 Apr 2026 09:25:50 +0800 Subject: [PATCH] Fix "no relation entry for relid 0" in nested UNION ALL with array coercion. This patch addresses an issue where a three-branch (or more) UNION ALL fails during the planning/costing stage if it involves array type promotion. The error "no relation entry for relid 0" occurs because when UNION ALL branches are nested, the planner may generate a Var node with varno 0 to represent a coerced sub-tree (e.g., promoting int[] to bigint[]). Previously, the costing logic for array expressions did not account for these Vars with varno = 0, leading to a lookup failure. Example of failing query: SELECT NULL::int[] UNION ALL SELECT NULL::int[] UNION ALL SELECT NULL::bigint[]; The fix ensures that such Var nodes are recognized and assigned a default cost, allowing the planner to proceed correctly. --- src/backend/utils/adt/selfuncs.c | 9 +++++++++ src/test/regress/expected/union.out | 11 +++++++++++ src/test/regress/sql/union.sql | 5 +++++ 3 files changed, 25 insertions(+) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 4160d2d6e24..adccb13dd0d 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -2265,6 +2265,15 @@ estimate_array_length(PlannerInfo *root, Node *arrayexpr) AttStatsSlot sslot; double nelem = 0; + /* + * Handle Var nodes with varno 0: + * in cases like (int[] UNION ALL int[]) UNION ALL bigint[]. + * The planner may generate a Var node with varno 0 when coercing + * the result of nested set operations. See recurse_set_operations(). + */ + if (IsA(arrayexpr, Var) && ((Var *) arrayexpr)->varno == 0 ) + return 10; + examine_variable(root, arrayexpr, 0, &vardata); if (HeapTupleIsValid(vardata.statsTuple)) { diff --git a/src/test/regress/expected/union.out b/src/test/regress/expected/union.out index 709c85f2294..2c7643b5289 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -1661,3 +1661,14 @@ on true limit 1; -> Result (6 rows) +-- +-- Test nested UNION ALL with type coercion +-- +SELECT NULL::int[] UNION ALL SELECT NULL::int[] UNION ALL SELECT NULL::bigint[]; + int4 +------ + + + +(3 rows) + diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index d0c70fafbea..cc5fd029fa3 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -664,3 +664,8 @@ select * from tenk1 t1 left join lateral (select t1.tenthous from tenk2 t2 union all (values(1))) on true limit 1; + +-- +-- Test nested UNION ALL with type coercion +-- +SELECT NULL::int[] UNION ALL SELECT NULL::int[] UNION ALL SELECT NULL::bigint[]; \ No newline at end of file -- 2.34.1