diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index c55e5ecd1494e05d3946b63aad9c6a11ee68411e..b22ad7634982003f66f721dea37dc7bcf2079cd6 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.68 2002/12/14 00:17:50 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.69 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,7 +55,7 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 		InstrEndLoop(node->instrument);
 
 	/* If we have changed parameters, propagate that info */
-	if (node->chgParam != NIL)
+	if (node->chgParam != NULL)
 	{
 		List	   *lst;
 
@@ -64,10 +64,10 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 			SubPlanState  *sstate = (SubPlanState *) lfirst(lst);
 			PlanState  *splan = sstate->planstate;
 
-			if (splan->plan->extParam != NIL)	/* don't care about child
-												 * locParam */
-				SetChangedParamList(splan, node->chgParam);
-			if (splan->chgParam != NIL)
+			if (splan->plan->extParam != NULL)	/* don't care about child
+												 * local Params */
+				UpdateChangedParamSet(splan, node->chgParam);
+			if (splan->chgParam != NULL)
 				ExecReScanSetParamPlan(sstate, node);
 		}
 		foreach(lst, node->subPlan)
@@ -75,14 +75,14 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 			SubPlanState  *sstate = (SubPlanState *) lfirst(lst);
 			PlanState  *splan = sstate->planstate;
 
-			if (splan->plan->extParam != NIL)
-				SetChangedParamList(splan, node->chgParam);
+			if (splan->plan->extParam != NULL)
+				UpdateChangedParamSet(splan, node->chgParam);
 		}
 		/* Well. Now set chgParam for left/right trees. */
 		if (node->lefttree != NULL)
-			SetChangedParamList(node->lefttree, node->chgParam);
+			UpdateChangedParamSet(node->lefttree, node->chgParam);
 		if (node->righttree != NULL)
-			SetChangedParamList(node->righttree, node->chgParam);
+			UpdateChangedParamSet(node->righttree, node->chgParam);
 	}
 
 	switch (nodeTag(node))
@@ -165,10 +165,10 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 			return;
 	}
 
-	if (node->chgParam != NIL)
+	if (node->chgParam != NULL)
 	{
-		freeList(node->chgParam);
-		node->chgParam = NIL;
+		bms_free(node->chgParam);
+		node->chgParam = NULL;
 	}
 }
 
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index dc5a3085ead72f835ff64e2c355a8469c9ffbeb1..8d2bc0f8bd93faff9125cc94f10b52bf81d7c3c5 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.34 2002/12/14 00:17:50 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.35 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -282,7 +282,7 @@ ExecProcNode(PlanState *node)
 	if (node == NULL)
 		return NULL;
 
-	if (node->chgParam != NIL)	/* something changed */
+	if (node->chgParam != NULL)	/* something changed */
 		ExecReScan(node, NULL); /* let ReScan handle this */
 
 	if (node->instrument)
@@ -504,10 +504,10 @@ ExecEndNode(PlanState *node)
 	foreach(subp, node->subPlan)
 		ExecEndSubPlan((SubPlanState *) lfirst(subp));
 
-	if (node->chgParam != NIL)
+	if (node->chgParam != NULL)
 	{
-		freeList(node->chgParam);
-		node->chgParam = NIL;
+		bms_free(node->chgParam);
+		node->chgParam = NULL;
 	}
 
 	switch (nodeTag(node))
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 90bd8adf1ae13beef3fb1230e223979127473bae..b2fe0a2276a94d00f2f1d29825dc5d29f5e387ed 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.96 2003/01/23 05:10:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.97 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -874,25 +874,28 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 	}
 }
 
+/*
+ * UpdateChangedParamSet
+ *		Add changed parameters to a plan node's chgParam set
+ */
 void
-SetChangedParamList(PlanState *node, List *newchg)
+UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
 {
-	List	   *nl;
-
-	foreach(nl, newchg)
-	{
-		int			paramId = lfirsti(nl);
+	Bitmapset  *parmset;
 
-		/* if this node doesn't depend on a param ... */
-		if (!intMember(paramId, node->plan->extParam) &&
-			!intMember(paramId, node->plan->locParam))
-			continue;
-		/* if this param is already in list of changed ones ... */
-		if (intMember(paramId, node->chgParam))
-			continue;
-		/* else - add this param to the list */
-		node->chgParam = lappendi(node->chgParam, paramId);
-	}
+	/*
+	 * The plan node only depends on params listed in its allParam set.
+	 * Don't include anything else into its chgParam set.
+	 */
+	parmset = bms_intersect(node->plan->allParam, newchg);
+	/*
+	 * Keep node->chgParam == NULL if there's not actually any members;
+	 * this allows the simplest possible tests in executor node files.
+	 */
+	if (!bms_is_empty(parmset))
+		node->chgParam = bms_join(node->chgParam, parmset);
+	else
+		bms_free(parmset);
 }
 
 /*
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 0cb2f3e2b6ffc994b9cee44be9b872527afcfc95..bbdda3540a7ec4e910d8bf7dc124a8305d9f2971 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.103 2003/02/04 00:48:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.104 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1405,7 +1405,7 @@ ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NIL)
+	if (((PlanState *) node)->lefttree->chgParam == NULL)
 		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
 }
 
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index bcb50fb7979917e0baa79f838cb2082b1835a3d0..e79d37fd857e184c86dac00482a63de1a248b376 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.51 2002/12/05 15:50:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.52 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -361,14 +361,14 @@ ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
 		 * ExecReScan doesn't know about my subplans, so I have to do
 		 * changed-parameter signaling myself.
 		 */
-		if (node->ps.chgParam != NIL)
-			SetChangedParamList(subnode, node->ps.chgParam);
+		if (node->ps.chgParam != NULL)
+			UpdateChangedParamSet(subnode, node->ps.chgParam);
 
 		/*
 		 * if chgParam of subnode is not null then plan will be re-scanned
 		 * by first ExecProcNode.
 		 */
-		if (subnode->chgParam == NIL)
+		if (subnode->chgParam == NULL)
 		{
 			/* make sure estate is correct for this subnode (needed??) */
 			node->as_whichplan = i;
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index d3f32913914f6fae8cc2689959be060725f935c4..4fd8af2ae4d77b65dfb8eb92c8c4ed62e154763e 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.43 2003/01/12 04:03:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.44 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -80,7 +80,7 @@ ExecHashSubPlan(SubPlanState *node,
 	 * If first time through or we need to rescan the subplan, build
 	 * the hash table.
 	 */
-	if (node->hashtable == NULL || planstate->chgParam != NIL)
+	if (node->hashtable == NULL || planstate->chgParam != NULL)
 		buildSubPlanHash(node);
 
 	/*
@@ -218,22 +218,18 @@ ExecScanSubPlan(SubPlanState *node,
 	 * Set Params of this plan from parent plan correlation Vars
 	 */
 	pvar = node->args;
-	if (subplan->parParam != NIL)
+	foreach(lst, subplan->parParam)
 	{
-		foreach(lst, subplan->parParam)
-		{
-			ParamExecData *prm;
-
-			prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
-			Assert(pvar != NIL);
-			prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
-												   econtext,
-												   &(prm->isnull),
-												   NULL);
-			pvar = lnext(pvar);
-		}
-		planstate->chgParam = nconc(planstate->chgParam,
-									listCopy(subplan->parParam));
+		int		paramid = lfirsti(lst);
+		ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
+
+		Assert(pvar != NIL);
+		prm->value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
+											   econtext,
+											   &(prm->isnull),
+											   NULL);
+		pvar = lnext(pvar);
+		planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
 	}
 	Assert(pvar == NIL);
 
@@ -686,7 +682,12 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
 
 	/*
 	 * If this plan is un-correlated or undirect correlated one and want
-	 * to set params for parent plan then prepare parameters.
+	 * to set params for parent plan then mark parameters as needing
+	 * evaluation.
+	 *
+	 * Note that in the case of un-correlated subqueries we don't care
+	 * about setting parent->chgParam here: indices take care about
+	 * it, for others - it doesn't matter...
 	 */
 	if (subplan->setParam != NIL)
 	{
@@ -694,16 +695,11 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
 
 		foreach(lst, subplan->setParam)
 		{
-			ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
+			int		paramid = lfirsti(lst);
+			ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
 
 			prm->execPlan = node;
 		}
-
-		/*
-		 * Note that in the case of un-correlated subqueries we don't care
-		 * about setting parent->chgParam here: indices take care about
-		 * it, for others - it doesn't matter...
-		 */
 	}
 
 	/*
@@ -884,7 +880,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 
 		if (subLinkType == EXISTS_SUBLINK)
 		{
-			ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(subplan->setParam)]);
+			/* There can be only one param... */
+			int		paramid = lfirsti(subplan->setParam);
+			ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
 			prm->execPlan = NULL;
 			prm->value = BoolGetDatum(true);
@@ -914,9 +912,13 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 		node->curTuple = tup;
 		MemoryContextSwitchTo(node->sub_estate->es_query_cxt);
 
+		/*
+		 * Now set all the setParam params from the columns of the tuple
+		 */
 		foreach(lst, subplan->setParam)
 		{
-			ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
+			int		paramid = lfirsti(lst);
+			ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
 			prm->execPlan = NULL;
 			prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
@@ -928,7 +930,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 	{
 		if (subLinkType == EXISTS_SUBLINK)
 		{
-			ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(subplan->setParam)]);
+			/* There can be only one param... */
+			int		paramid = lfirsti(subplan->setParam);
+			ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
 			prm->execPlan = NULL;
 			prm->value = BoolGetDatum(false);
@@ -938,7 +942,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 		{
 			foreach(lst, subplan->setParam)
 			{
-				ParamExecData *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
+				int		paramid = lfirsti(lst);
+				ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
 				prm->execPlan = NULL;
 				prm->value = (Datum) 0;
@@ -979,12 +984,12 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
 	EState	   *estate = parent->state;
 	List	   *lst;
 
-	if (subplan->parParam != NULL)
+	if (subplan->parParam != NIL)
 		elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
-	if (subplan->setParam == NULL)
-		elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
-	if (planstate->plan->extParam == NULL)
-		elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
+	if (subplan->setParam == NIL)
+		elog(ERROR, "ExecReScanSetParamPlan: setParam list is empty");
+	if (bms_is_empty(planstate->plan->extParam))
+		elog(ERROR, "ExecReScanSetParamPlan: extParam set of plan is empty");
 
 	/*
 	 * Don't actually re-scan: ExecSetParamPlan does it if needed.
@@ -995,10 +1000,10 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
 	 */
 	foreach(lst, subplan->setParam)
 	{
-		ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
+		int		paramid = lfirsti(lst);
+		ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
 
 		prm->execPlan = node;
+		parent->chgParam = bms_add_member(parent->chgParam, paramid);
 	}
-
-	parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));
 }
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index c5ad1e9cd5fff8f0e460312fe9f50b106869fecd..ba4804fcebb4d48aefdefbb12a13c7f727e95354 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.17 2003/01/12 22:01:38 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.18 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -261,10 +261,10 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
 	 * ExecReScan doesn't know about my subplan, so I have to do
 	 * changed-parameter signaling myself.  This is just as well,
 	 * because the subplan has its own memory context in which its
-	 * chgParam lists live.
+	 * chgParam state lives.
 	 */
 	if (node->ss.ps.chgParam != NULL)
-		SetChangedParamList(node->subplan, node->ss.ps.chgParam);
+		UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam);
 
 	/*
 	 * if chgParam of subnode is not null then plan will be re-scanned by
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index e1a2165709e778af8747000d0290b89e2bbb79eb..962d00cd144e1cac15d8a40040c8bfd7e019e0f0 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.32 2003/02/03 15:07:07 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.33 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -349,7 +349,7 @@ ExecInitTidScan(TidScan *node, EState *estate)
 	Oid			relid;
 	Oid			reloid;
 	Relation	currentRelation;
-	List	   *execParam = NIL;
+	Bitmapset  *execParam = NULL;
 
 	/*
 	 * create state structure
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 55b4eeaf4b736adb7de5fccebad96af7de1c978f..ba7f48bc20089b47e320a7751f3317ba930e1376 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.240 2003/02/08 20:20:53 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.241 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -120,8 +120,8 @@ CopyPlanFields(Plan *from, Plan *newnode)
 	COPY_NODE_FIELD(lefttree);
 	COPY_NODE_FIELD(righttree);
 	COPY_NODE_FIELD(initPlan);
-	COPY_INTLIST_FIELD(extParam);
-	COPY_INTLIST_FIELD(locParam);
+	COPY_BITMAPSET_FIELD(extParam);
+	COPY_BITMAPSET_FIELD(allParam);
 	COPY_SCALAR_FIELD(nParamExec);
 }
 
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b4aefc78002f363453610f79d55e0d9e28402b59..9d4f977f22d3d7d5d10e5a487c5c260e3b394c40 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.196 2003/02/08 20:20:54 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.197 2003/02/09 00:30:39 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -255,8 +255,8 @@ _outPlanInfo(StringInfo str, Plan *node)
 	WRITE_NODE_FIELD(lefttree);
 	WRITE_NODE_FIELD(righttree);
 	WRITE_NODE_FIELD(initPlan);
-	WRITE_INTLIST_FIELD(extParam);
-	WRITE_INTLIST_FIELD(locParam);
+	WRITE_BITMAPSET_FIELD(extParam);
+	WRITE_BITMAPSET_FIELD(allParam);
 	WRITE_INT_FIELD(nParamExec);
 }
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ad68253109d7cb1da979680970db17ad3e0ace81..9608d9a17fa3f77f27e4813cba9f648bff7d23d0 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.144 2003/02/04 00:50:00 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.145 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -268,14 +268,14 @@ subquery_planner(Query *parse, double tuple_fraction)
 
 	/*
 	 * If any subplans were generated, or if we're inside a subplan, build
-	 * initPlan, extParam and locParam lists for plan nodes.
+	 * initPlan list and extParam/allParam sets for plan nodes.
 	 */
 	if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
 	{
 		Cost	initplan_cost = 0;
 
-		/* Prepare extParam/locParam data for all nodes in tree */
-		(void) SS_finalize_plan(plan, parse->rtable);
+		/* Prepare extParam/allParam sets for all nodes in tree */
+		SS_finalize_plan(plan, parse->rtable);
 
 		/*
 		 * SS_finalize_plan doesn't handle initPlans, so we have to manually
@@ -293,8 +293,8 @@ subquery_planner(Query *parse, double tuple_fraction)
 		{
 			SubPlan	   *initplan = (SubPlan *) lfirst(lst);
 
-			plan->extParam = set_unioni(plan->extParam,
-										initplan->plan->extParam);
+			plan->extParam = bms_add_members(plan->extParam,
+											 initplan->plan->extParam);
 			initplan_cost += initplan->plan->total_cost;
 		}
 
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index a2c8053b5dcfeb6e91a055fd5333e415ca76c948..d28a6674764ae020a05b9e09db5668a98c6e67d9 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
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.70 2003/02/08 20:20:54 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.71 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,10 +57,11 @@ int			PlannerPlanId = 0;	/* to assign unique ID to subquery plans */
  */
 
 
-typedef struct finalize_primnode_results
+typedef struct finalize_primnode_context
 {
-	List	   *paramids;		/* List of PARAM_EXEC paramids found */
-} finalize_primnode_results;
+	Bitmapset   *paramids;		/* Set of PARAM_EXEC paramids found */
+	Bitmapset   *outer_params;	/* Set of accessible outer paramids */
+} finalize_primnode_context;
 
 
 static List *convert_sublink_opers(List *lefthand, List *operOids,
@@ -69,7 +70,10 @@ static List *convert_sublink_opers(List *lefthand, List *operOids,
 static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
 static Node *replace_correlation_vars_mutator(Node *node, void *context);
 static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
-static bool finalize_primnode(Node *node, finalize_primnode_results *results);
+static Bitmapset *finalize_plan(Plan *plan, List *rtable,
+								Bitmapset *outer_params,
+								Bitmapset *valid_params);
+static bool finalize_primnode(Node *node, finalize_primnode_context *context);
 
 
 /*
@@ -178,6 +182,8 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 	Query	   *subquery = (Query *) (slink->subselect);
 	double		tuple_fraction;
 	Plan	   *plan;
+	Bitmapset  *tmpset;
+	int			paramid;
 	List	   *lst;
 	Node	   *result;
 
@@ -246,15 +252,16 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 	 * Make parParam list of params that current query level will pass to
 	 * this child plan.
 	 */
-	foreach(lst, plan->extParam)
+	tmpset = bms_copy(plan->extParam);
+	while ((paramid = bms_first_member(tmpset)) >= 0)
 	{
-		int			paramid = lfirsti(lst);
 		Var		   *var = nth(paramid, PlannerParamVar);
 
 		/* note varlevelsup is absolute level number */
 		if (var->varlevelsup == PlannerQueryLevel)
 			node->parParam = lappendi(node->parParam, paramid);
 	}
+	bms_free(tmpset);
 
 	/*
 	 * Un-correlated or undirect correlated plans of EXISTS, EXPR, or
@@ -269,7 +276,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 		Param	   *prm;
 
 		prm = generate_new_param(BOOLOID, -1);
-		node->setParam = lappendi(node->setParam, prm->paramid);
+		node->setParam = makeListi1(prm->paramid);
 		PlannerInitPlan = lappend(PlannerInitPlan, node);
 		result = (Node *) prm;
 	}
@@ -280,7 +287,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 
 		Assert(!te->resdom->resjunk);
 		prm = generate_new_param(te->resdom->restype, te->resdom->restypmod);
-		node->setParam = lappendi(node->setParam, prm->paramid);
+		node->setParam = makeListi1(prm->paramid);
 		PlannerInitPlan = lappend(PlannerInitPlan, node);
 		result = (Node *) prm;
 	}
@@ -294,7 +301,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 									  plan->targetlist,
 									  0,
 									  &node->paramIds);
-		node->setParam = nconc(node->setParam, listCopy(node->paramIds));
+		node->setParam = listCopy(node->paramIds);
 		PlannerInitPlan = lappend(PlannerInitPlan, node);
 		/*
 		 * The executable expressions are returned to become part of the
@@ -387,8 +394,8 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
 				matplan->plan_rows = plan->plan_rows;
 				matplan->plan_width = plan->plan_width;
 				/* parameter kluge --- see comments above */
-				matplan->extParam = listCopy(plan->extParam);
-				matplan->locParam = listCopy(plan->locParam);
+				matplan->extParam = bms_copy(plan->extParam);
+				matplan->allParam = bms_copy(plan->allParam);
 				node->plan = plan = matplan;
 			}
 		}
@@ -769,44 +776,94 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
 /*
  * SS_finalize_plan - do final sublink processing for a completed Plan.
  *
- * This recursively computes and sets the extParam and locParam lists
- * for every Plan node in the given tree.
+ * This recursively computes the extParam and allParam sets
+ * for every Plan node in the given plan tree.
  */
-List *
+void
 SS_finalize_plan(Plan *plan, List *rtable)
 {
-	List	   *extParam = NIL;
-	List	   *locParam = NIL;
-	finalize_primnode_results results;
+	Bitmapset  *outer_params = NULL;
+	Bitmapset  *valid_params = NULL;
+	int			paramid;
+	List	   *lst;
+
+	/*
+	 * 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.
+	 */
+	paramid = 0;
+	foreach(lst, PlannerParamVar)
+	{
+		Var		   *var = (Var *) lfirst(lst);
+
+		/* note varlevelsup is absolute level number */
+		if (var->varlevelsup < PlannerQueryLevel)
+		{
+			/* valid outer-level parameter */
+			outer_params = bms_add_member(outer_params, paramid);
+			valid_params = bms_add_member(valid_params, paramid);
+		}
+		else if (var->varlevelsup == PlannerQueryLevel &&
+				 var->varno == 0 && var->varattno == 0)
+		{
+			/* valid local parameter (i.e., a setParam of my child) */
+			valid_params = bms_add_member(valid_params, paramid);
+		}
+
+		paramid++;
+	}
+
+	/*
+	 * Now recurse through plan tree.
+	 */
+	(void) finalize_plan(plan, rtable, outer_params, valid_params);
+
+	bms_free(outer_params);
+	bms_free(valid_params);
+}
+
+/*
+ * Recursive processing of all nodes in the plan tree
+ *
+ * The return value is the computed allParam set for the given Plan node.
+ * This is just an internal notational convenience.
+ */
+static Bitmapset *
+finalize_plan(Plan *plan, List *rtable,
+			  Bitmapset *outer_params, Bitmapset *valid_params)
+{
+	finalize_primnode_context context;
 	List	   *lst;
 
 	if (plan == NULL)
-		return NIL;
+		return NULL;
 
-	results.paramids = NIL;		/* initialize list to NIL */
+	context.paramids = NULL;	/* initialize set to empty */
+	context.outer_params = outer_params;
 
 	/*
-	 * When we call finalize_primnode, results.paramids lists are
+	 * When we call finalize_primnode, context.paramids sets are
 	 * automatically merged together.  But when recursing to self, we have
-	 * to do it the hard way.  We want the paramids list to include params
+	 * to do it the hard way.  We want the paramids set to include params
 	 * in subplans as well as at this level.
 	 */
 
 	/* Find params in targetlist and qual */
-	finalize_primnode((Node *) plan->targetlist, &results);
-	finalize_primnode((Node *) plan->qual, &results);
+	finalize_primnode((Node *) plan->targetlist, &context);
+	finalize_primnode((Node *) plan->qual, &context);
 
 	/* Check additional node-type-specific fields */
 	switch (nodeTag(plan))
 	{
 		case T_Result:
 			finalize_primnode(((Result *) plan)->resconstantqual,
-							  &results);
+							  &context);
 			break;
 
 		case T_IndexScan:
 			finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
-							  &results);
+							  &context);
 
 			/*
 			 * we need not look at indxqualorig, since it will have the
@@ -816,7 +873,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
 
 		case T_TidScan:
 			finalize_primnode((Node *) ((TidScan *) plan)->tideval,
-							  &results);
+							  &context);
 			break;
 
 		case T_SubqueryScan:
@@ -828,7 +885,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
 			 * subplan's extParams list, which represents the params it
 			 * needs from my level and higher levels.
 			 */
-			results.paramids = set_unioni(results.paramids,
+			context.paramids = bms_add_members(context.paramids,
 							 ((SubqueryScan *) plan)->subplan->extParam);
 			break;
 
@@ -839,39 +896,44 @@ SS_finalize_plan(Plan *plan, List *rtable)
 				rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
 							   rtable);
 				Assert(rte->rtekind == RTE_FUNCTION);
-				finalize_primnode(rte->funcexpr, &results);
+				finalize_primnode(rte->funcexpr, &context);
 			}
 			break;
 
 		case T_Append:
 			foreach(lst, ((Append *) plan)->appendplans)
-				results.paramids = set_unioni(results.paramids,
-								   SS_finalize_plan((Plan *) lfirst(lst),
-													rtable));
+			{
+				context.paramids =
+					bms_add_members(context.paramids,
+									finalize_plan((Plan *) lfirst(lst),
+												  rtable,
+												  outer_params,
+												  valid_params));
+			}
 			break;
 
 		case T_NestLoop:
 			finalize_primnode((Node *) ((Join *) plan)->joinqual,
-							  &results);
+							  &context);
 			break;
 
 		case T_MergeJoin:
 			finalize_primnode((Node *) ((Join *) plan)->joinqual,
-							  &results);
+							  &context);
 			finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,
-							  &results);
+							  &context);
 			break;
 
 		case T_HashJoin:
 			finalize_primnode((Node *) ((Join *) plan)->joinqual,
-							  &results);
+							  &context);
 			finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,
-							  &results);
+							  &context);
 			break;
 
 		case T_Hash:
 			finalize_primnode((Node *) ((Hash *) plan)->hashkeys,
-							  &results);
+							  &context);
 			break;
 
 		case T_Agg:
@@ -885,50 +947,55 @@ SS_finalize_plan(Plan *plan, List *rtable)
 			break;
 
 		default:
-			elog(ERROR, "SS_finalize_plan: node %d unsupported",
+			elog(ERROR, "finalize_plan: node %d unsupported",
 				 nodeTag(plan));
 	}
 
 	/* Process left and right child plans, if any */
-	results.paramids = set_unioni(results.paramids,
-								  SS_finalize_plan(plan->lefttree,
-												   rtable));
-	results.paramids = set_unioni(results.paramids,
-								  SS_finalize_plan(plan->righttree,
-												   rtable));
+	context.paramids = bms_add_members(context.paramids,
+									   finalize_plan(plan->lefttree,
+													 rtable,
+													 outer_params,
+													 valid_params));
+
+	context.paramids = bms_add_members(context.paramids,
+									   finalize_plan(plan->righttree,
+													 rtable,
+													 outer_params,
+													 valid_params));
 
 	/* Now we have all the paramids */
 
-	foreach(lst, results.paramids)
-	{
-		int			paramid = lfirsti(lst);
-		Var		   *var = nth(paramid, PlannerParamVar);
+	if (!bms_is_subset(context.paramids, valid_params))
+		elog(ERROR, "finalize_plan: plan shouldn't reference subplan's variable");
 
-		/* note varlevelsup is absolute level number */
-		if (var->varlevelsup < PlannerQueryLevel)
-			extParam = lappendi(extParam, paramid);
-		else if (var->varlevelsup > PlannerQueryLevel)
-			elog(ERROR, "SS_finalize_plan: plan shouldn't reference subplan's variable");
-		else
-		{
-			Assert(var->varno == 0 && var->varattno == 0);
-			locParam = lappendi(locParam, paramid);
-		}
-	}
+	plan->extParam = bms_intersect(context.paramids, outer_params);
+	plan->allParam = context.paramids;
 
-	plan->extParam = extParam;
-	plan->locParam = locParam;
+	/*
+	 * For speed at execution time, make sure extParam/allParam are actually
+	 * NULL if they are empty sets.
+	 */
+	if (bms_is_empty(plan->extParam))
+	{
+		bms_free(plan->extParam);
+		plan->extParam = NULL;
+	}
+	if (bms_is_empty(plan->allParam))
+	{
+		bms_free(plan->allParam);
+		plan->allParam = NULL;
+	}
 
-	return results.paramids;
+	return plan->allParam;
 }
 
 /*
- * finalize_primnode: build lists of params appearing
- * in the given expression tree.  NOTE: items are added to list passed in,
- * so caller must initialize list to NIL before first call!
+ * finalize_primnode: add IDs of all PARAM_EXEC params appearing in the given
+ * expression tree to the result set.
  */
 static bool
-finalize_primnode(Node *node, finalize_primnode_results *results)
+finalize_primnode(Node *node, finalize_primnode_context *context)
 {
 	if (node == NULL)
 		return false;
@@ -938,29 +1005,20 @@ finalize_primnode(Node *node, finalize_primnode_results *results)
 		{
 			int			paramid = (int) ((Param *) node)->paramid;
 
-			if (!intMember(paramid, results->paramids))
-				results->paramids = lconsi(paramid, results->paramids);
+			context->paramids = bms_add_member(context->paramids, paramid);
 		}
 		return false;			/* no more to do here */
 	}
 	if (is_subplan(node))
 	{
 		SubPlan	   *subplan = (SubPlan *) node;
-		List	   *lst;
 
-		/* Check extParam list for params to add to paramids */
-		foreach(lst, subplan->plan->extParam)
-		{
-			int			paramid = lfirsti(lst);
-			Var		   *var = nth(paramid, PlannerParamVar);
-
-			/* note varlevelsup is absolute level number */
-			if (var->varlevelsup < PlannerQueryLevel &&
-				!intMember(paramid, results->paramids))
-				results->paramids = lconsi(paramid, results->paramids);
-		}
+		/* Add outer-level params needed by the subplan to paramids */
+		context->paramids = bms_join(context->paramids,
+									 bms_intersect(subplan->plan->extParam,
+												   context->outer_params));
 		/* fall through to recurse into subplan args */
 	}
 	return expression_tree_walker(node, finalize_primnode,
-								  (void *) results);
+								  (void *) context);
 }
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 2f329ca57af3a1285458846a18b2fe247d728597..ee30f51896974e74b279589bedf93f6437d9bb0f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.88 2003/02/03 15:07:07 tgl Exp $
+ * $Id: executor.h,v 1.89 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -160,7 +160,7 @@ extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
 extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
 					  TupleDesc tupType);
 extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
-extern void SetChangedParamList(PlanState *node, List *newchg);
+extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
 
 typedef struct TupOutputState
 {
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index ccb253206624c3b7f003a63a066ced472f940c11..8d2b13059840ad6511bfdeb7fc544d570a94551b 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.93 2003/02/03 21:15:44 tgl Exp $
+ * $Id: execnodes.h,v 1.94 2003/02/09 00:30:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "executor/hashjoin.h"
 #include "executor/tuptable.h"
 #include "fmgr.h"
+#include "nodes/bitmapset.h"
 #include "nodes/params.h"
 #include "nodes/plannodes.h"
 #include "utils/tuplestore.h"
@@ -616,7 +617,7 @@ typedef struct PlanState
 	/*
 	 * State for management of parameter-change-driven rescanning
 	 */
-	List	   *chgParam;		/* integer list of IDs of changed Params */
+	Bitmapset  *chgParam;		/* set of IDs of changed Params */
 
 	/*
 	 * Other run-time state needed by most if not all node types.
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 67a4d48782f1c072f2964ef74307cfefaadc36c5..2ca16b63272e16030a518996abda1707798dba71 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.63 2002/12/12 15:49:40 tgl Exp $
+ * $Id: plannodes.h,v 1.64 2003/02/09 00:30:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,6 +15,7 @@
 #define PLANNODES_H
 
 #include "access/sdir.h"
+#include "nodes/bitmapset.h"
 #include "nodes/primnodes.h"
 
 
@@ -65,14 +66,17 @@ typedef struct Plan
 
 	/*
 	 * Information for management of parameter-change-driven rescanning
+	 *
+	 * extParam includes the paramIDs of all external PARAM_EXEC params
+	 * affecting this plan node or its children.  setParam params from
+	 * the node's initPlans are not included, but their extParams are.
+	 *
+	 * allParam includes all the extParam paramIDs, plus the IDs of local
+	 * params that affect the node (i.e., the setParams of its initplans).
+	 * These are _all_ the PARAM_EXEC params that affect this node.
 	 */
-	List	   *extParam;		/* indices of _all_ _external_ PARAM_EXEC
-								 * for this plan in global
-								 * es_param_exec_vals. Params from
-								 * setParam from initPlan-s are not
-								 * included, but their execParam-s are
-								 * here!!! */
-	List	   *locParam;		/* someones from setParam-s */
+	Bitmapset  *extParam;
+	Bitmapset  *allParam;
 
 	/*
 	 * We really need in some TopPlan node to store range table and
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index ad1c73612554cfdf01215908943801816e2f1fd2..be917c4f2606e36311f23e2596e075ad23f4c665 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.78 2003/02/03 21:15:44 tgl Exp $
+ * $Id: primnodes.h,v 1.79 2003/02/09 00:30:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -435,9 +435,11 @@ typedef struct SubLink
  * expressions to be evaluated in the outer-query context (currently these
  * args are always just Vars, but in principle they could be any expression).
  * The values are assigned to the global PARAM_EXEC params indexed by parParam
- * (the parParam and args lists must have the same length).  setParam is a
+ * (the parParam and args lists must have the same ordering).  setParam is a
  * list of the PARAM_EXEC params that are computed by the sub-select, if it
- * is an initplan.
+ * is an initplan; they are listed in order by sub-select output column
+ * position.  (parParam and setParam are integer Lists, not Bitmapsets,
+ * because their ordering is significant.)
  */
 typedef struct SubPlan
 {
@@ -449,6 +451,7 @@ typedef struct SubPlan
 	/* The combining operators, transformed to executable expressions: */
 	List	   *exprs;			/* list of OpExpr expression trees */
 	List	   *paramIds;		/* IDs of Params embedded in the above */
+	/* Note: paramIds has a one-to-one correspondence to the exprs list */
 	/* The subselect, transformed to a Plan: */
 	struct Plan *plan;			/* subselect plan itself */
 	int			plan_id;		/* dummy thing because of we haven't equal
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index 2e6a4640684f916d96583e46a428663129c7e280..9dce88e0a8d0a3beb7f73417a47985dabd892e28 100644
--- a/src/include/optimizer/subselect.h
+++ b/src/include/optimizer/subselect.h
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: subselect.h,v 1.17 2003/01/20 18:55:05 tgl Exp $
+ * $Id: subselect.h,v 1.18 2003/02/09 00:30:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,6 @@ extern int	PlannerPlanId;		/* to assign unique ID to subquery plans */
 extern Node *convert_IN_to_join(Query *parse, SubLink *sublink);
 extern Node *SS_replace_correlation_vars(Node *expr);
 extern Node *SS_process_sublinks(Node *expr, bool isQual);
-extern List *SS_finalize_plan(Plan *plan, List *rtable);
+extern void SS_finalize_plan(Plan *plan, List *rtable);
 
 #endif   /* SUBSELECT_H */