When a nested set operation's output type doesn't match the parent's
expected type, recurse_set_operations builds a projection target list
using generate_setop_tlist with varno 0. If the required type
coercion involves an ArrayCoerceExpr, estimate_array_length could be
called on such a Var, and would pass it to examine_variable, which
errors in find_base_rel because varno 0 has no valid relation entry.
Fix by skipping the statistics lookup for Vars with varno 0.
Bug introduced by commit
9391f7152. Back-patch to v17, where
estimate_array_length was taught to use statistics.
Reported-by: Justin Pryzby <pryzby@telsasoft.com>
Author: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/adjW8rfPDkplC7lF@pryzbyj2023
Backpatch-through: 17
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))
{
-> 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)
+
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[];