aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVadim B. Mikheev <vadim4o@yahoo.com>1998-02-13 03:26:53 +0000
committerVadim B. Mikheev <vadim4o@yahoo.com>1998-02-13 03:26:53 +0000
commit1a105cefbd4769a1ef857f94a71faed6cb76717b (patch)
tree2c9b0cf10965e5e1d31106451552aad0c7c7e18d /src
parent13637df458b1d5a4f773bd17d3b894d9ff27197b (diff)
downloadpostgresql-1a105cefbd4769a1ef857f94a71faed6cb76717b.tar.gz
postgresql-1a105cefbd4769a1ef857f94a71faed6cb76717b.zip
Support for subselects.
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/Makefile4
-rw-r--r--src/backend/executor/execAmi.c90
-rw-r--r--src/backend/executor/execMain.c40
-rw-r--r--src/backend/executor/execProcnode.c55
-rw-r--r--src/backend/executor/execQual.c29
-rw-r--r--src/backend/executor/execUtils.c34
-rw-r--r--src/backend/executor/functions.c9
-rw-r--r--src/backend/executor/nodeAgg.c18
-rw-r--r--src/backend/executor/nodeHash.c22
-rw-r--r--src/backend/executor/nodeHashjoin.c50
-rw-r--r--src/backend/executor/nodeIndexscan.c71
-rw-r--r--src/backend/executor/nodeMaterial.c23
-rw-r--r--src/backend/executor/nodeNestloop.c48
-rw-r--r--src/backend/executor/nodeResult.c57
-rw-r--r--src/backend/executor/nodeSubplan.c280
15 files changed, 677 insertions, 153 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index b1ebb0b2155..9ae3cfc3518 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -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
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 2349f32411e..759d17be4fd 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -37,6 +37,13 @@
#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;
}
}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index c4bea118db6..8702ede2483 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -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++)
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index a2bd3e6ca6d..017fdfba4d1 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -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;
}
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 98a8042cc3d..78c91539c7f 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -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;
}
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index e02205828ae..69ef6671075 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -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);
+ }
+
+}
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 2cd62e39c0c..f6e034d9881 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -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);
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 444a5bc9db6..9778e365a58 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -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);
+
+}
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 031d718250d..5ebf508c0c0 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -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);
+
+}
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index c5fa8a092de..21132410d45 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -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);
+
+}
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6e220800f2e..d15c9bfb35a 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -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.
* ----------------
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index f821459f2a7..800bab2b315 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -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
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index ff9327ee994..4d1fb12cd2f 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -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;
+}
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index 78f8c762619..7dcb9376ca0 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -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
index 00000000000..610f0a09643
--- /dev/null
+++ b/src/backend/executor/nodeSubplan.c
@@ -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));
+
+}