diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 4160d2d6e24..f2b58ebfe1e 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -2265,6 +2265,18 @@ estimate_array_length(PlannerInfo *root, Node *arrayexpr) AttStatsSlot sslot; double nelem = 0; + /* + * Skip calling examine_variable for Var with varno 0, which has no + * valid relation entry and would error in find_base_rel. Such a Var + * can appear when a nested set operation's output type doesn't match + * the parent's expected type, because recurse_set_operations builds a + * projection target list using generate_setop_tlist with varno 0, and + * if the required type coercion involves an ArrayCoerceExpr, we can + * be called on that Var. + */ + if (IsA(arrayexpr, Var) && ((Var *) arrayexpr)->varno == 0) + return 10; /* default guess, should match scalararraysel */ + 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..3a49b354058 100644 --- a/src/test/regress/expected/union.out +++ b/src/test/regress/expected/union.out @@ -1661,3 +1661,20 @@ on true limit 1; -> Result (6 rows) +-- Test handling of Vars with varno 0 in estimate_array_length +explain (verbose, costs off) +select null::int[] union all select null::int[] union all select null::bigint[]; + QUERY PLAN +--------------------------------------------- + Append + -> Result + Output: (NULL::integer[]) + -> Append + -> Result + Output: NULL::integer[] + -> Result + Output: NULL::integer[] + -> Result + Output: NULL::bigint[] +(10 rows) + diff --git a/src/test/regress/sql/union.sql b/src/test/regress/sql/union.sql index d0c70fafbea..078c858429f 100644 --- a/src/test/regress/sql/union.sql +++ b/src/test/regress/sql/union.sql @@ -664,3 +664,7 @@ select * from tenk1 t1 left join lateral (select t1.tenthous from tenk2 t2 union all (values(1))) on true limit 1; + +-- Test handling of Vars with varno 0 in estimate_array_length +explain (verbose, costs off) +select null::int[] union all select null::int[] union all select null::bigint[];