77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.131 2008/07/1001:17:29 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.132 2008/07/1002:14:03 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -1027,11 +1027,12 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context)
10271027 * SS_finalize_plan - do final sublink processing for a completed Plan.
10281028 *
10291029 * This recursively computes the extParam and allParam sets for every Plan
1030- * node in the given plan tree. It also attaches any generated InitPlans
1031- * to the top plan node.
1030+ * node in the given plan tree. It also optionally attaches any previously
1031+ * generated InitPlans to the top plan node. (Any InitPlans should already
1032+ * have been put through SS_finalize_plan.)
10321033 */
10331034void
1034- SS_finalize_plan (PlannerInfo * root ,Plan * plan )
1035+ SS_finalize_plan (PlannerInfo * root ,Plan * plan , bool attach_initplans )
10351036{
10361037Bitmapset * valid_params ,
10371038* initExtParam ,
@@ -1041,14 +1042,45 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
10411042ListCell * l ;
10421043
10431044/*
1044- * First, scan the param list to discover the sets of params that are
1045- * available from outer query levels and my own query level. We do this
1046- * once to save time in the per-plan recursion steps. (This calculation
1047- * is overly generous: it can include a lot of params that actually
1048- * shouldn't be referenced here. However, valid_params is just used as
1049- * a debugging crosscheck, so it's not worth trying to be exact.)
1045+ * Examine any initPlans to determine the set of external params they
1046+ * reference, the set of output params they supply, and their total cost.
1047+ * We'll use at least some of this info below. (Note we are assuming that
1048+ * finalize_plan doesn't touch the initPlans.)
1049+ *
1050+ * In the case where attach_initplans is false, we are assuming that the
1051+ * existing initPlans are siblings that might supply params needed by the
1052+ * current plan.
1053+ */
1054+ initExtParam = initSetParam = NULL ;
1055+ initplan_cost = 0 ;
1056+ foreach (l ,root -> init_plans )
1057+ {
1058+ SubPlan * initsubplan = (SubPlan * )lfirst (l );
1059+ Plan * initplan = planner_subplan_get_plan (root ,initsubplan );
1060+ ListCell * l2 ;
1061+
1062+ initExtParam = bms_add_members (initExtParam ,initplan -> extParam );
1063+ foreach (l2 ,initsubplan -> setParam )
1064+ {
1065+ initSetParam = bms_add_member (initSetParam ,lfirst_int (l2 ));
1066+ }
1067+ initplan_cost += get_initplan_cost (root ,initsubplan );
1068+ }
1069+
1070+ /*
1071+ * Now determine the set of params that are validly referenceable in this
1072+ * query level; to wit, those available from outer query levels plus the
1073+ * output parameters of any initPlans. (We do not include output
1074+ * parameters of regular subplans. Those should only appear within the
1075+ * testexpr of SubPlan nodes, and are taken care of locally within
1076+ * finalize_primnode.)
1077+ *
1078+ * Note: this is a bit overly generous since some parameters of upper
1079+ * query levels might belong to query subtrees that don't include this
1080+ * query. However, valid_params is only a debugging crosscheck, so it
1081+ * doesn't seem worth expending lots of cycles to try to be exact.
10501082 */
1051- valid_params = NULL ;
1083+ valid_params = bms_copy ( initSetParam ) ;
10521084paramid = 0 ;
10531085foreach (l ,root -> glob -> paramlist )
10541086{
@@ -1059,12 +1091,6 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
10591091/* valid outer-level parameter */
10601092valid_params = bms_add_member (valid_params ,paramid );
10611093}
1062- else if (pitem -> abslevel == root -> query_level &&
1063- IsA (pitem -> item ,Param ))
1064- {
1065- /* valid local parameter (i.e., a setParam of my child) */
1066- valid_params = bms_add_member (valid_params ,paramid );
1067- }
10681094
10691095paramid ++ ;
10701096}
@@ -1088,37 +1114,25 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
10881114 * top node. This is a conservative overestimate, since in fact each
10891115 * initPlan might be executed later than plan startup, or even not at all.
10901116 */
1091- plan -> initPlan = root -> init_plans ;
1092- root -> init_plans = NIL ;/* make sure they're not attached twice */
1093-
1094- initExtParam = initSetParam = NULL ;
1095- initplan_cost = 0 ;
1096- foreach (l ,plan -> initPlan )
1117+ if (attach_initplans )
10971118{
1098- SubPlan * initsubplan = (SubPlan * )lfirst (l );
1099- Plan * initplan = planner_subplan_get_plan (root ,initsubplan );
1100- ListCell * l2 ;
1101-
1102- initExtParam = bms_add_members (initExtParam ,initplan -> extParam );
1103- foreach (l2 ,initsubplan -> setParam )
1104- {
1105- initSetParam = bms_add_member (initSetParam ,lfirst_int (l2 ));
1106- }
1107- initplan_cost += get_initplan_cost (root ,initsubplan );
1119+ plan -> initPlan = root -> init_plans ;
1120+ root -> init_plans = NIL ;/* make sure they're not attached twice */
1121+
1122+ /* allParam must include all these params */
1123+ plan -> allParam = bms_add_members (plan -> allParam ,initExtParam );
1124+ plan -> allParam = bms_add_members (plan -> allParam ,initSetParam );
1125+ /* extParam must include any child extParam */
1126+ plan -> extParam = bms_add_members (plan -> extParam ,initExtParam );
1127+ /* but extParam shouldn't include any setParams */
1128+ plan -> extParam = bms_del_members (plan -> extParam ,initSetParam );
1129+ /* ensure extParam is exactly NULL if it's empty */
1130+ if (bms_is_empty (plan -> extParam ))
1131+ plan -> extParam = NULL ;
1132+
1133+ plan -> startup_cost += initplan_cost ;
1134+ plan -> total_cost += initplan_cost ;
11081135}
1109- /* allParam must include all these params */
1110- plan -> allParam = bms_add_members (plan -> allParam ,initExtParam );
1111- plan -> allParam = bms_add_members (plan -> allParam ,initSetParam );
1112- /* extParam must include any child extParam */
1113- plan -> extParam = bms_add_members (plan -> extParam ,initExtParam );
1114- /* but extParam shouldn't include any setParams */
1115- plan -> extParam = bms_del_members (plan -> extParam ,initSetParam );
1116- /* ensure extParam is exactly NULL if it's empty */
1117- if (bms_is_empty (plan -> extParam ))
1118- plan -> extParam = NULL ;
1119-
1120- plan -> startup_cost += initplan_cost ;
1121- plan -> total_cost += initplan_cost ;
11221136}
11231137
11241138/*
@@ -1412,29 +1426,22 @@ Param *
14121426SS_make_initplan_from_plan (PlannerInfo * root ,Plan * plan ,
14131427Oid resulttype ,int32 resulttypmod )
14141428{
1415- List * saved_init_plans ;
14161429SubPlan * node ;
14171430Param * prm ;
14181431
14191432/*
14201433 * We must run SS_finalize_plan(), since that's normally done before a
1421- * subplan gets put into the initplan list. However it will try to attach
1422- * any pre-existing initplans to this one, which we don't want (they are
1423- * siblings not children of this initplan). So, a quick kluge to hide
1424- * them. (This is something else that could perhaps be cleaner if we did
1425- * extParam/allParam processing in setrefs.c instead of here? See notes
1426- * for materialize_finished_plan.)
1434+ * subplan gets put into the initplan list. Tell it not to attach any
1435+ * pre-existing initplans to this one, since they are siblings not
1436+ * children of this initplan. (This is something else that could perhaps
1437+ * be cleaner if we did extParam/allParam processing in setrefs.c instead
1438+ * of here? See notes for materialize_finished_plan.)
14271439 */
1428- saved_init_plans = root -> init_plans ;
1429- root -> init_plans = NIL ;
14301440
14311441/*
14321442 * Build extParam/allParam sets for plan nodes.
14331443 */
1434- SS_finalize_plan (root ,plan );
1435-
1436- /* Restore outer initplan list */
1437- root -> init_plans = saved_init_plans ;
1444+ SS_finalize_plan (root ,plan , false);
14381445
14391446/*
14401447 * Add the subplan and its rtable to the global lists.
@@ -1446,6 +1453,8 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
14461453
14471454/*
14481455 * Create a SubPlan node and add it to the outer list of InitPlans.
1456+ * Note it has to appear after any other InitPlans it might depend on
1457+ * (see comments in ExecReScan).
14491458 */
14501459node = makeNode (SubPlan );
14511460node -> subLinkType = EXPR_SUBLINK ;