diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index dfc36365807087ac00d489b401efa7c1f2a33ce7..f37a7602ef4e4fcec0c2b1c1a9dfa2f4ca249db2 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.108 2010/02/14 18:42:14 rhaas Exp $
+ *	$PostgreSQL: pgsql/src/backend/executor/execAmi.c,v 1.109 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,17 +59,9 @@ static bool IndexSupportsBackwardScan(Oid indexid);
  *
  * Note that if the plan node has parameters that have changed value,
  * the output might be different from last time.
- *
- * The second parameter is currently only used to pass a NestLoop plan's
- * econtext down to its inner child plan, in case that is an indexscan that
- * needs access to variables of the current outer tuple.  (The handling of
- * this parameter is currently pretty inconsistent: some callers pass NULL
- * and some pass down their parent's value; so don't rely on it in other
- * situations.	It'd probably be better to remove the whole thing and use
- * the generalized parameter mechanism instead.)
  */
 void
-ExecReScan(PlanState *node, ExprContext *exprCtxt)
+ExecReScan(PlanState *node)
 {
 	/* If collecting timing stats, update them */
 	if (node->instrument)
@@ -126,119 +118,119 @@ ExecReScan(PlanState *node, ExprContext *exprCtxt)
 	switch (nodeTag(node))
 	{
 		case T_ResultState:
-			ExecReScanResult((ResultState *) node, exprCtxt);
+			ExecReScanResult((ResultState *) node);
 			break;
 
 		case T_ModifyTableState:
-			ExecReScanModifyTable((ModifyTableState *) node, exprCtxt);
+			ExecReScanModifyTable((ModifyTableState *) node);
 			break;
 
 		case T_AppendState:
-			ExecReScanAppend((AppendState *) node, exprCtxt);
+			ExecReScanAppend((AppendState *) node);
 			break;
 
 		case T_RecursiveUnionState:
-			ExecRecursiveUnionReScan((RecursiveUnionState *) node, exprCtxt);
+			ExecReScanRecursiveUnion((RecursiveUnionState *) node);
 			break;
 
 		case T_BitmapAndState:
-			ExecReScanBitmapAnd((BitmapAndState *) node, exprCtxt);
+			ExecReScanBitmapAnd((BitmapAndState *) node);
 			break;
 
 		case T_BitmapOrState:
-			ExecReScanBitmapOr((BitmapOrState *) node, exprCtxt);
+			ExecReScanBitmapOr((BitmapOrState *) node);
 			break;
 
 		case T_SeqScanState:
-			ExecSeqReScan((SeqScanState *) node, exprCtxt);
+			ExecReScanSeqScan((SeqScanState *) node);
 			break;
 
 		case T_IndexScanState:
-			ExecIndexReScan((IndexScanState *) node, exprCtxt);
+			ExecReScanIndexScan((IndexScanState *) node);
 			break;
 
 		case T_BitmapIndexScanState:
-			ExecBitmapIndexReScan((BitmapIndexScanState *) node, exprCtxt);
+			ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
 			break;
 
 		case T_BitmapHeapScanState:
-			ExecBitmapHeapReScan((BitmapHeapScanState *) node, exprCtxt);
+			ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
 			break;
 
 		case T_TidScanState:
-			ExecTidReScan((TidScanState *) node, exprCtxt);
+			ExecReScanTidScan((TidScanState *) node);
 			break;
 
 		case T_SubqueryScanState:
-			ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt);
+			ExecReScanSubqueryScan((SubqueryScanState *) node);
 			break;
 
 		case T_FunctionScanState:
-			ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
+			ExecReScanFunctionScan((FunctionScanState *) node);
 			break;
 
 		case T_ValuesScanState:
-			ExecValuesReScan((ValuesScanState *) node, exprCtxt);
+			ExecReScanValuesScan((ValuesScanState *) node);
 			break;
 
 		case T_CteScanState:
-			ExecCteScanReScan((CteScanState *) node, exprCtxt);
+			ExecReScanCteScan((CteScanState *) node);
 			break;
 
 		case T_WorkTableScanState:
-			ExecWorkTableScanReScan((WorkTableScanState *) node, exprCtxt);
+			ExecReScanWorkTableScan((WorkTableScanState *) node);
 			break;
 
 		case T_NestLoopState:
-			ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
+			ExecReScanNestLoop((NestLoopState *) node);
 			break;
 
 		case T_MergeJoinState:
-			ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt);
+			ExecReScanMergeJoin((MergeJoinState *) node);
 			break;
 
 		case T_HashJoinState:
-			ExecReScanHashJoin((HashJoinState *) node, exprCtxt);
+			ExecReScanHashJoin((HashJoinState *) node);
 			break;
 
 		case T_MaterialState:
-			ExecMaterialReScan((MaterialState *) node, exprCtxt);
+			ExecReScanMaterial((MaterialState *) node);
 			break;
 
 		case T_SortState:
-			ExecReScanSort((SortState *) node, exprCtxt);
+			ExecReScanSort((SortState *) node);
 			break;
 
 		case T_GroupState:
-			ExecReScanGroup((GroupState *) node, exprCtxt);
+			ExecReScanGroup((GroupState *) node);
 			break;
 
 		case T_AggState:
-			ExecReScanAgg((AggState *) node, exprCtxt);
+			ExecReScanAgg((AggState *) node);
 			break;
 
 		case T_WindowAggState:
-			ExecReScanWindowAgg((WindowAggState *) node, exprCtxt);
+			ExecReScanWindowAgg((WindowAggState *) node);
 			break;
 
 		case T_UniqueState:
-			ExecReScanUnique((UniqueState *) node, exprCtxt);
+			ExecReScanUnique((UniqueState *) node);
 			break;
 
 		case T_HashState:
-			ExecReScanHash((HashState *) node, exprCtxt);
+			ExecReScanHash((HashState *) node);
 			break;
 
 		case T_SetOpState:
-			ExecReScanSetOp((SetOpState *) node, exprCtxt);
+			ExecReScanSetOp((SetOpState *) node);
 			break;
 
 		case T_LockRowsState:
-			ExecReScanLockRows((LockRowsState *) node, exprCtxt);
+			ExecReScanLockRows((LockRowsState *) node);
 			break;
 
 		case T_LimitState:
-			ExecReScanLimit((LimitState *) node, exprCtxt);
+			ExecReScanLimit((LimitState *) node);
 			break;
 
 		default:
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 473fbcdae1c1f12ed4a43901ac503c7030c54b23..9eb765378f5282714be4c4a9ba83f683524686a5 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.350 2010/07/09 14:06:01 rhaas Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.351 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -400,7 +400,7 @@ ExecutorRewind(QueryDesc *queryDesc)
 	/*
 	 * rescan plan
 	 */
-	ExecReScan(queryDesc->planstate, NULL);
+	ExecReScan(queryDesc->planstate);
 
 	MemoryContextSwitchTo(oldcontext);
 }
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index b464e7699337220e4ab211ad8038fa94b5ad2898..2830bff8716feb5a867de84627d79b3f890ff41e 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.70 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execProcnode.c,v 1.71 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -341,7 +341,7 @@ ExecProcNode(PlanState *node)
 	CHECK_FOR_INTERRUPTS();
 
 	if (node->chgParam != NULL) /* something changed */
-		ExecReScan(node, NULL); /* let ReScan handle this */
+		ExecReScan(node);		/* let ReScan handle this */
 
 	if (node->instrument)
 		InstrStartNode(node->instrument);
@@ -504,7 +504,7 @@ MultiExecProcNode(PlanState *node)
 	CHECK_FOR_INTERRUPTS();
 
 	if (node->chgParam != NULL) /* something changed */
-		ExecReScan(node, NULL); /* let ReScan handle this */
+		ExecReScan(node);		/* let ReScan handle this */
 
 	switch (nodeTag(node))
 	{
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index e381e112821b58e36301906a2c3145bb1dda79df..e30689bba30f7a6776db2b3838ded19f8b41c39a 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.263 2010/02/26 02:00:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.264 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,7 +78,9 @@ static Datum ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
 					 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
 			  bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
+static Datum ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
+			  bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext,
 			  bool *isNull, ExprDoneCond *isDone);
 static void init_fcache(Oid foid, FuncExprState *fcache,
 			MemoryContext fcacheCxt, bool needDescForSets);
@@ -961,80 +963,87 @@ ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
 }
 
 /* ----------------------------------------------------------------
- *		ExecEvalParam
+ *		ExecEvalParamExec
  *
- *		Returns the value of a parameter.  A param node contains
- *		something like ($.name) and the expression context contains
- *		the current parameter bindings (name = "sam") (age = 34)...
- *		so our job is to find and return the appropriate datum ("sam").
+ *		Returns the value of a PARAM_EXEC parameter.
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
-			  bool *isNull, ExprDoneCond *isDone)
+ExecEvalParamExec(ExprState *exprstate, ExprContext *econtext,
+				  bool *isNull, ExprDoneCond *isDone)
 {
 	Param	   *expression = (Param *) exprstate->expr;
 	int			thisParamId = expression->paramid;
+	ParamExecData *prm;
 
 	if (isDone)
 		*isDone = ExprSingleResult;
 
-	if (expression->paramkind == PARAM_EXEC)
+	/*
+	 * PARAM_EXEC params (internal executor parameters) are stored in the
+	 * ecxt_param_exec_vals array, and can be accessed by array index.
+	 */
+	prm = &(econtext->ecxt_param_exec_vals[thisParamId]);
+	if (prm->execPlan != NULL)
 	{
-		/*
-		 * PARAM_EXEC params (internal executor parameters) are stored in the
-		 * ecxt_param_exec_vals array, and can be accessed by array index.
-		 */
-		ParamExecData *prm;
-
-		prm = &(econtext->ecxt_param_exec_vals[thisParamId]);
-		if (prm->execPlan != NULL)
-		{
-			/* Parameter not evaluated yet, so go do it */
-			ExecSetParamPlan(prm->execPlan, econtext);
-			/* ExecSetParamPlan should have processed this param... */
-			Assert(prm->execPlan == NULL);
-		}
-		*isNull = prm->isnull;
-		return prm->value;
+		/* Parameter not evaluated yet, so go do it */
+		ExecSetParamPlan(prm->execPlan, econtext);
+		/* ExecSetParamPlan should have processed this param... */
+		Assert(prm->execPlan == NULL);
 	}
-	else
-	{
-		/*
-		 * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
-		 */
-		ParamListInfo paramInfo = econtext->ecxt_param_list_info;
+	*isNull = prm->isnull;
+	return prm->value;
+}
 
-		Assert(expression->paramkind == PARAM_EXTERN);
-		if (paramInfo &&
-			thisParamId > 0 && thisParamId <= paramInfo->numParams)
-		{
-			ParamExternData *prm = &paramInfo->params[thisParamId - 1];
+/* ----------------------------------------------------------------
+ *		ExecEvalParamExtern
+ *
+ *		Returns the value of a PARAM_EXTERN parameter.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalParamExtern(ExprState *exprstate, ExprContext *econtext,
+					bool *isNull, ExprDoneCond *isDone)
+{
+	Param	   *expression = (Param *) exprstate->expr;
+	int			thisParamId = expression->paramid;
+	ParamListInfo paramInfo = econtext->ecxt_param_list_info;
 
-			/* give hook a chance in case parameter is dynamic */
-			if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL)
-				(*paramInfo->paramFetch) (paramInfo, thisParamId);
+	if (isDone)
+		*isDone = ExprSingleResult;
 
-			if (OidIsValid(prm->ptype))
-			{
-				/* safety check in case hook did something unexpected */
-				if (prm->ptype != expression->paramtype)
-					ereport(ERROR,
-							(errcode(ERRCODE_DATATYPE_MISMATCH),
-							 errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
-									thisParamId,
-									format_type_be(prm->ptype),
-									format_type_be(expression->paramtype))));
+	/*
+	 * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
+	 */
+	if (paramInfo &&
+		thisParamId > 0 && thisParamId <= paramInfo->numParams)
+	{
+		ParamExternData *prm = &paramInfo->params[thisParamId - 1];
 
-				*isNull = prm->isnull;
-				return prm->value;
-			}
+		/* give hook a chance in case parameter is dynamic */
+		if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL)
+			(*paramInfo->paramFetch) (paramInfo, thisParamId);
+
+		if (OidIsValid(prm->ptype))
+		{
+			/* safety check in case hook did something unexpected */
+			if (prm->ptype != expression->paramtype)
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
+								thisParamId,
+								format_type_be(prm->ptype),
+								format_type_be(expression->paramtype))));
+
+			*isNull = prm->isnull;
+			return prm->value;
 		}
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("no value found for parameter %d", thisParamId)));
-		return (Datum) 0;		/* keep compiler quiet */
 	}
+
+	ereport(ERROR,
+			(errcode(ERRCODE_UNDEFINED_OBJECT),
+			 errmsg("no value found for parameter %d", thisParamId)));
+	return (Datum) 0;		/* keep compiler quiet */
 }
 
 
@@ -4228,7 +4237,19 @@ ExecInitExpr(Expr *node, PlanState *parent)
 			break;
 		case T_Param:
 			state = (ExprState *) makeNode(ExprState);
-			state->evalfunc = ExecEvalParam;
+			switch (((Param *) node)->paramkind)
+			{
+				case PARAM_EXEC:
+					state->evalfunc = ExecEvalParamExec;
+					break;
+				case PARAM_EXTERN:
+					state->evalfunc = ExecEvalParamExtern;
+					break;
+				default:
+					elog(ERROR, "unrecognized paramkind: %d",
+						 (int) ((Param *) node)->paramkind);
+					break;
+			}
 			break;
 		case T_CoerceToDomainValue:
 			state = (ExprState *) makeNode(ExprState);
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 74fc87a66a59af611dd31d0d6cfc229de7b347b6..a28d73fd32e4302b6a8ce2c40c5c2c9ad2c1e858 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -71,7 +71,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.175 2010/02/26 02:00:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.176 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1886,7 +1886,7 @@ ExecEndAgg(AggState *node)
 }
 
 void
-ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
+ExecReScanAgg(AggState *node)
 {
 	ExprContext *econtext = node->ss.ps.ps_ExprContext;
 	int			aggno;
@@ -1911,7 +1911,7 @@ ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
 		 * parameter changes, then we can just rescan the existing hash table;
 		 * no need to build it again.
 		 */
-		if (((PlanState *) node)->lefttree->chgParam == NULL)
+		if (node->ss.ps.lefttree->chgParam == NULL)
 		{
 			ResetTupleHashIterator(node->hashtable, &node->hashiter);
 			return;
@@ -1967,8 +1967,8 @@ 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 == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ss.ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ss.ps.lefttree);
 }
 
 /*
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 60026613c049da6e9726ce0fc963fd70090562eb..4a40b831ddf87b97331e4bb18cd56beb847eaa17 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.77 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.78 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -263,7 +263,7 @@ ExecEndAppend(AppendState *node)
 }
 
 void
-ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
+ExecReScanAppend(AppendState *node)
 {
 	int			i;
 
@@ -280,12 +280,10 @@ ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
 
 		/*
 		 * If chgParam of subnode is not null then plan will be re-scanned by
-		 * first ExecProcNode.	However, if caller is passing us an exprCtxt
-		 * then forcibly rescan all the subnodes now, so that we can pass the
-		 * exprCtxt down to the subnodes (needed for appendrel indexscan).
+		 * first ExecProcNode.
 		 */
-		if (subnode->chgParam == NULL || exprCtxt != NULL)
-			ExecReScan(subnode, exprCtxt);
+		if (subnode->chgParam == NULL)
+			ExecReScan(subnode);
 	}
 	node->as_whichplan = 0;
 	exec_append_initialize_next(node);
diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c
index dbfcfb1cab00882e514643a1f2214cba24aceda0..9ae2df76aff4a9cdc4b36892a1e32dea1cadacd2 100644
--- a/src/backend/executor/nodeBitmapAnd.c
+++ b/src/backend/executor/nodeBitmapAnd.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.13 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapAnd.c,v 1.14 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -185,7 +185,7 @@ ExecEndBitmapAnd(BitmapAndState *node)
 }
 
 void
-ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt)
+ExecReScanBitmapAnd(BitmapAndState *node)
 {
 	int			i;
 
@@ -201,9 +201,10 @@ ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt)
 			UpdateChangedParamSet(subnode, node->ps.chgParam);
 
 		/*
-		 * Always rescan the inputs immediately, to ensure we can pass down
-		 * any outer tuple that might be used in index quals.
+		 * If chgParam of subnode is not null then plan will be re-scanned by
+		 * first ExecProcNode.
 		 */
-		ExecReScan(subnode, exprCtxt);
+		if (subnode->chgParam == NULL)
+			ExecReScan(subnode);
 	}
 }
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 2a7ce624321af315b99a00ce9d035a9cad83d49d..0ea3a88e4514e6b4f9ba4caa92ba6c80ffe118e3 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.38 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.39 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,7 +30,7 @@
  *		ExecBitmapHeapScan			scans a relation using bitmap info
  *		ExecBitmapHeapNext			workhorse for above
  *		ExecInitBitmapHeapScan		creates and initializes state info.
- *		ExecBitmapHeapReScan		prepares to rescan the plan.
+ *		ExecReScanBitmapHeapScan	prepares to rescan the plan.
  *		ExecEndBitmapHeapScan		releases all storage.
  */
 #include "postgres.h"
@@ -420,24 +420,12 @@ ExecBitmapHeapScan(BitmapHeapScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecBitmapHeapReScan(node)
+ *		ExecReScanBitmapHeapScan(node)
  * ----------------------------------------------------------------
  */
 void
-ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt)
+ExecReScanBitmapHeapScan(BitmapHeapScanState *node)
 {
-	/*
-	 * If we are being passed an outer tuple, link it into the "regular"
-	 * per-tuple econtext for possible qual eval.
-	 */
-	if (exprCtxt != NULL)
-	{
-		ExprContext *stdecontext;
-
-		stdecontext = node->ss.ps.ps_ExprContext;
-		stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
-	}
-
 	/* rescan to release any page pin */
 	heap_rescan(node->ss.ss_currentScanDesc, NULL);
 
@@ -455,10 +443,11 @@ ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt)
 	ExecScanReScan(&node->ss);
 
 	/*
-	 * Always rescan the input immediately, to ensure we can pass down any
-	 * outer tuple that might be used in index quals.
+	 * if chgParam of subnode is not null then plan will be re-scanned by
+	 * first ExecProcNode.
 	 */
-	ExecReScan(outerPlanState(node), exprCtxt);
+	if (node->ss.ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ss.ps.lefttree);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
index 0781c21676b6c84a7bceebc0edd08040e7fca024..73b569458d37a8de2aa04655e15a22f2a8d09f42 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.33 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapIndexscan.c,v 1.34 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,7 @@
  * INTERFACE ROUTINES
  *		MultiExecBitmapIndexScan	scans a relation using index.
  *		ExecInitBitmapIndexScan		creates and initializes state info.
- *		ExecBitmapIndexReScan		prepares to rescan the plan.
+ *		ExecReScanBitmapIndexScan	prepares to rescan the plan.
  *		ExecEndBitmapIndexScan		releases all storage.
  */
 #include "postgres.h"
@@ -60,7 +60,7 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
 	if (!node->biss_RuntimeKeysReady &&
 		(node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
 	{
-		ExecReScan((PlanState *) node, NULL);
+		ExecReScan((PlanState *) node);
 		doscan = node->biss_RuntimeKeysReady;
 	}
 	else
@@ -106,39 +106,28 @@ MultiExecBitmapIndexScan(BitmapIndexScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecBitmapIndexReScan(node)
+ *		ExecReScanBitmapIndexScan(node)
  *
- *		Recalculates the value of the scan keys whose value depends on
- *		information known at runtime and rescans the indexed relation.
+ *		Recalculates the values of any scan keys whose value depends on
+ *		information known at runtime, then rescans the indexed relation.
  * ----------------------------------------------------------------
  */
 void
-ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt)
+ExecReScanBitmapIndexScan(BitmapIndexScanState *node)
 {
-	ExprContext *econtext;
-
-	econtext = node->biss_RuntimeContext;		/* context for runtime keys */
+	ExprContext *econtext = node->biss_RuntimeContext;
 
+	/*
+	 * Reset the runtime-key context so we don't leak memory as each outer
+	 * tuple is scanned.  Note this assumes that we will recalculate *all*
+	 * runtime keys on each call.
+	 */
 	if (econtext)
-	{
-		/*
-		 * If we are being passed an outer tuple, save it for runtime key
-		 * calc.
-		 */
-		if (exprCtxt != NULL)
-			econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
-
-		/*
-		 * Reset the runtime-key context so we don't leak memory as each outer
-		 * tuple is scanned.  Note this assumes that we will recalculate *all*
-		 * runtime keys on each call.
-		 */
 		ResetExprContext(econtext);
-	}
 
 	/*
-	 * If we are doing runtime key calculations (ie, the index keys depend on
-	 * data from an outer scan), compute the new key values.
+	 * If we are doing runtime key calculations (ie, any of the index key
+	 * values weren't simple Consts), compute the new key values.
 	 *
 	 * Array keys are also treated as runtime keys; note that if we return
 	 * with biss_RuntimeKeysReady still false, then there is an empty array
diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c
index 97cadd6b852e551140895d1993741d71fc2a1fc2..8faba8b30028f2abde35a3e3deac0b6f8bfe7a4d 100644
--- a/src/backend/executor/nodeBitmapOr.c
+++ b/src/backend/executor/nodeBitmapOr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.12 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapOr.c,v 1.13 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -201,7 +201,7 @@ ExecEndBitmapOr(BitmapOrState *node)
 }
 
 void
-ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt)
+ExecReScanBitmapOr(BitmapOrState *node)
 {
 	int			i;
 
@@ -217,9 +217,10 @@ ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt)
 			UpdateChangedParamSet(subnode, node->ps.chgParam);
 
 		/*
-		 * Always rescan the inputs immediately, to ensure we can pass down
-		 * any outer tuple that might be used in index quals.
+		 * If chgParam of subnode is not null then plan will be re-scanned by
+		 * first ExecProcNode.
 		 */
-		ExecReScan(subnode, exprCtxt);
+		if (subnode->chgParam == NULL)
+			ExecReScan(subnode);
 	}
 }
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 0c90a1e37e38c4669c50edc02e32b126d79ea68c..408cd051207666a7260f81461437e0e23a4c0f4b 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeCtescan.c,v 1.8 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeCtescan.c,v 1.9 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -298,13 +298,13 @@ ExecEndCteScan(CteScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecCteScanReScan
+ *		ExecReScanCteScan
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecCteScanReScan(CteScanState *node, ExprContext *exprCtxt)
+ExecReScanCteScan(CteScanState *node)
 {
 	Tuplestorestate *tuplestorestate = node->leader->cte_table;
 
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 6989961f8a40bae624e7a137ba34d87937cfc8da..e64b57d09ad3b2faae2675733e7488bef9432c12 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.55 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.56 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,7 @@
  *		ExecFunctionNext		retrieve next tuple in sequential order.
  *		ExecInitFunctionScan	creates and initializes a functionscan node.
  *		ExecEndFunctionScan		releases any storage allocated.
- *		ExecFunctionReScan		rescans the function
+ *		ExecReScanFunctionScan	rescans the function
  */
 #include "postgres.h"
 
@@ -255,13 +255,13 @@ ExecEndFunctionScan(FunctionScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecFunctionReScan
+ *		ExecReScanFunctionScan
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
+ExecReScanFunctionScan(FunctionScanState *node)
 {
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 26b59df86631489ef819fc09535f5b1e6f7d9b14..e56fddadd8301712a98ff6783af310580d99587f 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -15,7 +15,7 @@
  *	  locate group boundaries.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.77 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeGroup.c,v 1.78 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -277,14 +277,18 @@ ExecEndGroup(GroupState *node)
 }
 
 void
-ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
+ExecReScanGroup(GroupState *node)
 {
 	node->grp_done = FALSE;
 	node->ss.ps.ps_TupFromTlist = false;
 	/* must clear first tuple */
 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
 
-	if (((PlanState *) node)->lefttree &&
-		((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	/*
+	 * if chgParam of subnode is not null then plan will be re-scanned by
+	 * first ExecProcNode.
+	 */
+	if (node->ss.ps.lefttree &&
+		node->ss.ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ss.ps.lefttree);
 }
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index be45d732e09ccb03075211982b773057d5d10b65..0fa8b33606a8d627fceedabd0a25ae0e3687270a 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.129 2010/02/26 02:00:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.130 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -961,14 +961,14 @@ ExecHashTableReset(HashJoinTable hashtable)
 }
 
 void
-ExecReScanHash(HashState *node, ExprContext *exprCtxt)
+ExecReScanHash(HashState *node)
 {
 	/*
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ps.lefttree);
 }
 
 
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 4749d353b99d6e2add568a3cde0891f299612e47..a6cd481f7ed56a8ed8ca25c34a73a08c469f480a 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.103 2010/01/02 16:57:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.104 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -842,7 +842,7 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
 
 
 void
-ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
+ExecReScanHashJoin(HashJoinState *node)
 {
 	/*
 	 * In a multi-batch join, we currently have to do rescans the hard way,
@@ -854,7 +854,7 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
 	if (node->hj_HashTable != NULL)
 	{
 		if (node->hj_HashTable->nbatch == 1 &&
-			((PlanState *) node)->righttree->chgParam == NULL)
+			node->js.ps.righttree->chgParam == NULL)
 		{
 			/*
 			 * okay to reuse the hash table; needn't rescan inner, either.
@@ -880,8 +880,8 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
 			 * if chgParam of subnode is not null then plan will be re-scanned
 			 * by first ExecProcNode.
 			 */
-			if (((PlanState *) node)->righttree->chgParam == NULL)
-				ExecReScan(((PlanState *) node)->righttree, exprCtxt);
+			if (node->js.ps.righttree->chgParam == NULL)
+				ExecReScan(node->js.ps.righttree);
 		}
 	}
 
@@ -900,6 +900,6 @@ ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->js.ps.lefttree->chgParam == NULL)
+		ExecReScan(node->js.ps.lefttree);
 }
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 0994dbf84efe6ef35596e0ae97243fb5e99f3c19..ad64c148241ffc9e3fcb6cfafa39ce7fc1e0a699 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.139 2010/02/26 02:00:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.140 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,7 @@
  *		ExecIndexScan			scans a relation using indices
  *		ExecIndexNext			using index to retrieve next tuple
  *		ExecInitIndexScan		creates and initializes state info.
- *		ExecIndexReScan			rescans the indexed relation.
+ *		ExecReScanIndexScan		rescans the indexed relation.
  *		ExecEndIndexScan		releases all storage.
  *		ExecIndexMarkPos		marks scan position.
  *		ExecIndexRestrPos		restores scan position.
@@ -141,7 +141,7 @@ ExecIndexScan(IndexScanState *node)
 	 * If we have runtime keys and they've not already been set up, do it now.
 	 */
 	if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
-		ExecReScan((PlanState *) node, NULL);
+		ExecReScan((PlanState *) node);
 
 	return ExecScan(&node->ss,
 					(ExecScanAccessMtd) IndexNext,
@@ -149,54 +149,35 @@ ExecIndexScan(IndexScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecIndexReScan(node)
+ *		ExecReScanIndexScan(node)
+ *
+ *		Recalculates the values of any scan keys whose value depends on
+ *		information known at runtime, then rescans the indexed relation.
  *
- *		Recalculates the value of the scan keys whose value depends on
- *		information known at runtime and rescans the indexed relation.
  *		Updating the scan key was formerly done separately in
  *		ExecUpdateIndexScanKeys. Integrating it into ReScan makes
  *		rescans of indices and relations/general streams more uniform.
  * ----------------------------------------------------------------
  */
 void
-ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
+ExecReScanIndexScan(IndexScanState *node)
 {
-	ExprContext *econtext;
-
-	econtext = node->iss_RuntimeContext;		/* context for runtime keys */
-
-	if (econtext)
-	{
-		/*
-		 * If we are being passed an outer tuple, save it for runtime key
-		 * calc.  We also need to link it into the "regular" per-tuple
-		 * econtext, so it can be used during indexqualorig evaluations.
-		 */
-		if (exprCtxt != NULL)
-		{
-			ExprContext *stdecontext;
-
-			econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
-			stdecontext = node->ss.ps.ps_ExprContext;
-			stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
-		}
-
-		/*
-		 * Reset the runtime-key context so we don't leak memory as each outer
-		 * tuple is scanned.  Note this assumes that we will recalculate *all*
-		 * runtime keys on each call.
-		 */
-		ResetExprContext(econtext);
-	}
-
 	/*
-	 * If we are doing runtime key calculations (ie, the index keys depend on
-	 * data from an outer scan), compute the new key values
+	 * If we are doing runtime key calculations (ie, any of the index key
+	 * values weren't simple Consts), compute the new key values.  But first,
+	 * reset the context so we don't leak memory as each outer tuple is
+	 * scanned.  Note this assumes that we will recalculate *all* runtime keys
+	 * on each call.
 	 */
 	if (node->iss_NumRuntimeKeys != 0)
+	{
+		ExprContext *econtext = node->iss_RuntimeContext;
+
+		ResetExprContext(econtext);
 		ExecIndexEvalRuntimeKeys(econtext,
 								 node->iss_RuntimeKeys,
 								 node->iss_NumRuntimeKeys);
+	}
 	node->iss_RuntimeKeysReady = true;
 
 	/* reset index scan */
@@ -229,11 +210,11 @@ ExecIndexEvalRuntimeKeys(ExprContext *econtext,
 
 		/*
 		 * For each run-time key, extract the run-time expression and evaluate
-		 * it with respect to the current outer tuple.	We then stick the
-		 * result into the proper scan key.
+		 * it with respect to the current context.  We then stick the result
+		 * into the proper scan key.
 		 *
 		 * Note: the result of the eval could be a pass-by-ref value that's
-		 * stored in the outer scan's tuple, not in
+		 * stored in some outer scan's tuple, not in
 		 * econtext->ecxt_per_tuple_memory.  We assume that the outer tuple
 		 * will stay put throughout our scan.  If this is wrong, we could copy
 		 * the result into our context explicitly, but I think that's not
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 48fb32d3843c7e3f5d1e62746e30ec822cdf1af8..a873ab88f651b550ebfdfa8e00c6401370008b7b 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeLimit.c,v 1.41 2010/01/02 16:57:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeLimit.c,v 1.42 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -404,7 +404,7 @@ ExecEndLimit(LimitState *node)
 
 
 void
-ExecReScanLimit(LimitState *node, ExprContext *exprCtxt)
+ExecReScanLimit(LimitState *node)
 {
 	/*
 	 * Recompute limit/offset in case parameters changed, and reset the state
@@ -417,6 +417,6 @@ ExecReScanLimit(LimitState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 0eafa0afa2ccccf81ea4258c8d1b7cb8354ee1b8..d573853eba9fdf69ad7e2cea33271a9131267f94 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeLockRows.c,v 1.4 2010/02/26 02:00:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeLockRows.c,v 1.5 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -339,12 +339,12 @@ ExecEndLockRows(LockRowsState *node)
 
 
 void
-ExecReScanLockRows(LockRowsState *node, ExprContext *exprCtxt)
+ExecReScanLockRows(LockRowsState *node)
 {
 	/*
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 414ff5339053593633ab8bd72379147e33ebe977..78f29d872e615fbe71586f9bc00206a682c53c76 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.71 2010/01/02 16:57:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.72 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -309,22 +309,22 @@ ExecMaterialRestrPos(MaterialState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecMaterialReScan
+ *		ExecReScanMaterial
  *
  *		Rescans the materialized relation.
  * ----------------------------------------------------------------
  */
 void
-ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
+ExecReScanMaterial(MaterialState *node)
 {
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 	if (node->eflags != 0)
 	{
 		/*
-		 * If we haven't materialized yet, just return. If outerplan' chgParam
-		 * is not NULL then it will be re-scanned by ExecProcNode, else - no
-		 * reason to re-scan it at all.
+		 * If we haven't materialized yet, just return. If outerplan's
+		 * chgParam is not NULL then it will be re-scanned by ExecProcNode,
+		 * else no reason to re-scan it at all.
 		 */
 		if (!node->tuplestorestate)
 			return;
@@ -339,13 +339,13 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
 		 * Otherwise we can just rewind and rescan the stored output. The
 		 * state of the subnode does not change.
 		 */
-		if (((PlanState *) node)->lefttree->chgParam != NULL ||
+		if (node->ss.ps.lefttree->chgParam != NULL ||
 			(node->eflags & EXEC_FLAG_REWIND) == 0)
 		{
 			tuplestore_end(node->tuplestorestate);
 			node->tuplestorestate = NULL;
-			if (((PlanState *) node)->lefttree->chgParam == NULL)
-				ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+			if (node->ss.ps.lefttree->chgParam == NULL)
+				ExecReScan(node->ss.ps.lefttree);
 			node->eof_underlying = false;
 		}
 		else
@@ -359,8 +359,8 @@ ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
 		 * if chgParam of subnode is not null then plan will be re-scanned by
 		 * first ExecProcNode.
 		 */
-		if (((PlanState *) node)->lefttree->chgParam == NULL)
-			ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+		if (node->ss.ps.lefttree->chgParam == NULL)
+			ExecReScan(node->ss.ps.lefttree);
 		node->eof_underlying = false;
 	}
 }
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 948f5800958f2e42254c91522d9e733b7f7e6202..104482a633659f0d6b0b17f462df135275713584 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.103 2010/07/06 19:18:56 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.104 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1680,7 +1680,7 @@ ExecEndMergeJoin(MergeJoinState *node)
 }
 
 void
-ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt)
+ExecReScanMergeJoin(MergeJoinState *node)
 {
 	ExecClearTuple(node->mj_MarkedTupleSlot);
 
@@ -1695,9 +1695,9 @@ ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnodes is not null then plans will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
-	if (((PlanState *) node)->righttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->righttree, exprCtxt);
+	if (node->js.ps.lefttree->chgParam == NULL)
+		ExecReScan(node->js.ps.lefttree);
+	if (node->js.ps.righttree->chgParam == NULL)
+		ExecReScan(node->js.ps.righttree);
 
 }
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index adfe97cefde9fad6c0b0def0fadbb4cb8eb7475f..a5e24def37236a36e22791ac641a48d4d492afdd 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.7 2010/02/26 02:00:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.8 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1045,7 +1045,7 @@ ExecEndModifyTable(ModifyTableState *node)
 }
 
 void
-ExecReScanModifyTable(ModifyTableState *node, ExprContext *exprCtxt)
+ExecReScanModifyTable(ModifyTableState *node)
 {
 	/*
 	 * Currently, we don't need to support rescan on ModifyTable nodes. The
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 1bcaef96e606c0335f729ba6511fa10f569d34d8..d59ed92f0181688b7a7d70390d437596bd3aaa62 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.55 2010/01/02 16:57:44 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeNestloop.c,v 1.56 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,7 @@
 TupleTableSlot *
 ExecNestLoop(NestLoopState *node)
 {
+	NestLoop   *nl;
 	PlanState  *innerPlan;
 	PlanState  *outerPlan;
 	TupleTableSlot *outerTupleSlot;
@@ -66,12 +67,14 @@ ExecNestLoop(NestLoopState *node)
 	List	   *joinqual;
 	List	   *otherqual;
 	ExprContext *econtext;
+	ListCell   *lc;
 
 	/*
 	 * get information from the node
 	 */
 	ENL1_printf("getting info from node");
 
+	nl = (NestLoop *) node->js.ps.plan;
 	joinqual = node->js.joinqual;
 	otherqual = node->js.ps.qual;
 	outerPlan = outerPlanState(node);
@@ -134,16 +137,33 @@ ExecNestLoop(NestLoopState *node)
 			node->nl_MatchedOuter = false;
 
 			/*
-			 * now rescan the inner plan
+			 * fetch the values of any outer Vars that must be passed to
+			 * the inner scan, and store them in the appropriate PARAM_EXEC
+			 * slots.
 			 */
-			ENL1_printf("rescanning inner plan");
+			foreach(lc, nl->nestParams)
+			{
+				NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
+				int			paramno = nlp->paramno;
+				ParamExecData *prm;
+
+				prm = &(econtext->ecxt_param_exec_vals[paramno]);
+				/* Param value should be an OUTER var */
+				Assert(nlp->paramval->varno == OUTER);
+				Assert(nlp->paramval->varattno > 0);
+				prm->value = slot_getattr(outerTupleSlot,
+										  nlp->paramval->varattno,
+										  &(prm->isnull));
+				/* Flag parameter value as changed */
+				innerPlan->chgParam = bms_add_member(innerPlan->chgParam,
+													 paramno);
+			}
 
 			/*
-			 * The scan key of the inner plan might depend on the current
-			 * outer tuple (e.g. in index scans), that's why we pass our expr
-			 * context.
+			 * now rescan the inner plan
 			 */
-			ExecReScan(innerPlan, econtext);
+			ENL1_printf("rescanning inner plan");
+			ExecReScan(innerPlan);
 		}
 
 		/*
@@ -308,15 +328,18 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
 	/*
 	 * initialize child nodes
 	 *
-	 * Tell the inner child that cheap rescans would be good.  (This is
-	 * unnecessary if we are doing nestloop with inner indexscan, because the
-	 * rescan will always be with a fresh parameter --- but since
-	 * nodeIndexscan doesn't actually care about REWIND, there's no point in
-	 * dealing with that refinement.)
+	 * If we have no parameters to pass into the inner rel from the outer,
+	 * tell the inner child that cheap rescans would be good.  If we do have
+	 * such parameters, then there is no point in REWIND support at all in
+	 * the inner child, because it will always be rescanned with fresh
+	 * parameter values.
 	 */
 	outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate, eflags);
-	innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate,
-										   eflags | EXEC_FLAG_REWIND);
+	if (node->nestParams == NIL)
+		eflags |= EXEC_FLAG_REWIND;
+	else
+		eflags &= ~EXEC_FLAG_REWIND;
+	innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate, eflags);
 
 	/*
 	 * tuple table initialization
@@ -395,18 +418,22 @@ ExecEndNestLoop(NestLoopState *node)
  * ----------------------------------------------------------------
  */
 void
-ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt)
+ExecReScanNestLoop(NestLoopState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 
 	/*
 	 * If outerPlan->chgParam is not null then plan will be automatically
-	 * re-scanned by first ExecProcNode. innerPlan is re-scanned for each new
-	 * outer tuple and MUST NOT be re-scanned from here or you'll get troubles
-	 * from inner index scans when outer Vars are used as run-time keys...
+	 * re-scanned by first ExecProcNode.
 	 */
 	if (outerPlan->chgParam == NULL)
-		ExecReScan(outerPlan, exprCtxt);
+		ExecReScan(outerPlan);
+
+	/*
+	 * innerPlan is re-scanned for each new outer tuple and MUST NOT be
+	 * re-scanned from here or you'll get troubles from inner index scans when
+	 * outer Vars are used as run-time keys...
+	 */
 
 	node->js.ps.ps_TupFromTlist = false;
 	node->nl_NeedNewOuter = true;
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 68484ef0929693362358087a4f0d95dc6887ee9a..3cd9495f8a2759249abc9a5b61bc867bbf254657 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeRecursiveunion.c,v 1.6 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeRecursiveunion.c,v 1.7 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -299,13 +299,13 @@ ExecEndRecursiveUnion(RecursiveUnionState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecRecursiveUnionReScan
+ *		ExecReScanRecursiveUnion
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt)
+ExecReScanRecursiveUnion(RecursiveUnionState *node)
 {
 	PlanState  *outerPlan = outerPlanState(node);
 	PlanState  *innerPlan = innerPlanState(node);
@@ -323,7 +323,7 @@ ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt)
 	 * non-recursive term.
 	 */
 	if (outerPlan->chgParam == NULL)
-		ExecReScan(outerPlan, exprCtxt);
+		ExecReScan(outerPlan);
 
 	/* Release any hashtable storage */
 	if (node->tableContext)
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 537df9d5d7b38379c8096eee5727d4fc88a60464..a9ad0dca874a0dda399b99e327389ed32793f885 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -38,7 +38,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.45 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeResult.c,v 1.46 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -292,7 +292,7 @@ ExecEndResult(ResultState *node)
 }
 
 void
-ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
+ExecReScanResult(ResultState *node)
 {
 	node->rs_done = false;
 	node->ps.ps_TupFromTlist = false;
@@ -300,11 +300,9 @@ ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
 
 	/*
 	 * If chgParam of subnode is not null then plan will be re-scanned by
-	 * first ExecProcNode.	However, if caller is passing us an exprCtxt then
-	 * forcibly rescan the subnode now, so that we can pass the exprCtxt down
-	 * to the subnode (needed for gated indexscan).
+	 * first ExecProcNode.
 	 */
 	if (node->ps.lefttree &&
-		(node->ps.lefttree->chgParam == NULL || exprCtxt != NULL))
-		ExecReScan(node->ps.lefttree, exprCtxt);
+		node->ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 75623be3715b1d5609bb96c2fdc3b9cab09edc3e..f65a79310f93171c9e2e576fa2bd189b6aa37bd3 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSeqscan.c,v 1.70 2010/02/26 02:00:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSeqscan.c,v 1.71 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,7 @@
  *		ExecSeqNext				retrieve next tuple in sequential order.
  *		ExecInitSeqScan			creates and initializes a seqscan node.
  *		ExecEndSeqScan			releases any storage allocated.
- *		ExecSeqReScan			rescans the relation
+ *		ExecReScanSeqScan		rescans the relation
  *		ExecSeqMarkPos			marks scan position
  *		ExecSeqRestrPos			restores scan position
  */
@@ -255,13 +255,13 @@ ExecEndSeqScan(SeqScanState *node)
  */
 
 /* ----------------------------------------------------------------
- *		ExecSeqReScan
+ *		ExecReScanSeqScan
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt)
+ExecReScanSeqScan(SeqScanState *node)
 {
 	HeapScanDesc scan;
 
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 7b3ee6d92dbb677bad9ffd09cf1b94f7cecebe3b..1063ff701bad86326798c8a09ab328261c63bd83 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSetOp.c,v 1.33 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSetOp.c,v 1.34 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -597,7 +597,7 @@ ExecEndSetOp(SetOpState *node)
 
 
 void
-ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
+ExecReScanSetOp(SetOpState *node)
 {
 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
 	node->setop_done = false;
@@ -619,7 +619,7 @@ ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
 		 * parameter changes, then we can just rescan the existing hash table;
 		 * no need to build it again.
 		 */
-		if (((PlanState *) node)->lefttree->chgParam == NULL)
+		if (node->ps.lefttree->chgParam == NULL)
 		{
 			ResetTupleHashIterator(node->hashtable, &node->hashiter);
 			return;
@@ -648,6 +648,6 @@ ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 5b925da75a00e5d5e529e157adb59702f8fc6bdf..5b993c199b0475cae4d0b93b8f6b4e83e4f1fa08 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.67 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.68 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -287,11 +287,11 @@ ExecSortRestrPos(SortState *node)
 }
 
 void
-ExecReScanSort(SortState *node, ExprContext *exprCtxt)
+ExecReScanSort(SortState *node)
 {
 	/*
-	 * If we haven't sorted yet, just return. If outerplan' chgParam is not
-	 * NULL then it will be re-scanned by ExecProcNode, else - no reason to
+	 * If we haven't sorted yet, just return. If outerplan's chgParam is not
+	 * NULL then it will be re-scanned by ExecProcNode, else no reason to
 	 * re-scan it at all.
 	 */
 	if (!node->sort_Done)
@@ -307,7 +307,7 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt)
 	 *
 	 * Otherwise we can just rewind and rescan the sorted output.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam != NULL ||
+	if (node->ss.ps.lefttree->chgParam != NULL ||
 		node->bounded != node->bounded_Done ||
 		node->bound != node->bound_Done ||
 		!node->randomAccess)
@@ -320,8 +320,8 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt)
 		 * if chgParam of subnode is not null then plan will be re-scanned by
 		 * first ExecProcNode.
 		 */
-		if (((PlanState *) node)->lefttree->chgParam == NULL)
-			ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+		if (node->ss.ps.lefttree->chgParam == NULL)
+			ExecReScan(node->ss.ps.lefttree);
 	}
 	else
 		tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index f5ac47402e13984189679bba9fabe1d867b0733e..419f3f36bd2838c98082330a122e96416932833d 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
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.101 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.102 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -256,7 +256,7 @@ ExecScanSubPlan(SubPlanState *node,
 	/*
 	 * Now that we've set up its parameters, we can reset the subplan.
 	 */
-	ExecReScan(planstate, NULL);
+	ExecReScan(planstate);
 
 	/*
 	 * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
@@ -508,7 +508,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
 	/*
 	 * Reset subplan to start.
 	 */
-	ExecReScan(planstate, NULL);
+	ExecReScan(planstate);
 
 	/*
 	 * Scan the subplan and load the hash table(s).  Note that when there are
@@ -884,7 +884,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
  *
  *		Executes an InitPlan subplan and sets its output parameters.
  *
- * This is called from ExecEvalParam() when the value of a PARAM_EXEC
+ * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
  * parameter is requested and the param's execPlan field is set (indicating
  * that the param has not yet been evaluated).	This allows lazy evaluation
  * of initplans: we don't run the subplan until/unless we need its output.
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index dbd42d79720265283e3928815ee761c52f055b87..9741a103b50a4c40facb5aa78e460bd1f9300b40 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.45 2010/02/26 02:00:42 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.46 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,7 +22,7 @@
  *		ExecSubqueryNext			retrieve next tuple in sequential order.
  *		ExecInitSubqueryScan		creates and initializes a subqueryscan node.
  *		ExecEndSubqueryScan			releases any storage allocated.
- *		ExecSubqueryReScan			rescans the relation
+ *		ExecReScanSubqueryScan		rescans the relation
  *
  */
 #include "postgres.h"
@@ -187,13 +187,13 @@ ExecEndSubqueryScan(SubqueryScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecSubqueryReScan
+ *		ExecReScanSubqueryScan
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
+ExecReScanSubqueryScan(SubqueryScanState *node)
 {
 	ExecScanReScan(&node->ss);
 
@@ -210,5 +210,5 @@ ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
 	 * first ExecProcNode.
 	 */
 	if (node->subplan->chgParam == NULL)
-		ExecReScan(node->subplan, NULL);
+		ExecReScan(node->subplan);
 }
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index e66f97833fe0725ac9dc99f6bfa4744b8037226c..7a8c7479aa8c0d0b93f58bb8e4661839e3e7f1a3 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.65 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeTidscan.c,v 1.66 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,7 @@
  *
  *		ExecTidScan			scans a relation using tids
  *		ExecInitTidScan		creates and initializes state info.
- *		ExecTidReScan		rescans the tid relation.
+ *		ExecReScanTidScan	rescans the tid relation.
  *		ExecEndTidScan		releases all storage.
  *		ExecTidMarkPos		marks scan position.
  *		ExecTidRestrPos		restores scan position.
@@ -398,17 +398,12 @@ ExecTidScan(TidScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecTidReScan(node)
+ *		ExecReScanTidScan(node)
  * ----------------------------------------------------------------
  */
 void
-ExecTidReScan(TidScanState *node, ExprContext *exprCtxt)
+ExecReScanTidScan(TidScanState *node)
 {
-	/* If we are being passed an outer tuple, save it for runtime key calc */
-	if (exprCtxt != NULL)
-		node->ss.ps.ps_ExprContext->ecxt_outertuple =
-			exprCtxt->ecxt_outertuple;
-
 	if (node->tss_TidList)
 		pfree(node->tss_TidList);
 	node->tss_TidList = NULL;
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 82abb18477553e5ffa38922db60827cd5502a743..1fd110905180d3320c1a0821d575c7ba675128d4 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -16,7 +16,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.63 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeUnique.c,v 1.64 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -184,7 +184,7 @@ ExecEndUnique(UniqueState *node)
 
 
 void
-ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
+ExecReScanUnique(UniqueState *node)
 {
 	/* must clear result tuple so first input tuple is returned */
 	ExecClearTuple(node->ps.ps_ResultTupleSlot);
@@ -193,6 +193,6 @@ ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ps.lefttree);
 }
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 482577b2fe487c34817ed9db2c87543edbac1a8c..79d41ecc270cc3c65e6e82f8f23287163e65532d 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.12 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.13 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,7 +19,7 @@
  *		ExecValuesNext			retrieve next tuple in sequential order.
  *		ExecInitValuesScan		creates and initializes a valuesscan node.
  *		ExecEndValuesScan		releases any storage allocated.
- *		ExecValuesReScan		rescans the values list
+ *		ExecReScanValuesScan	rescans the values list
  */
 #include "postgres.h"
 
@@ -319,13 +319,13 @@ ExecValuesRestrPos(ValuesScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecValuesReScan
+ *		ExecReScanValuesScan
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
+ExecReScanValuesScan(ValuesScanState *node)
 {
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index de6d0385e920ff5aad5171066d2b95f9ac199443..ad20c3cca17e8ad8a527606274caa20e2233f0e7 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -27,7 +27,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.13 2010/03/21 00:17:58 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeWindowAgg.c,v 1.14 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1664,7 +1664,7 @@ ExecEndWindowAgg(WindowAggState *node)
  * -----------------
  */
 void
-ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt)
+ExecReScanWindowAgg(WindowAggState *node)
 {
 	ExprContext *econtext = node->ss.ps.ps_ExprContext;
 
@@ -1691,8 +1691,8 @@ ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt)
 	 * if chgParam of subnode is not null then plan will be re-scanned by
 	 * first ExecProcNode.
 	 */
-	if (((PlanState *) node)->lefttree->chgParam == NULL)
-		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
+	if (node->ss.ps.lefttree->chgParam == NULL)
+		ExecReScan(node->ss.ps.lefttree);
 }
 
 /*
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index 3fba4e3d9b3621b6c62e03070e43d81eb12863a7..d0d22e6481f2e9a1f48d6dce244cadbdd5160eb7 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.10 2010/01/02 16:57:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeWorktablescan.c,v 1.11 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -203,13 +203,13 @@ ExecEndWorkTableScan(WorkTableScanState *node)
 }
 
 /* ----------------------------------------------------------------
- *		ExecWorkTableScanReScan
+ *		ExecReScanWorkTableScan
  *
  *		Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecWorkTableScanReScan(WorkTableScanState *node, ExprContext *exprCtxt)
+ExecReScanWorkTableScan(WorkTableScanState *node)
 {
 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 829dc7ba8d27ef303d3d08155c87bebdaf021038..8e47403a485fa0c0e463cb30184a434bbbbc1fce 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
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.464 2010/02/26 02:00:43 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.465 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -564,6 +564,11 @@ _copyNestLoop(NestLoop *from)
 	 */
 	CopyJoinFields((Join *) from, (Join *) newnode);
 
+	/*
+	 * copy remainder of node
+	 */
+	COPY_NODE_FIELD(nestParams);
+
 	return newnode;
 }
 
@@ -844,6 +849,20 @@ _copyLimit(Limit *from)
 	return newnode;
 }
 
+/*
+ * _copyNestLoopParam
+ */
+static NestLoopParam *
+_copyNestLoopParam(NestLoopParam *from)
+{
+	NestLoopParam *newnode = makeNode(NestLoopParam);
+
+	COPY_SCALAR_FIELD(paramno);
+	COPY_NODE_FIELD(paramval);
+
+	return newnode;
+}
+
 /*
  * _copyPlanRowMark
  */
@@ -3671,6 +3690,9 @@ copyObject(void *from)
 		case T_Limit:
 			retval = _copyLimit(from);
 			break;
+		case T_NestLoopParam:
+			retval = _copyNestLoopParam(from);
+			break;
 		case T_PlanRowMark:
 			retval = _copyPlanRowMark(from);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index dba8d4b66906e9cb11af71afdf472454f3c4e728..ff4a9aaeefd1f577081a24b80f5141bfba68e2a2 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.385 2010/03/30 21:58:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.386 2010/07/12 17:01:05 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -517,6 +517,8 @@ _outNestLoop(StringInfo str, NestLoop *node)
 	WRITE_NODE_TYPE("NESTLOOP");
 
 	_outJoinPlanInfo(str, (Join *) node);
+
+	WRITE_NODE_FIELD(nestParams);
 }
 
 static void
@@ -748,6 +750,15 @@ _outLimit(StringInfo str, Limit *node)
 	WRITE_NODE_FIELD(limitCount);
 }
 
+static void
+_outNestLoopParam(StringInfo str, NestLoopParam *node)
+{
+	WRITE_NODE_TYPE("NESTLOOPPARAM");
+
+	WRITE_INT_FIELD(paramno);
+	WRITE_NODE_FIELD(paramval);
+}
+
 static void
 _outPlanRowMark(StringInfo str, PlanRowMark *node)
 {
@@ -1565,6 +1576,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
 	WRITE_BOOL_FIELD(hasPseudoConstantQuals);
 	WRITE_BOOL_FIELD(hasRecursion);
 	WRITE_INT_FIELD(wt_param_id);
+	WRITE_BITMAPSET_FIELD(curOuterRels);
+	WRITE_NODE_FIELD(curOuterParams);
 }
 
 static void
@@ -2562,6 +2575,9 @@ _outNode(StringInfo str, void *obj)
 			case T_Limit:
 				_outLimit(str, obj);
 				break;
+			case T_NestLoopParam:
+				_outNestLoopParam(str, obj);
+				break;
 			case T_PlanRowMark:
 				_outPlanRowMark(str, obj);
 				break;
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 3d6f9f94faa2f050fbb4ab411ad10da5e695d449..434babc5d85b23e2d60f2ff7b23fcffdcec35a28 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.275 2010/05/25 17:44:41 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.276 2010/07/12 17:01:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,7 @@
 #include "optimizer/planmain.h"
 #include "optimizer/predtest.h"
 #include "optimizer/restrictinfo.h"
+#include "optimizer/subselect.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
 #include "parser/parse_clause.h"
@@ -35,6 +36,7 @@
 #include "utils/lsyscache.h"
 
 
+static Plan *create_plan_recurse(PlannerInfo *root, Path *best_path);
 static Plan *create_scan_plan(PlannerInfo *root, Path *best_path);
 static List *build_relation_tlist(RelOptInfo *rel);
 static bool use_physical_tlist(PlannerInfo *root, RelOptInfo *rel);
@@ -72,7 +74,10 @@ static MergeJoin *create_mergejoin_plan(PlannerInfo *root, MergePath *best_path,
 					  Plan *outer_plan, Plan *inner_plan);
 static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path,
 					 Plan *outer_plan, Plan *inner_plan);
-static List *fix_indexqual_references(List *indexquals, IndexPath *index_path);
+static Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
+static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root);
+static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path,
+						 List *indexquals);
 static List *get_switched_clauses(List *clauses, Relids outerrelids);
 static List *order_qual_clauses(PlannerInfo *root, List *clauses);
 static void copy_path_costsize(Plan *dest, Path *src);
@@ -103,7 +108,7 @@ static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
 static BitmapAnd *make_bitmap_and(List *bitmapplans);
 static BitmapOr *make_bitmap_or(List *bitmapplans);
 static NestLoop *make_nestloop(List *tlist,
-			  List *joinclauses, List *otherclauses,
+			  List *joinclauses, List *otherclauses, List *nestParams,
 			  Plan *lefttree, Plan *righttree,
 			  JoinType jointype);
 static HashJoin *make_hashjoin(List *tlist,
@@ -133,8 +138,8 @@ static Material *make_material(Plan *lefttree);
 
 /*
  * create_plan
- *	  Creates the access plan for a query by tracing backwards through the
- *	  desired chain of pathnodes, starting at the node 'best_path'.  For
+ *	  Creates the access plan for a query by recursively processing the
+ *	  desired tree of pathnodes, starting at the node 'best_path'.  For
  *	  every pathnode found, we create a corresponding plan node containing
  *	  appropriate id, target list, and qualification information.
  *
@@ -151,6 +156,29 @@ create_plan(PlannerInfo *root, Path *best_path)
 {
 	Plan	   *plan;
 
+	/* Initialize this module's private workspace in PlannerInfo */
+	root->curOuterRels = NULL;
+	root->curOuterParams = NIL;
+
+	/* Recursively process the path tree */
+	plan = create_plan_recurse(root, best_path);
+
+	/* Check we successfully assigned all NestLoopParams to plan nodes */
+	if (root->curOuterParams != NIL)
+		elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
+
+	return plan;
+}
+
+/*
+ * create_plan_recurse
+ *	  Recursive guts of create_plan().
+ */
+static Plan *
+create_plan_recurse(PlannerInfo *root, Path *best_path)
+{
+	Plan	   *plan;
+
 	switch (best_path->pathtype)
 	{
 		case T_SeqScan:
@@ -477,9 +505,16 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
 	Plan	   *outer_plan;
 	Plan	   *inner_plan;
 	Plan	   *plan;
+	Relids		saveOuterRels = root->curOuterRels;
+
+	outer_plan = create_plan_recurse(root, best_path->outerjoinpath);
 
-	outer_plan = create_plan(root, best_path->outerjoinpath);
-	inner_plan = create_plan(root, best_path->innerjoinpath);
+	/* For a nestloop, include outer relids in curOuterRels for inner side */
+	if (best_path->path.pathtype == T_NestLoop)
+		root->curOuterRels = bms_union(root->curOuterRels,
+								   best_path->outerjoinpath->parent->relids);
+
+	inner_plan = create_plan_recurse(root, best_path->innerjoinpath);
 
 	switch (best_path->path.pathtype)
 	{
@@ -496,6 +531,10 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
 												 inner_plan);
 			break;
 		case T_NestLoop:
+			/* Restore curOuterRels */
+			bms_free(root->curOuterRels);
+			root->curOuterRels = saveOuterRels;
+
 			plan = (Plan *) create_nestloop_plan(root,
 												 (NestPath *) best_path,
 												 outer_plan,
@@ -571,7 +610,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 	{
 		Path	   *subpath = (Path *) lfirst(subpaths);
 
-		subplans = lappend(subplans, create_plan(root, subpath));
+		subplans = lappend(subplans, create_plan_recurse(root, subpath));
 	}
 
 	plan = make_append(subplans, tlist);
@@ -616,7 +655,7 @@ create_material_plan(PlannerInfo *root, MaterialPath *best_path)
 	Material   *plan;
 	Plan	   *subplan;
 
-	subplan = create_plan(root, best_path->subpath);
+	subplan = create_plan_recurse(root, best_path->subpath);
 
 	/* We don't want any excess columns in the materialized tuples */
 	disuse_physical_tlist(subplan, best_path->subpath);
@@ -650,7 +689,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
 	int			groupColPos;
 	ListCell   *l;
 
-	subplan = create_plan(root, best_path->subpath);
+	subplan = create_plan_recurse(root, best_path->subpath);
 
 	/* Done if we don't need to do any actual unique-ifying */
 	if (best_path->umethod == UNIQUE_PATH_NOOP)
@@ -904,7 +943,7 @@ create_indexscan_plan(PlannerInfo *root,
 	 * The executor needs a copy with the indexkey on the left of each clause
 	 * and with index attr numbers substituted for table ones.
 	 */
-	fixed_indexquals = fix_indexqual_references(indexquals, best_path);
+	fixed_indexquals = fix_indexqual_references(root, best_path, indexquals);
 
 	/*
 	 * If this is an innerjoin scan, the indexclauses will contain join
@@ -975,6 +1014,22 @@ create_indexscan_plan(PlannerInfo *root,
 	/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
 	qpqual = extract_actual_clauses(qpqual, false);
 
+	/*
+	 * We have to replace any outer-relation variables with nestloop params
+	 * in the indexqualorig and qpqual expressions.  A bit annoying to have to
+	 * do this separately from the processing in fix_indexqual_references ---
+	 * rethink this when generalizing the inner indexscan support.  But note
+	 * we can't really do this earlier because it'd break the comparisons to
+	 * predicates above ... (or would it?  Those wouldn't have outer refs)
+	 */
+	if (best_path->isjoininner)
+	{
+		stripped_indexquals = (List *)
+			replace_nestloop_params(root, (Node *) stripped_indexquals);
+		qpqual = (List *)
+			replace_nestloop_params(root, (Node *) qpqual);
+	}
+
 	/* Finally ready to build the plan node */
 	scan_plan = make_indexscan(tlist,
 							   qpqual,
@@ -1267,6 +1322,17 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
 				*indexqual = lappend(*indexqual, pred);
 			}
 		}
+		/*
+		 * Replace outer-relation variables with nestloop params, but only
+		 * after doing the above comparisons to index predicates.
+		 */
+		if (ipath->isjoininner)
+		{
+			*qual = (List *)
+				replace_nestloop_params(root, (Node *) *qual);
+			*indexqual = (List *)
+				replace_nestloop_params(root, (Node *) *indexqual);
+		}
 	}
 	else
 	{
@@ -1572,11 +1638,16 @@ create_nestloop_plan(PlannerInfo *root,
 					 Plan *outer_plan,
 					 Plan *inner_plan)
 {
+	NestLoop   *join_plan;
 	List	   *tlist = build_relation_tlist(best_path->path.parent);
 	List	   *joinrestrictclauses = best_path->joinrestrictinfo;
 	List	   *joinclauses;
 	List	   *otherclauses;
-	NestLoop   *join_plan;
+	Relids		outerrelids;
+	List	   *nestParams;
+	ListCell   *cell;
+	ListCell   *prev;
+	ListCell   *next;
 
 	/*
 	 * If the inner path is a nestloop inner indexscan, it might be using some
@@ -1605,9 +1676,32 @@ create_nestloop_plan(PlannerInfo *root,
 		otherclauses = NIL;
 	}
 
+	/*
+	 * Identify any nestloop parameters that should be supplied by this join
+	 * node, and move them from root->curOuterParams to the nestParams list.
+	 */
+	outerrelids = best_path->outerjoinpath->parent->relids;
+	nestParams = NIL;
+	prev = NULL;
+	for (cell = list_head(root->curOuterParams); cell; cell = next)
+	{
+		NestLoopParam *nlp = (NestLoopParam *) lfirst(cell);
+
+		next = lnext(cell);
+		if (bms_is_member(nlp->paramval->varno, outerrelids))
+		{
+			root->curOuterParams = list_delete_cell(root->curOuterParams,
+													cell, prev);
+			nestParams = lappend(nestParams, nlp);
+		}
+		else
+			prev = cell;
+	}
+
 	join_plan = make_nestloop(tlist,
 							  joinclauses,
 							  otherclauses,
+							  nestParams,
 							  outer_plan,
 							  inner_plan,
 							  best_path->jointype);
@@ -2015,13 +2109,73 @@ create_hashjoin_plan(PlannerInfo *root,
  *
  *****************************************************************************/
 
+/*
+ * replace_nestloop_params
+ *	  Replace outer-relation Vars in the given expression with nestloop Params
+ *
+ * All Vars belonging to the relation(s) identified by root->curOuterRels
+ * are replaced by Params, and entries are added to root->curOuterParams if
+ * not already present.
+ */
+static Node *
+replace_nestloop_params(PlannerInfo *root, Node *expr)
+{
+	/* No setup needed for tree walk, so away we go */
+	return replace_nestloop_params_mutator(expr, root);
+}
+
+static Node *
+replace_nestloop_params_mutator(Node *node, PlannerInfo *root)
+{
+	if (node == NULL)
+		return NULL;
+	if (IsA(node, Var))
+	{
+		Var	   *var = (Var *) node;
+		Param  *param;
+		NestLoopParam *nlp;
+		ListCell *lc;
+
+		/* Upper-level Vars should be long gone at this point */
+		Assert(var->varlevelsup == 0);
+		/* If not to be replaced, we can just return the Var unmodified */
+		if (!bms_is_member(var->varno, root->curOuterRels))
+			return node;
+		/* Create a Param representing the Var */
+		param = assign_nestloop_param(root, var);
+		/* Is this param already listed in root->curOuterParams? */
+		foreach(lc, root->curOuterParams)
+		{
+			nlp = (NestLoopParam *) lfirst(lc);
+			if (nlp->paramno == param->paramid)
+			{
+				Assert(equal(var, nlp->paramval));
+				/* Present, so we can just return the Param */
+				return (Node *) param;
+			}
+		}
+		/* No, so add it */
+		nlp = makeNode(NestLoopParam);
+		nlp->paramno = param->paramid;
+		nlp->paramval = var;
+		root->curOuterParams = lappend(root->curOuterParams, nlp);
+		/* And return the replacement Param */
+		return (Node *) param;
+	}
+	return expression_tree_mutator(node,
+								   replace_nestloop_params_mutator,
+								   (void *) root);
+}
+
 /*
  * fix_indexqual_references
  *	  Adjust indexqual clauses to the form the executor's indexqual
  *	  machinery needs.
  *
- * We have three tasks here:
+ * We have four tasks here:
  *	* Remove RestrictInfo nodes from the input clauses.
+ *	* Replace any outer-relation Var nodes with nestloop Params.
+ *	  (XXX eventually, that responsibility should go elsewhere?)
  *	* Index keys must be represented by Var nodes with varattno set to the
  *	  index's attribute number, not the attribute number in the original rel.
  *	* If the index key is on the right, commute the clause to put it on the
@@ -2033,7 +2187,8 @@ create_hashjoin_plan(PlannerInfo *root,
  * two separate copies of the subplan tree, or things will go awry).
  */
 static List *
-fix_indexqual_references(List *indexquals, IndexPath *index_path)
+fix_indexqual_references(PlannerInfo *root, IndexPath *index_path,
+						 List *indexquals)
 {
 	IndexOptInfo *index = index_path->indexinfo;
 	List	   *fixed_indexquals;
@@ -2041,26 +2196,20 @@ fix_indexqual_references(List *indexquals, IndexPath *index_path)
 
 	fixed_indexquals = NIL;
 
-	/*
-	 * For each qual clause, commute if needed to put the indexkey operand on
-	 * the left, and then fix its varattno.  (We do not need to change the
-	 * other side of the clause.)
-	 */
 	foreach(l, indexquals)
 	{
 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
-		Expr	   *clause;
+		Node	   *clause;
 
 		Assert(IsA(rinfo, RestrictInfo));
 
 		/*
-		 * Make a copy that will become the fixed clause.
+		 * Replace any outer-relation variables with nestloop params.
 		 *
-		 * We used to try to do a shallow copy here, but that fails if there
-		 * is a subplan in the arguments of the opclause.  So just do a full
-		 * copy.
+		 * This also makes a copy of the clause, so it's safe to modify it
+		 * in-place below.
 		 */
-		clause = (Expr *) copyObject((Node *) rinfo->clause);
+		clause = replace_nestloop_params(root, (Node *) rinfo->clause);
 
 		if (IsA(clause, OpExpr))
 		{
@@ -2765,6 +2914,7 @@ static NestLoop *
 make_nestloop(List *tlist,
 			  List *joinclauses,
 			  List *otherclauses,
+			  List *nestParams,
 			  Plan *lefttree,
 			  Plan *righttree,
 			  JoinType jointype)
@@ -2779,6 +2929,7 @@ make_nestloop(List *tlist,
 	plan->righttree = righttree;
 	node->join.jointype = jointype;
 	node->join.joinqual = joinclauses;
+	node->nestParams = nestParams;
 
 	return node;
 }
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 70be2e66f2d20d7dcd7e64cc45fc98e9f37fcfa9..450970e5c37a07a6a33d44085c26a6008cbec6e7 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.160 2010/02/26 02:00:45 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.161 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,8 +89,6 @@ static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset);
 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
 static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset);
-static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
-						  indexed_tlist *outer_itlist);
 static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset);
 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
 static indexed_tlist *build_tlist_index(List *tlist);
@@ -878,12 +876,11 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
 		Assert(var->varlevelsup == 0);
 
 		/*
-		 * We should not see any Vars marked INNER, but in a nestloop inner
-		 * scan there could be OUTER Vars.	Leave them alone.
+		 * We should not see any Vars marked INNER or OUTER.
 		 */
 		Assert(var->varno != INNER);
-		if (var->varno > 0 && var->varno != OUTER)
-			var->varno += context->rtoffset;
+		Assert(var->varno != OUTER);
+		var->varno += context->rtoffset;
 		if (var->varnoold > 0)
 			var->varnoold += context->rtoffset;
 		return (Node *) var;
@@ -927,10 +924,6 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
  *	  values to the result domain number of either the corresponding outer
  *	  or inner join tuple item.  Also perform opcode lookup for these
  *	  expressions. and add regclass OIDs to glob->relationOids.
- *
- * In the case of a nestloop with inner indexscan, we will also need to
- * apply the same transformation to any outer vars appearing in the
- * quals of the child indexscan.  set_inner_join_references does that.
  */
 static void
 set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
@@ -966,8 +959,18 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
 	/* Now do join-type-specific stuff */
 	if (IsA(join, NestLoop))
 	{
-		/* This processing is split out to handle possible recursion */
-		set_inner_join_references(glob, inner_plan, outer_itlist);
+		NestLoop   *nl = (NestLoop *) join;
+		ListCell   *lc;
+
+		foreach(lc, nl->nestParams)
+		{
+			NestLoopParam *nlp = (NestLoopParam *) lfirst(lc);
+
+			nlp->paramval = (Var *) fix_upper_expr(glob,
+												   (Node *) nlp->paramval,
+												   outer_itlist,
+												   rtoffset);
+		}
 	}
 	else if (IsA(join, MergeJoin))
 	{
@@ -996,193 +999,6 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
 	pfree(inner_itlist);
 }
 
-/*
- * set_inner_join_references
- *		Handle join references appearing in an inner indexscan's quals
- *
- * To handle bitmap-scan plan trees, we have to be able to recurse down
- * to the bottom BitmapIndexScan nodes; likewise, appendrel indexscans
- * require recursing through Append nodes.	This is split out as a separate
- * function so that it can recurse.
- *
- * Note we do *not* apply any rtoffset for non-join Vars; this is because
- * the quals will be processed again by fix_scan_expr when the set_plan_refs
- * recursion reaches the inner indexscan, and so we'd have done it twice.
- */
-static void
-set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
-						  indexed_tlist *outer_itlist)
-{
-	if (IsA(inner_plan, IndexScan))
-	{
-		/*
-		 * An index is being used to reduce the number of tuples scanned in
-		 * the inner relation.	If there are join clauses being used with the
-		 * index, we must update their outer-rel var nodes to refer to the
-		 * outer side of the join.
-		 */
-		IndexScan  *innerscan = (IndexScan *) inner_plan;
-		List	   *indexqualorig = innerscan->indexqualorig;
-
-		/* No work needed if indexqual refers only to its own rel... */
-		if (NumRelids((Node *) indexqualorig) > 1)
-		{
-			Index		innerrel = innerscan->scan.scanrelid;
-
-			/* only refs to outer vars get changed in the inner qual */
-			innerscan->indexqualorig = fix_join_expr(glob,
-													 indexqualorig,
-													 outer_itlist,
-													 NULL,
-													 innerrel,
-													 0);
-			innerscan->indexqual = fix_join_expr(glob,
-												 innerscan->indexqual,
-												 outer_itlist,
-												 NULL,
-												 innerrel,
-												 0);
-
-			/*
-			 * We must fix the inner qpqual too, if it has join clauses (this
-			 * could happen if special operators are involved: some indexquals
-			 * may get rechecked as qpquals).
-			 */
-			if (NumRelids((Node *) inner_plan->qual) > 1)
-				inner_plan->qual = fix_join_expr(glob,
-												 inner_plan->qual,
-												 outer_itlist,
-												 NULL,
-												 innerrel,
-												 0);
-		}
-	}
-	else if (IsA(inner_plan, BitmapIndexScan))
-	{
-		/*
-		 * Same, but index is being used within a bitmap plan.
-		 */
-		BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
-		List	   *indexqualorig = innerscan->indexqualorig;
-
-		/* No work needed if indexqual refers only to its own rel... */
-		if (NumRelids((Node *) indexqualorig) > 1)
-		{
-			Index		innerrel = innerscan->scan.scanrelid;
-
-			/* only refs to outer vars get changed in the inner qual */
-			innerscan->indexqualorig = fix_join_expr(glob,
-													 indexqualorig,
-													 outer_itlist,
-													 NULL,
-													 innerrel,
-													 0);
-			innerscan->indexqual = fix_join_expr(glob,
-												 innerscan->indexqual,
-												 outer_itlist,
-												 NULL,
-												 innerrel,
-												 0);
-			/* no need to fix inner qpqual */
-			Assert(inner_plan->qual == NIL);
-		}
-	}
-	else if (IsA(inner_plan, BitmapHeapScan))
-	{
-		/*
-		 * The inner side is a bitmap scan plan.  Fix the top node, and
-		 * recurse to get the lower nodes.
-		 *
-		 * Note: create_bitmap_scan_plan removes clauses from bitmapqualorig
-		 * if they are duplicated in qpqual, so must test these independently.
-		 */
-		BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan;
-		Index		innerrel = innerscan->scan.scanrelid;
-		List	   *bitmapqualorig = innerscan->bitmapqualorig;
-
-		/* only refs to outer vars get changed in the inner qual */
-		if (NumRelids((Node *) bitmapqualorig) > 1)
-			innerscan->bitmapqualorig = fix_join_expr(glob,
-													  bitmapqualorig,
-													  outer_itlist,
-													  NULL,
-													  innerrel,
-													  0);
-
-		/*
-		 * We must fix the inner qpqual too, if it has join clauses (this
-		 * could happen if special operators are involved: some indexquals may
-		 * get rechecked as qpquals).
-		 */
-		if (NumRelids((Node *) inner_plan->qual) > 1)
-			inner_plan->qual = fix_join_expr(glob,
-											 inner_plan->qual,
-											 outer_itlist,
-											 NULL,
-											 innerrel,
-											 0);
-
-		/* Now recurse */
-		set_inner_join_references(glob, inner_plan->lefttree, outer_itlist);
-	}
-	else if (IsA(inner_plan, BitmapAnd))
-	{
-		/* All we need do here is recurse */
-		BitmapAnd  *innerscan = (BitmapAnd *) inner_plan;
-		ListCell   *l;
-
-		foreach(l, innerscan->bitmapplans)
-		{
-			set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
-		}
-	}
-	else if (IsA(inner_plan, BitmapOr))
-	{
-		/* All we need do here is recurse */
-		BitmapOr   *innerscan = (BitmapOr *) inner_plan;
-		ListCell   *l;
-
-		foreach(l, innerscan->bitmapplans)
-		{
-			set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
-		}
-	}
-	else if (IsA(inner_plan, TidScan))
-	{
-		TidScan    *innerscan = (TidScan *) inner_plan;
-		Index		innerrel = innerscan->scan.scanrelid;
-
-		innerscan->tidquals = fix_join_expr(glob,
-											innerscan->tidquals,
-											outer_itlist,
-											NULL,
-											innerrel,
-											0);
-	}
-	else if (IsA(inner_plan, Append))
-	{
-		/*
-		 * The inner side is an append plan.  Recurse to see if it contains
-		 * indexscans that need to be fixed.
-		 */
-		Append	   *appendplan = (Append *) inner_plan;
-		ListCell   *l;
-
-		foreach(l, appendplan->appendplans)
-		{
-			set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
-		}
-	}
-	else if (IsA(inner_plan, Result))
-	{
-		/* Recurse through a gating Result node (similar to Append case) */
-		Result	   *result = (Result *) inner_plan;
-
-		if (result->plan.lefttree)
-			set_inner_join_references(glob, result->plan.lefttree, outer_itlist);
-	}
-}
-
 /*
  * set_upper_references
  *	  Update the targetlist and quals of an upper-level plan node
@@ -1532,23 +1348,21 @@ search_indexed_tlist_for_sortgroupref(Node *node,
  *
  * This is used in two different scenarios: a normal join clause, where
  * all the Vars in the clause *must* be replaced by OUTER or INNER references;
- * and an indexscan being used on the inner side of a nestloop join.
- * In the latter case we want to replace the outer-relation Vars by OUTER
- * references, while Vars of the inner relation should be adjusted by rtoffset.
- * (We also implement RETURNING clause fixup using this second scenario.)
+ * and a RETURNING clause, which may contain both Vars of the target relation
+ * and Vars of other relations.  In the latter case we want to replace the
+ * other-relation Vars by OUTER references, while leaving target Vars alone.
  *
  * For a normal join, acceptable_rel should be zero so that any failure to
- * match a Var will be reported as an error.  For the indexscan case,
- * pass inner_itlist = NULL and acceptable_rel = the (not-offseted-yet) ID
- * of the inner relation.
+ * match a Var will be reported as an error.  For the RETURNING case, pass
+ * inner_itlist = NULL and acceptable_rel = the ID of the target relation.
  *
  * 'clauses' is the targetlist or list of join clauses
  * 'outer_itlist' is the indexed target list of the outer join relation
  * 'inner_itlist' is the indexed target list of the inner join relation,
  *		or NULL
  * 'acceptable_rel' is either zero or the rangetable index of a relation
- *		whose Vars may appear in the clause without provoking an error.
- * 'rtoffset' is what to add to varno for Vars of acceptable_rel.
+ *		whose Vars may appear in the clause without provoking an error
+ * 'rtoffset': how much to increment varnoold by
  *
  * Returns the new expression tree.  The original clause structure is
  * not modified.
@@ -1603,8 +1417,8 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
 		if (var->varno == context->acceptable_rel)
 		{
 			var = copyVar(var);
-			var->varno += context->rtoffset;
-			var->varnoold += context->rtoffset;
+			if (var->varnoold > 0)
+				var->varnoold += context->rtoffset;
 			return (Node *) var;
 		}
 
@@ -1783,7 +1597,7 @@ set_returning_clause_references(PlannerGlobal *glob,
 
 	/*
 	 * We can perform the desired Var fixup by abusing the fix_join_expr
-	 * machinery that normally handles inner indexscan fixup.  We search the
+	 * machinery that formerly handled inner indexscan fixup.  We search the
 	 * top plan's targetlist for Vars of non-result relations, and use
 	 * fix_join_expr to convert RETURNING Vars into references to those tlist
 	 * entries, while leaving result-rel Vars as-is.
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index cf503d51135d2b34947cf3eca30b8cb75be96859..b94419a09dc20c10b090d0bbc7a0b7b1a76f7e26 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.162 2010/04/19 00:55:25 rhaas Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.163 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,30 +83,20 @@ static bool finalize_primnode(Node *node, finalize_primnode_context *context);
 
 
 /*
- * Generate a Param node to replace the given Var,
- * which is expected to have varlevelsup > 0 (ie, it is not local).
+ * Select a PARAM_EXEC number to identify the given Var.
+ * If the Var already has a param slot, return that one.
  */
-static Param *
-replace_outer_var(PlannerInfo *root, Var *var)
+static int
+assign_param_for_var(PlannerInfo *root, Var *var)
 {
-	Param	   *retval;
 	ListCell   *ppl;
 	PlannerParamItem *pitem;
 	Index		abslevel;
 	int			i;
 
-	Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
 	abslevel = root->query_level - var->varlevelsup;
 
-	/*
-	 * 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 Param
-	 * number.	As long as we check the vartype/typmod as well, I believe that
-	 * this sort of aliasing will cause no trouble.  The correct field should
-	 * get stored into the Param slot at execution in each part of the tree.
-	 */
+	/* If there's already a paramlist entry for this same Var, just use it */
 	i = 0;
 	foreach(ppl, root->glob->paramlist)
 	{
@@ -119,24 +109,76 @@ replace_outer_var(PlannerInfo *root, Var *var)
 				pvar->varattno == var->varattno &&
 				pvar->vartype == var->vartype &&
 				pvar->vartypmod == var->vartypmod)
-				break;
+				return i;
 		}
 		i++;
 	}
 
-	if (!ppl)
-	{
-		/* Nope, so make a new one */
-		var = (Var *) copyObject(var);
-		var->varlevelsup = 0;
+	/* Nope, so make a new one */
+	var = (Var *) copyObject(var);
+	var->varlevelsup = 0;
 
-		pitem = makeNode(PlannerParamItem);
-		pitem->item = (Node *) var;
-		pitem->abslevel = abslevel;
+	pitem = makeNode(PlannerParamItem);
+	pitem->item = (Node *) var;
+	pitem->abslevel = abslevel;
 
-		root->glob->paramlist = lappend(root->glob->paramlist, pitem);
-		/* i is already the correct index for the new item */
-	}
+	root->glob->paramlist = lappend(root->glob->paramlist, pitem);
+
+	/* i is already the correct list index for the new item */
+	return i;
+}
+
+/*
+ * Generate a Param node to replace the given Var,
+ * which is expected to have varlevelsup > 0 (ie, it is not local).
+ */
+static Param *
+replace_outer_var(PlannerInfo *root, Var *var)
+{
+	Param	   *retval;
+	int			i;
+
+	Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
+
+	/*
+	 * Find the Var in root->glob->paramlist, or add it if not present.
+	 *
+	 * 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 Param
+	 * number.	As long as we check the vartype/typmod as well, I believe that
+	 * this sort of aliasing will cause no trouble.  The correct field should
+	 * get stored into the Param slot at execution in each part of the tree.
+	 */
+	i = assign_param_for_var(root, var);
+
+	retval = makeNode(Param);
+	retval->paramkind = PARAM_EXEC;
+	retval->paramid = i;
+	retval->paramtype = var->vartype;
+	retval->paramtypmod = var->vartypmod;
+	retval->location = -1;
+
+	return retval;
+}
+
+/*
+ * Generate a Param node to replace the given Var, which will be supplied
+ * from an upper NestLoop join node.
+ *
+ * Because we allow nestloop and subquery Params to alias each other,
+ * this is effectively the same as replace_outer_var, except that we expect
+ * the Var to be local to the current query level.
+ */
+Param *
+assign_nestloop_param(PlannerInfo *root, Var *var)
+{
+	Param	   *retval;
+	int			i;
+
+	Assert(var->varlevelsup == 0);
+
+	i = assign_param_for_var(root, var);
 
 	retval = makeNode(Param);
 	retval->paramkind = PARAM_EXEC;
@@ -1773,8 +1815,9 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan, bool attach_initplans)
 	 *
 	 * Note: this is a bit overly generous since some parameters of upper
 	 * query levels might belong to query subtrees that don't include this
-	 * query.  However, valid_params is only a debugging crosscheck, so it
-	 * doesn't seem worth expending lots of cycles to try to be exact.
+	 * query, or might be nestloop params that won't be passed down at all.
+	 * However, valid_params is only a debugging crosscheck, so it doesn't
+	 * seem worth expending lots of cycles to try to be exact.
 	 */
 	valid_params = bms_copy(initSetParam);
 	paramid = 0;
@@ -1849,6 +1892,8 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
 {
 	finalize_primnode_context context;
 	int			locally_added_param;
+	Bitmapset  *nestloop_params;
+	Bitmapset  *child_params;
 
 	if (plan == NULL)
 		return NULL;
@@ -1856,6 +1901,7 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
 	context.root = root;
 	context.paramids = NULL;	/* initialize set to empty */
 	locally_added_param = -1;	/* there isn't one */
+	nestloop_params = NULL;		/* there aren't any */
 
 	/*
 	 * When we call finalize_primnode, context.paramids sets are automatically
@@ -2056,8 +2102,20 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
 			break;
 
 		case T_NestLoop:
-			finalize_primnode((Node *) ((Join *) plan)->joinqual,
-							  &context);
+			{
+				ListCell   *l;
+
+				finalize_primnode((Node *) ((Join *) plan)->joinqual,
+								  &context);
+				/* collect set of params that will be passed to right child */
+				foreach(l, ((NestLoop *) plan)->nestParams)
+				{
+					NestLoopParam *nlp = (NestLoopParam *) lfirst(l);
+
+					nestloop_params = bms_add_member(nestloop_params,
+													 nlp->paramno);
+				}
+			}
 			break;
 
 		case T_MergeJoin:
@@ -2120,17 +2178,32 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
 	}
 
 	/* Process left and right child plans, if any */
-	context.paramids = bms_add_members(context.paramids,
-									   finalize_plan(root,
-													 plan->lefttree,
-													 valid_params,
-													 scan_params));
-
-	context.paramids = bms_add_members(context.paramids,
-									   finalize_plan(root,
-													 plan->righttree,
-													 valid_params,
-													 scan_params));
+	child_params = finalize_plan(root,
+								 plan->lefttree,
+								 valid_params,
+								 scan_params);
+	context.paramids = bms_add_members(context.paramids, child_params);
+
+	if (nestloop_params)
+	{
+		/* right child can reference nestloop_params as well as valid_params */
+		child_params = finalize_plan(root,
+									 plan->righttree,
+									 bms_union(nestloop_params, valid_params),
+									 scan_params);
+		/* ... and they don't count as parameters used at my level */
+		child_params = bms_difference(child_params, nestloop_params);
+		bms_free(nestloop_params);
+	}
+	else
+	{
+		/* easy case */
+		child_params = finalize_plan(root,
+									 plan->righttree,
+									 valid_params,
+									 scan_params);
+	}
+	context.paramids = bms_add_members(context.paramids, child_params);
 
 	/*
 	 * Any locally generated parameter doesn't count towards its generating
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 119cc2505b2edeb6bb02b2e10e9212628648ae49..ecaaab5f75cff870269ae7671e8313128481b289 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.169 2010/07/09 14:06:01 rhaas Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.170 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,7 +82,7 @@ extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
 /*
  * prototypes from functions in execAmi.c
  */
-extern void ExecReScan(PlanState *node, ExprContext *exprCtxt);
+extern void ExecReScan(PlanState *node);
 extern void ExecMarkPos(PlanState *node);
 extern void ExecRestrPos(PlanState *node);
 extern bool ExecSupportsMarkRestore(NodeTag plantype);
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index 67cc71c84b6175d111f3afbd04b51c7720c2d82e..5e7ab5913b76cc82c7b9d16cd7d95505cafac226 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeAgg.h,v 1.32 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeAgg.h,v 1.33 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,7 +19,7 @@
 extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecAgg(AggState *node);
 extern void ExecEndAgg(AggState *node);
-extern void ExecReScanAgg(AggState *node, ExprContext *exprCtxt);
+extern void ExecReScanAgg(AggState *node);
 
 extern Size hash_agg_entry_size(int numAggs);
 
diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h
index fbecd8204948a8a074129eb74131b7f936a3219c..9e3f293785919fbe04371463bd9f33b263bdfcc7 100644
--- a/src/include/executor/nodeAppend.h
+++ b/src/include/executor/nodeAppend.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeAppend.h,v 1.30 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeAppend.h,v 1.31 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecAppend(AppendState *node);
 extern void ExecEndAppend(AppendState *node);
-extern void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt);
+extern void ExecReScanAppend(AppendState *node);
 
 #endif   /* NODEAPPEND_H */
diff --git a/src/include/executor/nodeBitmapAnd.h b/src/include/executor/nodeBitmapAnd.h
index 6a8bdf4363a5c3a54673711c8f21f6ffabe8d39f..fa09a790fb8b566367ee0445a382b71c376d47f0 100644
--- a/src/include/executor/nodeBitmapAnd.h
+++ b/src/include/executor/nodeBitmapAnd.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeBitmapAnd.h,v 1.8 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeBitmapAnd.h,v 1.9 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern BitmapAndState *ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags);
 extern Node *MultiExecBitmapAnd(BitmapAndState *node);
 extern void ExecEndBitmapAnd(BitmapAndState *node);
-extern void ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt);
+extern void ExecReScanBitmapAnd(BitmapAndState *node);
 
 #endif   /* NODEBITMAPAND_H */
diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h
index 174f60dd0a694e2b26448cfaa2a5deb7c86065e4..472181881ffa5853a7d392e57a48f0a14d2ce75a 100644
--- a/src/include/executor/nodeBitmapHeapscan.h
+++ b/src/include/executor/nodeBitmapHeapscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeBitmapHeapscan.h,v 1.8 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeBitmapHeapscan.h,v 1.9 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
 extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
-extern void ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
 
 #endif   /* NODEBITMAPHEAPSCAN_H */
diff --git a/src/include/executor/nodeBitmapIndexscan.h b/src/include/executor/nodeBitmapIndexscan.h
index 480494be0c8e5fbc8a1426e7f1b5c0ad86384bac..bb4b28cc1ae2433a7fe513837188dbc137d5c05e 100644
--- a/src/include/executor/nodeBitmapIndexscan.h
+++ b/src/include/executor/nodeBitmapIndexscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeBitmapIndexscan.h,v 1.8 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeBitmapIndexscan.h,v 1.9 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern BitmapIndexScanState *ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags);
 extern Node *MultiExecBitmapIndexScan(BitmapIndexScanState *node);
 extern void ExecEndBitmapIndexScan(BitmapIndexScanState *node);
-extern void ExecBitmapIndexReScan(BitmapIndexScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanBitmapIndexScan(BitmapIndexScanState *node);
 
 #endif   /* NODEBITMAPINDEXSCAN_H */
diff --git a/src/include/executor/nodeBitmapOr.h b/src/include/executor/nodeBitmapOr.h
index a9ada8f63f98ac95079653dee8a084437d9134a8..8987c700c5b0492bef5cb11cba7d4028564b4550 100644
--- a/src/include/executor/nodeBitmapOr.h
+++ b/src/include/executor/nodeBitmapOr.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeBitmapOr.h,v 1.8 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeBitmapOr.h,v 1.9 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern BitmapOrState *ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags);
 extern Node *MultiExecBitmapOr(BitmapOrState *node);
 extern void ExecEndBitmapOr(BitmapOrState *node);
-extern void ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt);
+extern void ExecReScanBitmapOr(BitmapOrState *node);
 
 #endif   /* NODEBITMAPOR_H */
diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h
index 54008f8b74541aff4b8cfb5c3885540f85f32c0c..22e6dd21520c2859f66c0b3e751fc0c401dea6c8 100644
--- a/src/include/executor/nodeCtescan.h
+++ b/src/include/executor/nodeCtescan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeCtescan.h,v 1.4 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeCtescan.h,v 1.5 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecCteScan(CteScanState *node);
 extern void ExecEndCteScan(CteScanState *node);
-extern void ExecCteScanReScan(CteScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanCteScan(CteScanState *node);
 
 #endif   /* NODECTESCAN_H */
diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h
index 21e868aff64e6f6389ee561161aa112750696620..1584783ed0ad962a89058a4126af5b4339a2b132 100644
--- a/src/include/executor/nodeFunctionscan.h
+++ b/src/include/executor/nodeFunctionscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeFunctionscan.h,v 1.15 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeFunctionscan.h,v 1.16 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
 extern void ExecEndFunctionScan(FunctionScanState *node);
-extern void ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanFunctionScan(FunctionScanState *node);
 
 #endif   /* NODEFUNCTIONSCAN_H */
diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h
index a7362b2a79d0bd9b0a594fbfd371fafefd324b70..8af917a83f78bacdc6426303aa8cba7bd4ee1721 100644
--- a/src/include/executor/nodeGroup.h
+++ b/src/include/executor/nodeGroup.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeGroup.h,v 1.35 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeGroup.h,v 1.36 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecGroup(GroupState *node);
 extern void ExecEndGroup(GroupState *node);
-extern void ExecReScanGroup(GroupState *node, ExprContext *exprCtxt);
+extern void ExecReScanGroup(GroupState *node);
 
 #endif   /* NODEGROUP_H */
diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h
index c5e18a93e7de1b7c910407593c03a45d8c196cbb..53348c435fb9e7e94169009afdf8bd4bba10d937 100644
--- a/src/include/executor/nodeHash.h
+++ b/src/include/executor/nodeHash.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.49 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.50 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,7 @@ extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecHash(HashState *node);
 extern Node *MultiExecHash(HashState *node);
 extern void ExecEndHash(HashState *node);
-extern void ExecReScanHash(HashState *node, ExprContext *exprCtxt);
+extern void ExecReScanHash(HashState *node);
 
 extern HashJoinTable ExecHashTableCreate(Hash *node, List *hashOperators);
 extern void ExecHashTableDestroy(HashJoinTable hashtable);
diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h
index 462410d95c7bc1e2305de0fec378241904240711..0a68e65f51c01d6c15cd405fb519a8fa22b0d242 100644
--- a/src/include/executor/nodeHashjoin.h
+++ b/src/include/executor/nodeHashjoin.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeHashjoin.h,v 1.40 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeHashjoin.h,v 1.41 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,7 +20,7 @@
 extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecHashJoin(HashJoinState *node);
 extern void ExecEndHashJoin(HashJoinState *node);
-extern void ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt);
+extern void ExecReScanHashJoin(HashJoinState *node);
 
 extern void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue,
 					  BufFile **fileptr);
diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h
index 15608cdff8b7d2a9f36bc23adc6de2343fa40f9a..2a740a4f3e42e20d83c8058f964230ba23ace93e 100644
--- a/src/include/executor/nodeIndexscan.h
+++ b/src/include/executor/nodeIndexscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.36 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeIndexscan.h,v 1.37 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,7 @@ extern TupleTableSlot *ExecIndexScan(IndexScanState *node);
 extern void ExecEndIndexScan(IndexScanState *node);
 extern void ExecIndexMarkPos(IndexScanState *node);
 extern void ExecIndexRestrPos(IndexScanState *node);
-extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanIndexScan(IndexScanState *node);
 
 /* routines exported to share code with nodeBitmapIndexscan.c */
 extern void ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h
index 33cd5e298d895a4aa56d56861419b97db34168cd..1e57eca5599bdd546a07c1367939b7c5dd56f0f4 100644
--- a/src/include/executor/nodeLimit.h
+++ b/src/include/executor/nodeLimit.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeLimit.h,v 1.18 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeLimit.h,v 1.19 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecLimit(LimitState *node);
 extern void ExecEndLimit(LimitState *node);
-extern void ExecReScanLimit(LimitState *node, ExprContext *exprCtxt);
+extern void ExecReScanLimit(LimitState *node);
 
 #endif   /* NODELIMIT_H */
diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h
index c2ea69611ee168eff6e8616ab250280ca69f0a7c..b3bb3a277c5932400f9a5634ffef55e9897048b0 100644
--- a/src/include/executor/nodeLockRows.h
+++ b/src/include/executor/nodeLockRows.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeLockRows.h,v 1.2 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeLockRows.h,v 1.3 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecLockRows(LockRowsState *node);
 extern void ExecEndLockRows(LockRowsState *node);
-extern void ExecReScanLockRows(LockRowsState *node, ExprContext *exprCtxt);
+extern void ExecReScanLockRows(LockRowsState *node);
 
 #endif   /* NODELOCKROWS_H */
diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h
index bc350d1bde6ba78984be1ab97b8896858c341cdf..ff1087b0cc1ec68825cfff2b36e60344544207b1 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeMaterial.h,v 1.30 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeMaterial.h,v 1.31 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,6 @@ extern TupleTableSlot *ExecMaterial(MaterialState *node);
 extern void ExecEndMaterial(MaterialState *node);
 extern void ExecMaterialMarkPos(MaterialState *node);
 extern void ExecMaterialRestrPos(MaterialState *node);
-extern void ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt);
+extern void ExecReScanMaterial(MaterialState *node);
 
 #endif   /* NODEMATERIAL_H */
diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h
index 24b4835ec0860f7e07da11a2d4a684ac16ccd117..6a176d90f061d9814e31edc27c943e9eaa62a362 100644
--- a/src/include/executor/nodeMergejoin.h
+++ b/src/include/executor/nodeMergejoin.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeMergejoin.h,v 1.29 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeMergejoin.h,v 1.30 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node);
 extern void ExecEndMergeJoin(MergeJoinState *node);
-extern void ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt);
+extern void ExecReScanMergeJoin(MergeJoinState *node);
 
 #endif   /* NODEMERGEJOIN_H */
diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h
index a503581943d645d09d48642dc24cfac928fc8976..373ae1c13f421a15588df618e37a989d5623915b 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeModifyTable.h,v 1.2 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeModifyTable.h,v 1.3 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,6 @@
 extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
 extern void ExecEndModifyTable(ModifyTableState *node);
-extern void ExecReScanModifyTable(ModifyTableState *node, ExprContext *exprCtxt);
+extern void ExecReScanModifyTable(ModifyTableState *node);
 
 #endif   /* NODEMODIFYTABLE_H */
diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h
index ce960de8f2637d4c3d3c54869e081c7eb1069f50..01e22b60822bf2a0bb09782e089aaf7d77fd46eb 100644
--- a/src/include/executor/nodeNestloop.h
+++ b/src/include/executor/nodeNestloop.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeNestloop.h,v 1.30 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeNestloop.h,v 1.31 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
 extern void ExecEndNestLoop(NestLoopState *node);
-extern void ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt);
+extern void ExecReScanNestLoop(NestLoopState *node);
 
 #endif   /* NODENESTLOOP_H */
diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h
index 8d8c99b0e67e02ce152472a3f023aa9a86a98b49..87d9888f86cc975ac381c785e402589ecc2a669a 100644
--- a/src/include/executor/nodeRecursiveunion.h
+++ b/src/include/executor/nodeRecursiveunion.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeRecursiveunion.h,v 1.4 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeRecursiveunion.h,v 1.5 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecRecursiveUnion(RecursiveUnionState *node);
 extern void ExecEndRecursiveUnion(RecursiveUnionState *node);
-extern void ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt);
+extern void ExecReScanRecursiveUnion(RecursiveUnionState *node);
 
 #endif   /* NODERECURSIVEUNION_H */
diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h
index 89085e8945a21b21cbc53a83118afd6e280281ba..4c6234d6882be2bb82bf869fc5d8d0c2170b0afe 100644
--- a/src/include/executor/nodeResult.h
+++ b/src/include/executor/nodeResult.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeResult.h,v 1.28 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeResult.h,v 1.29 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,6 @@ extern TupleTableSlot *ExecResult(ResultState *node);
 extern void ExecEndResult(ResultState *node);
 extern void ExecResultMarkPos(ResultState *node);
 extern void ExecResultRestrPos(ResultState *node);
-extern void ExecReScanResult(ResultState *node, ExprContext *exprCtxt);
+extern void ExecReScanResult(ResultState *node);
 
 #endif   /* NODERESULT_H */
diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h
index 6184c3edcdbfaff6ddba6472929c8fc9c1d24ea7..334fd44920aad11507b4571a6d952f20ef957eeb 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeSeqscan.h,v 1.29 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeSeqscan.h,v 1.30 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,6 @@ extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
 extern void ExecEndSeqScan(SeqScanState *node);
 extern void ExecSeqMarkPos(SeqScanState *node);
 extern void ExecSeqRestrPos(SeqScanState *node);
-extern void ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanSeqScan(SeqScanState *node);
 
 #endif   /* NODESEQSCAN_H */
diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h
index 791b6595aa0888131a22dc20c3eb0937aa1ef469..cdb0579afd186ed48a7af3b6cbaa6966796b69e2 100644
--- a/src/include/executor/nodeSetOp.h
+++ b/src/include/executor/nodeSetOp.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeSetOp.h,v 1.18 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeSetOp.h,v 1.19 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecSetOp(SetOpState *node);
 extern void ExecEndSetOp(SetOpState *node);
-extern void ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt);
+extern void ExecReScanSetOp(SetOpState *node);
 
 #endif   /* NODESETOP_H */
diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h
index d5a87e892307886bd99af5b65ee99ed8e9601d9e..ee63274af2d6f1dae55d64af7160fedc7de5f106 100644
--- a/src/include/executor/nodeSort.h
+++ b/src/include/executor/nodeSort.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeSort.h,v 1.27 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeSort.h,v 1.28 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,6 @@ extern TupleTableSlot *ExecSort(SortState *node);
 extern void ExecEndSort(SortState *node);
 extern void ExecSortMarkPos(SortState *node);
 extern void ExecSortRestrPos(SortState *node);
-extern void ExecReScanSort(SortState *node, ExprContext *exprCtxt);
+extern void ExecReScanSort(SortState *node);
 
 #endif   /* NODESORT_H */
diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h
index 387a12b045a8e6985c62c8c1cab7e9f6b2e40713..1139ce3f3e29e0cea5b75dbdede811a84b6859aa 100644
--- a/src/include/executor/nodeSubqueryscan.h
+++ b/src/include/executor/nodeSubqueryscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeSubqueryscan.h,v 1.18 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeSubqueryscan.h,v 1.19 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
 extern void ExecEndSubqueryScan(SubqueryScanState *node);
-extern void ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanSubqueryScan(SubqueryScanState *node);
 
 #endif   /* NODESUBQUERYSCAN_H */
diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h
index 1bbbb1e52f8ee50c094a9ebd54ce12ab3ae63bc9..45b9b814cb64a74927e264c35e0d161a7a1651e6 100644
--- a/src/include/executor/nodeTidscan.h
+++ b/src/include/executor/nodeTidscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeTidscan.h,v 1.22 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeTidscan.h,v 1.23 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,6 @@ extern TupleTableSlot *ExecTidScan(TidScanState *node);
 extern void ExecEndTidScan(TidScanState *node);
 extern void ExecTidMarkPos(TidScanState *node);
 extern void ExecTidRestrPos(TidScanState *node);
-extern void ExecTidReScan(TidScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanTidScan(TidScanState *node);
 
 #endif   /* NODETIDSCAN_H */
diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h
index 4fd4d92d4db6134ed1988baa91df91f9cd8050c4..1c57a23fb16f05f654bf8dab0eae148e524d8ceb 100644
--- a/src/include/executor/nodeUnique.h
+++ b/src/include/executor/nodeUnique.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeUnique.h,v 1.27 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeUnique.h,v 1.28 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecUnique(UniqueState *node);
 extern void ExecEndUnique(UniqueState *node);
-extern void ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt);
+extern void ExecReScanUnique(UniqueState *node);
 
 #endif   /* NODEUNIQUE_H */
diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h
index 81b2f4108d9812caf9442b440144807dc5884be0..049d66923a31f7f6a92510302f91a0f9d8f286db 100644
--- a/src/include/executor/nodeValuesscan.h
+++ b/src/include/executor/nodeValuesscan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeValuesscan.h,v 1.7 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeValuesscan.h,v 1.8 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,6 @@ extern TupleTableSlot *ExecValuesScan(ValuesScanState *node);
 extern void ExecEndValuesScan(ValuesScanState *node);
 extern void ExecValuesMarkPos(ValuesScanState *node);
 extern void ExecValuesRestrPos(ValuesScanState *node);
-extern void ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanValuesScan(ValuesScanState *node);
 
 #endif   /* NODEVALUESSCAN_H */
diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h
index 759120a7e7c9622e1e02ce1ab4e7b8ec2dc3740d..5e944e45a8a09a920351a8e19cd00f28e71ec750 100644
--- a/src/include/executor/nodeWindowAgg.h
+++ b/src/include/executor/nodeWindowAgg.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeWindowAgg.h,v 1.4 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeWindowAgg.h,v 1.5 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecWindowAgg(WindowAggState *node);
 extern void ExecEndWindowAgg(WindowAggState *node);
-extern void ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt);
+extern void ExecReScanWindowAgg(WindowAggState *node);
 
 #endif   /* NODEWINDOWAGG_H */
diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h
index cda6d0a91e550e4f13b91b986a573c2cb96b70d1..53e465ce3354407f755af4070cde280e2776f9ec 100644
--- a/src/include/executor/nodeWorktablescan.h
+++ b/src/include/executor/nodeWorktablescan.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeWorktablescan.h,v 1.4 2010/01/02 16:58:03 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeWorktablescan.h,v 1.5 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,6 @@
 extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
 extern TupleTableSlot *ExecWorkTableScan(WorkTableScanState *node);
 extern void ExecEndWorkTableScan(WorkTableScanState *node);
-extern void ExecWorkTableScanReScan(WorkTableScanState *node, ExprContext *exprCtxt);
+extern void ExecReScanWorkTableScan(WorkTableScanState *node);
 
 #endif   /* NODEWORKTABLESCAN_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 401b69e08839be9ebb9e52f11901ae20a03024c1..24ddb3f0d3ffccb804ad12502c7a3c892ff1b011 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.234 2010/03/28 22:59:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.235 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -74,6 +74,7 @@ typedef enum NodeTag
 	T_LockRows,
 	T_Limit,
 	/* these aren't subclasses of Plan: */
+	T_NestLoopParam,
 	T_PlanRowMark,
 	T_PlanInvalItem,
 
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 79876100d5ae6a40e5d10a49c9fb01dd73223f54..5ca1b0f8fbe52a97d5f7da6f2e13389310236e28 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.117 2010/02/26 02:01:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.118 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -432,13 +432,26 @@ typedef struct Join
 
 /* ----------------
  *		nest loop join node
+ *
+ * The nestParams list identifies any executor Params that must be passed
+ * into execution of the inner subplan carrying values from the current row
+ * of the outer subplan.  Currently we restrict these values to be simple
+ * Vars, but perhaps someday that'd be worth relaxing.
  * ----------------
  */
 typedef struct NestLoop
 {
 	Join		join;
+	List	   *nestParams;		/* list of NestLoopParam nodes */
 } NestLoop;
 
+typedef struct NestLoopParam
+{
+	NodeTag		type;
+	int			paramno;		/* number of the PARAM_EXEC Param to set */
+	Var		   *paramval;		/* outer-relation Var to assign to Param */
+} NestLoopParam;
+
 /* ----------------
  *		merge join node
  *
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 3fc3d3483bcca1bf37df6ad81ec9e4c639a2ee8f..484eb0d62738e6884534a19e83ced95389c90936 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.156 2010/02/26 02:01:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.157 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,7 +175,8 @@ typedef struct Const
  *				Such parameters are numbered from 1 to n.
  *
  *		PARAM_EXEC:  The parameter is an internal executor parameter, used
- *				for passing values into and out of sub-queries.
+ *				for passing values into and out of sub-queries or from
+ *				nestloop joins to their inner scans.
  *				For historical reasons, such parameters are numbered from 0.
  *				These numbers are independent of PARAM_EXTERN numbers.
  *
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index a684f192220bd94eeb6c24b4e47acf50c732f115..3374e5fae745195276b57b823d4fbacc6391b594 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.187 2010/07/06 19:19:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.188 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -209,6 +209,10 @@ typedef struct PlannerInfo
 	int			wt_param_id;	/* PARAM_EXEC ID for the work table */
 	struct Plan *non_recursive_plan;	/* plan for non-recursive term */
 
+	/* These fields are workspace for createplan.c */
+	Relids		curOuterRels;			/* outer rels above current node */
+	List	   *curOuterParams;			/* not-yet-assigned NestLoopParams */
+
 	/* optional private data for join_search_hook, e.g., GEQO */
 	void	   *join_search_private;
 } PlannerInfo;
@@ -1330,16 +1334,20 @@ typedef struct PlaceHolderInfo
 /*
  * 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.
+ * around from one plan node to another.  They can be used to pass values
+ * down into subqueries (for outer references in subqueries), or up out of
+ * subqueries (for the results of a subplan), or from a NestLoop plan node
+ * into its inner relation (when the inner scan is parameterized with values
+ * from the outer relation).  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
+ * down because subqueries have outer references to it, or must be passed
+ * from a NestLoop node of that level to its inner scan.  The varlevelsup
  * value in the Var will always be zero.
  *
  * An Aggref (with an expression tree representing its argument): the slot
@@ -1352,7 +1360,13 @@ typedef struct PlaceHolderInfo
  * 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.
+ * but we do not bother to do this for Aggrefs, and it would be incorrect
+ * to do so for Param slots.  Duplicate detection is actually *necessary*
+ * in the case of NestLoop parameters since it serves to match up the usage
+ * of a Param (in the inner scan) with the assignment of the value (in the
+ * NestLoop node).  This might result in the same PARAM_EXEC slot being used
+ * by multiple NestLoop nodes or SubPlan nodes, but no harm is done since
+ * the same value would be assigned anyway.
  */
 typedef struct PlannerParamItem
 {
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index 1bc52cc14c8f97499c2143075311793eef0028b8..abbbd58c24ca91af1a7b341d063799bdc4964e7f 100644
--- a/src/include/optimizer/subselect.h
+++ b/src/include/optimizer/subselect.h
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.39 2010/01/02 16:58:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.40 2010/07/12 17:01:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,7 @@ extern void SS_finalize_plan(PlannerInfo *root, Plan *plan,
 				 bool attach_initplans);
 extern Param *SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
 						   Oid resulttype, int32 resulttypmod);
+extern Param *assign_nestloop_param(PlannerInfo *root, Var *var);
 extern int	SS_assign_special_param(PlannerInfo *root);
 
 #endif   /* SUBSELECT_H */
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index 66736a3564c41e6c74f120f54a21634c953ca994..f1466e0d442f484e11b8c4b2404f2783fafc7bea 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -281,7 +281,7 @@ INSERT INTO foorescan values(5007,5,'abc.5007.5');
 INSERT INTO foorescan values(5008,5,'abc.5008.5');
 INSERT INTO foorescan values(5009,5,'abc.5009.5');
 CREATE FUNCTION foorescan(int,int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid >= $1 and fooid < $2 ;' LANGUAGE SQL;
---invokes ExecFunctionReScan
+--invokes ExecReScanFunctionScan
 SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM foorescan(5002,5004)) ORDER BY 1,2;
  fooid | foosubid |  fooname   
 -------+----------+------------
@@ -298,7 +298,7 @@ SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM foorescan(5002,500
 (10 rows)
 
 CREATE VIEW vw_foorescan AS SELECT * FROM foorescan(5002,5004);
---invokes ExecFunctionReScan
+--invokes ExecReScanFunctionScan
 SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM vw_foorescan) ORDER BY 1,2;
  fooid | foosubid |  fooname   
 -------+----------+------------
@@ -323,7 +323,7 @@ INSERT INTO barrescan values(5006);
 INSERT INTO barrescan values(5007);
 INSERT INTO barrescan values(5008);
 CREATE FUNCTION foorescan(int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid = $1;' LANGUAGE SQL;
---invokes ExecFunctionReScan with chgParam != NULL
+--invokes ExecReScanFunctionScan with chgParam != NULL
 SELECT f.* FROM barrescan b, foorescan f WHERE f.fooid = b.fooid AND b.fooid IN (SELECT fooid FROM foorescan(b.fooid)) ORDER BY 1,2;
  fooid | foosubid |  fooname   
 -------+----------+------------
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index db74770228d291bcaa93b0efdccc349bb05f59c8..d1b9db7e51396c18056008b87511e066789ca7e8 100644
--- a/src/test/regress/sql/rangefuncs.sql
+++ b/src/test/regress/sql/rangefuncs.sql
@@ -164,12 +164,12 @@ INSERT INTO foorescan values(5009,5,'abc.5009.5');
 
 CREATE FUNCTION foorescan(int,int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid >= $1 and fooid < $2 ;' LANGUAGE SQL;
 
---invokes ExecFunctionReScan
+--invokes ExecReScanFunctionScan
 SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM foorescan(5002,5004)) ORDER BY 1,2;
 
 CREATE VIEW vw_foorescan AS SELECT * FROM foorescan(5002,5004);
 
---invokes ExecFunctionReScan
+--invokes ExecReScanFunctionScan
 SELECT * FROM foorescan f WHERE f.fooid IN (SELECT fooid FROM vw_foorescan) ORDER BY 1,2;
 
 CREATE TABLE barrescan (fooid int primary key);
@@ -182,7 +182,7 @@ INSERT INTO barrescan values(5008);
 
 CREATE FUNCTION foorescan(int) RETURNS setof foorescan AS 'SELECT * FROM foorescan WHERE fooid = $1;' LANGUAGE SQL;
 
---invokes ExecFunctionReScan with chgParam != NULL
+--invokes ExecReScanFunctionScan with chgParam != NULL
 SELECT f.* FROM barrescan b, foorescan f WHERE f.fooid = b.fooid AND b.fooid IN (SELECT fooid FROM foorescan(b.fooid)) ORDER BY 1,2;
 SELECT b.fooid, max(f.foosubid) FROM barrescan b, foorescan f WHERE f.fooid = b.fooid AND b.fooid IN (SELECT fooid FROM foorescan(b.fooid)) GROUP BY b.fooid ORDER BY 1,2;