postgres.git / summary / log / commit / refs

commit    53e35fb560abe1e32dd3a831acde8bfdb34a6a70
Author:   Richard Guo <rguo@postgresql.org>
Date:     Wed Sep 03 07:09:23 2025 +0000
First released in: 13.23, 14.20, 15.15, 16.11, 17.7, 18.0

    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


src/backend/optimizer/path/costsize.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 0ba26b207b0..7c094f68010 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4146,10 +4146,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) { [parent: 0b274c4759a9]