From 3c333a5e3984ca188e82e3408251e989ffd47104 Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Tue, 2 Sep 2025 12:18:12 +0900 Subject: [PATCH v2] 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. --- src/backend/optimizer/path/costsize.c | 18 ++++++++++++++++-- src/test/regress/expected/subselect.out | 19 +++++++++++++++++++ src/test/regress/sql/subselect.sql | 9 +++++++++ 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..029a670bae7 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -979,6 +979,25 @@ select (select (a.*)::text) from view_a a; (42) (1 row) +-- +-- Test case for bug #19037: no relation entry for relid N +-- +explain (costs off) +select ((1 = any(array_agg(f1)))::int) = any (select 0) from int4_tbl; + QUERY PLAN +---------------------------- + Aggregate + -> Seq Scan on int4_tbl + SubPlan 1 + -> Result +(4 rows) + +select ((1 = any(array_agg(f1)))::int) = any (select 0) 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..46ae3665f1f 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -479,6 +479,15 @@ select (select view_a) from view_a; 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)))::int) = any (select 0) from int4_tbl; + +select ((1 = any(array_agg(f1)))::int) = any (select 0) from int4_tbl; + -- -- Check that whole-row Vars reading the result of a subselect don't include -- any junk columns therein -- 2.39.5 (Apple Git-154)