]> granicus.if.org Git - postgresql/commitdiff
Tighten up SS_finalize_plan's computation of valid_params to exclude Params of
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Jul 2008 02:14:03 +0000 (02:14 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Jul 2008 02:14:03 +0000 (02:14 +0000)
the current query level that aren't in fact output parameters of the current
initPlans.  (This means, for example, output parameters of regular subplans.)
To make this work correctly for output parameters coming from sibling
initplans requires rejiggering the API of SS_finalize_plan just a bit:
we need the siblings to be visible to it, rather than hidden as
SS_make_initplan_from_plan had been doing.  This is really part of my response
to bug #4290, but I concluded this part probably shouldn't be back-patched,
since all that it's doing is to make a debugging cross-check tighter.

src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/subselect.c
src/include/optimizer/subselect.h

index 240c529fa401c7d421664495ad9cd264d2527048..af140d4acb5d8ff0c7bdf8bdfc2279c9848024b3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.40 2008/07/10 01:17:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.41 2008/07/10 02:14:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -486,7 +486,6 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
         */
        memcpy(&subroot, root, sizeof(PlannerInfo));
        subroot.parse = subparse = (Query *) copyObject(root->parse);
-       subroot.init_plans = NIL;
        subparse->commandType = CMD_SELECT;
        subparse->resultRelation = 0;
        subparse->returningList = NIL;
@@ -564,11 +563,9 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
                                                                                         -1);
 
        /*
-        * Make sure the InitPlan gets into the outer list.  It has to appear
-        * after any other InitPlans it might depend on, too (see comments in
-        * ExecReScan).
+        * Put the updated list of InitPlans back into the outer PlannerInfo.
         */
-       root->init_plans = list_concat(root->init_plans, subroot.init_plans);
+       root->init_plans = subroot.init_plans;
 }
 
 /*
index a6ad9dbdcec3c8b7d40eb8f1f8cbfb156830aa55..9248022d8b352b851c555fc7ffe62d55fa5a6a74 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.233 2008/05/02 21:26:09 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.234 2008/07/10 02:14:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -459,7 +459,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
         */
        if (list_length(glob->subplans) != num_old_subplans ||
                root->query_level > 1)
-               SS_finalize_plan(root, plan);
+               SS_finalize_plan(root, plan, true);
 
        /* Return internal info if caller wants it */
        if (subroot)
index 460b5ad1c761c1a2c49b87e3f839c62701d2dac8..72e951abd05ead554613c12d72eba6295adf045b 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.131 2008/07/10 01:17:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.132 2008/07/10 02:14:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1027,11 +1027,12 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
  * SS_finalize_plan - do final sublink processing for a completed Plan.
  *
  * This recursively computes the extParam and allParam sets for every Plan
- * node in the given plan tree.  It also attaches any generated InitPlans
- * to the top plan node.
+ * node in the given plan tree.  It also optionally attaches any previously
+ * generated InitPlans to the top plan node.  (Any InitPlans should already
+ * have been put through SS_finalize_plan.)
  */
 void
-SS_finalize_plan(PlannerInfo *root, Plan *plan)
+SS_finalize_plan(PlannerInfo *root, Plan *plan, bool attach_initplans)
 {
        Bitmapset  *valid_params,
                           *initExtParam,
@@ -1041,14 +1042,45 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
        ListCell   *l;
 
        /*
-        * First, scan the param list to discover the sets of params that are
-        * available from outer query levels and my own query level. We do this
-        * once to save time in the per-plan recursion steps.  (This calculation
-        * is overly generous: it can include a lot of params that actually
-        * shouldn't be referenced here.  However, valid_params is just used as
-        * a debugging crosscheck, so it's not worth trying to be exact.)
+        * Examine any initPlans to determine the set of external params they
+        * reference, the set of output params they supply, and their total cost.
+        * We'll use at least some of this info below.  (Note we are assuming that
+        * finalize_plan doesn't touch the initPlans.)
+        *
+        * In the case where attach_initplans is false, we are assuming that the
+        * existing initPlans are siblings that might supply params needed by the
+        * current plan.
+        */
+       initExtParam = initSetParam = NULL;
+       initplan_cost = 0;
+       foreach(l, root->init_plans)
+       {
+               SubPlan    *initsubplan = (SubPlan *) lfirst(l);
+               Plan       *initplan = planner_subplan_get_plan(root, initsubplan);
+               ListCell   *l2;
+
+               initExtParam = bms_add_members(initExtParam, initplan->extParam);
+               foreach(l2, initsubplan->setParam)
+               {
+                       initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
+               }
+               initplan_cost += get_initplan_cost(root, initsubplan);
+       }
+
+       /*
+        * Now determine the set of params that are validly referenceable in this
+        * query level; to wit, those available from outer query levels plus the
+        * output parameters of any initPlans.  (We do not include output
+        * parameters of regular subplans.  Those should only appear within the
+        * testexpr of SubPlan nodes, and are taken care of locally within
+        * finalize_primnode.)
+        *
+        * Note: this is a bit overly generous since some parameters of upper
+        * query levels might belong to query subtrees that don't include this
+        * query.  However, valid_params is only a debugging crosscheck, so it
+        * doesn't seem worth expending lots of cycles to try to be exact.
         */
-       valid_params = NULL;
+       valid_params = bms_copy(initSetParam);
        paramid = 0;
        foreach(l, root->glob->paramlist)
        {
@@ -1059,12 +1091,6 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
                        /* valid outer-level parameter */
                        valid_params = bms_add_member(valid_params, paramid);
                }
-               else if (pitem->abslevel == root->query_level &&
-                                IsA(pitem->item, Param))
-               {
-                       /* valid local parameter (i.e., a setParam of my child) */
-                       valid_params = bms_add_member(valid_params, paramid);
-               }
 
                paramid++;
        }
@@ -1088,37 +1114,25 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
         * top node.  This is a conservative overestimate, since in fact each
         * initPlan might be executed later than plan startup, or even not at all.
         */
-       plan->initPlan = root->init_plans;
-       root->init_plans = NIL;         /* make sure they're not attached twice */
-
-       initExtParam = initSetParam = NULL;
-       initplan_cost = 0;
-       foreach(l, plan->initPlan)
+       if (attach_initplans)
        {
-               SubPlan    *initsubplan = (SubPlan *) lfirst(l);
-               Plan       *initplan = planner_subplan_get_plan(root, initsubplan);
-               ListCell   *l2;
-
-               initExtParam = bms_add_members(initExtParam, initplan->extParam);
-               foreach(l2, initsubplan->setParam)
-               {
-                       initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
-               }
-               initplan_cost += get_initplan_cost(root, initsubplan);
+               plan->initPlan = root->init_plans;
+               root->init_plans = NIL;         /* make sure they're not attached twice */
+
+               /* allParam must include all these params */
+               plan->allParam = bms_add_members(plan->allParam, initExtParam);
+               plan->allParam = bms_add_members(plan->allParam, initSetParam);
+               /* extParam must include any child extParam */
+               plan->extParam = bms_add_members(plan->extParam, initExtParam);
+               /* but extParam shouldn't include any setParams */
+               plan->extParam = bms_del_members(plan->extParam, initSetParam);
+               /* ensure extParam is exactly NULL if it's empty */
+               if (bms_is_empty(plan->extParam))
+                       plan->extParam = NULL;
+
+               plan->startup_cost += initplan_cost;
+               plan->total_cost += initplan_cost;
        }
-       /* allParam must include all these params */
-       plan->allParam = bms_add_members(plan->allParam, initExtParam);
-       plan->allParam = bms_add_members(plan->allParam, initSetParam);
-       /* extParam must include any child extParam */
-       plan->extParam = bms_add_members(plan->extParam, initExtParam);
-       /* but extParam shouldn't include any setParams */
-       plan->extParam = bms_del_members(plan->extParam, initSetParam);
-       /* ensure extParam is exactly NULL if it's empty */
-       if (bms_is_empty(plan->extParam))
-               plan->extParam = NULL;
-
-       plan->startup_cost += initplan_cost;
-       plan->total_cost += initplan_cost;
 }
 
 /*
@@ -1412,29 +1426,22 @@ Param *
 SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
                                                   Oid resulttype, int32 resulttypmod)
 {
-       List       *saved_init_plans;
        SubPlan    *node;
        Param      *prm;
 
        /*
         * We must run SS_finalize_plan(), since that's normally done before a
-        * subplan gets put into the initplan list.  However it will try to attach
-        * any pre-existing initplans to this one, which we don't want (they are
-        * siblings not children of this initplan).  So, a quick kluge to hide
-        * them.  (This is something else that could perhaps be cleaner if we did
-        * extParam/allParam processing in setrefs.c instead of here?  See notes
-        * for materialize_finished_plan.)
+        * subplan gets put into the initplan list.  Tell it not to attach any
+        * pre-existing initplans to this one, since they are siblings not
+        * children of this initplan.  (This is something else that could perhaps
+        * be cleaner if we did extParam/allParam processing in setrefs.c instead
+        * of here?  See notes for materialize_finished_plan.)
         */
-       saved_init_plans = root->init_plans;
-       root->init_plans = NIL;
 
        /*
         * Build extParam/allParam sets for plan nodes.
         */
-       SS_finalize_plan(root, plan);
-
-       /* Restore outer initplan list */
-       root->init_plans = saved_init_plans;
+       SS_finalize_plan(root, plan, false);
 
        /*
         * Add the subplan and its rtable to the global lists.
@@ -1446,6 +1453,8 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
 
        /*
         * Create a SubPlan node and add it to the outer list of InitPlans.
+        * Note it has to appear after any other InitPlans it might depend on
+        * (see comments in ExecReScan).
         */
        node = makeNode(SubPlan);
        node->subLinkType = EXPR_SUBLINK;
index 150eaaf002d65f06e610cb8465b8205f0a239319..bb60aac9d4f089301b564761d902fe6410a228d8 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.30 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.31 2008/07/10 02:14:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,8 @@
 extern Node *convert_IN_to_join(PlannerInfo *root, SubLink *sublink);
 extern Node *SS_replace_correlation_vars(PlannerInfo *root, Node *expr);
 extern Node *SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual);
-extern void SS_finalize_plan(PlannerInfo *root, Plan *plan);
+extern void SS_finalize_plan(PlannerInfo *root, Plan *plan,
+                                                        bool attach_initplans);
 extern Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
                                                   Oid resulttype, int32 resulttypmod);