]> granicus.if.org Git - postgresql/commitdiff
Fix calculation of plan node extParams to account for the possibility that one
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 May 2006 00:24:56 +0000 (00:24 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 May 2006 00:24:56 +0000 (00:24 +0000)
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.

src/backend/optimizer/plan/subselect.c

index b9e123d8e63e87d3649d8174f5783efa69f5f7e5..1b5533cded4a06d6a628552383efd5ae767c64dd 100644 (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;