Support for subselects.
authorVadim B. Mikheev
Fri, 13 Feb 1998 03:26:53 +0000 (03:26 +0000)
committerVadim B. Mikheev
Fri, 13 Feb 1998 03:26:53 +0000 (03:26 +0000)
ExecReScan for nodeAgg, nodeHash, nodeHashjoin, nodeNestloop and nodeResult.
Fixed ExecReScan for nodeMaterial.
Get rid of #ifdef INDEXSCAN_PATCH.
Get rid of ExecMarkPos and ExecRestrPos in nodeNestloop.

15 files changed:
src/backend/executor/Makefile
src/backend/executor/execAmi.c
src/backend/executor/execMain.c
src/backend/executor/execProcnode.c
src/backend/executor/execQual.c
src/backend/executor/execUtils.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeIndexscan.c
src/backend/executor/nodeMaterial.c
src/backend/executor/nodeNestloop.c
src/backend/executor/nodeResult.c
src/backend/executor/nodeSubplan.c [new file with mode: 0644]

index b1ebb0b2155e7aef542aeef1feead1bb4b965901..9ae3cfc351880633704b6c72d8bc1e1d60b0eb50 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for executor
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.5 1997/12/20 00:23:37 scrappy Exp $
+#    $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.6 1998/02/13 03:26:35 vadim Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -20,7 +20,7 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
        execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \
        nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
        nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSort.o \
-       nodeUnique.o nodeTee.o nodeGroup.o spi.o
+       nodeUnique.o nodeTee.o nodeGroup.o spi.o nodeSubplan.o
 
 all: SUBSYS.o
 
index 2349f32411e0e63f0e747e7d1fb3d8c0a4162e08..759d17be4fd51447524269dcdd7916d5bc8f4699 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.16 1998/01/16 23:19:47 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.17 1998/02/13 03:26:36 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/nodeIndexscan.h"
 #include "executor/nodeSort.h"
 #include "executor/nodeTee.h"
+#include "executor/nodeMaterial.h"
+#include "executor/nodeNestloop.h"
+#include "executor/nodeHashjoin.h"
+#include "executor/nodeHash.h"
+#include "executor/nodeAgg.h"
+#include "executor/nodeResult.h"
+#include "executor/nodeSubplan.h"
 #include "executor/execdebug.h"
 #include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */
 #include "access/genam.h"
@@ -287,35 +294,82 @@ ExecCloseR(Plan *node)
 void
 ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
 {
+
+   if ( node->chgParam != NULL )   /* Wow! */
+   {
+       List   *lst;
+       
+       foreach (lst, node->initPlan)
+       {
+           Plan   *splan = ((SubPlan*) lfirst (lst))->plan;
+           if ( splan->extParam != NULL )  /* don't care about child locParam */
+               SetChangedParamList (splan, node->chgParam);
+           if ( splan->chgParam != NULL )
+               ExecReScanSetParamPlan ((SubPlan*) lfirst (lst), node);
+       }
+       foreach (lst, node->subPlan)
+       {
+           Plan   *splan = ((SubPlan*) lfirst (lst))->plan;
+           if ( splan->extParam != NULL )
+               SetChangedParamList (splan, node->chgParam);
+       }
+       /* Well. Now set chgParam for left/right trees. */
+       if ( node->lefttree != NULL )
+           SetChangedParamList (node->lefttree, node->chgParam);
+       if ( node->righttree != NULL )
+           SetChangedParamList (node->righttree, node->chgParam);
+   }
+
    switch (nodeTag(node))
    {
-           case T_SeqScan:
+       case T_SeqScan:
            ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
-           return;
+           break;
 
        case T_IndexScan:
            ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
-           return;
+           break;
 
        case T_Material:
+           ExecMaterialReScan((Material*) node, exprCtxt, parent);
+           break;
 
-           /*
-            * the first call to ExecReScan should have no effect because
-            * everything is initialized properly already.  the following
-            * calls will be handled by ExecSeqReScan() because the nodes
-            * below the Material node have already been materialized into
-            * a temp relation.
-            */
-           return;
+       case T_NestLoop:
+           ExecReScanNestLoop((NestLoop*) node, exprCtxt, parent);
+           break;
+
+       case T_HashJoin:
+           ExecReScanHashJoin((HashJoin*) node, exprCtxt, parent);
+           break;
+
+       case T_Hash:
+           ExecReScanHash((Hash*) node, exprCtxt, parent);
+           break;
+
+       case T_Agg:
+           ExecReScanAgg((Agg*) node, exprCtxt, parent);
+           break;
 
+       case T_Result:
+           ExecReScanResult((Result*) node, exprCtxt, parent);
+           break;
+
+/* 
+ * Tee is never used
        case T_Tee:
            ExecTeeReScan((Tee *) node, exprCtxt, parent);
            break;
-
+ */
        default:
-           elog(ERROR, "ExecReScan: not a seqscan or indexscan node.");
+           elog(ERROR, "ExecReScan: node type %u not supported", nodeTag(node));
            return;
    }
+   
+   if ( node->chgParam != NULL )
+   {
+       freeList (node->chgParam);
+       node->chgParam = NULL;
+   }
 }
 
 /* ----------------------------------------------------------------
@@ -352,7 +406,7 @@ ExecMarkPos(Plan *node)
 {
    switch (nodeTag(node))
    {
-           case T_SeqScan:
+       case T_SeqScan:
            ExecSeqMarkPos((SeqScan *) node);
            break;
 
@@ -365,7 +419,7 @@ ExecMarkPos(Plan *node)
            break;
 
        default:
-           /* elog(DEBUG, "ExecMarkPos: unsupported node type"); */
+           elog(DEBUG, "ExecMarkPos: node type %u not supported", nodeTag(node));
            break;
    }
    return;
@@ -382,7 +436,7 @@ ExecRestrPos(Plan *node)
 {
    switch (nodeTag(node))
    {
-           case T_SeqScan:
+       case T_SeqScan:
            ExecSeqRestrPos((SeqScan *) node);
            return;
 
@@ -395,7 +449,7 @@ ExecRestrPos(Plan *node)
            return;
 
        default:
-           /* elog(DEBUG, "ExecRestrPos: node type not supported"); */
+           elog(DEBUG, "ExecRestrPos: node type %u not supported", nodeTag(node));
            return;
    }
 }
index c4bea118db67e71bc976597c96effe102ef2cde0..8702ede2483763efc43bfcbc8f954ad05316e392 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.41 1998/02/10 04:00:45 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.42 1998/02/13 03:26:38 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,7 +110,14 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
 
    /* sanity checks */
    Assert(queryDesc != NULL);
-
+   
+   if (queryDesc->plantree->nParamExec > 0)
+   {
+       estate->es_param_exec_vals = (ParamExecData*) 
+           palloc (queryDesc->plantree->nParamExec * sizeof (ParamExecData));
+       memset (estate->es_param_exec_vals, 0 , queryDesc->plantree->nParamExec * sizeof (ParamExecData));
+   }
+   
    result = InitPlan(queryDesc->operation,
                      queryDesc->parsetree,
                      queryDesc->plantree,
@@ -177,31 +184,6 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
    estate->es_processed = 0;
    estate->es_lastoid = InvalidOid;
 
-#if 0
-
-   /*
-    * It doesn't work in common case (i.g. if function has a aggregate).
-    * Now we store parameter values before ExecutorStart. - vadim
-    * 01/22/97
-    */
-#ifdef INDEXSCAN_PATCH
-
-   /*
-    * If the plan is an index scan and some of the scan key are function
-    * arguments rescan the indices after the parameter values have been
-    * stored in the execution state.  DZ - 27-8-1996
-    */
-   if ((nodeTag(plan) == T_IndexScan) &&
-       (((IndexScan *) plan)->indxstate->iss_RuntimeKeyInfo != NULL))
-   {
-       ExprContext *econtext;
-
-       econtext = ((IndexScan *) plan)->scan.scanstate->cstate.cs_ExprContext;
-       ExecIndexReScan((IndexScan *) plan, econtext, plan);
-   }
-#endif
-#endif
-
    switch (feature)
    {
 
@@ -1246,7 +1228,8 @@ ExecAttrDefault(Relation rel, HeapTuple tuple)
    econtext->ecxt_outertuple = NULL;   /* outer tuple slot */
    econtext->ecxt_relation = NULL;     /* relation */
    econtext->ecxt_relid = 0;   /* relid */
-   econtext->ecxt_param_list_info = NULL;      /* param list info */
+   econtext->ecxt_param_list_info = NULL;  /* param list info */
+   econtext->ecxt_param_exec_vals = NULL;  /* exec param values */
    econtext->ecxt_range_table = NULL;  /* range table */
    for (i = 0; i < ndef; i++)
    {
@@ -1322,6 +1305,7 @@ ExecRelCheck(Relation rel, HeapTuple tuple)
    econtext->ecxt_relation = rel;      /* relation */
    econtext->ecxt_relid = 0;   /* relid */
    econtext->ecxt_param_list_info = NULL;      /* param list info */
+   econtext->ecxt_param_exec_vals = NULL;      /* exec param values */
    econtext->ecxt_range_table = rtlist;        /* range table */
 
    for (i = 0; i < ncheck; i++)
index a2bd3e6ca6dae0dabfa272976cfd84d2fdea6143..017fdfba4d1109e5637362ca25e16a5e7d33aac1 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.7 1998/01/07 21:02:44 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.8 1998/02/13 03:26:40 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,6 +89,7 @@
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "executor/nodeTee.h"
+#include "executor/nodeSubplan.h"
 
 /* ------------------------------------------------------------------------
  *     ExecInitNode
@@ -106,6 +107,7 @@ bool
 ExecInitNode(Plan *node, EState *estate, Plan *parent)
 {
    bool        result;
+   List       *subp;
 
    /* ----------------
     *  do nothing when we get to the end
@@ -114,7 +116,14 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
     */
    if (node == NULL)
        return FALSE;
-
+   
+   foreach (subp, node->initPlan)
+   {
+       result = ExecInitSubPlan ((SubPlan*) lfirst (subp), estate, node);
+       if ( result == FALSE )
+           return (FALSE);
+   }
+   
    switch (nodeTag(node))
    {
            /* ----------------
@@ -190,10 +199,19 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
            break;
 
        default:
-           elog(DEBUG, "ExecInitNode: node not yet supported: %d",
-                nodeTag(node));
+           elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node));
            result = FALSE;
    }
+   
+   if ( result != FALSE )
+   {
+       foreach (subp, node->subPlan)
+       {
+           result = ExecInitSubPlan ((SubPlan*) lfirst (subp), estate, node);
+           if ( result == FALSE )
+               return (FALSE);
+       }
+   }
 
    return result;
 }
@@ -217,7 +235,10 @@ ExecProcNode(Plan *node, Plan *parent)
     */
    if (node == NULL)
        return NULL;
-
+   
+   if ( node->chgParam != NULL )               /* something changed */
+       ExecReScan (node, NULL, parent);        /* let ReScan handle this */
+   
    switch (nodeTag(node))
    {
            /* ----------------
@@ -293,9 +314,8 @@ ExecProcNode(Plan *node, Plan *parent)
            break;
 
        default:
-           elog(DEBUG, "ExecProcNode: node not yet supported: %d",
-                nodeTag(node));
-           result = FALSE;
+           elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node));
+           result = NULL;
    }
 
    return result;
@@ -389,6 +409,8 @@ ExecCountSlotsNode(Plan *node)
 void
 ExecEndNode(Plan *node, Plan *parent)
 {
+   List       *subp;
+   
    /* ----------------
     *  do nothing when we get to the end
     *  of a leaf on tree.
@@ -396,6 +418,20 @@ ExecEndNode(Plan *node, Plan *parent)
     */
    if (node == NULL)
        return;
+   
+   foreach (subp, node->initPlan)
+   {
+       ExecEndSubPlan ((SubPlan*) lfirst (subp));
+   }
+   foreach (subp, node->subPlan)
+   {
+       ExecEndSubPlan ((SubPlan*) lfirst (subp));
+   }
+   if ( node->chgParam != NULL )
+   {
+       freeList (node->chgParam);
+       node->chgParam = NULL;
+   }
 
    switch (nodeTag(node))
    {
@@ -476,8 +512,7 @@ ExecEndNode(Plan *node, Plan *parent)
            break;
 
        default:
-           elog(DEBUG, "ExecEndNode: node not yet supported",
-                nodeTag(node));
+           elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node));
            break;
    }
 }
index 98a8042cc3d754422ca19660a51d36b479a63d05..78c91539c7feaa7e440c766ab2533179e18ee758 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.24 1998/01/31 04:38:27 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.25 1998/02/13 03:26:42 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,7 @@
 #include "executor/execdebug.h"
 #include "executor/execFlatten.h"
 #include "executor/functions.h"
+#include "executor/nodeSubplan.h"
 #include "access/heapam.h"
 #include "utils/memutils.h"
 #include "utils/builtins.h"
@@ -374,14 +375,23 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
 {
 
    char       *thisParameterName;
-   int         thisParameterKind;
-   AttrNumber  thisParameterId;
+   int         thisParameterKind = expression->paramkind;
+   AttrNumber  thisParameterId = expression->paramid;
    int         matchFound;
    ParamListInfo paramList;
-
+   
+   if ( thisParameterKind == PARAM_EXEC )
+   {
+       ParamExecData   *prm = &(econtext->ecxt_param_exec_vals[thisParameterId]);
+       
+       if ( prm->execPlan != NULL )
+           ExecSetParamPlan (prm->execPlan);
+       Assert (prm->execPlan == NULL);
+       *isNull = prm->isnull;
+       return (prm->value);
+   }
+   
    thisParameterName = expression->paramname;
-   thisParameterKind = expression->paramkind;
-   thisParameterId = expression->paramid;
    paramList = econtext->ecxt_param_list_info;
 
    *isNull = false;
@@ -1227,14 +1237,17 @@ ExecEvalExpr(Node *expression,
                    case NOT_EXPR:
                        retDatum = (Datum) ExecEvalNot(expr, econtext, isNull);
                        break;
+                   case SUBPLAN_EXPR:
+                       retDatum = (Datum) ExecSubPlan((SubPlan*) expr->oper, expr->args, econtext);
+                       break;
                    default:
-                       elog(ERROR, "ExecEvalExpr: unknown expression type");
+                       elog(ERROR, "ExecEvalExpr: unknown expression type %d", expr->opType);
                        break;
                }
                break;
            }
        default:
-           elog(ERROR, "ExecEvalExpr: unknown expression type");
+           elog(ERROR, "ExecEvalExpr: unknown expression type %d", nodeTag(expression));
            break;
    }
 
index e02205828aeb91b05b3b032c8c55984f99f57022..69ef6671075e9badbb2b83343e2fbb6af64148cb 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.28 1998/02/10 04:00:52 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.29 1998/02/13 03:26:43 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -180,11 +180,6 @@ void
 ExecAssignExprContext(EState *estate, CommonState *commonstate)
 {
    ExprContext *econtext;
-   ParamListInfo paraminfo;
-   List       *rangeTable;
-
-   paraminfo = estate->es_param_list_info;
-   rangeTable = estate->es_range_table;
 
    econtext = makeNode(ExprContext);
    econtext->ecxt_scantuple = NULL;    /* scan tuple slot */
@@ -192,8 +187,9 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
    econtext->ecxt_outertuple = NULL;   /* outer tuple slot */
    econtext->ecxt_relation = NULL;     /* relation */
    econtext->ecxt_relid = 0;   /* relid */
-   econtext->ecxt_param_list_info = paraminfo; /* param list info */
-   econtext->ecxt_range_table = rangeTable;    /* range table */
+   econtext->ecxt_param_list_info = estate->es_param_list_info;
+   econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
+   econtext->ecxt_range_table = estate->es_range_table;    /* range table */
 
    commonstate->cs_ExprContext = econtext;
 }
@@ -1179,3 +1175,25 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
    if (econtext != NULL)
        pfree(econtext);
 }
+
+void 
+SetChangedParamList (Plan *node, List *newchg)
+{
+   List   *nl;
+   
+   foreach (nl, newchg)
+   {
+       int paramId = lfirsti(nl);
+       
+       /* if this node doesn't depend on a param ... */
+       if ( !intMember (paramId, node->extParam) &&
+               !intMember (paramId, node->locParam) )
+           continue;
+       /* if this param is already in list of changed ones ... */
+       if ( intMember (paramId, node->chgParam) )
+           continue;
+       /* else - add this param to the list */
+       node->chgParam = lappendi (node->chgParam, paramId);
+   }
+
+}
index 2cd62e39c0c133d76d2f8ed21083f5472cf58cd8..f6e034d9881bff7440aeb28f657db51c8adfb9a2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.15 1998/01/31 04:38:28 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.16 1998/02/13 03:26:44 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -303,8 +303,6 @@ postquel_execute(execution_state *es,
    TupleTableSlot *slot;
    Datum       value;
 
-#ifdef INDEXSCAN_PATCH
-
    /*
     * It's more right place to do it (before
     * postquel_start->ExecutorStart). Now
@@ -313,17 +311,12 @@ postquel_execute(execution_state *es,
     */
    if (fcache->nargs > 0)
        postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
-#endif
 
    if (es->status == F_EXEC_START)
    {
        postquel_start(es);
        es->status = F_EXEC_RUN;
    }
-#ifndef INDEXSCAN_PATCH
-   if (fcache->nargs > 0)
-       postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
-#endif
 
    slot = postquel_getnext(es);
 
index 444a5bc9db699017225b9837f5ffba486214f463..9778e365a58b0821746927b22e689edb38712f8f 100644 (file)
@@ -676,3 +676,21 @@ aggGetAttr(TupleTableSlot *slot,
 
    return result;
 }
+
+void
+ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
+{
+   AggState       *aggstate = node->aggstate;
+   ExprContext    *econtext = aggstate->csstate.cstate.cs_ExprContext;
+
+   aggstate->agg_done = FALSE;
+   MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
+   MemSet(econtext->ecxt_nulls, 0, length(node->aggs));
+   /* 
+    * if chgParam of subnode is not null then plan
+    * will be re-scanned by first ExecProcNode.
+    */
+   if (((Plan*) node)->lefttree->chgParam == NULL)
+       ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
+   
+}
index 031d718250d7150b9a1a7015d6c124a9da40d3a5..5ebf508c0c0b25218b35fa1861c2f26f37c8ad1e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.18 1998/02/11 19:10:28 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.19 1998/02/13 03:26:46 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -890,3 +890,23 @@ mk_hj_temp(char *tempname)
    sprintf(tempname, "HJ%d.%d", (int) MyProcPid, hjtmpcnt);
    hjtmpcnt = (hjtmpcnt + 1) % 1000;
 }
+
+void
+ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
+{
+   HashState  *hashstate = node->hashstate;
+
+   if (hashstate->hashBatches != NULL)
+   {
+       pfree(hashstate->hashBatches);
+       hashstate->hashBatches = NULL;
+   }
+   
+   /* 
+    * if chgParam of subnode is not null then plan
+    * will be re-scanned by first ExecProcNode.
+    */
+   if (((Plan*) node)->lefttree->chgParam == NULL)
+       ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
+   
+}
index c5fa8a092de0d0d153640a19bc83a2c2e3ffb042..21132410d45f4094175849aa5c2b9e7e50e23a11 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.9 1998/01/13 04:03:58 scrappy Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.10 1998/02/13 03:26:47 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,6 +154,9 @@ ExecHashJoin(HashJoin *node)
        curbatch = 0;
        node->hashdone = true;
    }
+   else if (hashtable == NULL)
+       return (NULL);
+   
    nbatch = hashtable->nbatch;
    outerbatches = hjstate->hj_OuterBatches;
    if (nbatch > 0 && outerbatches == NULL)
@@ -209,14 +212,12 @@ ExecHashJoin(HashJoin *node)
 
        while (curbatch <= nbatch && TupIsNull(outerTupleSlot))
        {
-
            /*
             * if the current batch runs out, switch to new batch
             */
            curbatch = ExecHashJoinNewBatch(hjstate);
            if (curbatch > nbatch)
            {
-
                /*
                 * when the last batch runs out, clean up
                 */
@@ -349,7 +350,6 @@ ExecHashJoin(HashJoin *node)
            curbatch = ExecHashJoinNewBatch(hjstate);
            if (curbatch > nbatch)
            {
-
                /*
                 * when the last batch runs out, clean up
                 */
@@ -841,3 +841,45 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
 
    return position;
 }
+
+void
+ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
+{
+   HashJoinState  *hjstate = node->hashjoinstate;
+
+   if (!node->hashdone)
+       return;
+   
+   node->hashdone = false;
+   
+   /* 
+    * Unfortunately, currently we have to destroy hashtable 
+    * in all cases...
+    */
+   if (hjstate->hj_HashTable)
+   {
+       ExecHashTableDestroy(hjstate->hj_HashTable);
+       hjstate->hj_HashTable = NULL;
+   }
+   hjstate->hj_CurBucket = (HashBucket) NULL;
+   hjstate->hj_CurTuple = (HeapTuple) NULL;
+   hjstate->hj_CurOTuple = (OverflowTuple) NULL;
+   hjstate->hj_InnerHashKey = (Var *) NULL;
+   hjstate->hj_OuterBatches = (File *) NULL;
+   hjstate->hj_InnerBatches = (File *) NULL;
+   hjstate->hj_OuterReadPos = (char *) NULL;
+   hjstate->hj_OuterReadBlk = (int) 0;
+
+   hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
+   hjstate->jstate.cs_TupFromTlist = (bool) false;
+   
+   /* 
+    * if chgParam of subnodes is not null then plans
+    * will be re-scanned by first ExecProcNode.
+    */
+   if (((Plan*) node)->lefttree->chgParam == NULL)
+       ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
+   if (((Plan*) node)->righttree->chgParam == NULL)
+       ExecReScan (((Plan*) node)->righttree, exprCtxt, (Plan *) node);
+   
+}
index 6e220800f2e723303a335c6434d50208dc90ca7c..d15c9bfb35a457988f019c5063eee944f1dee657 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.13 1998/01/07 21:02:54 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.14 1998/02/13 03:26:49 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -247,7 +247,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
    indexstate = node->indxstate;
    estate = node->scan.plan.state;
    direction = estate->es_direction;
-   indexstate = node->indxstate;
    numIndices = indexstate->iss_NumIndices;
    scanDescs = indexstate->iss_ScanDescs;
    scanKeys = indexstate->iss_ScanKeys;
@@ -268,7 +267,11 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
        n_keys = numScanKeys[indexPtr];
        run_keys = (int *) runtimeKeyInfo[indexPtr];
        scan_keys = (ScanKey) scanKeys[indexPtr];
-
+       
+       /* it's possible in subselects */
+       if (exprCtxt == NULL)
+           exprCtxt = node->scan.scanstate->cstate.cs_ExprContext;
+       
        for (j = 0; j < n_keys; j++)
        {
 
@@ -485,6 +488,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
    HeapScanDesc currentScanDesc;
    ScanDirection direction;
    int         baseid;
+   
+   List       *execParam = NULL;
 
    /* ----------------
     *  assign execution state to node
@@ -696,7 +701,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                 */
                run_keys[j] = NO_OP;
                scanvalue = ((Const *) leftop)->constvalue;
-#ifdef INDEXSCAN_PATCH
            }
            else if (IsA(leftop, Param))
            {
@@ -707,13 +711,24 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                 *  it identifies the value to place in our scan key.
                 * ----------------
                 */
-               run_keys[j] = NO_OP;
-               scanvalue = ExecEvalParam((Param *) leftop,
-                                       scanstate->cstate.cs_ExprContext,
-                                         &isnull);
-               if (isnull)
-                   flags |= SK_ISNULL;
-#endif
+               
+               /* Life was so easy before ... subselects */
+               if ( ((Param *) leftop)->paramkind == PARAM_EXEC )
+               {
+                   have_runtime_keys = true;
+                   run_keys[j] = LEFT_OP;
+                   execParam = lappendi (execParam, ((Param*) leftop)->paramid);
+               }
+               else
+               {
+                   scanvalue = ExecEvalParam((Param *) leftop,
+                                             scanstate->cstate.cs_ExprContext,
+                                             &isnull);
+                   if (isnull)
+                       flags |= SK_ISNULL;
+                   
+                   run_keys[j] = NO_OP;
+               }
            }
            else if (leftop != NULL &&
                     is_funcclause(leftop) &&
@@ -779,7 +794,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                 */
                run_keys[j] = NO_OP;
                scanvalue = ((Const *) rightop)->constvalue;
-#ifdef INDEXSCAN_PATCH
            }
            else if (IsA(rightop, Param))
            {
@@ -790,13 +804,24 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
                 *  it identifies the value to place in our scan key.
                 * ----------------
                 */
-               run_keys[j] = NO_OP;
-               scanvalue = ExecEvalParam((Param *) rightop,
-                                       scanstate->cstate.cs_ExprContext,
-                                         &isnull);
-               if (isnull)
-                   flags |= SK_ISNULL;
-#endif
+               
+               /* Life was so easy before ... subselects */
+               if ( ((Param *) rightop)->paramkind == PARAM_EXEC )
+               {
+                   have_runtime_keys = true;
+                   run_keys[j] = RIGHT_OP;
+                   execParam = lappendi (execParam, ((Param*) rightop)->paramid);
+               }
+               else
+               {
+                   scanvalue = ExecEvalParam((Param *) rightop,
+                                             scanstate->cstate.cs_ExprContext,
+                                             &isnull);
+                   if (isnull)
+                       flags |= SK_ISNULL;
+                   
+                   run_keys[j] = NO_OP;
+               }
            }
            else if (rightop != NULL &&
                     is_funcclause(rightop) &&
@@ -964,7 +989,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
    indexstate->iss_ScanDescs = scanDescs;
 
    indexstate->cstate.cs_TupFromTlist = false;
-
+   
+   /* 
+    * if there are some PARAM_EXEC in skankeys then
+    * force index rescan on first scan.
+    */
+   ((Plan*) node)->chgParam = execParam;
+   
    /* ----------------
     *  all done.
     * ----------------
index f821459f2a788e14d7c98aa13e85a104293746f1..800bab2b315c28bba0628f046a5ddb9503bcc789 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.11 1997/11/28 17:27:25 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.12 1998/02/13 03:26:50 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -341,6 +341,27 @@ ExecEndMaterial(Material *node)
    ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
 }
 
+/* ----------------------------------------------------------------
+ *     ExecMaterialReScan
+ *
+ *     Rescans the temporary relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
+{
+   MaterialState  *matstate = node->matstate;
+
+   if (matstate->mat_Flag == false)
+       return;
+   
+   matstate->csstate.css_currentScanDesc = 
+                   ExecReScanR (matstate->csstate.css_currentRelation, 
+                                matstate->csstate.css_currentScanDesc, 
+                                node->plan.state->es_direction, 0, NULL);
+   
+}
+
 #ifdef NOT_USED                    /* not used */
 /* ----------------------------------------------------------------
  *     ExecMaterialMarkPos
index ff9327ee994eb23c3d78d692d80e0dda31f3eb91..4d1fb12cd2f6b35d528ee4952c0ab5c0006138dc 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.7 1997/09/08 21:43:16 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.8 1998/02/13 03:26:51 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,7 +86,8 @@ ExecNestLoop(NestLoop *node, Plan *parent)
     */
    econtext = nlstate->jstate.cs_ExprContext;
 
-   /* ----------------         * get the current outer tuple
+   /* ----------------
+    * get the current outer tuple
     * ----------------
     */
    outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
@@ -118,16 +119,9 @@ ExecNestLoop(NestLoop *node, Plan *parent)
         */
        needNewOuterTuple = false;
 
-       /* ----------------
-        *  If outer tuple is not null then that means
-        *  we are in the middle of a scan and we should
-        *  restore our previously saved scan position.
-        * ----------------
-        */
        if (!TupIsNull(outerTupleSlot))
        {
-           ENL1_printf("have outer tuple, restoring outer plan");
-           ExecRestrPos(outerPlan);
+           ENL1_printf("have outer tuple, deal with it");
        }
        else
        {
@@ -179,14 +173,7 @@ ExecNestLoop(NestLoop *node, Plan *parent)
                return NULL;
            }
 
-           /* ----------------
-            *  we have a new outer tuple so we mark our position
-            *  in the outer scan and save the outer tuple in the
-            *  NestLoop state
-            * ----------------
-            */
            ENL1_printf("saving new outer tuple information");
-           ExecMarkPos(outerPlan);
            nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
 
            /* ----------------
@@ -385,3 +372,30 @@ ExecEndNestLoop(NestLoop *node)
    NL1_printf("ExecEndNestLoop: %s\n",
               "node processing ended");
 }
+
+/* ----------------------------------------------------------------
+ *     ExecReScanNestLoop
+ * ----------------------------------------------------------------
+ */
+void
+ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
+{
+   NestLoopState      *nlstate = node->nlstate;
+   Plan               *outerPlan = outerPlan((Plan*) 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...
+    */
+   if (outerPlan->chgParam == NULL)
+       ExecReScan (outerPlan, exprCtxt, (Plan *) node);
+
+   /* let outerPlan to free its result typle ... */
+   nlstate->jstate.cs_OuterTupleSlot = NULL;
+   nlstate->jstate.cs_TupFromTlist = false;
+
+   return;
+}
index 78f8c762619009d95746554aab922975b467d230..7dcb9376ca077acdc98c4415a71c07c3648118c4 100644 (file)
@@ -27,7 +27,7 @@
  *                SeqScan (emp.all)
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.5 1997/09/08 21:43:16 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.6 1998/02/13 03:26:52 vadim Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,8 +58,6 @@ ExecResult(Result *node)
    TupleTableSlot *resultSlot;
    Plan       *outerPlan;
    ExprContext *econtext;
-   Node       *qual;
-   bool        qualResult;
    bool        isDone;
    ProjectionInfo *projInfo;
 
@@ -79,26 +77,16 @@ ExecResult(Result *node)
     *   check tautological qualifications like (2 > 1)
     * ----------------
     */
-   qual = node->resconstantqual;
-   if (qual != NULL)
+   if (resstate->rs_checkqual)
    {
-       qualResult = ExecQual((List *) qual, econtext);
-       /* ----------------
-        *  if we failed the constant qual, then there
-        *  is no need to continue processing because regardless of
-        *  what happens, the constant qual will be false..
-        * ----------------
-        */
+       bool    qualResult = ExecQual((List *) node->resconstantqual, econtext);
+       
+       resstate->rs_checkqual = false;
        if (qualResult == false)
+       {
+           resstate->rs_done = true;
            return NULL;
-
-       /* ----------------
-        *  our constant qualification succeeded so now we
-        *  throw away the qual because we know it will always
-        *  succeed.
-        * ----------------
-        */
-       node->resconstantqual = NULL;
+       }
    }
 
    if (resstate->cstate.cs_TupFromTlist)
@@ -204,9 +192,10 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
     * ----------------
     */
    resstate = makeNode(ResultState);
-   resstate->rs_done = 0;
+   resstate->rs_done = false;
+   resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
    node->resstate = resstate;
-
+   
    /* ----------------
     *  Miscellanious initialization
     *
@@ -243,12 +232,6 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
    ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
    ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
 
-   /* ----------------
-    *  set "are we done yet" to false
-    * ----------------
-    */
-   resstate->rs_done = 0;
-
    return TRUE;
 }
 
@@ -294,3 +277,21 @@ ExecEndResult(Result *node)
     */
    ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
 }
+
+void
+ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
+{
+   ResultState    *resstate = node->resstate;
+
+   resstate->rs_done = false;
+   resstate->cstate.cs_TupFromTlist = false;
+   resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
+   
+   /* 
+    * if chgParam of subnode is not null then plan
+    * will be re-scanned by first ExecProcNode.
+    */
+   if (((Plan*) node)->lefttree->chgParam == NULL)
+       ExecReScan (((Plan*) node)->lefttree, exprCtxt, (Plan *) node);
+   
+}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
new file mode 100644 (file)
index 0000000..610f0a0
--- /dev/null
@@ -0,0 +1,280 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeSubplan.c--
+ *   routines to support subselects
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ *  INTERFACE ROUTINES
+ *     ExecSubPlan  - process a subselect
+ *     ExecInitSubPlan - initialize a subselect
+ *     ExecEndSubPlan  - shut down a subselect
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "tcop/pquery.h"
+#include "executor/executor.h"
+#include "executor/execdebug.h"
+#include "executor/nodeSubplan.h"
+
+/* ----------------------------------------------------------------
+ *     ExecSubPlan(node)
+ *
+ * ----------------------------------------------------------------
+ */
+Datum
+ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
+{
+   Plan           *plan = node->plan;
+   SubLink        *sublink = node->sublink;
+   TupleTableSlot *slot;
+   List           *lst;
+   bool            result = false;
+   bool            found = false;
+   
+   if ( node->setParam != NULL )
+       elog (ERROR, "ExecSubPlan: can't set parent params from subquery");
+   
+   /*
+    * Set Params of this plan from parent plan correlation Vars
+    */
+   if ( node->parParam != NULL )
+   {
+       foreach (lst, node->parParam)
+       {
+           ParamExecData   *prm = &(econtext->ecxt_param_exec_vals[lfirsti(lst)]);
+           
+           prm->value = ExecEvalExpr ((Node*) lfirst(pvar), 
+                                           econtext, 
+                                           &(prm->isnull), NULL);
+           pvar = lnext (pvar);
+       }
+       plan->chgParam = nconc (plan->chgParam, listCopy(node->parParam));
+   }
+   
+   ExecReScan (plan, (ExprContext*) NULL, plan);
+   
+   for (slot = ExecProcNode (plan, plan); 
+           !TupIsNull(slot); 
+               slot = ExecProcNode (plan, plan))
+   {
+       HeapTuple   tup = slot->val;
+       TupleDesc   tdesc = slot->ttc_tupleDescriptor;
+       int         i = 1;
+       
+       if ( sublink->subLinkType == EXPR_SUBLINK && found )
+       {
+           elog (ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
+           return ((Datum) false);
+       }
+       
+       if ( sublink->subLinkType == EXISTS_SUBLINK )
+           return ((Datum) true);
+       
+       found = true;
+       
+       foreach (lst, sublink->oper)
+       {
+           Expr   *expr = (Expr*) lfirst(lst);
+           Const  *con = lsecond(expr->args);
+           bool    isnull;
+           
+           con->constvalue = heap_getattr (tup, i, tdesc, &(con->constisnull));
+           result = (bool) ExecEvalExpr ((Node*) expr, econtext, &isnull, (bool*) NULL);
+           if ( isnull )
+               result = false;
+           if ( (!result && !(sublink->useor)) || (result && sublink->useor) )
+               break;
+           i++;
+       }
+           
+       if ( (!result && sublink->subLinkType == ALL_SUBLINK) ||
+               (result && sublink->subLinkType == ANY_SUBLINK) )
+           break;
+   }
+   
+   return ((Datum) result);
+}
+
+/* ----------------------------------------------------------------
+ *     ExecInitSubPlan
+ *
+ * ----------------------------------------------------------------
+ */
+bool
+ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
+{
+   EState   *sp_estate = CreateExecutorState ();
+   
+   sp_estate->es_range_table = node->rtable;
+   sp_estate->es_param_list_info = estate->es_param_list_info;
+   sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
+   sp_estate->es_tupleTable = 
+       ExecCreateTupleTable (ExecCountSlotsNode(node->plan) + 10);
+   pfree (sp_estate->es_refcount);
+   sp_estate->es_refcount = estate->es_refcount;
+   
+   if ( !ExecInitNode (node->plan, sp_estate, NULL) )
+       return (false);
+   
+   node->shutdown = true;
+   
+   /*
+    * If this plan is un-correlated or undirect correlated one and 
+    * want to set params for parent plan then prepare parameters.
+    */
+   if ( node->setParam != NULL )
+   {
+       List   *lst;
+       
+       foreach (lst, node->setParam)
+       {
+           ParamExecData   *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
+           
+           prm->execPlan = node;
+       }
+       /*
+        * Note that in the case of un-correlated subqueries we don't care
+        * about setting parent->chgParam here: indices take care about it,
+        * for others - it doesn't matter...
+        */
+   }
+   
+   return (true);
+}
+
+/* ----------------------------------------------------------------
+ *     ExecSetParamPlan
+ *
+ *     Executes plan of node and sets parameters.
+ * ----------------------------------------------------------------
+ */
+void
+ExecSetParamPlan (SubPlan *node)
+{
+   Plan           *plan = node->plan;
+   SubLink        *sublink = node->sublink;
+   TupleTableSlot *slot;
+   List           *lst;
+   bool            found = false;
+   
+   if ( sublink->subLinkType == ANY_SUBLINK ||
+           sublink->subLinkType == ALL_SUBLINK )
+       elog (ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
+   
+   if ( plan->chgParam != NULL )
+       ExecReScan (plan, (ExprContext*) NULL, plan);
+   
+   for (slot = ExecProcNode (plan, plan); 
+           !TupIsNull(slot); 
+               slot = ExecProcNode (plan, plan))
+   {
+       HeapTuple   tup = slot->val;
+       TupleDesc   tdesc = slot->ttc_tupleDescriptor;
+       int         i = 1;
+       
+       if ( sublink->subLinkType == EXPR_SUBLINK && found )
+       {
+           elog (ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect");
+           return;
+       }
+       
+       found = true;
+       
+       if ( sublink->subLinkType == EXISTS_SUBLINK )
+       {
+           ParamExecData   *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
+           
+           prm->execPlan = NULL;
+           prm->value = (Datum) true;
+           prm->isnull = false;
+           break;
+       }
+       
+       foreach (lst, node->setParam)
+       {
+           ParamExecData   *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
+           
+           prm->execPlan = NULL;
+           prm->value = heap_getattr (tup, i, tdesc, &(prm->isnull));
+           i++;
+       }
+   }
+   
+   if ( !found )
+   {
+       if ( sublink->subLinkType == EXISTS_SUBLINK )
+       {
+           ParamExecData   *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
+           
+           prm->execPlan = NULL;
+           prm->value = (Datum) false;
+           prm->isnull = false;
+       }
+       else
+       {
+           foreach (lst, node->setParam)
+           {
+               ParamExecData   *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
+               
+               prm->execPlan = NULL;
+               prm->value = (Datum) NULL;
+               prm->isnull = true;
+           }
+       }
+   }
+   
+   if ( plan->extParam == NULL )   /* un-correlated ... */
+   {
+       ExecEndNode (plan, plan);
+       node->shutdown = false;
+   }
+}
+
+/* ----------------------------------------------------------------
+ *     ExecEndSubPlan
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndSubPlan(SubPlan *node)
+{
+   
+   if ( node->shutdown )
+   {
+       ExecEndNode (node->plan, node->plan);
+       node->shutdown = false;
+   }
+   
+}
+
+void 
+ExecReScanSetParamPlan (SubPlan *node, Plan *parent)
+{
+   Plan   *plan = node->plan;
+   List   *lst;
+   
+   if ( node->parParam != NULL )
+       elog (ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
+   if ( node->setParam == NULL )
+       elog (ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
+   if ( plan->extParam == NULL )
+       elog (ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
+   
+   /* 
+    * Don't actual re-scan: ExecSetParamPlan does re-scan if 
+    * node->plan->chgParam is not NULL...
+   ExecReScan (plan, NULL, plan);
+    */
+   
+   foreach (lst, node->setParam)
+   {
+       ParamExecData   *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
+       
+       prm->execPlan = node;
+   }
+   
+   parent->chgParam = nconc (parent->chgParam, listCopy(node->setParam));
+
+}