]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Support for subselects.
authorVadim B. Mikheev <vadim4o@yahoo.com>
Fri, 13 Feb 1998 03:26:53 +0000 (03:26 +0000)
committerVadim B. Mikheev <vadim4o@yahoo.com>
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));
+
+}