diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index a173cf59dff671e75bde996a1b6778d61a1ed8f9..0600f63b5567616427dab633f0f4c3d5793d5623 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.298 2007/02/19 02:23:12 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.299 2007/02/19 07:03:27 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -1225,6 +1225,16 @@ _outHashPath(StringInfo str, HashPath *node)
 	WRITE_NODE_FIELD(path_hashclauses);
 }
 
+static void
+_outPlannerGlobal(StringInfo str, PlannerGlobal *node)
+{
+	WRITE_NODE_TYPE("PLANNERGLOBAL");
+
+	/* NB: this isn't a complete set of fields */
+	WRITE_NODE_FIELD(paramlist);
+	WRITE_INT_FIELD(next_plan_id);
+}
+
 static void
 _outPlannerInfo(StringInfo str, PlannerInfo *node)
 {
@@ -1232,7 +1242,10 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
 
 	/* NB: this isn't a complete set of fields */
 	WRITE_NODE_FIELD(parse);
+	WRITE_NODE_FIELD(glob);
+	WRITE_UINT_FIELD(query_level);
 	WRITE_NODE_FIELD(join_rel_list);
+	WRITE_NODE_FIELD(init_plans);
 	WRITE_NODE_FIELD(eq_classes);
 	WRITE_NODE_FIELD(canon_pathkeys);
 	WRITE_NODE_FIELD(left_join_clauses);
@@ -1416,6 +1429,15 @@ _outAppendRelInfo(StringInfo str, AppendRelInfo *node)
 	WRITE_OID_FIELD(parent_reloid);
 }
 
+static void
+_outPlannerParamItem(StringInfo str, PlannerParamItem *node)
+{
+	WRITE_NODE_TYPE("PLANNERPARAMITEM");
+
+	WRITE_NODE_FIELD(item);
+	WRITE_UINT_FIELD(abslevel);
+}
+
 /*****************************************************************************
  *
  *	Stuff from parsenodes.h.
@@ -2195,6 +2217,9 @@ _outNode(StringInfo str, void *obj)
 			case T_HashPath:
 				_outHashPath(str, obj);
 				break;
+			case T_PlannerGlobal:
+				_outPlannerGlobal(str, obj);
+				break;
 			case T_PlannerInfo:
 				_outPlannerInfo(str, obj);
 				break;
@@ -2228,6 +2253,9 @@ _outNode(StringInfo str, void *obj)
 			case T_AppendRelInfo:
 				_outAppendRelInfo(str, obj);
 				break;
+			case T_PlannerParamItem:
+				_outPlannerParamItem(str, obj);
+				break;
 
 			case T_CreateStmt:
 				_outCreateStmt(str, obj);
diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README
index 60505814fd49c1f1cb8a11b5c54d2aec2f59d0ec..6f9d008cbfffa5abe99a45c49fe13dcb638575b6 100644
--- a/src/backend/optimizer/README
+++ b/src/backend/optimizer/README
@@ -317,7 +317,10 @@ planner()
 Optimizer Data Structures
 -------------------------
 
-PlannerInfo     - global information for planning a particular Query
+PlannerGlobal   - global information for a single planner invocation
+
+PlannerInfo     - information for planning a particular Query (we make
+                  a separate PlannerInfo node for each sub-Query)
 
 RelOptInfo      - a relation or joined relations
 
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 43891a184594b0bde3f57bad62fd838d6744e6dc..1cb1d86be1b58374dc2c0f94a328e29e94f58dc9 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.158 2007/01/28 18:50:40 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.159 2007/02/19 07:03:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -517,7 +517,9 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		tuple_fraction = root->tuple_fraction;
 
 	/* Generate the plan for the subquery */
-	rel->subplan = subquery_planner(subquery, tuple_fraction,
+	rel->subplan = subquery_planner(root->glob, subquery,
+									root->query_level + 1,
+									tuple_fraction,
 									&subquery_pathkeys);
 
 	/* Copy number of output rows from subplan */
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index f80e18a202093721e0efdcfc247f68bab1ad28c6..405ab6fcc3a6275dc1a132e547693b6ce6bbde07 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.83 2007/01/05 22:19:31 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.84 2007/02/19 07:03:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -537,7 +537,7 @@ clause_selectivity(PlannerInfo *root,
 	else if (IsA(clause, Param))
 	{
 		/* see if we can replace the Param */
-		Node	   *subst = estimate_expression_value(clause);
+		Node	   *subst = estimate_expression_value(root, clause);
 
 		if (IsA(subst, Const))
 		{
diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c
index 77ad0176db256f448ba06ee4d74fdcedf63d60a1..be26d17a28a2bca78bffb6a63e3a483e2e5677fe 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.26 2007/02/06 06:50:26 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.27 2007/02/19 07:03:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -450,6 +450,7 @@ 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->resultRelations = NIL;
@@ -524,6 +525,9 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
 	info->param = SS_make_initplan_from_plan(&subroot, plan,
 											 exprType((Node *) tle->expr),
 											 -1);
+
+	/* Make sure the InitPlan gets into the outer list */
+	root->init_plans = list_concat(root->init_plans, subroot.init_plans);
 }
 
 /*
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ae9c10fc6b6f9fb4d50c5b9b0764c210e6535733..f4a940175ea5c89c08ed9c8bd2e703072fcd585a 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.212 2007/01/20 20:45:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.213 2007/02/19 07:03:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,9 +42,6 @@
 #include "utils/syscache.h"
 
 
-ParamListInfo PlannerBoundParamList = NULL;		/* current boundParams */
-
-
 /* Expression kind codes for preprocess_expression */
 #define EXPRKIND_QUAL		0
 #define EXPRKIND_TARGET		1
@@ -86,35 +83,21 @@ Plan *
 planner(Query *parse, bool isCursor, int cursorOptions,
 		ParamListInfo boundParams)
 {
+	PlannerGlobal *glob;
 	double		tuple_fraction;
 	Plan	   *result_plan;
-	Index		save_PlannerQueryLevel;
-	List	   *save_PlannerParamList;
-	ParamListInfo save_PlannerBoundParamList;
 
 	/*
-	 * The planner can be called recursively (an example is when
-	 * eval_const_expressions tries to pre-evaluate an SQL function). So,
-	 * these global state variables must be saved and restored.
-	 *
-	 * Query level and the param list cannot be moved into the per-query
-	 * PlannerInfo structure since their whole purpose is communication across
-	 * multiple sub-queries. Also, boundParams is explicitly info from outside
-	 * the query, and so is likewise better handled as a global variable.
-	 *
-	 * Note we do NOT save and restore PlannerPlanId: it exists to assign
-	 * unique IDs to SubPlan nodes, and we want those IDs to be unique for the
-	 * life of a backend.  Also, PlannerInitPlan is saved/restored in
-	 * subquery_planner, not here.
+	 * Set up global state for this planner invocation.  This data is needed
+	 * across all levels of sub-Query that might exist in the given command,
+	 * so we keep it in a separate struct that's linked to by each per-Query
+	 * PlannerInfo.
 	 */
-	save_PlannerQueryLevel = PlannerQueryLevel;
-	save_PlannerParamList = PlannerParamList;
-	save_PlannerBoundParamList = PlannerBoundParamList;
+	glob = makeNode(PlannerGlobal);
 
-	/* Initialize state for handling outer-level references and params */
-	PlannerQueryLevel = 0;		/* will be 1 in top-level subquery_planner */
-	PlannerParamList = NIL;
-	PlannerBoundParamList = boundParams;
+	glob->boundParams = boundParams;
+	glob->paramlist = NIL;
+	glob->next_plan_id = 0;
 
 	/* Determine what fraction of the plan is likely to be scanned */
 	if (isCursor)
@@ -134,10 +117,7 @@ planner(Query *parse, bool isCursor, int cursorOptions,
 	}
 
 	/* primary planning entry point (may recurse for subqueries) */
-	result_plan = subquery_planner(parse, tuple_fraction, NULL);
-
-	/* check we popped out the right number of levels */
-	Assert(PlannerQueryLevel == 0);
+	result_plan = subquery_planner(glob, parse, 1, tuple_fraction, NULL);
 
 	/*
 	 * If creating a plan for a scrollable cursor, make sure it can run
@@ -153,12 +133,7 @@ planner(Query *parse, bool isCursor, int cursorOptions,
 	result_plan = set_plan_references(result_plan, parse->rtable);
 
 	/* executor wants to know total number of Params used overall */
-	result_plan->nParamExec = list_length(PlannerParamList);
-
-	/* restore state for outer planner, if any */
-	PlannerQueryLevel = save_PlannerQueryLevel;
-	PlannerParamList = save_PlannerParamList;
-	PlannerBoundParamList = save_PlannerBoundParamList;
+	result_plan->nParamExec = list_length(glob->paramlist);
 
 	return result_plan;
 }
@@ -169,7 +144,9 @@ planner(Query *parse, bool isCursor, int cursorOptions,
  *	  Invokes the planner on a subquery.  We recurse to here for each
  *	  sub-SELECT found in the query tree.
  *
+ * glob is the global state for the current planner run.
  * parse is the querytree produced by the parser & rewriter.
+ * level is the current recursion depth (1 at the top-level Query).
  * tuple_fraction is the fraction of tuples we expect will be retrieved.
  * tuple_fraction is interpreted as explained for grouping_planner, below.
  *
@@ -189,24 +166,23 @@ planner(Query *parse, bool isCursor, int cursorOptions,
  *--------------------
  */
 Plan *
-subquery_planner(Query *parse, double tuple_fraction,
+subquery_planner(PlannerGlobal *glob, Query *parse,
+				 Index level, double tuple_fraction,
 				 List **subquery_pathkeys)
 {
-	List	   *saved_initplan = PlannerInitPlan;
-	int			saved_planid = PlannerPlanId;
+	int			saved_plan_id = glob->next_plan_id;
 	PlannerInfo *root;
 	Plan	   *plan;
 	List	   *newHaving;
 	ListCell   *l;
 
-	/* Set up for a new level of subquery */
-	PlannerQueryLevel++;
-	PlannerInitPlan = NIL;
-
 	/* Create a PlannerInfo data structure for this subquery */
 	root = makeNode(PlannerInfo);
 	root->parse = parse;
+	root->glob = glob;
+	root->query_level = level;
 	root->planner_cxt = CurrentMemoryContext;
+	root->init_plans = NIL;
 	root->eq_classes = NIL;
 	root->in_info_list = NIL;
 	root->append_rel_list = NIL;
@@ -396,18 +372,13 @@ subquery_planner(Query *parse, double tuple_fraction,
 	 * initPlan list and extParam/allParam sets for plan nodes, and attach the
 	 * initPlans to the top plan node.
 	 */
-	if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
-		SS_finalize_plan(plan, parse->rtable);
+	if (root->glob->next_plan_id != saved_plan_id || root->query_level > 1)
+		SS_finalize_plan(root, plan);
 
 	/* Return sort ordering info if caller wants it */
 	if (subquery_pathkeys)
 		*subquery_pathkeys = root->query_pathkeys;
 
-	/* Return to outer subquery context */
-	PlannerQueryLevel--;
-	PlannerInitPlan = saved_initplan;
-	/* we do NOT restore PlannerPlanId; that's not an oversight! */
-
 	return plan;
 }
 
@@ -460,7 +431,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
 	if (kind != EXPRKIND_VALUES &&
 		(root->parse->jointree->fromlist != NIL ||
 		 kind == EXPRKIND_QUAL ||
-		 PlannerQueryLevel > 1))
+		 root->query_level > 1))
 		expr = eval_const_expressions(expr);
 
 	/*
@@ -478,7 +449,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
 
 	/* Expand SubLinks to SubPlans */
 	if (root->parse->hasSubLinks)
-		expr = SS_process_sublinks(expr, (kind == EXPRKIND_QUAL));
+		expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL));
 
 	/*
 	 * XXX do not insert anything here unless you have grokked the comments in
@@ -486,8 +457,8 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind)
 	 */
 
 	/* Replace uplevel vars with Param nodes (this IS possible in VALUES) */
-	if (PlannerQueryLevel > 1)
-		expr = SS_replace_correlation_vars(expr);
+	if (root->query_level > 1)
+		expr = SS_replace_correlation_vars(root, expr);
 
 	/*
 	 * If it's a qual or havingQual, convert it to implicit-AND format. (We
@@ -590,6 +561,7 @@ inheritance_planner(PlannerInfo *root)
 		subroot.in_info_list = (List *)
 			adjust_appendrel_attrs((Node *) root->in_info_list,
 								   appinfo);
+		subroot.init_plans = NIL;
 		/* There shouldn't be any OJ info to translate, as yet */
 		Assert(subroot.oj_info_list == NIL);
 
@@ -612,6 +584,9 @@ inheritance_planner(PlannerInfo *root)
 
 		subplans = lappend(subplans, subplan);
 
+		/* Make sure any initplans from this rel get into the outer list */
+		root->init_plans = list_concat(root->init_plans, subroot.init_plans);
+
 		/* Build target-relations list for the executor */
 		resultRelations = lappend_int(resultRelations, appinfo->child_relid);
 
@@ -1201,7 +1176,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
 	 */
 	if (parse->limitCount)
 	{
-		est = estimate_expression_value(parse->limitCount);
+		est = estimate_expression_value(root, parse->limitCount);
 		if (est && IsA(est, Const))
 		{
 			if (((Const *) est)->constisnull)
@@ -1224,7 +1199,7 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
 
 	if (parse->limitOffset)
 	{
-		est = estimate_expression_value(parse->limitOffset);
+		est = estimate_expression_value(root, parse->limitOffset);
 		if (est && IsA(est, Const))
 		{
 			if (((Const *) est)->constisnull)
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index af035d9b104cbbff3e3fd395f85fa7c3d019f122..b62aeb853d85e0e4e460c1e8cb696ff3afe6a1cc 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.119 2007/02/19 02:23:12 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.120 2007/02/19 07:03:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,52 +31,19 @@
 #include "utils/syscache.h"
 
 
-Index		PlannerQueryLevel;	/* level of current query */
-List	   *PlannerInitPlan;	/* init subplans for current query */
-List	   *PlannerParamList;	/* to keep track of cross-level Params */
-
-int			PlannerPlanId = 0;	/* to assign unique ID to subquery plans */
-
-/*
- * PlannerParamList keeps track of the PARAM_EXEC slots that we have decided
- * we need for the query.  At runtime these slots are used to pass values
- * either down into subqueries (for outer references in subqueries) or up out
- * of subqueries (for the results of a subplan).  The n'th entry in the list
- * (n counts from 0) corresponds to Param->paramid = n.
- *
- * Each ParamList item shows the absolute query level it is associated with,
- * where the outermost query is level 1 and nested subqueries have higher
- * numbers.  The item the parameter slot represents can be one of three kinds:
- *
- * A Var: the slot represents a variable of that level that must be passed
- * down because subqueries have outer references to it.  The varlevelsup
- * value in the Var will always be zero.
- *
- * An Aggref (with an expression tree representing its argument): the slot
- * represents an aggregate expression that is an outer reference for some
- * subquery.  The Aggref itself has agglevelsup = 0, and its argument tree
- * is adjusted to match in level.
- *
- * A Param: the slot holds the result of a subplan (it is a setParam item
- * for that subplan).  The absolute level shown for such items corresponds
- * to the parent query of the subplan.
- *
- * Note: we detect duplicate Var parameters and coalesce them into one slot,
- * but we do not do this for Aggref or Param slots.
- */
-typedef struct PlannerParamItem
-{
-	Node	   *item;			/* the Var, Aggref, or Param */
-	Index		abslevel;		/* its absolute query level */
-} PlannerParamItem;
-
-
 typedef struct convert_testexpr_context
 {
+	PlannerInfo *root;
 	int			rtindex;		/* RT index for Vars, or 0 for Params */
 	List	   *righthandIds;	/* accumulated list of Vars or Param IDs */
 } convert_testexpr_context;
 
+typedef struct process_sublinks_context
+{
+	PlannerInfo *root;
+	bool		isTopQual;
+} process_sublinks_context;
+
 typedef struct finalize_primnode_context
 {
 	Bitmapset  *paramids;		/* Set of PARAM_EXEC paramids found */
@@ -84,15 +51,17 @@ typedef struct finalize_primnode_context
 } finalize_primnode_context;
 
 
-static Node *convert_testexpr(Node *testexpr,
-				 int rtindex,
-				 List **righthandIds);
+static Node *convert_testexpr(PlannerInfo *root,
+							  Node *testexpr,
+							  int rtindex,
+							  List **righthandIds);
 static Node *convert_testexpr_mutator(Node *node,
 						 convert_testexpr_context *context);
 static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
 static bool hash_ok_operator(OpExpr *expr);
-static Node *replace_correlation_vars_mutator(Node *node, void *context);
-static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
+static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root);
+static Node *process_sublinks_mutator(Node *node,
+									  process_sublinks_context *context);
 static Bitmapset *finalize_plan(Plan *plan, List *rtable,
 			  Bitmapset *outer_params,
 			  Bitmapset *valid_params);
@@ -104,7 +73,7 @@ static bool finalize_primnode(Node *node, finalize_primnode_context *context);
  * which is expected to have varlevelsup > 0 (ie, it is not local).
  */
 static Param *
-replace_outer_var(Var *var)
+replace_outer_var(PlannerInfo *root, Var *var)
 {
 	Param	   *retval;
 	ListCell   *ppl;
@@ -112,11 +81,11 @@ replace_outer_var(Var *var)
 	Index		abslevel;
 	int			i;
 
-	Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel);
-	abslevel = PlannerQueryLevel - var->varlevelsup;
+	Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
+	abslevel = root->query_level - var->varlevelsup;
 
 	/*
-	 * If there's already a PlannerParamList entry for this same Var, just use
+	 * If there's already a paramlist entry for this same Var, just use
 	 * it.	NOTE: in sufficiently complex querytrees, it is possible for the
 	 * same varno/abslevel to refer to different RTEs in different parts of
 	 * the parsetree, so that different fields might end up sharing the same
@@ -130,7 +99,7 @@ replace_outer_var(Var *var)
 	 * a subplan's args list.
 	 */
 	i = 0;
-	foreach(ppl, PlannerParamList)
+	foreach(ppl, root->glob->paramlist)
 	{
 		pitem = (PlannerParamItem *) lfirst(ppl);
 		if (pitem->abslevel == abslevel && IsA(pitem->item, Var))
@@ -152,11 +121,11 @@ replace_outer_var(Var *var)
 		var = (Var *) copyObject(var);
 		var->varlevelsup = 0;
 
-		pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem));
+		pitem = makeNode(PlannerParamItem);
 		pitem->item = (Node *) var;
 		pitem->abslevel = abslevel;
 
-		PlannerParamList = lappend(PlannerParamList, pitem);
+		root->glob->paramlist = lappend(root->glob->paramlist, pitem);
 		/* i is already the correct index for the new item */
 	}
 
@@ -174,15 +143,15 @@ replace_outer_var(Var *var)
  * which is expected to have agglevelsup > 0 (ie, it is not local).
  */
 static Param *
-replace_outer_agg(Aggref *agg)
+replace_outer_agg(PlannerInfo *root, Aggref *agg)
 {
 	Param	   *retval;
 	PlannerParamItem *pitem;
 	Index		abslevel;
 	int			i;
 
-	Assert(agg->agglevelsup > 0 && agg->agglevelsup < PlannerQueryLevel);
-	abslevel = PlannerQueryLevel - agg->agglevelsup;
+	Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level);
+	abslevel = root->query_level - agg->agglevelsup;
 
 	/*
 	 * It does not seem worthwhile to try to match duplicate outer aggs. Just
@@ -192,12 +161,12 @@ replace_outer_agg(Aggref *agg)
 	IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
 	Assert(agg->agglevelsup == 0);
 
-	pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem));
+	pitem = makeNode(PlannerParamItem);
 	pitem->item = (Node *) agg;
 	pitem->abslevel = abslevel;
 
-	PlannerParamList = lappend(PlannerParamList, pitem);
-	i = list_length(PlannerParamList) - 1;
+	root->glob->paramlist = lappend(root->glob->paramlist, pitem);
+	i = list_length(root->glob->paramlist) - 1;
 
 	retval = makeNode(Param);
 	retval->paramkind = PARAM_EXEC;
@@ -214,22 +183,22 @@ replace_outer_agg(Aggref *agg)
  * This is used to allocate PARAM_EXEC slots for subplan outputs.
  */
 static Param *
-generate_new_param(Oid paramtype, int32 paramtypmod)
+generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
 {
 	Param	   *retval;
 	PlannerParamItem *pitem;
 
 	retval = makeNode(Param);
 	retval->paramkind = PARAM_EXEC;
-	retval->paramid = list_length(PlannerParamList);
+	retval->paramid = list_length(root->glob->paramlist);
 	retval->paramtype = paramtype;
 	retval->paramtypmod = paramtypmod;
 
-	pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem));
+	pitem = makeNode(PlannerParamItem);
 	pitem->item = (Node *) retval;
-	pitem->abslevel = PlannerQueryLevel;
+	pitem->abslevel = root->query_level;
 
-	PlannerParamList = lappend(PlannerParamList, pitem);
+	root->glob->paramlist = lappend(root->glob->paramlist, pitem);
 
 	return retval;
 }
@@ -248,7 +217,7 @@ generate_new_param(Oid paramtype, int32 paramtypmod)
  * tree containing InitPlan Param nodes.
  */
 static Node *
-make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
+make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
 {
 	SubPlan    *node = makeNode(SubPlan);
 	Query	   *subquery = (Query *) (slink->subselect);
@@ -297,9 +266,13 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 	/*
 	 * Generate the plan for the subquery.
 	 */
-	node->plan = plan = subquery_planner(subquery, tuple_fraction, NULL);
+	node->plan = plan = subquery_planner(root->glob, subquery,
+										 root->query_level + 1,
+										 tuple_fraction,
+										 NULL);
 
-	node->plan_id = PlannerPlanId++;	/* Assign unique ID to this SubPlan */
+	/* Assign quasi-unique ID to this SubPlan */
+	node->plan_id = root->glob->next_plan_id++;
 
 	node->rtable = subquery->rtable;
 
@@ -323,9 +296,9 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 	tmpset = bms_copy(plan->extParam);
 	while ((paramid = bms_first_member(tmpset)) >= 0)
 	{
-		PlannerParamItem *pitem = list_nth(PlannerParamList, paramid);
+		PlannerParamItem *pitem = list_nth(root->glob->paramlist, paramid);
 
-		if (pitem->abslevel == PlannerQueryLevel)
+		if (pitem->abslevel == root->query_level)
 			node->parParam = lappend_int(node->parParam, paramid);
 	}
 	bms_free(tmpset);
@@ -342,9 +315,9 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 	{
 		Param	   *prm;
 
-		prm = generate_new_param(BOOLOID, -1);
+		prm = generate_new_param(root, BOOLOID, -1);
 		node->setParam = list_make1_int(prm->paramid);
-		PlannerInitPlan = lappend(PlannerInitPlan, node);
+		root->init_plans = lappend(root->init_plans, node);
 		result = (Node *) prm;
 	}
 	else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK)
@@ -353,10 +326,11 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 		Param	   *prm;
 
 		Assert(!te->resjunk);
-		prm = generate_new_param(exprType((Node *) te->expr),
+		prm = generate_new_param(root,
+								 exprType((Node *) te->expr),
 								 exprTypmod((Node *) te->expr));
 		node->setParam = list_make1_int(prm->paramid);
-		PlannerInitPlan = lappend(PlannerInitPlan, node);
+		root->init_plans = lappend(root->init_plans, node);
 		result = (Node *) prm;
 	}
 	else if (node->parParam == NIL && slink->subLinkType == ARRAY_SUBLINK)
@@ -370,19 +344,22 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 		if (!OidIsValid(arraytype))
 			elog(ERROR, "could not find array type for datatype %s",
 				 format_type_be(exprType((Node *) te->expr)));
-		prm = generate_new_param(arraytype, exprTypmod((Node *) te->expr));
+		prm = generate_new_param(root,
+								 arraytype,
+								 exprTypmod((Node *) te->expr));
 		node->setParam = list_make1_int(prm->paramid);
-		PlannerInitPlan = lappend(PlannerInitPlan, node);
+		root->init_plans = lappend(root->init_plans, node);
 		result = (Node *) prm;
 	}
 	else if (node->parParam == NIL && slink->subLinkType == ROWCOMPARE_SUBLINK)
 	{
 		/* Adjust the Params */
-		result = convert_testexpr(testexpr,
+		result = convert_testexpr(root,
+								  testexpr,
 								  0,
 								  &node->paramIds);
 		node->setParam = list_copy(node->paramIds);
-		PlannerInitPlan = lappend(PlannerInitPlan, node);
+		root->init_plans = lappend(root->init_plans, node);
 
 		/*
 		 * The executable expression is returned to become part of the outer
@@ -395,7 +372,8 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 		ListCell   *l;
 
 		/* Adjust the Params */
-		node->testexpr = convert_testexpr(testexpr,
+		node->testexpr = convert_testexpr(root,
+										  testexpr,
 										  0,
 										  &node->paramIds);
 
@@ -442,7 +420,8 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
 		args = NIL;
 		foreach(l, node->parParam)
 		{
-			PlannerParamItem *pitem = list_nth(PlannerParamList, lfirst_int(l));
+			PlannerParamItem *pitem = list_nth(root->glob->paramlist,
+											   lfirst_int(l));
 
 			/*
 			 * The Var or Aggref has already been adjusted to have the correct
@@ -477,13 +456,15 @@ make_subplan(SubLink *slink, Node *testexpr, bool isTopQual)
  * any we find are for our own level of SubLink.
  */
 static Node *
-convert_testexpr(Node *testexpr,
+convert_testexpr(PlannerInfo *root,
+				 Node *testexpr,
 				 int rtindex,
 				 List **righthandIds)
 {
 	Node	   *result;
 	convert_testexpr_context context;
 
+	context.root = root;
 	context.rtindex = rtindex;
 	context.righthandIds = NIL;
 	result = convert_testexpr_mutator(testexpr, &context);
@@ -536,7 +517,8 @@ convert_testexpr_mutator(Node *node,
 				/* Make the Param node representing the subplan's result */
 				Param	   *newparam;
 
-				newparam = generate_new_param(param->paramtype,
+				newparam = generate_new_param(context->root,
+											  param->paramtype,
 											  param->paramtypmod);
 				/* Record its ID */
 				context->righthandIds = lappend_int(context->righthandIds,
@@ -765,7 +747,8 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
 	 * ininfo->sub_targetlist is filled with a list of Vars representing the
 	 * subselect outputs.
 	 */
-	result = convert_testexpr(sublink->testexpr,
+	result = convert_testexpr(root,
+							  sublink->testexpr,
 							  rtindex,
 							  &ininfo->sub_targetlist);
 
@@ -795,30 +778,30 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
  * argument expressions, either in the parent or the child level.
  */
 Node *
-SS_replace_correlation_vars(Node *expr)
+SS_replace_correlation_vars(PlannerInfo *root, Node *expr)
 {
 	/* No setup needed for tree walk, so away we go */
-	return replace_correlation_vars_mutator(expr, NULL);
+	return replace_correlation_vars_mutator(expr, root);
 }
 
 static Node *
-replace_correlation_vars_mutator(Node *node, void *context)
+replace_correlation_vars_mutator(Node *node, PlannerInfo *root)
 {
 	if (node == NULL)
 		return NULL;
 	if (IsA(node, Var))
 	{
 		if (((Var *) node)->varlevelsup > 0)
-			return (Node *) replace_outer_var((Var *) node);
+			return (Node *) replace_outer_var(root, (Var *) node);
 	}
 	if (IsA(node, Aggref))
 	{
 		if (((Aggref *) node)->agglevelsup > 0)
-			return (Node *) replace_outer_agg((Aggref *) node);
+			return (Node *) replace_outer_agg(root, (Aggref *) node);
 	}
 	return expression_tree_mutator(node,
 								   replace_correlation_vars_mutator,
-								   context);
+								   (void *) root);
 }
 
 /*
@@ -829,16 +812,21 @@ replace_correlation_vars_mutator(Node *node, void *context)
  * not distinguish FALSE from UNKNOWN return values.
  */
 Node *
-SS_process_sublinks(Node *expr, bool isQual)
+SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual)
 {
-	/* The only context needed is the initial are-we-in-a-qual flag */
-	return process_sublinks_mutator(expr, &isQual);
+	process_sublinks_context context;
+
+	context.root = root;
+	context.isTopQual = isQual;
+	return process_sublinks_mutator(expr, &context);
 }
 
 static Node *
-process_sublinks_mutator(Node *node, bool *isTopQual)
+process_sublinks_mutator(Node *node, process_sublinks_context *context)
 {
-	bool		locTopQual;
+	process_sublinks_context locContext;
+
+	locContext.root = context->root;
 
 	if (node == NULL)
 		return NULL;
@@ -849,14 +837,18 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
 
 		/*
 		 * First, recursively process the lefthand-side expressions, if any.
+		 * They're not top-level anymore.
 		 */
-		locTopQual = false;
-		testexpr = process_sublinks_mutator(sublink->testexpr, &locTopQual);
+		locContext.isTopQual = false;
+		testexpr = process_sublinks_mutator(sublink->testexpr, &locContext);
 
 		/*
 		 * Now build the SubPlan node and make the expr to return.
 		 */
-		return make_subplan(sublink, testexpr, *isTopQual);
+		return make_subplan(context->root,
+							sublink,
+							testexpr,
+							context->isTopQual);
 	}
 
 	/*
@@ -883,14 +875,13 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
 		ListCell   *l;
 
 		/* Still at qual top-level */
-		locTopQual = *isTopQual;
+		locContext.isTopQual = context->isTopQual;
 
 		foreach(l, ((BoolExpr *) node)->args)
 		{
 			Node	   *newarg;
 
-			newarg = process_sublinks_mutator(lfirst(l),
-											  (void *) &locTopQual);
+			newarg = process_sublinks_mutator(lfirst(l), &locContext);
 			if (and_clause(newarg))
 				newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);
 			else
@@ -900,7 +891,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
 	}
 
 	/* otherwise not at qual top-level */
-	locTopQual = false;
+	locContext.isTopQual = false;
 
 	if (or_clause(node))
 	{
@@ -911,8 +902,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
 		{
 			Node	   *newarg;
 
-			newarg = process_sublinks_mutator(lfirst(l),
-											  (void *) &locTopQual);
+			newarg = process_sublinks_mutator(lfirst(l), &locContext);
 			if (or_clause(newarg))
 				newargs = list_concat(newargs, ((BoolExpr *) newarg)->args);
 			else
@@ -923,7 +913,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
 
 	return expression_tree_mutator(node,
 								   process_sublinks_mutator,
-								   (void *) &locTopQual);
+								   (void *) &locContext);
 }
 
 /*
@@ -934,7 +924,7 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
  * to the top plan node.
  */
 void
-SS_finalize_plan(Plan *plan, List *rtable)
+SS_finalize_plan(PlannerInfo *root, Plan *plan)
 {
 	Bitmapset  *outer_params,
 			   *valid_params,
@@ -951,17 +941,17 @@ SS_finalize_plan(Plan *plan, List *rtable)
 	 */
 	outer_params = valid_params = NULL;
 	paramid = 0;
-	foreach(l, PlannerParamList)
+	foreach(l, root->glob->paramlist)
 	{
 		PlannerParamItem *pitem = (PlannerParamItem *) lfirst(l);
 
-		if (pitem->abslevel < PlannerQueryLevel)
+		if (pitem->abslevel < root->query_level)
 		{
 			/* valid outer-level parameter */
 			outer_params = bms_add_member(outer_params, paramid);
 			valid_params = bms_add_member(valid_params, paramid);
 		}
-		else if (pitem->abslevel == PlannerQueryLevel &&
+		else if (pitem->abslevel == root->query_level &&
 				 IsA(pitem->item, Param))
 		{
 			/* valid local parameter (i.e., a setParam of my child) */
@@ -974,7 +964,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
 	/*
 	 * Now recurse through plan tree.
 	 */
-	(void) finalize_plan(plan, rtable, outer_params, valid_params);
+	(void) finalize_plan(plan, root->parse->rtable, outer_params, valid_params);
 
 	bms_free(outer_params);
 	bms_free(valid_params);
@@ -991,8 +981,8 @@ SS_finalize_plan(Plan *plan, List *rtable)
 	 * 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 = PlannerInitPlan;
-	PlannerInitPlan = NIL;		/* make sure they're not attached twice */
+	plan->initPlan = root->init_plans;
+	root->init_plans = NIL;		/* make sure they're not attached twice */
 
 	initExtParam = initSetParam = NULL;
 	initplan_cost = 0;
@@ -1287,25 +1277,27 @@ Param *
 SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
 						   Oid resulttype, int32 resulttypmod)
 {
-	List	   *saved_initplan = PlannerInitPlan;
+	List	   *saved_init_plans;
 	SubPlan    *node;
 	Param	   *prm;
 
 	/*
 	 * Set up for a new level of subquery.	This is just to keep
-	 * SS_finalize_plan from becoming confused.
+	 * SS_finalize_plan from becoming confused; we don't bother with making
+	 * a whole new PlannerInfo struct.
 	 */
-	PlannerQueryLevel++;
-	PlannerInitPlan = NIL;
+	root->query_level++;
+	saved_init_plans = root->init_plans;
+	root->init_plans = NIL;
 
 	/*
 	 * Build extParam/allParam sets for plan nodes.
 	 */
-	SS_finalize_plan(plan, root->parse->rtable);
+	SS_finalize_plan(root, plan);
 
 	/* Return to outer subquery context */
-	PlannerQueryLevel--;
-	PlannerInitPlan = saved_initplan;
+	root->query_level--;
+	root->init_plans = saved_init_plans;
 
 	/*
 	 * Create a SubPlan node and add it to the outer list of InitPlans.
@@ -1313,11 +1305,12 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
 	node = makeNode(SubPlan);
 	node->subLinkType = EXPR_SUBLINK;
 	node->plan = plan;
-	node->plan_id = PlannerPlanId++;	/* Assign unique ID to this SubPlan */
+	/* Assign quasi-unique ID to this SubPlan */
+	node->plan_id = root->glob->next_plan_id++;
 
 	node->rtable = root->parse->rtable;
 
-	PlannerInitPlan = lappend(PlannerInitPlan, node);
+	root->init_plans = lappend(root->init_plans, node);
 
 	/*
 	 * The node can't have any inputs (since it's an initplan), so the
@@ -1327,7 +1320,7 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
 	/*
 	 * Make a Param that will be the subplan's output.
 	 */
-	prm = generate_new_param(resulttype, resulttypmod);
+	prm = generate_new_param(root, resulttype, resulttypmod);
 	node->setParam = list_make1_int(prm->paramid);
 
 	return prm;
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index ce6f9cc38e4b470b0fc88a59076db765eaf6fdda..1519c01e60e725c8c5ad72ddd0a6f96fda58edc5 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.46 2007/01/20 20:45:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.47 2007/02/19 07:03:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -292,7 +292,10 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
 	 */
 	subroot = makeNode(PlannerInfo);
 	subroot->parse = subquery;
+	subroot->glob = root->glob;
+	subroot->query_level = root->query_level;
 	subroot->planner_cxt = CurrentMemoryContext;
+	subroot->init_plans = NIL;
 	subroot->in_info_list = NIL;
 	subroot->append_rel_list = NIL;
 
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index b8d98cc9e3cd7ead395795c6d02324cef13ace42..310b57392cd9460e14039d3920929e9f6256d45d 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -16,7 +16,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.85 2007/01/05 22:19:32 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.86 2007/02/19 07:03:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -124,7 +124,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
 		/*
 		 * Currently the executor only supports FOR UPDATE/SHARE at top level
 		 */
-		if (PlannerQueryLevel > 1)
+		if (root->query_level > 1)
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			errmsg("SELECT FOR UPDATE/SHARE is not allowed in subqueries")));
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 5ee03b75cffd7e87e9d1322eda94390cb5f8f710..2f06e1bf5322dfe3a03c14d310c9dbc03d964590 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.137 2007/01/22 20:00:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.138 2007/02/19 07:03:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -177,7 +177,10 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
 		/*
 		 * Generate plan for primitive subquery
 		 */
-		subplan = subquery_planner(subquery, tuple_fraction, NULL);
+		subplan = subquery_planner(root->glob, subquery,
+								   root->query_level + 1,
+								   tuple_fraction,
+								   NULL);
 
 		/*
 		 * Add a SubqueryScan with the caller-requested targetlist
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 528f02ed111389beef7c228d18678d0002db662d..f90d55001979b65c15f8fdb222473cc349e83a1e 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.234 2007/02/16 23:32:08 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.235 2007/02/19 07:03:30 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -49,6 +49,7 @@
 
 typedef struct
 {
+	ParamListInfo boundParams;
 	List	   *active_fns;
 	Node	   *case_val;
 	bool		estimate;
@@ -1578,6 +1579,7 @@ eval_const_expressions(Node *node)
 {
 	eval_const_expressions_context context;
 
+	context.boundParams = NULL;	/* don't use any bound params */
 	context.active_fns = NIL;	/* nothing being recursively simplified */
 	context.case_val = NULL;	/* no CASE being examined */
 	context.estimate = false;	/* safe transformations only */
@@ -1601,10 +1603,11 @@ eval_const_expressions(Node *node)
  *--------------------
  */
 Node *
-estimate_expression_value(Node *node)
+estimate_expression_value(PlannerInfo *root, Node *node)
 {
 	eval_const_expressions_context context;
 
+	context.boundParams = root->glob->boundParams;	/* bound Params */
 	context.active_fns = NIL;	/* nothing being recursively simplified */
 	context.case_val = NULL;	/* no CASE being examined */
 	context.estimate = true;	/* unsafe transformations OK */
@@ -1623,11 +1626,11 @@ eval_const_expressions_mutator(Node *node,
 
 		/* Look to see if we've been given a value for this Param */
 		if (param->paramkind == PARAM_EXTERN &&
-			PlannerBoundParamList != NULL &&
+			context->boundParams != NULL &&
 			param->paramid > 0 &&
-			param->paramid <= PlannerBoundParamList->numParams)
+			param->paramid <= context->boundParams->numParams)
 		{
-			ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
+			ParamExternData *prm = &context->boundParams->params[param->paramid - 1];
 
 			if (OidIsValid(prm->ptype))
 			{
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 7908ab15167a74ddf34a705fd33458d45b027f67..c6b8e8481c498d822de7700ca293713910021716 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.225 2007/01/31 16:54:51 teodor Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.226 2007/02/19 07:03:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3411,7 +3411,7 @@ get_restriction_variable(PlannerInfo *root, List *args, int varRelid,
 	if (vardata->rel && rdata.rel == NULL)
 	{
 		*varonleft = true;
-		*other = estimate_expression_value(rdata.var);
+		*other = estimate_expression_value(root, rdata.var);
 		/* Assume we need no ReleaseVariableStats(rdata) here */
 		return true;
 	}
@@ -3419,7 +3419,7 @@ get_restriction_variable(PlannerInfo *root, List *args, int varRelid,
 	if (vardata->rel == NULL && rdata.rel)
 	{
 		*varonleft = false;
-		*other = estimate_expression_value(vardata->var);
+		*other = estimate_expression_value(root, vardata->var);
 		/* Assume we need no ReleaseVariableStats(*vardata) here */
 		*vardata = rdata;
 		return true;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 2452f792940788985bb36782abc2ab9d9bfbb7e4..44175591e7502c38910a2286bfecff1bd57a8940 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.194 2007/02/03 14:06:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.195 2007/02/19 07:03:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,6 +175,7 @@ typedef enum NodeTag
 	 * TAGS FOR PLANNER NODES (relation.h)
 	 */
 	T_PlannerInfo = 500,
+	T_PlannerGlobal,
 	T_RelOptInfo,
 	T_IndexOptInfo,
 	T_Path,
@@ -198,6 +199,7 @@ typedef enum NodeTag
 	T_OuterJoinInfo,
 	T_InClauseInfo,
 	T_AppendRelInfo,
+	T_PlannerParamItem,
 
 	/*
 	 * TAGS FOR MEMORY NODES (memnodes.h)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 298ac0d95d6f7920b3312bdd7e3e8151227f3bd1..caa689e262379074e18b09fd35dcd769fe068b29 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.124 2007/02/03 14:06:56 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.125 2007/02/19 07:03:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -442,10 +442,9 @@ typedef struct SubPlan
 	List	   *paramIds;		/* IDs of Params embedded in the above */
 	/* The subselect, transformed to a Plan: */
 	struct Plan *plan;			/* subselect plan itself */
-	int			plan_id;		/* dummy thing because of we haven't equal
-								 * funcs for plan nodes... actually, we could
-								 * put *plan itself somewhere else (TopPlan
-								 * node ?)... */
+	int			plan_id;		/* kluge because we haven't equal-funcs for
+								 * plan nodes... we compare this instead of
+								 * subselect plan */
 	List	   *rtable;			/* range table for subselect */
 	/* Information about execution strategy: */
 	bool		useHashTable;	/* TRUE to store subselect output in a hash
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index dac7d959bbd23bd8dcbd5a6ad779f8eec693ad5e..6de06ebc918f769327cf32ca075b3ab26ff9262a 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.135 2007/02/16 20:57:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.136 2007/02/19 07:03:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "access/sdir.h"
 #include "nodes/bitmapset.h"
+#include "nodes/params.h"
 #include "nodes/parsenodes.h"
 #include "storage/block.h"
 
@@ -46,6 +47,27 @@ typedef struct QualCost
 } QualCost;
 
 
+/*----------
+ * PlannerGlobal
+ *		Global information for planning/optimization
+ *
+ * PlannerGlobal holds state for an entire planner invocation; this state
+ * is shared across all levels of sub-Queries that exist in the command being
+ * planned.
+ *----------
+ */
+typedef struct PlannerGlobal
+{
+	NodeTag		type;
+
+	ParamListInfo boundParams;	/* Param values provided to planner() */
+
+	List	   *paramlist;		/* to keep track of cross-level Params */
+
+	int			next_plan_id;	/* hack for distinguishing SubPlans */
+} PlannerGlobal;
+
+
 /*----------
  * PlannerInfo
  *		Per-query information for planning/optimization
@@ -62,6 +84,10 @@ typedef struct PlannerInfo
 
 	Query	   *parse;			/* the Query being planned */
 
+	PlannerGlobal *glob;		/* global info for current planner run */
+
+	Index		query_level;	/* 1 at the outermost Query */
+
 	/*
 	 * simple_rel_array holds pointers to "base rels" and "other rels" (see
 	 * comments for RelOptInfo for more info).	It is indexed by rangetable
@@ -84,6 +110,8 @@ typedef struct PlannerInfo
 	List	   *join_rel_list;	/* list of join-relation RelOptInfos */
 	struct HTAB *join_rel_hash; /* optional hashtable for join relations */
 
+	List	   *init_plans;				/* init subplans for query */
+
 	List	   *eq_classes;				/* list of active EquivalenceClasses */
 
 	List	   *canon_pathkeys;			/* list of "canonical" PathKeys */
@@ -1109,4 +1137,39 @@ typedef struct AppendRelInfo
 	Oid			parent_reloid;	/* OID of parent relation */
 } AppendRelInfo;
 
+/*
+ * glob->paramlist keeps track of the PARAM_EXEC slots that we have decided
+ * we need for the query.  At runtime these slots are used to pass values
+ * either down into subqueries (for outer references in subqueries) or up out
+ * of subqueries (for the results of a subplan).  The n'th entry in the list
+ * (n counts from 0) corresponds to Param->paramid = n.
+ *
+ * Each paramlist item shows the absolute query level it is associated with,
+ * where the outermost query is level 1 and nested subqueries have higher
+ * numbers.  The item the parameter slot represents can be one of three kinds:
+ *
+ * A Var: the slot represents a variable of that level that must be passed
+ * down because subqueries have outer references to it.  The varlevelsup
+ * value in the Var will always be zero.
+ *
+ * An Aggref (with an expression tree representing its argument): the slot
+ * represents an aggregate expression that is an outer reference for some
+ * subquery.  The Aggref itself has agglevelsup = 0, and its argument tree
+ * is adjusted to match in level.
+ *
+ * A Param: the slot holds the result of a subplan (it is a setParam item
+ * for that subplan).  The absolute level shown for such items corresponds
+ * to the parent query of the subplan.
+ *
+ * Note: we detect duplicate Var parameters and coalesce them into one slot,
+ * but we do not do this for Aggref or Param slots.
+ */
+typedef struct PlannerParamItem
+{
+	NodeTag		type;
+
+	Node	   *item;			/* the Var, Aggref, or Param */
+	Index		abslevel;		/* its absolute query level */
+} PlannerParamItem;
+
 #endif   /* RELATION_H */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 500112591429a58a92915e014ab855dd098c24d9..bd4a7964355f3473db5324a3ac7851ee49c664b2 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.86 2007/01/22 01:35:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.87 2007/02/19 07:03:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -77,7 +77,7 @@ extern void set_coercionform_dontcare(Node *node);
 
 extern Node *eval_const_expressions(Node *node);
 
-extern Node *estimate_expression_value(Node *node);
+extern Node *estimate_expression_value(PlannerInfo *root, Node *node);
 
 extern bool expression_tree_walker(Node *node, bool (*walker) (),
 											   void *context);
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index 6567e5b8b77920e566079a77aaedbb0a3d2c3f80..44d03602694120f59dd557b3328ea1f2005f6420 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -7,23 +7,21 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.36 2007/01/05 22:19:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.37 2007/02/19 07:03:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PLANNER_H
 #define PLANNER_H
 
-#include "nodes/params.h"
-#include "nodes/parsenodes.h"
 #include "nodes/plannodes.h"
+#include "nodes/relation.h"
 
 
-extern ParamListInfo PlannerBoundParamList;		/* current boundParams */
-
 extern Plan *planner(Query *parse, bool isCursor, int cursorOptions,
 		ParamListInfo boundParams);
-extern Plan *subquery_planner(Query *parse, double tuple_fraction,
-				 List **subquery_pathkeys);
+extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse,
+							  Index level, double tuple_fraction,
+							  List **subquery_pathkeys);
 
 #endif   /* PLANNER_H */
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index 8a4328bd1f2d487017b7af1e5d39dc32885986f2..17c94bf6099ee8cfe4b68486b77f20277d1e93e0 100644
--- a/src/include/optimizer/subselect.h
+++ b/src/include/optimizer/subselect.h
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.28 2007/01/05 22:19:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.29 2007/02/19 07:03:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,16 +15,10 @@
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
 
-
-extern Index PlannerQueryLevel; /* level of current query */
-extern List *PlannerInitPlan;	/* init subplans for current query */
-extern List *PlannerParamList;	/* to keep track of cross-level Params */
-extern int	PlannerPlanId;		/* to assign unique ID to subquery plans */
-
 extern Node *convert_IN_to_join(PlannerInfo *root, SubLink *sublink);
-extern Node *SS_replace_correlation_vars(Node *expr);
-extern Node *SS_process_sublinks(Node *expr, bool isQual);
-extern void SS_finalize_plan(Plan *plan, List *rtable);
+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 Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
 						   Oid resulttype, int32 resulttypmod);