Fix calculation of plan node extParams to account for the possibility that one

initPlan sets a parameter for another.  This could not (I think) happen before
8.1, but it's possible now because the initPlans generated by MIN/MAX
optimization might themselves use initPlans.  We attach those initPlans as
siblings of the MIN/MAX ones, not children, to avoid duplicate computation
when multiple MIN/MAX aggregates are present; so this leads to the case of an
initPlan needing the result of a sibling initPlan, which is not possible with
ordinary query nesting.  Hadn't been noticed because in most contexts having
too much stuff listed in extParam is fairly harmless.  Fixes "plan should not
reference subplan's variable" bug reported by Catalin Pitis.
This commit is contained in:
Tom Lane 2006-05-03 00:24:56 +00:00
parent e57345975c
commit f4923880b3

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.106 2006/04/28 20:57:49 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.107 2006/05/03 00:24:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -912,9 +912,11 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
void
SS_finalize_plan(Plan *plan, List *rtable)
{
Bitmapset *outer_params = NULL;
Bitmapset *valid_params = NULL;
Cost initplan_cost = 0;
Bitmapset *outer_params,
*valid_params,
*initExtParam,
*initSetParam;
Cost initplan_cost;
int paramid;
ListCell *l;
@ -923,6 +925,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
* available from outer query levels and my own query level. We do this
* once to save time in the per-plan recursion steps.
*/
outer_params = valid_params = NULL;
paramid = 0;
foreach(l, PlannerParamList)
{
@ -954,7 +957,11 @@ SS_finalize_plan(Plan *plan, List *rtable)
/*
* Finally, attach any initPlans to the topmost plan node, and add their
* extParams to the topmost node's, too.
* extParams to the topmost node's, too. However, any setParams of the
* initPlans should not be present in the topmost node's extParams, only
* in its allParams. (As of PG 8.1, it's possible that some initPlans
* have extParams that are setParams of other initPlans, so we have to
* take care of this situation explicitly.)
*
* We also add the total_cost of each initPlan to the startup cost of the
* top node. This is a conservative overestimate, since in fact each
@ -963,17 +970,29 @@ SS_finalize_plan(Plan *plan, List *rtable)
plan->initPlan = PlannerInitPlan;
PlannerInitPlan = NIL; /* make sure they're not attached twice */
initExtParam = initSetParam = NULL;
initplan_cost = 0;
foreach(l, plan->initPlan)
{
SubPlan *initplan = (SubPlan *) lfirst(l);
ListCell *l2;
plan->extParam = bms_add_members(plan->extParam,
initplan->plan->extParam);
/* allParam must include all members of extParam */
plan->allParam = bms_add_members(plan->allParam,
plan->extParam);
initExtParam = bms_add_members(initExtParam,
initplan->plan->extParam);
foreach(l2, initplan->setParam)
{
initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
}
initplan_cost += initplan->plan->total_cost;
}
/* allParam must include all these params */
plan->allParam = bms_add_members(plan->allParam, initExtParam);
plan->allParam = bms_add_members(plan->allParam, initSetParam);
/* but extParam shouldn't include any setParams */
initExtParam = bms_del_members(initExtParam, initSetParam);
/* empty test ensures extParam is exactly NULL if it's empty */
if (!bms_is_empty(initExtParam))
plan->extParam = bms_join(plan->extParam, initExtParam);
plan->startup_cost += initplan_cost;
plan->total_cost += initplan_cost;