aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/Makefile4
-rw-r--r--src/backend/executor/execAmi.c7
-rw-r--r--src/backend/executor/execMain.c9
-rw-r--r--src/backend/executor/execProcnode.c18
-rw-r--r--src/backend/executor/execTuples.c14
-rw-r--r--src/backend/executor/nodeAppend.c29
-rw-r--r--src/backend/executor/nodeSetOp.c341
-rw-r--r--src/backend/executor/nodeSubplan.c18
-rw-r--r--src/backend/executor/nodeSubqueryscan.c55
9 files changed, 430 insertions, 65 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index f26c35e9e10..7c79df5904d 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.14 2000/09/29 18:21:28 tgl Exp $
+# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.15 2000/10/05 19:11:26 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -16,7 +16,7 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
execProcnode.o execQual.o execScan.o execTuples.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 \
+ nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \
nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \
nodeSubqueryscan.o nodeTidscan.o
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 31ad291236b..9d008494b30 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execAmi.c,v 1.52 2000/09/29 18:21:28 tgl Exp $
+ * $Id: execAmi.c,v 1.53 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,6 +42,7 @@
#include "executor/nodeNestloop.h"
#include "executor/nodeResult.h"
#include "executor/nodeSeqscan.h"
+#include "executor/nodeSetOp.h"
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
#include "executor/nodeSubqueryscan.h"
@@ -345,6 +346,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanUnique((Unique *) node, exprCtxt, parent);
break;
+ case T_SetOp:
+ ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
+ break;
+
case T_Sort:
ExecReScanSort((Sort *) node, exprCtxt, parent);
break;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index a202da98d2e..3393559d630 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.128 2000/09/29 18:21:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.129 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -463,7 +463,6 @@ ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
/* Append implements expansion of inheritance */
ExecCheckRTPerms(app->inheritrtable, operation);
- /* Check appended plans w/outer rangetable */
foreach(appendplans, app->appendplans)
{
ExecCheckPlanPerms((Plan *) lfirst(appendplans),
@@ -474,15 +473,11 @@ ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
else
{
/* Append implements UNION, which must be a SELECT */
- List *rtables = app->unionrtables;
-
- /* Check appended plans with their rangetables */
foreach(appendplans, app->appendplans)
{
ExecCheckPlanPerms((Plan *) lfirst(appendplans),
- (List *) lfirst(rtables),
+ rangeTable,
CMD_SELECT);
- rtables = lnext(rtables);
}
}
break;
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index d6a15371311..6269a7caa10 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.20 2000/09/29 18:21:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.21 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -88,6 +88,7 @@
#include "executor/nodeNestloop.h"
#include "executor/nodeResult.h"
#include "executor/nodeSeqscan.h"
+#include "executor/nodeSetOp.h"
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
#include "executor/nodeSubqueryscan.h"
@@ -199,6 +200,10 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitUnique((Unique *) node, estate, parent);
break;
+ case T_SetOp:
+ result = ExecInitSetOp((SetOp *) node, estate, parent);
+ break;
+
case T_Group:
result = ExecInitGroup((Group *) node, estate, parent);
break;
@@ -322,6 +327,10 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecUnique((Unique *) node);
break;
+ case T_SetOp:
+ result = ExecSetOp((SetOp *) node);
+ break;
+
case T_Group:
result = ExecGroup((Group *) node);
break;
@@ -401,6 +410,9 @@ ExecCountSlotsNode(Plan *node)
case T_Unique:
return ExecCountSlotsUnique((Unique *) node);
+ case T_SetOp:
+ return ExecCountSlotsSetOp((SetOp *) node);
+
case T_Group:
return ExecCountSlotsGroup((Group *) node);
@@ -519,6 +531,10 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndUnique((Unique *) node);
break;
+ case T_SetOp:
+ ExecEndSetOp((SetOp *) node);
+ break;
+
case T_Group:
ExecEndGroup((Group *) node);
break;
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 008105719f3..d1cdfabab3b 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.40 2000/09/29 18:21:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.41 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -762,6 +762,14 @@ NodeGetResultTupleSlot(Plan *node)
}
break;
+ case T_SetOp:
+ {
+ SetOpState *setopstate = ((SetOp *) node)->setopstate;
+
+ slot = setopstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
case T_MergeJoin:
{
MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
@@ -783,8 +791,8 @@ NodeGetResultTupleSlot(Plan *node)
* should never get here
* ----------------
*/
- elog(ERROR, "NodeGetResultTupleSlot: node not yet supported: %d ",
- nodeTag(node));
+ elog(ERROR, "NodeGetResultTupleSlot: node not yet supported: %d",
+ (int) nodeTag(node));
return NULL;
}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 2b1eceb15d9..6c547854b55 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.35 2000/07/12 02:37:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.36 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -80,11 +80,9 @@ exec_append_initialize_next(Append *node)
AppendState *appendstate;
TupleTableSlot *result_slot;
List *rangeTable;
-
int whichplan;
int nplans;
- List *rtables;
- List *rtable;
+ List *inheritrtable;
RangeTblEntry *rtentry;
/* ----------------
@@ -98,8 +96,7 @@ exec_append_initialize_next(Append *node)
whichplan = appendstate->as_whichplan;
nplans = appendstate->as_nplans;
- rtables = node->unionrtables;
- rtable = node->inheritrtable;
+ inheritrtable = node->inheritrtable;
if (whichplan < 0)
{
@@ -131,19 +128,17 @@ exec_append_initialize_next(Append *node)
/* ----------------
* initialize the scan
* (and update the range table appropriately)
- * (doesn't this leave the range table hosed for anybody upstream
- * of the Append node??? - jolly )
+ *
+ * (doesn't this leave the range table hosed for anybody upstream
+ * of the Append node??? - jolly )
* ----------------
*/
if (node->inheritrelid > 0)
{
- rtentry = nth(whichplan, rtable);
+ rtentry = nth(whichplan, inheritrtable);
Assert(rtentry != NULL);
-
rt_store(node->inheritrelid, rangeTable, rtentry);
}
- else
- estate->es_range_table = nth(whichplan, rtables);
if (appendstate->as_junkFilter_list)
{
@@ -181,7 +176,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
{
AppendState *appendstate;
int nplans;
- List *rtable;
+ List *inheritrtable;
List *appendplans;
bool *initialized;
int i;
@@ -201,7 +196,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
appendplans = node->appendplans;
nplans = length(appendplans);
- rtable = node->inheritrtable;
+ inheritrtable = node->inheritrtable;
initialized = (bool *) palloc(nplans * sizeof(bool));
MemSet(initialized, 0, nplans * sizeof(bool));
@@ -214,7 +209,6 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
appendstate->as_whichplan = 0;
appendstate->as_nplans = nplans;
appendstate->as_initialized = initialized;
- appendstate->as_rtentries = rtable;
node->appendstate = appendstate;
@@ -250,7 +244,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
inherited_result_rel = true;
- foreach(rtentryP, rtable)
+ foreach(rtentryP, inheritrtable)
{
RangeTblEntry *rtentry = lfirst(rtentryP);
Oid reloid = rtentry->relid;
@@ -522,8 +516,7 @@ ExecEndAppend(Append *node)
estate->es_result_relation_info = NULL;
/*
- * XXX should free appendstate->as_rtentries and
- * appendstate->as_junkfilter_list here
+ * XXX should free appendstate->as_junkfilter_list here
*/
}
void
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
new file mode 100644
index 00000000000..8c285525051
--- /dev/null
+++ b/src/backend/executor/nodeSetOp.c
@@ -0,0 +1,341 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeSetOp.c
+ * Routines to handle INTERSECT and EXCEPT selection
+ *
+ * The input of a SetOp node consists of tuples from two relations,
+ * which have been combined into one dataset and sorted on all the nonjunk
+ * attributes. In addition there is a junk attribute that shows which
+ * relation each tuple came from. The SetOp node scans each group of
+ * identical tuples to determine how many came from each input relation.
+ * Then it is a simple matter to emit the output demanded by the SQL spec
+ * for INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL.
+ *
+ * This node type is not used for UNION or UNION ALL, since those can be
+ * implemented more cheaply (there's no need for the junk attribute to
+ * identify the source relation).
+ *
+ *
+ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.1 2000/10/05 19:11:26 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ * ExecSetOp - filter input to generate INTERSECT/EXCEPT results
+ * ExecInitSetOp - initialize node and subnodes..
+ * ExecEndSetOp - shutdown node and subnodes
+ */
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "executor/executor.h"
+#include "executor/nodeGroup.h"
+#include "executor/nodeSetOp.h"
+
+/* ----------------------------------------------------------------
+ * ExecSetOp
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot * /* return: a tuple or NULL */
+ExecSetOp(SetOp *node)
+{
+ SetOpState *setopstate;
+ TupleTableSlot *resultTupleSlot;
+ Plan *outerPlan;
+ TupleDesc tupDesc;
+
+ /* ----------------
+ * get information from the node
+ * ----------------
+ */
+ setopstate = node->setopstate;
+ outerPlan = outerPlan((Plan *) node);
+ resultTupleSlot = setopstate->cstate.cs_ResultTupleSlot;
+ tupDesc = ExecGetResultType(&setopstate->cstate);
+
+ /* ----------------
+ * If the previously-returned tuple needs to be returned more than
+ * once, keep returning it.
+ * ----------------
+ */
+ if (setopstate->numOutput > 0)
+ {
+ setopstate->numOutput--;
+ return resultTupleSlot;
+ }
+
+ /* Flag that we have no current tuple */
+ ExecClearTuple(resultTupleSlot);
+
+ /* ----------------
+ * Absorb groups of duplicate tuples, counting them, and
+ * saving the first of each group as a possible return value.
+ * At the end of each group, decide whether to return anything.
+ *
+ * We assume that the tuples arrive in sorted order
+ * so we can detect duplicates easily.
+ * ----------------
+ */
+ for (;;)
+ {
+ TupleTableSlot *inputTupleSlot;
+ bool endOfGroup;
+
+ /* ----------------
+ * fetch a tuple from the outer subplan, unless we already did.
+ * ----------------
+ */
+ if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
+ ! setopstate->subplan_done)
+ {
+ setopstate->cstate.cs_OuterTupleSlot =
+ ExecProcNode(outerPlan, (Plan *) node);
+ if (TupIsNull(setopstate->cstate.cs_OuterTupleSlot))
+ setopstate->subplan_done = true;
+ }
+ inputTupleSlot = setopstate->cstate.cs_OuterTupleSlot;
+
+ if (TupIsNull(resultTupleSlot))
+ {
+ /*
+ * First of group: save a copy in result slot, and reset
+ * duplicate-counters for new group.
+ */
+ if (setopstate->subplan_done)
+ return NULL; /* no more tuples */
+ ExecStoreTuple(heap_copytuple(inputTupleSlot->val),
+ resultTupleSlot,
+ InvalidBuffer,
+ true); /* free copied tuple at ExecClearTuple */
+ setopstate->numLeft = 0;
+ setopstate->numRight = 0;
+ endOfGroup = false;
+ }
+ else if (setopstate->subplan_done)
+ {
+ /*
+ * Reached end of input, so finish processing final group
+ */
+ endOfGroup = true;
+ }
+ else
+ {
+ /*
+ * Else test if the new tuple and the previously saved tuple match.
+ */
+ if (execTuplesMatch(inputTupleSlot->val,
+ resultTupleSlot->val,
+ tupDesc,
+ node->numCols, node->dupColIdx,
+ setopstate->eqfunctions,
+ setopstate->tempContext))
+ endOfGroup = false;
+ else
+ endOfGroup = true;
+ }
+
+ if (endOfGroup)
+ {
+ /*
+ * We've reached the end of the group containing resultTuple.
+ * Decide how many copies (if any) to emit. This logic is
+ * straight from the SQL92 specification.
+ */
+ switch (node->cmd)
+ {
+ case SETOPCMD_INTERSECT:
+ if (setopstate->numLeft > 0 && setopstate->numRight > 0)
+ setopstate->numOutput = 1;
+ else
+ setopstate->numOutput = 0;
+ break;
+ case SETOPCMD_INTERSECT_ALL:
+ setopstate->numOutput =
+ (setopstate->numLeft < setopstate->numRight) ?
+ setopstate->numLeft : setopstate->numRight;
+ break;
+ case SETOPCMD_EXCEPT:
+ if (setopstate->numLeft > 0 && setopstate->numRight == 0)
+ setopstate->numOutput = 1;
+ else
+ setopstate->numOutput = 0;
+ break;
+ case SETOPCMD_EXCEPT_ALL:
+ setopstate->numOutput =
+ (setopstate->numLeft < setopstate->numRight) ?
+ 0 : (setopstate->numLeft - setopstate->numRight);
+ break;
+ default:
+ elog(ERROR, "ExecSetOp: bogus command code %d",
+ (int) node->cmd);
+ break;
+ }
+ /* Fall out of for-loop if we have tuples to emit */
+ if (setopstate->numOutput > 0)
+ break;
+ /* Else flag that we have no current tuple, and loop around */
+ ExecClearTuple(resultTupleSlot);
+ }
+ else
+ {
+ /*
+ * Current tuple is member of same group as resultTuple.
+ * Count it in the appropriate counter.
+ */
+ int flag;
+ bool isNull;
+
+ flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
+ node->flagColIdx,
+ tupDesc,
+ &isNull));
+ Assert(!isNull);
+ if (flag)
+ setopstate->numRight++;
+ else
+ setopstate->numLeft++;
+ /* Set flag to fetch a new input tuple, and loop around */
+ setopstate->cstate.cs_OuterTupleSlot = NULL;
+ }
+ }
+
+ /*
+ * If we fall out of loop, then we need to emit at least one copy
+ * of resultTuple.
+ */
+ Assert(setopstate->numOutput > 0);
+ setopstate->numOutput--;
+ return resultTupleSlot;
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitSetOp
+ *
+ * This initializes the setop node state structures and
+ * the node's subplan.
+ * ----------------------------------------------------------------
+ */
+bool /* return: initialization status */
+ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
+{
+ SetOpState *setopstate;
+ Plan *outerPlan;
+
+ /* ----------------
+ * assign execution state to node
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create new SetOpState for node
+ * ----------------
+ */
+ setopstate = makeNode(SetOpState);
+ node->setopstate = setopstate;
+ setopstate->cstate.cs_OuterTupleSlot = NULL;
+ setopstate->subplan_done = false;
+ setopstate->numOutput = 0;
+
+ /* ----------------
+ * Miscellaneous initialization
+ *
+ * SetOp nodes have no ExprContext initialization because
+ * they never call ExecQual or ExecProject. But they do need a
+ * per-tuple memory context anyway for calling execTuplesMatch.
+ * ----------------
+ */
+ setopstate->tempContext =
+ AllocSetContextCreate(CurrentMemoryContext,
+ "SetOp",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
+#define SETOP_NSLOTS 1
+ /* ------------
+ * Tuple table initialization
+ * ------------
+ */
+ ExecInitResultTupleSlot(estate, &setopstate->cstate);
+
+ /* ----------------
+ * then initialize outer plan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * setop nodes do no projections, so initialize
+ * projection info for this node appropriately
+ * ----------------
+ */
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, &setopstate->cstate);
+ setopstate->cstate.cs_ProjInfo = NULL;
+
+ /*
+ * Precompute fmgr lookup data for inner loop
+ */
+ setopstate->eqfunctions =
+ execTuplesMatchPrepare(ExecGetResultType(&setopstate->cstate),
+ node->numCols,
+ node->dupColIdx);
+
+ return TRUE;
+}
+
+int
+ExecCountSlotsSetOp(SetOp *node)
+{
+ return ExecCountSlotsNode(outerPlan(node)) +
+ ExecCountSlotsNode(innerPlan(node)) +
+ SETOP_NSLOTS;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndSetOp
+ *
+ * This shuts down the subplan and frees resources allocated
+ * to this node.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndSetOp(SetOp *node)
+{
+ SetOpState *setopstate = node->setopstate;
+
+ ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
+
+ MemoryContextDelete(setopstate->tempContext);
+
+ /* clean up tuple table */
+ ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
+ setopstate->cstate.cs_OuterTupleSlot = NULL;
+}
+
+
+void
+ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent)
+{
+ SetOpState *setopstate = node->setopstate;
+
+ ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
+ setopstate->cstate.cs_OuterTupleSlot = NULL;
+ setopstate->subplan_done = false;
+ setopstate->numOutput = 0;
+
+ /*
+ * 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
index aee6911e5e4..933dcc83425 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.27 2000/08/24 03:29:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.28 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -328,7 +328,14 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
/* ----------------------------------------------------------------
* ExecSetParamPlan
*
- * Executes plan of node and sets parameters.
+ * Executes an InitPlan subplan and sets its output parameters.
+ *
+ * This is called from ExecEvalParam() when the value of a PARAM_EXEC
+ * parameter is requested and the param's execPlan field is set (indicating
+ * that the param has not yet been evaluated). This allows lazy evaluation
+ * of initplans: we don't run the subplan until/unless we need its output.
+ * Note that this routine MUST clear the execPlan fields of the plan's
+ * output parameters after evaluating them!
* ----------------------------------------------------------------
*/
void
@@ -424,13 +431,13 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
}
}
- MemoryContextSwitchTo(oldcontext);
-
if (plan->extParam == NULL) /* un-correlated ... */
{
ExecEndNode(plan, plan);
node->needShutdown = false;
}
+
+ MemoryContextSwitchTo(oldcontext);
}
/* ----------------------------------------------------------------
@@ -470,6 +477,9 @@ ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
* node->plan->chgParam is not NULL... ExecReScan (plan, NULL, plan);
*/
+ /*
+ * Mark this subplan's output parameters as needing recalculation
+ */
foreach(lst, node->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index 45f07a08b10..5593f71d0c6 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -3,12 +3,16 @@
* nodeSubqueryscan.c
* Support routines for scanning subqueries (subselects in rangetable).
*
+ * This is just enough different from sublinks (nodeSubplan.c) to mean that
+ * we need two sets of code. Ought to look at trying to unify the cases.
+ *
+ *
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.1 2000/09/29 18:21:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.2 2000/10/05 19:11:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,9 +53,7 @@ SubqueryNext(SubqueryScan *node)
SubqueryScanState *subquerystate;
EState *estate;
ScanDirection direction;
- int execdir;
TupleTableSlot *slot;
- Const countOne;
/* ----------------
* get information from the estate and scan state
@@ -60,7 +62,6 @@ SubqueryNext(SubqueryScan *node)
estate = node->scan.plan.state;
subquerystate = (SubqueryScanState *) node->scan.scanstate;
direction = estate->es_direction;
- execdir = ScanDirectionIsBackward(direction) ? EXEC_BACK : EXEC_FOR;
slot = subquerystate->csstate.css_ScanTupleSlot;
/*
@@ -85,25 +86,13 @@ SubqueryNext(SubqueryScan *node)
return (slot);
}
- memset(&countOne, 0, sizeof(countOne));
- countOne.type = T_Const;
- countOne.consttype = INT4OID;
- countOne.constlen = sizeof(int4);
- countOne.constvalue = Int32GetDatum(1);
- countOne.constisnull = false;
- countOne.constbyval = true;
- countOne.constisset = false;
- countOne.constiscast = false;
-
/* ----------------
* get the next tuple from the sub-query
* ----------------
*/
- slot = ExecutorRun(subquerystate->sss_SubQueryDesc,
- subquerystate->sss_SubEState,
- execdir,
- NULL, /* offset */
- (Node *) &countOne);
+ subquerystate->sss_SubEState->es_direction = direction;
+
+ slot = ExecProcNode(node->subplan, node->subplan);
subquerystate->csstate.css_ScanTupleSlot = slot;
@@ -139,6 +128,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
{
SubqueryScanState *subquerystate;
RangeTblEntry *rte;
+ EState *sp_estate;
/* ----------------
* SubqueryScan should not have any "normal" children.
@@ -177,18 +167,25 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
/* ----------------
* initialize subquery
+ *
+ * This should agree with ExecInitSubPlan
* ----------------
*/
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
Assert(rte->subquery != NULL);
- subquerystate->sss_SubQueryDesc = CreateQueryDesc(rte->subquery,
- node->subplan,
- None);
- subquerystate->sss_SubEState = CreateExecutorState();
+ sp_estate = CreateExecutorState();
+ subquerystate->sss_SubEState = sp_estate;
+
+ sp_estate->es_range_table = rte->subquery->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->subplan) + 10);
+ sp_estate->es_snapshot = estate->es_snapshot;
- ExecutorStart(subquerystate->sss_SubQueryDesc,
- subquerystate->sss_SubEState);
+ if (!ExecInitNode(node->subplan, sp_estate, NULL))
+ return false;
subquerystate->csstate.css_ScanTupleSlot = NULL;
subquerystate->csstate.cstate.cs_TupFromTlist = false;
@@ -247,10 +244,9 @@ ExecEndSubqueryScan(SubqueryScan *node)
* close down subquery
* ----------------
*/
- ExecutorEnd(subquerystate->sss_SubQueryDesc,
- subquerystate->sss_SubEState);
+ ExecEndNode(node->subplan, node->subplan);
- /* XXX we seem to be leaking the querydesc and sub-EState... */
+ /* XXX we seem to be leaking the sub-EState and tuple table... */
subquerystate->csstate.css_ScanTupleSlot = NULL;
@@ -284,6 +280,7 @@ ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
return;
}
- ExecReScan(node->subplan, NULL, NULL);
+ ExecReScan(node->subplan, NULL, node->subplan);
+
subquerystate->csstate.css_ScanTupleSlot = NULL;
}