From f4923880b39ad8f671b3fa172d57e3a0ad1b5b0c Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 3 May 2006 00:24:56 +0000
Subject: [PATCH] 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.

---
 src/backend/optimizer/plan/subselect.c | 39 +++++++++++++++++++-------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index b9e123d8e63..1b5533cded4 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -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;
-- 
GitLab