v2-0001-Fix-planner-error-when-estimating-SubPlan-cost.patch

application/octet-stream

Filename: v2-0001-Fix-planner-error-when-estimating-SubPlan-cost.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #19037: Planner fails on estimating array length with "no relation entry" error

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v2-0001
Subject: Fix planner error when estimating SubPlan cost
File+
src/backend/optimizer/path/costsize.c 16 2
src/test/regress/expected/subselect.out 19 0
src/test/regress/sql/subselect.sql 9 0
From 3c333a5e3984ca188e82e3408251e989ffd47104 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
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)