summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Guo <rguo@postgresql.org>2025-09-03 16:00:38 +0900
committerRichard Guo <rguo@postgresql.org>2025-09-03 16:00:38 +0900
commitaba8f61c30911cbac1a310b7d21777e04711c66e (patch)
tree9e593f90eb5d15ff7de2a29882fb75be9daac488
parentf2dbc83501d441a98f7799863e1b6f18af8e8fbe (diff)
Fix planner error when estimating SubPlan cost
SubPlan nodes are typically built very early, before any RelOptInfos have been constructed for the parent query level. As a result, the simple_rel_array in the parent root has not yet been initialized. Currently, during cost estimation of a SubPlan's testexpr, we may call examine_variable() to look up statistical data about the expressions. This can lead to "no relation entry for relid" errors. To fix, pass root as NULL to cost_qual_eval() in cost_subplan(), since the root does not yet contain enough information to safely consult statistics. One exception is SubPlan nodes built for the initplans of MIN/MAX aggregates from indexes. In this case, having a NULL root is safe because testexpr will be NULL. Additionally, an initplan will by definition not consult anything from the parent plan. Backpatch to all supported branches. Although the reported call path that triggers this error is not reachable prior to v17, there's no guarantee that other code paths -- especially in extensions -- could not encounter the same issue when cost_qual_eval() is called with a root that lacks a valid simple_rel_array. The test case is not included in pre-v17 branches though. Bug: #19037 Reported-by: Alexander Lakhin <exclusion@gmail.com> Diagnosed-by: Tom Lane <tgl@sss.pgh.pa.us> Author: Richard Guo <guofenglinux@gmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/19037-3d1c7bb553c7ce84@postgresql.org Backpatch-through: 13
-rw-r--r--src/backend/optimizer/path/costsize.c18
-rw-r--r--src/test/regress/expected/subselect.out19
-rw-r--r--src/test/regress/sql/subselect.sql9
3 files changed, 44 insertions, 2 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 783dca8a4ac..94077e6a006 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4570,10 +4570,24 @@ cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan)
{
QualCost sp_cost;
- /* Figure any cost for evaluating the testexpr */
+ /*
+ * Figure any cost for evaluating the testexpr.
+ *
+ * Usually, SubPlan nodes are built very early, before we have constructed
+ * any RelOptInfos for the parent query level, which means the parent root
+ * does not yet contain enough information to safely consult statistics.
+ * Therefore, we pass root as NULL here. cost_qual_eval() is already
+ * well-equipped to handle a NULL root.
+ *
+ * One exception is SubPlan nodes built for the initplans of MIN/MAX
+ * aggregates from indexes (cf. SS_make_initplan_from_plan). In this
+ * case, having a NULL root is safe because testexpr will be NULL.
+ * Besides, an initplan will by definition not consult anything from the
+ * parent plan.
+ */
cost_qual_eval(&sp_cost,
make_ands_implicit((Expr *) subplan->testexpr),
- root);
+ NULL);
if (subplan->useHashTable)
{
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index 0563d0cd5a1..c16dff05bc1 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -980,6 +980,25 @@ select (select (a.*)::text) from view_a a;
(1 row)
--
+-- Test case for bug #19037: no relation entry for relid N
+--
+explain (costs off)
+select (1 = any(array_agg(f1))) = any (select false) from int4_tbl;
+ QUERY PLAN
+----------------------------
+ Aggregate
+ -> Seq Scan on int4_tbl
+ SubPlan 1
+ -> Result
+(4 rows)
+
+select (1 = any(array_agg(f1))) = any (select false) from int4_tbl;
+ ?column?
+----------
+ t
+(1 row)
+
+--
-- Check that whole-row Vars reading the result of a subselect don't include
-- any junk columns therein
--
diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql
index a6d276a115b..8ccebbe51e0 100644
--- a/src/test/regress/sql/subselect.sql
+++ b/src/test/regress/sql/subselect.sql
@@ -480,6 +480,15 @@ select (select (select view_a)) from view_a;
select (select (a.*)::text) from view_a a;
--
+-- Test case for bug #19037: no relation entry for relid N
+--
+
+explain (costs off)
+select (1 = any(array_agg(f1))) = any (select false) from int4_tbl;
+
+select (1 = any(array_agg(f1))) = any (select false) from int4_tbl;
+
+--
-- Check that whole-row Vars reading the result of a subselect don't include
-- any junk columns therein
--