* 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 $
  *
  *-------------------------------------------------------------------------
  */
  * 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,
    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)
    {
            /* 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++;
    }
     * 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;
 }
 
 /*
 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.
 
    /*
     * 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;