* 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 $
  *
  *-------------------------------------------------------------------------
  */
  *
  * 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)
    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:
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    /*
     * rescan plan
     */
-   ExecReScan(queryDesc->planstate, NULL);
+   ExecReScan(queryDesc->planstate);
 
    MemoryContextSwitchTo(oldcontext);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    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);
    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))
    {
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
                     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);
 }
 
 /* ----------------------------------------------------------------
- *     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 = ¶mInfo->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 = ¶mInfo->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 */
 }
 
 
            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);
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
+ExecReScanAgg(AggState *node)
 {
    ExprContext *econtext = node->ss.ps.ps_ExprContext;
    int         aggno;
         * 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;
     * 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);
 }
 
 /*
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
+ExecReScanAppend(AppendState *node)
 {
    int         i;
 
 
        /*
         * 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);
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanBitmapAnd(BitmapAndState *node, ExprContext *exprCtxt)
+ExecReScanBitmapAnd(BitmapAndState *node)
 {
    int         i;
 
            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);
    }
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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"
 }
 
 /* ----------------------------------------------------------------
- *     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);
 
    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);
 }
 
 /* ----------------------------------------------------------------
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  * 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"
    if (!node->biss_RuntimeKeysReady &&
        (node->biss_NumRuntimeKeys != 0 || node->biss_NumArrayKeys != 0))
    {
-       ExecReScan((PlanState *) node, NULL);
+       ExecReScan((PlanState *) node);
        doscan = node->biss_RuntimeKeysReady;
    }
    else
 }
 
 /* ----------------------------------------------------------------
- *     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
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanBitmapOr(BitmapOrState *node, ExprContext *exprCtxt)
+ExecReScanBitmapOr(BitmapOrState *node)
 {
    int         i;
 
            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);
    }
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 /* ----------------------------------------------------------------
- *     ExecCteScanReScan
+ *     ExecReScanCteScan
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecCteScanReScan(CteScanState *node, ExprContext *exprCtxt)
+ExecReScanCteScan(CteScanState *node)
 {
    Tuplestorestate *tuplestorestate = node->leader->cte_table;
 
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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"
 
 }
 
 /* ----------------------------------------------------------------
- *     ExecFunctionReScan
+ *     ExecReScanFunctionScan
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
+ExecReScanFunctionScan(FunctionScanState *node)
 {
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 
  *   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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 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);
 }
 
 
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 void
-ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
+ExecReScanHashJoin(HashJoinState *node)
 {
    /*
     * In a multi-batch join, we currently have to do rescans the hard way,
    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.
             * 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);
        }
    }
 
     * 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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.
     * 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,
 }
 
 /* ----------------------------------------------------------------
- *     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 */
 
        /*
         * 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
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 void
-ExecReScanLimit(LimitState *node, ExprContext *exprCtxt)
+ExecReScanLimit(LimitState *node)
 {
    /*
     * Recompute limit/offset in case parameters changed, and reset the state
     * 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 /* ----------------------------------------------------------------
- *     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;
         * 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
         * 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;
    }
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt)
+ExecReScanMergeJoin(MergeJoinState *node)
 {
    ExecClearTuple(node->mj_MarkedTupleSlot);
 
     * 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);
 
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanModifyTable(ModifyTableState *node, ExprContext *exprCtxt)
+ExecReScanModifyTable(ModifyTableState *node)
 {
    /*
     * Currently, we don't need to support rescan on ModifyTable nodes. The
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 TupleTableSlot *
 ExecNestLoop(NestLoopState *node)
 {
+   NestLoop   *nl;
    PlanState  *innerPlan;
    PlanState  *outerPlan;
    TupleTableSlot *outerTupleSlot;
    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);
            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);
        }
 
        /*
    /*
     * 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
  * ----------------------------------------------------------------
  */
 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;
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 /* ----------------------------------------------------------------
- *     ExecRecursiveUnionReScan
+ *     ExecReScanRecursiveUnion
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecRecursiveUnionReScan(RecursiveUnionState *node, ExprContext *exprCtxt)
+ExecReScanRecursiveUnion(RecursiveUnionState *node)
 {
    PlanState  *outerPlan = outerPlanState(node);
    PlanState  *innerPlan = innerPlanState(node);
     * non-recursive term.
     */
    if (outerPlan->chgParam == NULL)
-       ExecReScan(outerPlan, exprCtxt);
+       ExecReScan(outerPlan);
 
    /* Release any hashtable storage */
    if (node->tableContext)
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 void
-ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
+ExecReScanResult(ResultState *node)
 {
    node->rs_done = false;
    node->ps.ps_TupFromTlist = false;
 
    /*
     * 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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
  */
  */
 
 /* ----------------------------------------------------------------
- *     ExecSeqReScan
+ *     ExecReScanSeqScan
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt)
+ExecReScanSeqScan(SeqScanState *node)
 {
    HeapScanDesc scan;
 
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 void
-ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
+ExecReScanSetOp(SetOpState *node)
 {
    ExecClearTuple(node->ps.ps_ResultTupleSlot);
    node->setop_done = false;
         * 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;
     * 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 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)
     *
     * 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)
         * 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);
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    /*
     * 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
    /*
     * Reset subplan to start.
     */
-   ExecReScan(planstate, NULL);
+   ExecReScan(planstate);
 
    /*
     * Scan the subplan and load the hash table(s).  Note that when there are
  *
  *     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.
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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"
 }
 
 /* ----------------------------------------------------------------
- *     ExecSubqueryReScan
+ *     ExecReScanSubqueryScan
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
+ExecReScanSubqueryScan(SubqueryScanState *node)
 {
    ExecScanReScan(&node->ss);
 
     * first ExecProcNode.
     */
    if (node->subplan->chgParam == NULL)
-       ExecReScan(node->subplan, NULL);
+       ExecReScan(node->subplan);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *
  *     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.
 }
 
 /* ----------------------------------------------------------------
- *     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;
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 void
-ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
+ExecReScanUnique(UniqueState *node)
 {
    /* must clear result tuple so first input tuple is returned */
    ExecClearTuple(node->ps.ps_ResultTupleSlot);
     * 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);
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *     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"
 
 }
 
 /* ----------------------------------------------------------------
- *     ExecValuesReScan
+ *     ExecReScanValuesScan
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
+ExecReScanValuesScan(ValuesScanState *node)
 {
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  * -----------------
  */
 void
-ExecReScanWindowAgg(WindowAggState *node, ExprContext *exprCtxt)
+ExecReScanWindowAgg(WindowAggState *node)
 {
    ExprContext *econtext = node->ss.ps.ps_ExprContext;
 
     * 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);
 }
 
 /*
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 /* ----------------------------------------------------------------
- *     ExecWorkTableScanReScan
+ *     ExecReScanWorkTableScan
  *
  *     Rescans the relation.
  * ----------------------------------------------------------------
  */
 void
-ExecWorkTableScanReScan(WorkTableScanState *node, ExprContext *exprCtxt)
+ExecReScanWorkTableScan(WorkTableScanState *node)
 {
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
 
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
     */
    CopyJoinFields((Join *) from, (Join *) newnode);
 
+   /*
+    * copy remainder of node
+    */
+   COPY_NODE_FIELD(nestParams);
+
    return newnode;
 }
 
    return newnode;
 }
 
+/*
+ * _copyNestLoopParam
+ */
+static NestLoopParam *
+_copyNestLoopParam(NestLoopParam *from)
+{
+   NestLoopParam *newnode = makeNode(NestLoopParam);
+
+   COPY_SCALAR_FIELD(paramno);
+   COPY_NODE_FIELD(paramval);
+
+   return newnode;
+}
+
 /*
  * _copyPlanRowMark
  */
        case T_Limit:
            retval = _copyLimit(from);
            break;
+       case T_NestLoopParam:
+           retval = _copyNestLoopParam(from);
+           break;
        case T_PlanRowMark:
            retval = _copyPlanRowMark(from);
            break;
 
  *
  *
  * 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*
    WRITE_NODE_TYPE("NESTLOOP");
 
    _outJoinPlanInfo(str, (Join *) node);
+
+   WRITE_NODE_FIELD(nestParams);
 }
 
 static void
    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)
 {
    WRITE_BOOL_FIELD(hasPseudoConstantQuals);
    WRITE_BOOL_FIELD(hasRecursion);
    WRITE_INT_FIELD(wt_param_id);
+   WRITE_BITMAPSET_FIELD(curOuterRels);
+   WRITE_NODE_FIELD(curOuterParams);
 }
 
 static void
            case T_Limit:
                _outLimit(str, obj);
                break;
+           case T_NestLoopParam:
+               _outNestLoopParam(str, obj);
+               break;
            case T_PlanRowMark:
                _outPlanRowMark(str, obj);
                break;
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 #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"
 #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);
                      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);
 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,
 
 /*
  * 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.
  *
 {
    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:
    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)
    {
                                                 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,
    {
        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);
    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);
    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)
     * 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
    /* 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,
                *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
    {
                     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
        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);
  *
  *****************************************************************************/
 
+/*
+ * 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
  * 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;
 
    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))
        {
 make_nestloop(List *tlist,
              List *joinclauses,
              List *otherclauses,
+             List *nestParams,
              Plan *lefttree,
              Plan *righttree,
              JoinType jointype)
    plan->righttree = righttree;
    node->join.jointype = jointype;
    node->join.joinqual = joinclauses;
+   node->nestParams = nestParams;
 
    return node;
 }
 
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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);
        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;
  *   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)
    /* 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))
    {
    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
  *
  * 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.
        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;
        }
 
 
    /*
     * 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.
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 /*
- * 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)
    {
                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;
     *
     * 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;
 {
    finalize_primnode_context context;
    int         locally_added_param;
+   Bitmapset  *nestloop_params;
+   Bitmapset  *child_params;
 
    if (plan == NULL)
        return NULL;
    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
            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:
    }
 
    /* 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
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * 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);
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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);
 
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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);
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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);
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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,
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 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 */
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    T_LockRows,
    T_Limit,
    /* these aren't subclasses of Plan: */
+   T_NestLoopParam,
    T_PlanRowMark,
    T_PlanInvalItem,
 
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 
 /* ----------------
  *     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
  *
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
  *             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.
  *
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
    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;
 /*
  * 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
  * 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
 {
 
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
                 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 */
 
 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   
 -------+----------+------------
 (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   
 -------+----------+------------
 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   
 -------+----------+------------
 
 
 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);
 
 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;