1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Phase 1 of read-only-plans project: cause executor state nodes to point

to plan nodes, not vice-versa.  All executor state nodes now inherit from
struct PlanState.  Copying of plan trees has been simplified by not
storing a list of SubPlans in Plan nodes (eliminating duplicate links).
The executor still needs such a list, but it can build it during
ExecutorStart since it has to scan the plan tree anyway.
No initdb forced since no stored-on-disk structures changed, but you
will need a full recompile because of node-numbering changes.
This commit is contained in:
Tom Lane
2002-12-05 15:50:39 +00:00
parent 0f3b83edfa
commit 1fd0c59e25
71 changed files with 3032 additions and 3758 deletions

View File

@ -1,4 +1,4 @@
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.1 2001/05/15 00:35:50 tgl Exp $
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $
The Postgres Executor
---------------------
@ -39,6 +39,27 @@ delivered by the plan tree.
XXX a great deal more documentation needs to be written here...
Plan Trees and State Trees
--------------------------
The plan tree delivered by the planner contains a tree of Plan nodes (struct
types derived from struct Plan). Each Plan node may have expression trees
associated with it, to represent its target list, qualification conditions,
etc. During executor startup we build a parallel tree of identical structure
containing executor state nodes --- every plan and expression node type has
a corresponding executor state node type. Each node in the state tree has a
pointer to its corresponding node in the plan tree, plus executor state data
as needed to implement that node type. This arrangement allows the plan
tree to be completely read-only as far as the executor is concerned: all data
that is modified during execution is in the state tree. Read-only plan trees
make life much simpler for plan caching and reuse.
Altogether there are four classes of nodes used in these trees: Plan nodes,
their corresponding PlanState nodes, Expr nodes, and their corresponding
ExprState nodes. (Actually, there are also List nodes, which are used as
"glue" in all four kinds of tree.)
EvalPlanQual (READ COMMITTED update checking)
---------------------------------------------

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execAmi.c,v 1.65 2002/11/30 05:21:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.66 2002/12/05 15:50:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -19,12 +19,12 @@
#include "executor/instrument.h"
#include "executor/nodeAgg.h"
#include "executor/nodeAppend.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
#include "executor/nodeGroup.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "executor/nodeIndexscan.h"
#include "executor/nodeTidscan.h"
#include "executor/nodeLimit.h"
#include "executor/nodeMaterial.h"
#include "executor/nodeMergejoin.h"
@ -35,45 +35,45 @@
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeTidscan.h"
#include "executor/nodeUnique.h"
/* ----------------------------------------------------------------
* ExecReScan
*
* XXX this should be extended to cope with all the node types..
*
* takes the new expression context as an argument, so that
* index scans needn't have their scan keys updated separately
* - marcel 09/20/94
* ----------------------------------------------------------------
*/
void
ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
ExecReScan(PlanState *node, ExprContext *exprCtxt)
{
/* If collecting timing stats, update them */
if (node->instrument)
InstrEndLoop(node->instrument);
if (node->chgParam != NULL) /* Wow! */
/* If we have changed parameters, propagate that info */
if (node->chgParam != NIL)
{
List *lst;
foreach(lst, node->initPlan)
{
Plan *splan = ((SubPlan *) lfirst(lst))->plan;
PlanState *splan = ((SubPlanState *) lfirst(lst))->planstate;
if (splan->extParam != NULL) /* don't care about child
if (splan->plan->extParam != NIL) /* don't care about child
* locParam */
SetChangedParamList(splan, node->chgParam);
if (splan->chgParam != NULL)
ExecReScanSetParamPlan((SubPlan *) lfirst(lst), node);
if (splan->chgParam != NIL)
ExecReScanSetParamPlan((SubPlanState *) lfirst(lst), node);
}
foreach(lst, node->subPlan)
{
Plan *splan = ((SubPlan *) lfirst(lst))->plan;
PlanState *splan = ((SubPlanState *) lfirst(lst))->planstate;
if (splan->extParam != NULL)
if (splan->plan->extParam != NIL)
SetChangedParamList(splan, node->chgParam);
}
/* Well. Now set chgParam for left/right trees. */
@ -85,76 +85,76 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
switch (nodeTag(node))
{
case T_SeqScan:
ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
case T_ResultState:
ExecReScanResult((ResultState *) node, exprCtxt);
break;
case T_IndexScan:
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
case T_AppendState:
ExecReScanAppend((AppendState *) node, exprCtxt);
break;
case T_TidScan:
ExecTidReScan((TidScan *) node, exprCtxt, parent);
case T_SeqScanState:
ExecSeqReScan((SeqScanState *) node, exprCtxt);
break;
case T_SubqueryScan:
ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
case T_IndexScanState:
ExecIndexReScan((IndexScanState *) node, exprCtxt);
break;
case T_FunctionScan:
ExecFunctionReScan((FunctionScan *) node, exprCtxt, parent);
case T_TidScanState:
ExecTidReScan((TidScanState *) node, exprCtxt);
break;
case T_Material:
ExecMaterialReScan((Material *) node, exprCtxt, parent);
case T_SubqueryScanState:
ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt);
break;
case T_NestLoop:
ExecReScanNestLoop((NestLoop *) node, exprCtxt, parent);
case T_FunctionScanState:
ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
break;
case T_HashJoin:
ExecReScanHashJoin((HashJoin *) node, exprCtxt, parent);
case T_NestLoopState:
ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
break;
case T_Hash:
ExecReScanHash((Hash *) node, exprCtxt, parent);
case T_MergeJoinState:
ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt);
break;
case T_Agg:
ExecReScanAgg((Agg *) node, exprCtxt, parent);
case T_HashJoinState:
ExecReScanHashJoin((HashJoinState *) node, exprCtxt);
break;
case T_Group:
ExecReScanGroup((Group *) node, exprCtxt, parent);
case T_MaterialState:
ExecMaterialReScan((MaterialState *) node, exprCtxt);
break;
case T_Result:
ExecReScanResult((Result *) node, exprCtxt, parent);
case T_SortState:
ExecReScanSort((SortState *) node, exprCtxt);
break;
case T_Unique:
ExecReScanUnique((Unique *) node, exprCtxt, parent);
case T_GroupState:
ExecReScanGroup((GroupState *) node, exprCtxt);
break;
case T_SetOp:
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
case T_AggState:
ExecReScanAgg((AggState *) node, exprCtxt);
break;
case T_Limit:
ExecReScanLimit((Limit *) node, exprCtxt, parent);
case T_UniqueState:
ExecReScanUnique((UniqueState *) node, exprCtxt);
break;
case T_Sort:
ExecReScanSort((Sort *) node, exprCtxt, parent);
case T_HashState:
ExecReScanHash((HashState *) node, exprCtxt);
break;
case T_MergeJoin:
ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
case T_SetOpState:
ExecReScanSetOp((SetOpState *) node, exprCtxt);
break;
case T_Append:
ExecReScanAppend((Append *) node, exprCtxt, parent);
case T_LimitState:
ExecReScanLimit((LimitState *) node, exprCtxt);
break;
default:
@ -163,10 +163,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
return;
}
if (node->chgParam != NULL)
if (node->chgParam != NIL)
{
freeList(node->chgParam);
node->chgParam = NULL;
node->chgParam = NIL;
}
}
@ -176,37 +176,37 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
* Marks the current scan position.
*/
void
ExecMarkPos(Plan *node)
ExecMarkPos(PlanState *node)
{
switch (nodeTag(node))
{
case T_SeqScan:
ExecSeqMarkPos((SeqScan *) node);
case T_SeqScanState:
ExecSeqMarkPos((SeqScanState *) node);
break;
case T_IndexScan:
ExecIndexMarkPos((IndexScan *) node);
case T_IndexScanState:
ExecIndexMarkPos((IndexScanState *) node);
break;
case T_TidScan:
ExecTidMarkPos((TidScan *) node);
case T_TidScanState:
ExecTidMarkPos((TidScanState *) node);
break;
case T_FunctionScan:
ExecFunctionMarkPos((FunctionScan *) node);
case T_FunctionScanState:
ExecFunctionMarkPos((FunctionScanState *) node);
break;
case T_Material:
ExecMaterialMarkPos((Material *) node);
case T_MaterialState:
ExecMaterialMarkPos((MaterialState *) node);
break;
case T_Sort:
ExecSortMarkPos((Sort *) node);
case T_SortState:
ExecSortMarkPos((SortState *) node);
break;
default:
/* don't make hard error unless caller asks to restore... */
elog(LOG, "ExecMarkPos: node type %d not supported",
elog(DEBUG1, "ExecMarkPos: node type %d not supported",
nodeTag(node));
break;
}
@ -218,32 +218,32 @@ ExecMarkPos(Plan *node)
* restores the scan position previously saved with ExecMarkPos()
*/
void
ExecRestrPos(Plan *node)
ExecRestrPos(PlanState *node)
{
switch (nodeTag(node))
{
case T_SeqScan:
ExecSeqRestrPos((SeqScan *) node);
case T_SeqScanState:
ExecSeqRestrPos((SeqScanState *) node);
break;
case T_IndexScan:
ExecIndexRestrPos((IndexScan *) node);
case T_IndexScanState:
ExecIndexRestrPos((IndexScanState *) node);
break;
case T_TidScan:
ExecTidRestrPos((TidScan *) node);
case T_TidScanState:
ExecTidRestrPos((TidScanState *) node);
break;
case T_FunctionScan:
ExecFunctionRestrPos((FunctionScan *) node);
case T_FunctionScanState:
ExecFunctionRestrPos((FunctionScanState *) node);
break;
case T_Material:
ExecMaterialRestrPos((Material *) node);
case T_MaterialState:
ExecMaterialRestrPos((MaterialState *) node);
break;
case T_Sort:
ExecSortRestrPos((Sort *) node);
case T_SortState:
ExecSortRestrPos((SortState *) node);
break;
default:
@ -258,6 +258,7 @@ ExecRestrPos(Plan *node)
*
* XXX Ideally, all plan node types would support mark/restore, and this
* wouldn't be needed. For now, this had better match the routines above.
* But note the test is on Plan nodetype, not PlanState nodetype.
*/
bool
ExecSupportsMarkRestore(NodeTag plantype)

View File

@ -12,10 +12,9 @@
* ExecutorRun() and ExecutorEnd()
*
* These three procedures are the external interfaces to the executor.
* In each case, the query descriptor and the execution state is required
* as arguments
* In each case, the query descriptor is required as an argument.
*
* ExecutorStart() must be called at the beginning of any execution of any
* ExecutorStart() must be called at the beginning of execution of any
* query plan and ExecutorEnd() should always be called at the end of
* execution of a plan.
*
@ -27,7 +26,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.189 2002/12/05 04:04:42 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.190 2002/12/05 15:50:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -48,16 +47,13 @@
/* decls for local routines only used within this module */
static TupleDesc InitPlan(CmdType operation,
Query *parseTree,
Plan *plan,
EState *estate);
static void InitPlan(QueryDesc *queryDesc);
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
Index resultRelationIndex,
List *rangeTable,
CmdType operation);
static void EndPlan(Plan *plan, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
static void EndPlan(PlanState *planstate, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
CmdType operation,
long numberTuples,
ScanDirection direction,
@ -73,11 +69,6 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate);
static TupleTableSlot *EvalPlanQualNext(EState *estate);
static void EndEvalPlanQual(EState *estate);
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
Plan *plan);
static void ExecCheckPlanPerms(Plan *plan, List *rangeTable,
CmdType operation);
static void ExecCheckRTPerms(List *rangeTable, CmdType operation);
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
/* end of local decls */
@ -89,26 +80,40 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
* This routine must be called at the beginning of any execution of any
* query plan
*
* returns a TupleDesc which describes the attributes of the tuples to
* be returned by the query. (Same value is saved in queryDesc)
* Takes a QueryDesc previously created by CreateQueryDesc (it's not real
* clear why we bother to separate the two functions, but...). The tupDesc
* field of the QueryDesc is filled in to describe the tuples that will be
* returned, and the internal fields (estate and planstate) are set up.
*
* XXX this will change soon:
* NB: the CurrentMemoryContext when this is called must be the context
* to be used as the per-query context for the query plan. ExecutorRun()
* and ExecutorEnd() must be called in this same memory context.
* ----------------------------------------------------------------
*/
TupleDesc
ExecutorStart(QueryDesc *queryDesc, EState *estate)
void
ExecutorStart(QueryDesc *queryDesc)
{
TupleDesc result;
EState *estate;
/* sanity checks */
/* sanity checks: queryDesc must not be started already */
Assert(queryDesc != NULL);
Assert(queryDesc->estate == NULL);
/*
* Build EState, fill with parameters from queryDesc
*/
estate = CreateExecutorState();
queryDesc->estate = estate;
estate->es_param_list_info = queryDesc->params;
if (queryDesc->plantree->nParamExec > 0)
estate->es_param_exec_vals = (ParamExecData *)
palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
estate->es_instrument = queryDesc->doInstrument;
/*
* Make our own private copy of the current query snapshot data.
*
@ -119,16 +124,9 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
estate->es_snapshot = CopyQuerySnapshot();
/*
* Initialize the plan
* Initialize the plan state tree
*/
result = InitPlan(queryDesc->operation,
queryDesc->parsetree,
queryDesc->plantree,
estate);
queryDesc->tupDesc = result;
return result;
InitPlan(queryDesc);
}
/* ----------------------------------------------------------------
@ -150,11 +148,11 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc, EState *estate,
ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count)
{
CmdType operation;
Plan *plan;
EState *estate;
CommandDest dest;
DestReceiver *destfunc;
TupleTableSlot *result;
@ -169,7 +167,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
* feature.
*/
operation = queryDesc->operation;
plan = queryDesc->plantree;
estate = queryDesc->estate;
dest = queryDesc->dest;
/*
@ -189,7 +187,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
result = NULL;
else
result = ExecutePlan(estate,
plan,
queryDesc->planstate,
operation,
count,
direction,
@ -211,12 +209,16 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
* ----------------------------------------------------------------
*/
void
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
ExecutorEnd(QueryDesc *queryDesc)
{
EState *estate;
/* sanity checks */
Assert(queryDesc != NULL);
EndPlan(queryDesc->plantree, estate);
estate = queryDesc->estate;
EndPlan(queryDesc->planstate, estate);
if (estate->es_snapshot != NULL)
{
@ -235,97 +237,55 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
/*
* ExecCheckQueryPerms
* Check access permissions for all relations referenced in a query.
* CreateExecutorState
*/
static void
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
EState *
CreateExecutorState(void)
{
/*
* Check RTEs in the query's primary rangetable.
*/
ExecCheckRTPerms(parseTree->rtable, operation);
EState *state;
/*
* Search for subplans and APPEND nodes to check their rangetables.
* create a new executor state
*/
ExecCheckPlanPerms(plan, parseTree->rtable, operation);
state = makeNode(EState);
/*
* initialize the Executor State structure
*/
state->es_direction = ForwardScanDirection;
state->es_range_table = NIL;
state->es_result_relations = NULL;
state->es_num_result_relations = 0;
state->es_result_relation_info = NULL;
state->es_junkFilter = NULL;
state->es_into_relation_descriptor = NULL;
state->es_param_list_info = NULL;
state->es_param_exec_vals = NULL;
state->es_tupleTable = NULL;
state->es_query_cxt = CurrentMemoryContext;
state->es_instrument = false;
state->es_per_tuple_exprcontext = NULL;
/*
* return the executor state structure
*/
return state;
}
/*
* ExecCheckPlanPerms
* Recursively scan the plan tree to check access permissions in
* subplans.
*/
static void
ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
{
List *subp;
if (plan == NULL)
return;
/* Check subplans, which we assume are plain SELECT queries */
foreach(subp, plan->initPlan)
{
SubPlan *subplan = (SubPlan *) lfirst(subp);
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
}
foreach(subp, plan->subPlan)
{
SubPlan *subplan = (SubPlan *) lfirst(subp);
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
}
/* Check lower plan nodes */
ExecCheckPlanPerms(plan->lefttree, rangeTable, operation);
ExecCheckPlanPerms(plan->righttree, rangeTable, operation);
/* Do node-type-specific checks */
switch (nodeTag(plan))
{
case T_SubqueryScan:
{
SubqueryScan *scan = (SubqueryScan *) plan;
RangeTblEntry *rte;
/* Recursively check the subquery */
rte = rt_fetch(scan->scan.scanrelid, rangeTable);
Assert(rte->rtekind == RTE_SUBQUERY);
ExecCheckQueryPerms(operation, rte->subquery, scan->subplan);
break;
}
case T_Append:
{
Append *app = (Append *) plan;
List *appendplans;
foreach(appendplans, app->appendplans)
{
ExecCheckPlanPerms((Plan *) lfirst(appendplans),
rangeTable,
operation);
}
break;
}
default:
break;
}
}
/*
* ExecCheckRTPerms
* Check access permissions for all relations listed in a range table.
*/
static void
void
ExecCheckRTPerms(List *rangeTable, CmdType operation)
{
List *lp;
@ -350,11 +310,18 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
AclResult aclcheck_result;
/*
* Only plain-relation RTEs need to be checked here. Subquery RTEs
* will be checked when ExecCheckPlanPerms finds the SubqueryScan
* node, and function RTEs are checked by init_fcache when the
* function is prepared for execution. Join and special RTEs need no
* checks.
* If it's a subquery, recursively examine its rangetable.
*/
if (rte->rtekind == RTE_SUBQUERY)
{
ExecCheckRTPerms(rte->subquery->rtable, operation);
return;
}
/*
* Otherwise, only plain-relation RTEs need to be checked here.
* Function RTEs are checked by init_fcache when the function is prepared
* for execution. Join and special RTEs need no checks.
*/
if (rte->rtekind != RTE_RELATION)
return;
@ -367,7 +334,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
*
* Note: GetUserId() is presently fast enough that there's no harm in
* calling it separately for each RTE. If that stops being true, we
* could call it once in ExecCheckQueryPerms and pass the userid down
* could call it once in ExecCheckRTPerms and pass the userid down
* from there. But for now, no need for the extra clutter.
*/
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
@ -428,7 +395,8 @@ typedef struct execRowMark
typedef struct evalPlanQual
{
Plan *plan;
Plan *plan; /* XXX temporary */
PlanState *planstate;
Index rti;
EState estate;
struct evalPlanQual *free;
@ -441,17 +409,24 @@ typedef struct evalPlanQual
* and start up the rule manager
* ----------------------------------------------------------------
*/
static TupleDesc
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
static void
InitPlan(QueryDesc *queryDesc)
{
CmdType operation = queryDesc->operation;
Query *parseTree = queryDesc->parsetree;
Plan *plan = queryDesc->plantree;
EState *estate = queryDesc->estate;
PlanState *planstate;
List *rangeTable;
Relation intoRelationDesc;
TupleDesc tupType;
/*
* Do permissions checks.
* Do permissions checks. It's sufficient to examine the query's
* top rangetable here --- subplan RTEs will be checked during
* ExecInitSubPlan().
*/
ExecCheckQueryPerms(operation, parseTree, plan);
ExecCheckRTPerms(parseTree->rtable, operation);
/*
* get information from query descriptor
@ -575,14 +550,14 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
* query tree. This opens files, allocates storage and leaves us
* ready to start processing tuples.
*/
ExecInitNode(plan, estate, NULL);
planstate = ExecInitNode(plan, estate);
/*
* Get the tuple descriptor describing the type of tuples to return.
* (this is especially important if we are creating a relation with
* "SELECT INTO")
*/
tupType = ExecGetTupType(plan); /* tuple descriptor */
tupType = ExecGetTupType(planstate);
/*
* Initialize the junk filter if needed. SELECT and INSERT queries
@ -627,26 +602,29 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
*/
if (parseTree->resultRelations != NIL)
{
List *subplans;
PlanState **appendplans;
int as_nplans;
ResultRelInfo *resultRelInfo;
int i;
/* Top plan had better be an Append here. */
Assert(IsA(plan, Append));
Assert(((Append *) plan)->isTarget);
subplans = ((Append *) plan)->appendplans;
Assert(length(subplans) == estate->es_num_result_relations);
Assert(IsA(planstate, AppendState));
appendplans = ((AppendState *) planstate)->appendplans;
as_nplans = ((AppendState *) planstate)->as_nplans;
Assert(as_nplans == estate->es_num_result_relations);
resultRelInfo = estate->es_result_relations;
while (subplans != NIL)
for (i = 0; i < as_nplans; i++)
{
Plan *subplan = (Plan *) lfirst(subplans);
PlanState *subplan = appendplans[i];
JunkFilter *j;
j = ExecInitJunkFilter(subplan->targetlist,
j = ExecInitJunkFilter(subplan->plan->targetlist,
ExecGetTupType(subplan),
ExecAllocTableSlot(estate->es_tupleTable));
resultRelInfo->ri_junkFilter = j;
resultRelInfo++;
subplans = lnext(subplans);
}
/*
@ -661,7 +639,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
/* Normal case with just one JunkFilter */
JunkFilter *j;
j = ExecInitJunkFilter(plan->targetlist,
j = ExecInitJunkFilter(planstate->plan->targetlist,
tupType,
ExecAllocTableSlot(estate->es_tupleTable));
estate->es_junkFilter = j;
@ -755,7 +733,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
estate->es_into_relation_descriptor = intoRelationDesc;
return tupType;
queryDesc->tupDesc = tupType;
queryDesc->planstate = planstate;
}
/*
@ -816,11 +795,11 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
/* ----------------------------------------------------------------
* EndPlan
*
* Cleans up the query plan -- closes files and free up storages
* Cleans up the query plan -- closes files and frees up storage
* ----------------------------------------------------------------
*/
static void
EndPlan(Plan *plan, EState *estate)
EndPlan(PlanState *planstate, EState *estate)
{
ResultRelInfo *resultRelInfo;
int i;
@ -835,7 +814,7 @@ EndPlan(Plan *plan, EState *estate)
/*
* shut down the node-type-specific query processing
*/
ExecEndNode(plan, NULL);
ExecEndNode(planstate);
/*
* destroy the executor "tuple" table.
@ -902,7 +881,7 @@ EndPlan(Plan *plan, EState *estate)
*/
static TupleTableSlot *
ExecutePlan(EState *estate,
Plan *plan,
PlanState *planstate,
CmdType operation,
long numberTuples,
ScanDirection direction,
@ -964,10 +943,10 @@ lnext: ;
{
slot = EvalPlanQualNext(estate);
if (TupIsNull(slot))
slot = ExecProcNode(plan, NULL);
slot = ExecProcNode(planstate);
}
else
slot = ExecProcNode(plan, NULL);
slot = ExecProcNode(planstate);
/*
* if the tuple is null, then we assume there is nothing more to
@ -1765,7 +1744,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
Assert(oldepq->rti != 0);
/* stop execution */
ExecEndNode(epq->plan, NULL);
ExecEndNode(epq->planstate);
ExecDropTupleTable(epqstate->es_tupleTable, true);
epqstate->es_tupleTable = NULL;
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
@ -1793,10 +1772,8 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
/*
* Each stack level has its own copy of the plan tree. This
* is wasteful, but necessary as long as plan nodes point to
* exec state nodes rather than vice versa. Note that
* copyfuncs.c doesn't attempt to copy the exec state nodes,
* which is a good thing in this situation.
* is wasteful, but necessary until plan trees are fully
* read-only.
*/
newepq->plan = copyObject(estate->es_origPlan);
@ -1858,7 +1835,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
if (endNode)
{
/* stop execution */
ExecEndNode(epq->plan, NULL);
ExecEndNode(epq->planstate);
ExecDropTupleTable(epqstate->es_tupleTable, true);
epqstate->es_tupleTable = NULL;
}
@ -1886,7 +1863,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
epqstate->es_tupleTable =
ExecCreateTupleTable(estate->es_tupleTable->size);
ExecInitNode(epq->plan, epqstate, NULL);
epq->planstate = ExecInitNode(epq->plan, epqstate);
return EvalPlanQualNext(estate);
}
@ -1902,7 +1879,7 @@ EvalPlanQualNext(EState *estate)
Assert(epq->rti != 0);
lpqnext:;
slot = ExecProcNode(epq->plan, NULL);
slot = ExecProcNode(epq->planstate);
/*
* No more tuples for this PQ. Continue previous one.
@ -1910,7 +1887,7 @@ lpqnext:;
if (TupIsNull(slot))
{
/* stop execution */
ExecEndNode(epq->plan, NULL);
ExecEndNode(epq->planstate);
ExecDropTupleTable(epqstate->es_tupleTable, true);
epqstate->es_tupleTable = NULL;
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
@ -1951,7 +1928,7 @@ EndEvalPlanQual(EState *estate)
for (;;)
{
/* stop execution */
ExecEndNode(epq->plan, NULL);
ExecEndNode(epq->planstate);
ExecDropTupleTable(epqstate->es_tupleTable, true);
epqstate->es_tupleTable = NULL;
if (epqstate->es_evTuple[epq->rti - 1] != NULL)

View File

@ -5,23 +5,23 @@
* "get a tuple", and "cleanup" routines for the given node type.
* If the node has children, then it will presumably call ExecInitNode,
* ExecProcNode, or ExecEndNode on its subnodes and do the appropriate
* processing..
* processing.
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.30 2002/06/20 20:29:27 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.31 2002/12/05 15:50:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecCountSlotsNode - count tuple slots needed by plan tree
* ExecInitNode - initialize a plan node and its subplans
* ExecProcNode - get a tuple by executing the plan node
* ExecEndNode - shut down a plan node and its subplans
* ExecCountSlotsNode - count tuple slots needed by plan tree
* ExecGetTupType - get result tuple type of a plan node
*
* NOTES
@ -53,10 +53,12 @@
* * ExecInitNode() notices that it is looking at a nest loop and
* as the code below demonstrates, it calls ExecInitNestLoop().
* Eventually this calls ExecInitNode() on the right and left subplans
* and so forth until the entire plan is initialized.
* and so forth until the entire plan is initialized. The result
* of ExecInitNode() is a plan state tree built with the same structure
* as the underlying plan tree.
*
* * Then when ExecRun() is called, it calls ExecutePlan() which
* calls ExecProcNode() repeatedly on the top node of the plan.
* * Then when ExecRun() is called, it calls ExecutePlan() which calls
* ExecProcNode() repeatedly on the top node of the plan state tree.
* Each time this happens, ExecProcNode() will end up calling
* ExecNestLoop(), which calls ExecProcNode() on its subplans.
* Each of these subplans is a sequential scan so ExecSeqScan() is
@ -73,7 +75,6 @@
* ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
* their work to the appopriate node support routines which may
* in turn call these routines themselves on their subplans.
*
*/
#include "postgres.h"
@ -81,11 +82,11 @@
#include "executor/instrument.h"
#include "executor/nodeAgg.h"
#include "executor/nodeAppend.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "executor/nodeIndexscan.h"
#include "executor/nodeTidscan.h"
#include "executor/nodeLimit.h"
#include "executor/nodeMaterial.h"
#include "executor/nodeMergejoin.h"
@ -96,7 +97,7 @@
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeTidscan.h"
#include "executor/nodeUnique.h"
#include "miscadmin.h"
#include "tcop/tcopprot.h"
@ -109,32 +110,23 @@
*
* Initial States:
* 'node' is the plan produced by the query planner
* 'estate' is the shared execution state for the query tree
*
* returns TRUE/FALSE on whether the plan was successfully initialized
* Returns a PlanState node corresponding to the given Plan node.
* ------------------------------------------------------------------------
*/
bool
ExecInitNode(Plan *node, EState *estate, Plan *parent)
PlanState *
ExecInitNode(Plan *node, EState *estate)
{
bool result;
PlanState *result;
List *subps;
List *subp;
/*
* do nothing when we get to the end of a leaf on tree.
*/
if (node == NULL)
return FALSE;
/* Set up instrumentation for this node if the parent has it */
if (!node->instrument && parent && parent->instrument)
node->instrument = InstrAlloc();
foreach(subp, node->initPlan)
{
result = ExecInitSubPlan((SubPlan *) lfirst(subp), estate, node);
if (result == FALSE)
return FALSE;
}
return NULL;
switch (nodeTag(node))
{
@ -142,104 +134,124 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
* control nodes
*/
case T_Result:
result = ExecInitResult((Result *) node, estate, parent);
result = (PlanState *) ExecInitResult((Result *) node, estate);
break;
case T_Append:
result = ExecInitAppend((Append *) node, estate, parent);
result = (PlanState *) ExecInitAppend((Append *) node, estate);
break;
/*
* scan nodes
*/
case T_SeqScan:
result = ExecInitSeqScan((SeqScan *) node, estate, parent);
result = (PlanState *) ExecInitSeqScan((SeqScan *) node, estate);
break;
case T_IndexScan:
result = ExecInitIndexScan((IndexScan *) node, estate, parent);
result = (PlanState *) ExecInitIndexScan((IndexScan *) node, estate);
break;
case T_TidScan:
result = ExecInitTidScan((TidScan *) node, estate, parent);
result = (PlanState *) ExecInitTidScan((TidScan *) node, estate);
break;
case T_SubqueryScan:
result = ExecInitSubqueryScan((SubqueryScan *) node, estate,
parent);
result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node, estate);
break;
case T_FunctionScan:
result = ExecInitFunctionScan((FunctionScan *) node, estate,
parent);
result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node, estate);
break;
/*
* join nodes
*/
case T_NestLoop:
result = ExecInitNestLoop((NestLoop *) node, estate, parent);
result = (PlanState *) ExecInitNestLoop((NestLoop *) node, estate);
break;
case T_MergeJoin:
result = ExecInitMergeJoin((MergeJoin *) node, estate, parent);
break;
case T_Hash:
result = ExecInitHash((Hash *) node, estate, parent);
result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node, estate);
break;
case T_HashJoin:
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
result = (PlanState *) ExecInitHashJoin((HashJoin *) node, estate);
break;
/*
* materialization nodes
*/
case T_Material:
result = ExecInitMaterial((Material *) node, estate, parent);
result = (PlanState *) ExecInitMaterial((Material *) node, estate);
break;
case T_Sort:
result = ExecInitSort((Sort *) node, estate, parent);
break;
case T_Unique:
result = ExecInitUnique((Unique *) node, estate, parent);
break;
case T_SetOp:
result = ExecInitSetOp((SetOp *) node, estate, parent);
break;
case T_Limit:
result = ExecInitLimit((Limit *) node, estate, parent);
result = (PlanState *) ExecInitSort((Sort *) node, estate);
break;
case T_Group:
result = ExecInitGroup((Group *) node, estate, parent);
result = (PlanState *) ExecInitGroup((Group *) node, estate);
break;
case T_Agg:
result = ExecInitAgg((Agg *) node, estate, parent);
result = (PlanState *) ExecInitAgg((Agg *) node, estate);
break;
case T_Unique:
result = (PlanState *) ExecInitUnique((Unique *) node, estate);
break;
case T_Hash:
result = (PlanState *) ExecInitHash((Hash *) node, estate);
break;
case T_SetOp:
result = (PlanState *) ExecInitSetOp((SetOp *) node, estate);
break;
case T_Limit:
result = (PlanState *) ExecInitLimit((Limit *) node, estate);
break;
default:
elog(ERROR, "ExecInitNode: node type %d unsupported",
(int) nodeTag(node));
result = FALSE;
result = NULL; /* keep compiler quiet */
break;
}
if (result != FALSE)
/*
* Initialize any initPlans present in this node. The planner put
* them in a separate list for us.
*/
subps = NIL;
foreach(subp, node->initPlan)
{
foreach(subp, node->subPlan)
{
result = ExecInitSubPlan((SubPlan *) lfirst(subp), estate, node);
if (result == FALSE)
return FALSE;
}
SubPlan *subplan = (SubPlan *) lfirst(subp);
Assert(IsA(subplan, SubPlan));
subps = lappend(subps, ExecInitSubPlan(subplan, estate));
}
result->initPlan = subps;
/*
* Initialize any subPlans present in this node. These were found
* by ExecInitExpr during initialization of the PlanState.
*/
subps = NIL;
foreach(subp, result->subPlan)
{
SubPlan *subplan = (SubPlan *) lfirst(subp);
Assert(IsA(subplan, SubPlan));
subps = lappend(subps, ExecInitSubPlan(subplan, estate));
}
result->subPlan = subps;
/* Set up instrumentation for this node if requested */
if (estate->es_instrument)
result->instrument = InstrAlloc();
return result;
}
@ -248,12 +260,11 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
/* ----------------------------------------------------------------
* ExecProcNode
*
* Initial States:
* the query tree must be initialized once by calling ExecInit.
* Execute the given node to return a(nother) tuple.
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecProcNode(Plan *node, Plan *parent)
ExecProcNode(PlanState *node)
{
TupleTableSlot *result;
@ -265,8 +276,8 @@ ExecProcNode(Plan *node, Plan *parent)
if (node == NULL)
return NULL;
if (node->chgParam != NULL) /* something changed */
ExecReScan(node, NULL, parent); /* let ReScan handle this */
if (node->chgParam != NIL) /* something changed */
ExecReScan(node, NULL); /* let ReScan handle this */
if (node->instrument)
InstrStartNode(node->instrument);
@ -276,85 +287,85 @@ ExecProcNode(Plan *node, Plan *parent)
/*
* control nodes
*/
case T_Result:
result = ExecResult((Result *) node);
case T_ResultState:
result = ExecResult((ResultState *) node);
break;
case T_Append:
result = ExecProcAppend((Append *) node);
case T_AppendState:
result = ExecProcAppend((AppendState *) node);
break;
/*
* scan nodes
*/
case T_SeqScan:
result = ExecSeqScan((SeqScan *) node);
case T_SeqScanState:
result = ExecSeqScan((SeqScanState *) node);
break;
case T_IndexScan:
result = ExecIndexScan((IndexScan *) node);
case T_IndexScanState:
result = ExecIndexScan((IndexScanState *) node);
break;
case T_TidScan:
result = ExecTidScan((TidScan *) node);
case T_TidScanState:
result = ExecTidScan((TidScanState *) node);
break;
case T_SubqueryScan:
result = ExecSubqueryScan((SubqueryScan *) node);
case T_SubqueryScanState:
result = ExecSubqueryScan((SubqueryScanState *) node);
break;
case T_FunctionScan:
result = ExecFunctionScan((FunctionScan *) node);
case T_FunctionScanState:
result = ExecFunctionScan((FunctionScanState *) node);
break;
/*
* join nodes
*/
case T_NestLoop:
result = ExecNestLoop((NestLoop *) node);
case T_NestLoopState:
result = ExecNestLoop((NestLoopState *) node);
break;
case T_MergeJoin:
result = ExecMergeJoin((MergeJoin *) node);
case T_MergeJoinState:
result = ExecMergeJoin((MergeJoinState *) node);
break;
case T_Hash:
result = ExecHash((Hash *) node);
break;
case T_HashJoin:
result = ExecHashJoin((HashJoin *) node);
case T_HashJoinState:
result = ExecHashJoin((HashJoinState *) node);
break;
/*
* materialization nodes
*/
case T_Material:
result = ExecMaterial((Material *) node);
case T_MaterialState:
result = ExecMaterial((MaterialState *) node);
break;
case T_Sort:
result = ExecSort((Sort *) node);
case T_SortState:
result = ExecSort((SortState *) node);
break;
case T_Unique:
result = ExecUnique((Unique *) node);
case T_GroupState:
result = ExecGroup((GroupState *) node);
break;
case T_SetOp:
result = ExecSetOp((SetOp *) node);
case T_AggState:
result = ExecAgg((AggState *) node);
break;
case T_Limit:
result = ExecLimit((Limit *) node);
case T_UniqueState:
result = ExecUnique((UniqueState *) node);
break;
case T_Group:
result = ExecGroup((Group *) node);
case T_HashState:
result = ExecHash((HashState *) node);
break;
case T_Agg:
result = ExecAgg((Agg *) node);
case T_SetOpState:
result = ExecSetOp((SetOpState *) node);
break;
case T_LimitState:
result = ExecLimit((LimitState *) node);
break;
default:
@ -370,10 +381,16 @@ ExecProcNode(Plan *node, Plan *parent)
return result;
}
/*
* ExecCountSlotsNode - count up the number of tuple table slots needed
*
* Note that this scans a Plan tree, not a PlanState tree, because we
* haven't built the PlanState tree yet ...
*/
int
ExecCountSlotsNode(Plan *node)
{
if (node == (Plan *) NULL)
if (node == NULL)
return 0;
switch (nodeTag(node))
@ -414,9 +431,6 @@ ExecCountSlotsNode(Plan *node)
case T_MergeJoin:
return ExecCountSlotsMergeJoin((MergeJoin *) node);
case T_Hash:
return ExecCountSlotsHash((Hash *) node);
case T_HashJoin:
return ExecCountSlotsHashJoin((HashJoin *) node);
@ -429,26 +443,30 @@ ExecCountSlotsNode(Plan *node)
case T_Sort:
return ExecCountSlotsSort((Sort *) node);
case T_Group:
return ExecCountSlotsGroup((Group *) node);
case T_Agg:
return ExecCountSlotsAgg((Agg *) node);
case T_Unique:
return ExecCountSlotsUnique((Unique *) node);
case T_Hash:
return ExecCountSlotsHash((Hash *) node);
case T_SetOp:
return ExecCountSlotsSetOp((SetOp *) node);
case T_Limit:
return ExecCountSlotsLimit((Limit *) node);
case T_Group:
return ExecCountSlotsGroup((Group *) node);
case T_Agg:
return ExecCountSlotsAgg((Agg *) node);
default:
elog(ERROR, "ExecCountSlotsNode: node type %d unsupported",
(int) nodeTag(node));
break;
}
return 0;
}
@ -464,7 +482,7 @@ ExecCountSlotsNode(Plan *node)
* ----------------------------------------------------------------
*/
void
ExecEndNode(Plan *node, Plan *parent)
ExecEndNode(PlanState *node)
{
List *subp;
@ -474,14 +492,19 @@ ExecEndNode(Plan *node, Plan *parent)
if (node == NULL)
return;
if (node->instrument)
InstrEndLoop(node->instrument);
/* Clean up initPlans and subPlans */
foreach(subp, node->initPlan)
ExecEndSubPlan((SubPlan *) lfirst(subp));
ExecEndSubPlan((SubPlanState *) lfirst(subp));
foreach(subp, node->subPlan)
ExecEndSubPlan((SubPlan *) lfirst(subp));
if (node->chgParam != NULL)
ExecEndSubPlan((SubPlanState *) lfirst(subp));
if (node->chgParam != NIL)
{
freeList(node->chgParam);
node->chgParam = NULL;
node->chgParam = NIL;
}
switch (nodeTag(node))
@ -489,85 +512,85 @@ ExecEndNode(Plan *node, Plan *parent)
/*
* control nodes
*/
case T_Result:
ExecEndResult((Result *) node);
case T_ResultState:
ExecEndResult((ResultState *) node);
break;
case T_Append:
ExecEndAppend((Append *) node);
case T_AppendState:
ExecEndAppend((AppendState *) node);
break;
/*
* scan nodes
*/
case T_SeqScan:
ExecEndSeqScan((SeqScan *) node);
case T_SeqScanState:
ExecEndSeqScan((SeqScanState *) node);
break;
case T_IndexScan:
ExecEndIndexScan((IndexScan *) node);
case T_IndexScanState:
ExecEndIndexScan((IndexScanState *) node);
break;
case T_TidScan:
ExecEndTidScan((TidScan *) node);
case T_TidScanState:
ExecEndTidScan((TidScanState *) node);
break;
case T_SubqueryScan:
ExecEndSubqueryScan((SubqueryScan *) node);
case T_SubqueryScanState:
ExecEndSubqueryScan((SubqueryScanState *) node);
break;
case T_FunctionScan:
ExecEndFunctionScan((FunctionScan *) node);
case T_FunctionScanState:
ExecEndFunctionScan((FunctionScanState *) node);
break;
/*
* join nodes
*/
case T_NestLoop:
ExecEndNestLoop((NestLoop *) node);
case T_NestLoopState:
ExecEndNestLoop((NestLoopState *) node);
break;
case T_MergeJoin:
ExecEndMergeJoin((MergeJoin *) node);
case T_MergeJoinState:
ExecEndMergeJoin((MergeJoinState *) node);
break;
case T_Hash:
ExecEndHash((Hash *) node);
break;
case T_HashJoin:
ExecEndHashJoin((HashJoin *) node);
case T_HashJoinState:
ExecEndHashJoin((HashJoinState *) node);
break;
/*
* materialization nodes
*/
case T_Material:
ExecEndMaterial((Material *) node);
case T_MaterialState:
ExecEndMaterial((MaterialState *) node);
break;
case T_Sort:
ExecEndSort((Sort *) node);
case T_SortState:
ExecEndSort((SortState *) node);
break;
case T_Unique:
ExecEndUnique((Unique *) node);
case T_GroupState:
ExecEndGroup((GroupState *) node);
break;
case T_SetOp:
ExecEndSetOp((SetOp *) node);
case T_AggState:
ExecEndAgg((AggState *) node);
break;
case T_Limit:
ExecEndLimit((Limit *) node);
case T_UniqueState:
ExecEndUnique((UniqueState *) node);
break;
case T_Group:
ExecEndGroup((Group *) node);
case T_HashState:
ExecEndHash((HashState *) node);
break;
case T_Agg:
ExecEndAgg((Agg *) node);
case T_SetOpState:
ExecEndSetOp((SetOpState *) node);
break;
case T_LimitState:
ExecEndLimit((LimitState *) node);
break;
default:
@ -575,9 +598,6 @@ ExecEndNode(Plan *node, Plan *parent)
(int) nodeTag(node));
break;
}
if (node->instrument)
InstrEndLoop(node->instrument);
}
@ -592,7 +612,7 @@ ExecEndNode(Plan *node, Plan *parent)
* ----------------------------------------------------------------
*/
TupleDesc
ExecGetTupType(Plan *node)
ExecGetTupType(PlanState *node)
{
TupleTableSlot *slot;
@ -601,147 +621,147 @@ ExecGetTupType(Plan *node)
switch (nodeTag(node))
{
case T_Result:
case T_ResultState:
{
ResultState *resstate = ((Result *) node)->resstate;
ResultState *resstate = (ResultState *) node;
slot = resstate->cstate.cs_ResultTupleSlot;
slot = resstate->ps.ps_ResultTupleSlot;
}
break;
case T_SeqScan:
case T_AppendState:
{
CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
AppendState *appendstate = (AppendState *) node;
slot = scanstate->cstate.cs_ResultTupleSlot;
slot = appendstate->ps.ps_ResultTupleSlot;
}
break;
case T_NestLoop:
case T_SeqScanState:
{
NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
SeqScanState *scanstate = (SeqScanState *) node;
slot = nlstate->jstate.cs_ResultTupleSlot;
slot = scanstate->ps.ps_ResultTupleSlot;
}
break;
case T_Append:
case T_IndexScanState:
{
AppendState *appendstate = ((Append *) node)->appendstate;
IndexScanState *scanstate = (IndexScanState *) node;
slot = appendstate->cstate.cs_ResultTupleSlot;
slot = scanstate->ss.ps.ps_ResultTupleSlot;
}
break;
case T_IndexScan:
case T_TidScanState:
{
CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
TidScanState *scanstate = (TidScanState *) node;
slot = scanstate->cstate.cs_ResultTupleSlot;
slot = scanstate->ss.ps.ps_ResultTupleSlot;
}
break;
case T_TidScan:
case T_SubqueryScanState:
{
CommonScanState *scanstate = ((TidScan *) node)->scan.scanstate;
SubqueryScanState *scanstate = (SubqueryScanState *) node;
slot = scanstate->cstate.cs_ResultTupleSlot;
slot = scanstate->ss.ps.ps_ResultTupleSlot;
}
break;
case T_SubqueryScan:
case T_FunctionScanState:
{
CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
FunctionScanState *scanstate = (FunctionScanState *) node;
slot = scanstate->cstate.cs_ResultTupleSlot;
slot = scanstate->ss.ps.ps_ResultTupleSlot;
}
break;
case T_FunctionScan:
case T_NestLoopState:
{
CommonScanState *scanstate = ((FunctionScan *) node)->scan.scanstate;
NestLoopState *nlstate = (NestLoopState *) node;
slot = scanstate->cstate.cs_ResultTupleSlot;
slot = nlstate->js.ps.ps_ResultTupleSlot;
}
break;
case T_Material:
case T_MergeJoinState:
{
MaterialState *matstate = ((Material *) node)->matstate;
MergeJoinState *mergestate = (MergeJoinState *) node;
slot = matstate->csstate.css_ScanTupleSlot;
slot = mergestate->js.ps.ps_ResultTupleSlot;
}
break;
case T_Sort:
case T_HashJoinState:
{
SortState *sortstate = ((Sort *) node)->sortstate;
HashJoinState *hashjoinstate = (HashJoinState *) node;
slot = sortstate->csstate.css_ScanTupleSlot;
slot = hashjoinstate->js.ps.ps_ResultTupleSlot;
}
break;
case T_Agg:
case T_MaterialState:
{
AggState *aggstate = ((Agg *) node)->aggstate;
MaterialState *matstate = (MaterialState *) node;
slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
slot = matstate->ss.ss_ScanTupleSlot;
}
break;
case T_Group:
case T_SortState:
{
GroupState *grpstate = ((Group *) node)->grpstate;
SortState *sortstate = (SortState *) node;
slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
slot = sortstate->ss.ss_ScanTupleSlot;
}
break;
case T_Hash:
case T_GroupState:
{
HashState *hashstate = ((Hash *) node)->hashstate;
GroupState *grpstate = (GroupState *) node;
slot = hashstate->cstate.cs_ResultTupleSlot;
slot = grpstate->ss.ps.ps_ResultTupleSlot;
}
break;
case T_Unique:
case T_AggState:
{
UniqueState *uniquestate = ((Unique *) node)->uniquestate;
AggState *aggstate = (AggState *) node;
slot = uniquestate->cstate.cs_ResultTupleSlot;
slot = aggstate->ss.ps.ps_ResultTupleSlot;
}
break;
case T_SetOp:
case T_UniqueState:
{
SetOpState *setopstate = ((SetOp *) node)->setopstate;
UniqueState *uniquestate = (UniqueState *) node;
slot = setopstate->cstate.cs_ResultTupleSlot;
slot = uniquestate->ps.ps_ResultTupleSlot;
}
break;
case T_Limit:
case T_HashState:
{
LimitState *limitstate = ((Limit *) node)->limitstate;
HashState *hashstate = (HashState *) node;
slot = limitstate->cstate.cs_ResultTupleSlot;
slot = hashstate->ps.ps_ResultTupleSlot;
}
break;
case T_MergeJoin:
case T_SetOpState:
{
MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
SetOpState *setopstate = (SetOpState *) node;
slot = mergestate->jstate.cs_ResultTupleSlot;
slot = setopstate->ps.ps_ResultTupleSlot;
}
break;
case T_HashJoin:
case T_LimitState:
{
HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
LimitState *limitstate = (LimitState *) node;
slot = hashjoinstate->jstate.cs_ResultTupleSlot;
slot = limitstate->ps.ps_ResultTupleSlot;
}
break;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.112 2002/12/01 20:27:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.113 2002/12/05 15:50:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1766,7 +1766,8 @@ ExecEvalExpr(Node *expression,
isNull, isDone);
break;
case SUBPLAN_EXPR:
retDatum = ExecSubPlan((SubPlan *) expr->oper,
/* XXX temporary hack to find exec state node */
retDatum = ExecSubPlan(((SubPlan *) expr->oper)->pstate,
expr->args, econtext,
isNull);
break;
@ -1850,6 +1851,169 @@ ExecEvalExprSwitchContext(Node *expression,
}
/*
* ExecInitExpr: prepare an expression tree for execution
*
* 'node' is the root of the expression tree to examine
* 'parent' is the PlanState node that owns the expression,
* or NULL if we are preparing an expression that is not associated
* with a plan. (If so, it can't have Aggrefs or SubPlans.)
*
* Soon this will generate an expression state tree paralleling the given
* expression tree. Right now, it just searches the expression tree for
* Aggref and SubPlan nodes.
*/
Node *
ExecInitExpr(Node *node, PlanState *parent)
{
List *temp;
if (node == NULL)
return NULL;
switch (nodeTag(node))
{
case T_Var:
break;
case T_Const:
break;
case T_Param:
break;
case T_Aggref:
if (parent && IsA(parent, AggState))
{
AggState *aggstate = (AggState *) parent;
int naggs;
aggstate->aggs = lcons(node, aggstate->aggs);
naggs = ++aggstate->numaggs;
ExecInitExpr(((Aggref *) node)->target, parent);
/*
* Complain if the aggregate's argument contains any
* aggregates; nested agg functions are semantically
* nonsensical. (This probably was caught earlier,
* but we defend against it here anyway.)
*/
if (naggs != aggstate->numaggs)
elog(ERROR, "Aggregate function calls may not be nested");
}
else
elog(ERROR, "ExecInitExpr: Aggref not expected here");
break;
case T_ArrayRef:
{
ArrayRef *aref = (ArrayRef *) node;
ExecInitExpr((Node *) aref->refupperindexpr, parent);
ExecInitExpr((Node *) aref->reflowerindexpr, parent);
ExecInitExpr(aref->refexpr, parent);
ExecInitExpr(aref->refassgnexpr, parent);
}
break;
case T_Expr:
{
Expr *expr = (Expr *) node;
switch (expr->opType)
{
case OP_EXPR:
break;
case FUNC_EXPR:
break;
case OR_EXPR:
break;
case AND_EXPR:
break;
case NOT_EXPR:
break;
case DISTINCT_EXPR:
break;
case SUBPLAN_EXPR:
if (parent)
{
SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
/*
* Here we just add the SubPlan nodes to
* parent->subPlan. Later they will be expanded
* to SubPlanState nodes.
*/
parent->subPlan = lcons(expr->oper,
parent->subPlan);
/* Must recurse into oper list too */
Assert(IsA(sublink, SubLink));
if (sublink->lefthand)
elog(ERROR, "ExecInitExpr: sublink has not been transformed");
ExecInitExpr((Node *) sublink->oper, parent);
}
else
elog(ERROR, "ExecInitExpr: SubPlan not expected here");
break;
default:
elog(ERROR, "ExecInitExpr: unknown expression type %d",
expr->opType);
break;
}
/* for all Expr node types, examine args list */
ExecInitExpr((Node *) expr->args, parent);
}
break;
case T_FieldSelect:
ExecInitExpr(((FieldSelect *) node)->arg, parent);
break;
case T_RelabelType:
ExecInitExpr(((RelabelType *) node)->arg, parent);
break;
case T_CaseExpr:
{
CaseExpr *caseexpr = (CaseExpr *) node;
foreach(temp, caseexpr->args)
{
CaseWhen *when = (CaseWhen *) lfirst(temp);
Assert(IsA(when, CaseWhen));
ExecInitExpr(when->expr, parent);
ExecInitExpr(when->result, parent);
}
/* caseexpr->arg should be null, but we'll check it anyway */
ExecInitExpr(caseexpr->arg, parent);
ExecInitExpr(caseexpr->defresult, parent);
}
break;
case T_NullTest:
ExecInitExpr(((NullTest *) node)->arg, parent);
break;
case T_BooleanTest:
ExecInitExpr(((BooleanTest *) node)->arg, parent);
break;
case T_ConstraintTest:
ExecInitExpr(((ConstraintTest *) node)->arg, parent);
ExecInitExpr(((ConstraintTest *) node)->check_expr, parent);
break;
case T_ConstraintTestValue:
break;
case T_List:
foreach(temp, (List *) node)
{
ExecInitExpr((Node *) lfirst(temp), parent);
}
break;
case T_TargetEntry:
ExecInitExpr(((TargetEntry *) node)->expr, parent);
break;
default:
elog(ERROR, "ExecInitExpr: unknown expression type %d",
nodeTag(node));
break;
}
return node;
}
/* ----------------------------------------------------------------
* ExecQual / ExecTargetList / ExecProject
* ----------------------------------------------------------------

View File

@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.21 2002/09/02 02:47:02 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.22 2002/12/05 15:50:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -44,10 +44,9 @@
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecScan(Scan *node,
ExecScan(ScanState *node,
ExecScanAccessMtd accessMtd) /* function returning a tuple */
{
CommonScanState *scanstate;
EState *estate;
ExprContext *econtext;
List *qual;
@ -57,23 +56,22 @@ ExecScan(Scan *node,
/*
* Fetch data from node
*/
estate = node->plan.state;
scanstate = node->scanstate;
econtext = scanstate->cstate.cs_ExprContext;
qual = node->plan.qual;
estate = node->ps.state;
econtext = node->ps.ps_ExprContext;
qual = node->ps.qual;
/*
* Check to see if we're still projecting out tuples from a previous
* scan tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (scanstate->cstate.cs_TupFromTlist)
if (node->ps.ps_TupFromTlist)
{
resultSlot = ExecProject(scanstate->cstate.cs_ProjInfo, &isDone);
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return resultSlot;
/* Done with that source tuple... */
scanstate->cstate.cs_TupFromTlist = false;
node->ps.ps_TupFromTlist = false;
}
/*
@ -104,7 +102,7 @@ ExecScan(Scan *node,
if (TupIsNull(slot))
{
return ExecStoreTuple(NULL,
scanstate->cstate.cs_ProjInfo->pi_slot,
node->ps.ps_ProjInfo->pi_slot,
InvalidBuffer,
true);
}
@ -130,10 +128,10 @@ ExecScan(Scan *node,
* return it --- unless we find we can project no tuples from
* this scan tuple, in which case continue scan.
*/
resultSlot = ExecProject(scanstate->cstate.cs_ProjInfo, &isDone);
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
scanstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return resultSlot;
}
}

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.60 2002/09/28 20:00:19 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -483,11 +483,11 @@ ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */
* ----------------
*/
void
ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
{
INIT_SLOT_DEFS;
INIT_SLOT_ALLOC;
commonstate->cs_ResultTupleSlot = slot;
planstate->ps_ResultTupleSlot = slot;
}
/* ----------------
@ -495,11 +495,11 @@ ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
* ----------------
*/
void
ExecInitScanTupleSlot(EState *estate, CommonScanState *commonscanstate)
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
{
INIT_SLOT_DEFS;
INIT_SLOT_ALLOC;
commonscanstate->css_ScanTupleSlot = slot;
scanstate->ss_ScanTupleSlot = slot;
}
/* ----------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.90 2002/09/04 20:31:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.91 2002/12/05 15:50:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -142,7 +142,7 @@ DisplayTupleCount(FILE *statfp)
* ----------------
*/
void
ExecAssignExprContext(EState *estate, CommonState *commonstate)
ExecAssignExprContext(EState *estate, PlanState *planstate)
{
ExprContext *econtext = makeNode(ExprContext);
@ -166,7 +166,7 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
econtext->ecxt_aggnulls = NULL;
econtext->ecxt_callbacks = NULL;
commonstate->cs_ExprContext = econtext;
planstate->ps_ExprContext = econtext;
}
/* ----------------
@ -259,10 +259,10 @@ MakePerTupleExprContext(EState *estate)
* ----------------
*/
void
ExecAssignResultType(CommonState *commonstate,
ExecAssignResultType(PlanState *planstate,
TupleDesc tupDesc, bool shouldFree)
{
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
}
@ -272,15 +272,15 @@ ExecAssignResultType(CommonState *commonstate,
* ----------------
*/
void
ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
{
Plan *outerPlan;
PlanState *outerPlan;
TupleDesc tupDesc;
outerPlan = outerPlan(node);
outerPlan = outerPlanState(planstate);
tupDesc = ExecGetTupType(outerPlan);
ExecAssignResultType(commonstate, tupDesc, false);
ExecAssignResultType(planstate, tupDesc, false);
}
/* ----------------
@ -288,7 +288,7 @@ ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
* ----------------
*/
void
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
ExecAssignResultTypeFromTL(PlanState *planstate)
{
ResultRelInfo *ri;
bool hasoid = false;
@ -311,7 +311,7 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
* each of the child plans of the topmost Append plan. So, this is
* ugly but it works, for now ...
*/
ri = node->state->es_result_relation_info;
ri = planstate->state->es_result_relation_info;
if (ri != NULL)
{
Relation rel = ri->ri_RelationDesc;
@ -320,8 +320,13 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
hasoid = rel->rd_rel->relhasoids;
}
tupDesc = ExecTypeFromTL(node->targetlist, hasoid);
ExecAssignResultType(commonstate, tupDesc, true);
/*
* XXX Some plan nodes don't bother to set up planstate->targetlist,
* so use the underlying plan's targetlist instead. This will probably
* need to be fixed later.
*/
tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
ExecAssignResultType(planstate, tupDesc, true);
}
/* ----------------
@ -329,9 +334,9 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
* ----------------
*/
TupleDesc
ExecGetResultType(CommonState *commonstate)
ExecGetResultType(PlanState *planstate)
{
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
return slot->ttc_tupleDescriptor;
}
@ -342,23 +347,23 @@ ExecGetResultType(CommonState *commonstate)
* ----------------
*/
void
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
ExecAssignProjectionInfo(PlanState *planstate)
{
ProjectionInfo *projInfo;
List *targetList;
int len;
targetList = node->targetlist;
targetList = planstate->targetlist;
len = ExecTargetListLength(targetList);
projInfo = makeNode(ProjectionInfo);
projInfo->pi_targetlist = targetList;
projInfo->pi_len = len;
projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
projInfo->pi_exprContext = commonstate->cs_ExprContext;
projInfo->pi_slot = commonstate->cs_ResultTupleSlot;
projInfo->pi_exprContext = planstate->ps_ExprContext;
projInfo->pi_slot = planstate->ps_ResultTupleSlot;
commonstate->cs_ProjInfo = projInfo;
planstate->ps_ProjInfo = projInfo;
}
@ -367,7 +372,7 @@ ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
* ----------------
*/
void
ExecFreeProjectionInfo(CommonState *commonstate)
ExecFreeProjectionInfo(PlanState *planstate)
{
ProjectionInfo *projInfo;
@ -375,7 +380,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
* get projection info. if NULL then this node has none so we just
* return.
*/
projInfo = commonstate->cs_ProjInfo;
projInfo = planstate->ps_ProjInfo;
if (projInfo == NULL)
return;
@ -386,7 +391,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
pfree(projInfo->pi_tupValue);
pfree(projInfo);
commonstate->cs_ProjInfo = NULL;
planstate->ps_ProjInfo = NULL;
}
/* ----------------
@ -394,7 +399,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
* ----------------
*/
void
ExecFreeExprContext(CommonState *commonstate)
ExecFreeExprContext(PlanState *planstate)
{
ExprContext *econtext;
@ -402,7 +407,7 @@ ExecFreeExprContext(CommonState *commonstate)
* get expression context. if NULL then this node has none so we just
* return.
*/
econtext = commonstate->cs_ExprContext;
econtext = planstate->ps_ExprContext;
if (econtext == NULL)
return;
@ -416,7 +421,7 @@ ExecFreeExprContext(CommonState *commonstate)
*/
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext);
commonstate->cs_ExprContext = NULL;
planstate->ps_ExprContext = NULL;
}
/* ----------------------------------------------------------------
@ -434,9 +439,9 @@ ExecFreeExprContext(CommonState *commonstate)
* ----------------
*/
TupleDesc
ExecGetScanType(CommonScanState *csstate)
ExecGetScanType(ScanState *scanstate)
{
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
return slot->ttc_tupleDescriptor;
}
@ -446,10 +451,10 @@ ExecGetScanType(CommonScanState *csstate)
* ----------------
*/
void
ExecAssignScanType(CommonScanState *csstate,
ExecAssignScanType(ScanState *scanstate,
TupleDesc tupDesc, bool shouldFree)
{
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
}
@ -459,15 +464,15 @@ ExecAssignScanType(CommonScanState *csstate,
* ----------------
*/
void
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
{
Plan *outerPlan;
PlanState *outerPlan;
TupleDesc tupDesc;
outerPlan = outerPlan(node);
outerPlan = outerPlanState(scanstate);
tupDesc = ExecGetTupType(outerPlan);
ExecAssignScanType(csstate, tupDesc, false);
ExecAssignScanType(scanstate, tupDesc, false);
}
@ -718,7 +723,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
}
void
SetChangedParamList(Plan *node, List *newchg)
SetChangedParamList(PlanState *node, List *newchg)
{
List *nl;
@ -727,8 +732,8 @@ SetChangedParamList(Plan *node, List *newchg)
int paramId = lfirsti(nl);
/* if this node doesn't depend on a param ... */
if (!intMember(paramId, node->extParam) &&
!intMember(paramId, node->locParam))
if (!intMember(paramId, node->plan->extParam) &&
!intMember(paramId, node->plan->locParam))
continue;
/* if this param is already in list of changed ones ... */
if (intMember(paramId, node->chgParam))

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.60 2002/11/13 00:39:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,7 +28,9 @@
/*
* We have an execution_state record for each query in a function.
* We have an execution_state record for each query in a function. Each
* record contains a querytree and plantree for its query. If the query
* is currently in F_EXEC_RUN state then there's a QueryDesc too.
*/
typedef enum
{
@ -37,10 +39,11 @@ typedef enum
typedef struct local_es
{
QueryDesc *qd;
EState *estate;
struct local_es *next;
ExecStatus status;
Query *query;
Plan *plan;
QueryDesc *qd; /* null unless status == RUN */
} execution_state;
#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *) NULL)
@ -62,6 +65,8 @@ typedef struct
* we end execution of the function and
* free stuff */
ParamListInfo paramLI; /* Param list representing current args */
/* head of linked list of execution_state records */
execution_state *func_state;
} SQLFunctionCache;
@ -73,10 +78,11 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
static execution_state *init_execution_state(char *src,
Oid *argOidVect, int nargs);
static void init_sql_fcache(FmgrInfo *finfo);
static void postquel_start(execution_state *es);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static TupleTableSlot *postquel_getnext(execution_state *es);
static void postquel_end(execution_state *es);
static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo);
static void postquel_sub_params(SQLFunctionCachePtr fcache,
FunctionCallInfo fcinfo);
static Datum postquel_execute(execution_state *es,
FunctionCallInfo fcinfo,
SQLFunctionCachePtr fcache);
@ -101,7 +107,6 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
Query *queryTree = lfirst(qtl_item);
Plan *planTree;
execution_state *newes;
EState *estate;
planTree = pg_plan_query(queryTree);
@ -113,29 +118,9 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
newes->next = NULL;
newes->status = F_EXEC_START;
newes->qd = CreateQueryDesc(queryTree, planTree, None, NULL);
newes->estate = estate = CreateExecutorState();
if (nargs > 0)
{
int i;
ParamListInfo paramLI;
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
estate->es_param_list_info = paramLI;
for (i = 0; i < nargs; paramLI++, i++)
{
paramLI->kind = PARAM_NUM;
paramLI->id = i + 1;
paramLI->isnull = false;
paramLI->value = (Datum) NULL;
}
paramLI->kind = PARAM_INVALID;
}
else
estate->es_param_list_info = (ParamListInfo) NULL;
newes->query = queryTree;
newes->plan = planTree;
newes->qd = NULL;
preves = newes;
}
@ -219,6 +204,10 @@ init_sql_fcache(FmgrInfo *finfo)
else
fcache->funcSlot = NULL;
/*
* Parse and plan the queries. We need the argument info to pass
* to the parser.
*/
nargs = procedureStruct->pronargs;
if (nargs > 0)
@ -252,15 +241,18 @@ init_sql_fcache(FmgrInfo *finfo)
static void
postquel_start(execution_state *es)
postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
{
/*
* Do nothing for utility commands. (create, destroy...) DZ -
* 30-8-1996
*/
if (es->qd->operation == CMD_UTILITY)
return;
ExecutorStart(es->qd, es->estate);
Assert(es->qd == NULL);
es->qd = CreateQueryDesc(es->query, es->plan,
None, NULL,
fcache->paramLI, false);
/* Utility commands don't need Executor. */
if (es->qd->operation != CMD_UTILITY)
ExecutorStart(es->qd);
es->status = F_EXEC_RUN;
}
static TupleTableSlot *
@ -282,40 +274,52 @@ postquel_getnext(execution_state *es)
/* If it's not the last command, just run it to completion */
count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L;
return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count);
return ExecutorRun(es->qd, ForwardScanDirection, count);
}
static void
postquel_end(execution_state *es)
{
/*
* Do nothing for utility commands. (create, destroy...) DZ -
* 30-8-1996
*/
if (es->qd->operation == CMD_UTILITY)
return;
ExecutorEnd(es->qd, es->estate);
/* Utility commands don't need Executor. */
if (es->qd->operation != CMD_UTILITY)
ExecutorEnd(es->qd);
pfree(es->qd);
es->qd = NULL;
es->status = F_EXEC_DONE;
}
/* Build ParamListInfo array representing current arguments */
static void
postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo)
postquel_sub_params(SQLFunctionCachePtr fcache,
FunctionCallInfo fcinfo)
{
EState *estate;
ParamListInfo paramLI;
int nargs = fcinfo->nargs;
estate = es->estate;
paramLI = estate->es_param_list_info;
while (paramLI->kind != PARAM_INVALID)
if (nargs > 0)
{
if (paramLI->kind == PARAM_NUM)
int i;
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
for (i = 0; i < nargs; i++)
{
Assert(paramLI->id <= fcinfo->nargs);
paramLI->value = fcinfo->arg[paramLI->id - 1];
paramLI->isnull = fcinfo->argnull[paramLI->id - 1];
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
paramLI[i].value = fcinfo->arg[i];
paramLI[i].isnull = fcinfo->argnull[i];
}
paramLI++;
paramLI[nargs].kind = PARAM_INVALID;
}
else
paramLI = (ParamListInfo) NULL;
if (fcache->paramLI)
pfree(fcache->paramLI);
fcache->paramLI = paramLI;
}
static TupleTableSlot *
@ -359,27 +363,14 @@ postquel_execute(execution_state *es,
TupleTableSlot *slot;
Datum value;
/*
* It's more right place to do it (before
* postquel_start->ExecutorStart). Now
* ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
* note: I HOPE we can do it here). - vadim 01/22/97
*/
if (fcinfo->nargs > 0)
postquel_sub_params(es, fcinfo);
if (es->status == F_EXEC_START)
{
postquel_start(es);
es->status = F_EXEC_RUN;
}
postquel_start(es, fcache);
slot = postquel_getnext(es);
if (TupIsNull(slot))
{
postquel_end(es);
es->status = F_EXEC_DONE;
fcinfo->isnull = true;
/*
@ -438,10 +429,7 @@ postquel_execute(execution_state *es,
* execution now.
*/
if (!fcinfo->flinfo->fn_retset)
{
postquel_end(es);
es->status = F_EXEC_DONE;
}
return value;
}
@ -471,7 +459,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
/*
* Initialize fcache and execution state if first time through.
* Initialize fcache (build plans) if first time through.
*/
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
if (fcache == NULL)
@ -481,6 +469,13 @@ fmgr_sql(PG_FUNCTION_ARGS)
}
es = fcache->func_state;
/*
* Convert params to appropriate format if starting a fresh execution.
* (If continuing execution, we can re-use prior params.)
*/
if (es && es->status == F_EXEC_START)
postquel_sub_params(fcache, fcinfo);
/*
* Find first unfinished query in function.
*/
@ -506,7 +501,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
if (es == (execution_state *) NULL)
{
/*
* Reset the execution states to start over again
* Reset the execution states to start over again on next call.
*/
es = fcache->func_state;
while (es)

View File

@ -45,7 +45,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.97 2002/11/29 21:39:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.98 2002/12/05 15:50:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -212,11 +212,12 @@ static void finalize_aggregate(AggState *aggstate,
AggStatePerAgg peraggstate,
AggStatePerGroup pergroupstate,
Datum *resultVal, bool *resultIsNull);
static void build_hash_table(Agg *node);
static AggHashEntry lookup_hash_entry(Agg *node, TupleTableSlot *slot);
static TupleTableSlot *agg_retrieve_direct(Agg *node);
static void agg_fill_hash_table(Agg *node);
static TupleTableSlot *agg_retrieve_hash_table(Agg *node);
static void build_hash_table(AggState *aggstate);
static AggHashEntry lookup_hash_entry(AggState *aggstate,
TupleTableSlot *slot);
static TupleTableSlot *agg_retrieve_direct(AggState *aggstate);
static void agg_fill_hash_table(AggState *aggstate);
static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
@ -521,7 +522,7 @@ finalize_aggregate(AggState *aggstate,
{
MemoryContext oldContext;
oldContext = MemoryContextSwitchTo(aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory);
oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
/*
* Apply the agg's finalfn if one is provided, else return transValue.
@ -572,9 +573,9 @@ finalize_aggregate(AggState *aggstate,
* The hash table always lives in the aggcontext memory context.
*/
static void
build_hash_table(Agg *node)
build_hash_table(AggState *aggstate)
{
AggState *aggstate = node->aggstate;
Agg *node = (Agg *) aggstate->ss.ps.plan;
AggHashTable hashtable;
Size tabsize;
@ -596,9 +597,9 @@ build_hash_table(Agg *node)
* When called, CurrentMemoryContext should be the per-query context.
*/
static AggHashEntry
lookup_hash_entry(Agg *node, TupleTableSlot *slot)
lookup_hash_entry(AggState *aggstate, TupleTableSlot *slot)
{
AggState *aggstate = node->aggstate;
Agg *node = (Agg *) aggstate->ss.ps.plan;
AggHashTable hashtable = aggstate->hashtable;
MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
HeapTuple tuple = slot->val;
@ -684,16 +685,14 @@ lookup_hash_entry(Agg *node, TupleTableSlot *slot)
* the result tuple.
*/
TupleTableSlot *
ExecAgg(Agg *node)
ExecAgg(AggState *node)
{
AggState *aggstate = node->aggstate;
if (aggstate->agg_done)
if (node->agg_done)
return NULL;
if (node->aggstrategy == AGG_HASHED)
if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
{
if (!aggstate->table_filled)
if (!node->table_filled)
agg_fill_hash_table(node);
return agg_retrieve_hash_table(node);
}
@ -707,10 +706,10 @@ ExecAgg(Agg *node)
* ExecAgg for non-hashed case
*/
static TupleTableSlot *
agg_retrieve_direct(Agg *node)
agg_retrieve_direct(AggState *aggstate)
{
AggState *aggstate;
Plan *outerPlan;
Agg *node = (Agg *) aggstate->ss.ps.plan;
PlanState *outerPlan;
ExprContext *econtext;
ExprContext *tmpcontext;
ProjectionInfo *projInfo;
@ -726,22 +725,21 @@ agg_retrieve_direct(Agg *node)
/*
* get state info from node
*/
aggstate = node->aggstate;
outerPlan = outerPlan(node);
outerPlan = outerPlanState(aggstate);
/* econtext is the per-output-tuple expression context */
econtext = aggstate->csstate.cstate.cs_ExprContext;
econtext = aggstate->ss.ps.ps_ExprContext;
aggvalues = econtext->ecxt_aggvalues;
aggnulls = econtext->ecxt_aggnulls;
/* tmpcontext is the per-input-tuple expression context */
tmpcontext = aggstate->tmpcontext;
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
projInfo = aggstate->ss.ps.ps_ProjInfo;
peragg = aggstate->peragg;
pergroup = aggstate->pergroup;
firstSlot = aggstate->csstate.css_ScanTupleSlot;
firstSlot = aggstate->ss.ss_ScanTupleSlot;
/*
* We loop retrieving groups until we find one matching
* node->plan.qual
* aggstate->ss.ps.qual
*/
do
{
@ -754,7 +752,7 @@ agg_retrieve_direct(Agg *node)
*/
if (aggstate->grp_firstTuple == NULL)
{
outerslot = ExecProcNode(outerPlan, (Plan *) node);
outerslot = ExecProcNode(outerPlan);
if (!TupIsNull(outerslot))
{
/*
@ -810,7 +808,7 @@ agg_retrieve_direct(Agg *node)
/* Reset per-input-tuple context after each tuple */
ResetExprContext(tmpcontext);
outerslot = ExecProcNode(outerPlan, (Plan *) node);
outerslot = ExecProcNode(outerPlan);
if (TupIsNull(outerslot))
{
/* no more outer-plan tuples available */
@ -917,7 +915,7 @@ agg_retrieve_direct(Agg *node)
* Otherwise, return the tuple.
*/
}
while (!ExecQual(node->plan.qual, econtext, false));
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
return resultSlot;
}
@ -926,10 +924,9 @@ agg_retrieve_direct(Agg *node)
* ExecAgg for hashed case: phase 1, read input and build hash table
*/
static void
agg_fill_hash_table(Agg *node)
agg_fill_hash_table(AggState *aggstate)
{
AggState *aggstate;
Plan *outerPlan;
PlanState *outerPlan;
ExprContext *tmpcontext;
AggHashEntry entry;
TupleTableSlot *outerslot;
@ -937,8 +934,7 @@ agg_fill_hash_table(Agg *node)
/*
* get state info from node
*/
aggstate = node->aggstate;
outerPlan = outerPlan(node);
outerPlan = outerPlanState(aggstate);
/* tmpcontext is the per-input-tuple expression context */
tmpcontext = aggstate->tmpcontext;
@ -948,14 +944,14 @@ agg_fill_hash_table(Agg *node)
*/
for (;;)
{
outerslot = ExecProcNode(outerPlan, (Plan *) node);
outerslot = ExecProcNode(outerPlan);
if (TupIsNull(outerslot))
break;
/* set up for advance_aggregates call */
tmpcontext->ecxt_scantuple = outerslot;
/* Find or build hashtable entry for this tuple's group */
entry = lookup_hash_entry(node, outerslot);
entry = lookup_hash_entry(aggstate, outerslot);
/* Advance the aggregates */
advance_aggregates(aggstate, entry->pergroup);
@ -974,9 +970,8 @@ agg_fill_hash_table(Agg *node)
* ExecAgg for hashed case: phase 2, retrieving groups from hash table
*/
static TupleTableSlot *
agg_retrieve_hash_table(Agg *node)
agg_retrieve_hash_table(AggState *aggstate)
{
AggState *aggstate;
ExprContext *econtext;
ProjectionInfo *projInfo;
Datum *aggvalues;
@ -992,19 +987,18 @@ agg_retrieve_hash_table(Agg *node)
/*
* get state info from node
*/
aggstate = node->aggstate;
/* econtext is the per-output-tuple expression context */
econtext = aggstate->csstate.cstate.cs_ExprContext;
econtext = aggstate->ss.ps.ps_ExprContext;
aggvalues = econtext->ecxt_aggvalues;
aggnulls = econtext->ecxt_aggnulls;
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
projInfo = aggstate->ss.ps.ps_ProjInfo;
peragg = aggstate->peragg;
hashtable = aggstate->hashtable;
firstSlot = aggstate->csstate.css_ScanTupleSlot;
firstSlot = aggstate->ss.ss_ScanTupleSlot;
/*
* We loop retrieving groups until we find one matching
* node->plan.qual
* We loop retrieving groups until we find one satisfying
* aggstate->ss.ps.qual
*/
do
{
@ -1071,7 +1065,7 @@ agg_retrieve_hash_table(Agg *node)
* Otherwise, return the tuple.
*/
}
while (!ExecQual(node->plan.qual, econtext, false));
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
return resultSlot;
}
@ -1083,8 +1077,8 @@ agg_retrieve_hash_table(Agg *node)
* planner and initializes its outer subtree
* -----------------
*/
bool
ExecInitAgg(Agg *node, EState *estate, Plan *parent)
AggState *
ExecInitAgg(Agg *node, EState *estate)
{
AggState *aggstate;
AggStatePerAgg peragg;
@ -1094,16 +1088,15 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
aggno;
List *alist;
/*
* assign the node's execution state
*/
node->plan.state = estate;
/*
* create state structure
*/
aggstate = makeNode(AggState);
node->aggstate = aggstate;
aggstate->ss.ps.plan = (Plan *) node;
aggstate->ss.ps.state = estate;
aggstate->aggs = NIL;
aggstate->numaggs = 0;
aggstate->eqfunctions = NULL;
aggstate->peragg = NULL;
aggstate->agg_done = false;
@ -1111,38 +1104,14 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
aggstate->grp_firstTuple = NULL;
aggstate->hashtable = NULL;
/*
* find aggregates in targetlist and quals
*
* Note: pull_agg_clauses also checks that no aggs contain other agg
* calls in their arguments. This would make no sense under SQL
* semantics anyway (and it's forbidden by the spec). Because that is
* true, we don't need to worry about evaluating the aggs in any
* particular order.
*/
aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
pull_agg_clause((Node *) node->plan.qual));
aggstate->numaggs = numaggs = length(aggstate->aggs);
if (numaggs <= 0)
{
/*
* This is not an error condition: we might be using the Agg node just
* to do hash-based grouping. Even in the regular case,
* constant-expression simplification could optimize away all of the
* Aggrefs in the targetlist and qual. So keep going, but force local
* copy of numaggs positive so that palloc()s below don't choke.
*/
numaggs = 1;
}
/*
* Create expression contexts. We need two, one for per-input-tuple
* processing and one for per-output-tuple processing. We cheat a little
* by using ExecAssignExprContext() to build both.
*/
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
aggstate->tmpcontext = aggstate->csstate.cstate.cs_ExprContext;
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
ExecAssignExprContext(estate, &aggstate->ss.ps);
aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
ExecAssignExprContext(estate, &aggstate->ss.ps);
/*
* We also need a long-lived memory context for holding hashtable
@ -1163,14 +1132,64 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
/*
* tuple table initialization
*/
ExecInitScanTupleSlot(estate, &aggstate->csstate);
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
ExecInitScanTupleSlot(estate, &aggstate->ss);
ExecInitResultTupleSlot(estate, &aggstate->ss.ps);
/*
* initialize child expressions
*
* Note: ExecInitExpr finds Aggrefs for us, and also checks that no aggs
* contain other agg calls in their arguments. This would make no sense
* under SQL semantics anyway (and it's forbidden by the spec). Because
* that is true, we don't need to worry about evaluating the aggs in any
* particular order.
*/
aggstate->ss.ps.targetlist = (List *)
ExecInitExpr((Node *) node->plan.targetlist,
(PlanState *) aggstate);
aggstate->ss.ps.qual = (List *)
ExecInitExpr((Node *) node->plan.qual,
(PlanState *) aggstate);
/*
* initialize child nodes
*/
outerPlan = outerPlan(node);
outerPlanState(aggstate) = ExecInitNode(outerPlan, estate);
/*
* initialize source tuple type.
*/
ExecAssignScanTypeFromOuterPlan(&aggstate->ss);
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&aggstate->ss.ps);
ExecAssignProjectionInfo(&aggstate->ss.ps);
/*
* get the count of aggregates in targetlist and quals
*/
numaggs = aggstate->numaggs;
Assert(numaggs == length(aggstate->aggs));
if (numaggs <= 0)
{
/*
* This is not an error condition: we might be using the Agg node just
* to do hash-based grouping. Even in the regular case,
* constant-expression simplification could optimize away all of the
* Aggrefs in the targetlist and qual. So keep going, but force local
* copy of numaggs positive so that palloc()s below don't choke.
*/
numaggs = 1;
}
/*
* Set up aggregate-result storage in the output expr context, and also
* allocate my private per-agg working storage
*/
econtext = aggstate->csstate.cstate.cs_ExprContext;
econtext = aggstate->ss.ps.ps_ExprContext;
econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
@ -1179,7 +1198,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
if (node->aggstrategy == AGG_HASHED)
{
build_hash_table(node);
build_hash_table(aggstate);
aggstate->table_filled = false;
}
else
@ -1190,30 +1209,13 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
aggstate->pergroup = pergroup;
}
/*
* initialize child nodes
*/
outerPlan = outerPlan(node);
ExecInitNode(outerPlan, estate, (Plan *) node);
/*
* initialize source tuple type.
*/
ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL((Plan *) node, &aggstate->csstate.cstate);
ExecAssignProjectionInfo((Plan *) node, &aggstate->csstate.cstate);
/*
* If we are grouping, precompute fmgr lookup data for inner loop
*/
if (node->numCols > 0)
{
aggstate->eqfunctions =
execTuplesMatchPrepare(ExecGetScanType(&aggstate->csstate),
execTuplesMatchPrepare(ExecGetScanType(&aggstate->ss),
node->numCols,
node->grpColIdx);
}
@ -1330,7 +1332,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
ReleaseSysCache(aggTuple);
}
return TRUE;
return aggstate;
}
static Datum
@ -1372,84 +1374,82 @@ ExecCountSlotsAgg(Agg *node)
}
void
ExecEndAgg(Agg *node)
ExecEndAgg(AggState *node)
{
AggState *aggstate = node->aggstate;
Plan *outerPlan;
PlanState *outerPlan;
int aggno;
/* Make sure we have closed any open tuplesorts */
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
for (aggno = 0; aggno < node->numaggs; aggno++)
{
AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
AggStatePerAgg peraggstate = &node->peragg[aggno];
if (peraggstate->sortstate)
tuplesort_end(peraggstate->sortstate);
}
ExecFreeProjectionInfo(&aggstate->csstate.cstate);
ExecFreeProjectionInfo(&node->ss.ps);
/*
* Free both the expr contexts.
*/
ExecFreeExprContext(&aggstate->csstate.cstate);
aggstate->csstate.cstate.cs_ExprContext = aggstate->tmpcontext;
ExecFreeExprContext(&aggstate->csstate.cstate);
ExecFreeExprContext(&node->ss.ps);
node->ss.ps.ps_ExprContext = node->tmpcontext;
ExecFreeExprContext(&node->ss.ps);
MemoryContextDelete(aggstate->aggcontext);
MemoryContextDelete(node->aggcontext);
outerPlan = outerPlan(node);
ExecEndNode(outerPlan, (Plan *) node);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
/* clean up tuple table */
ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
if (aggstate->grp_firstTuple != NULL)
ExecClearTuple(node->ss.ss_ScanTupleSlot);
if (node->grp_firstTuple != NULL)
{
heap_freetuple(aggstate->grp_firstTuple);
aggstate->grp_firstTuple = NULL;
heap_freetuple(node->grp_firstTuple);
node->grp_firstTuple = NULL;
}
}
void
ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
{
AggState *aggstate = node->aggstate;
ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
ExprContext *econtext = node->ss.ps.ps_ExprContext;
int aggno;
/* Make sure we have closed any open tuplesorts */
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
for (aggno = 0; aggno < node->numaggs; aggno++)
{
AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
AggStatePerAgg peraggstate = &node->peragg[aggno];
if (peraggstate->sortstate)
tuplesort_end(peraggstate->sortstate);
peraggstate->sortstate = NULL;
}
aggstate->agg_done = false;
if (aggstate->grp_firstTuple != NULL)
node->agg_done = false;
if (node->grp_firstTuple != NULL)
{
heap_freetuple(aggstate->grp_firstTuple);
aggstate->grp_firstTuple = NULL;
heap_freetuple(node->grp_firstTuple);
node->grp_firstTuple = NULL;
}
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * aggstate->numaggs);
MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * aggstate->numaggs);
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
MemoryContextReset(aggstate->aggcontext);
MemoryContextReset(node->aggcontext);
if (node->aggstrategy == AGG_HASHED)
if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
{
build_hash_table(node);
aggstate->table_filled = false;
node->table_filled = false;
}
/*
* 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);
if (((PlanState *) node)->lefttree->chgParam == NIL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.50 2002/11/13 00:39:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.51 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -62,30 +62,27 @@
#include "executor/nodeAppend.h"
#include "parser/parsetree.h"
static bool exec_append_initialize_next(Append *node);
static bool exec_append_initialize_next(AppendState *appendstate);
/* ----------------------------------------------------------------
* exec_append_initialize_next
*
* Sets up the append node state (i.e. the append state node)
* for the "next" scan.
* Sets up the append state node for the "next" scan.
*
* Returns t iff there is a "next" scan to process.
* ----------------------------------------------------------------
*/
static bool
exec_append_initialize_next(Append *node)
exec_append_initialize_next(AppendState *appendstate)
{
EState *estate;
AppendState *appendstate;
int whichplan;
/*
* get information from the append node
*/
estate = node->plan.state;
appendstate = node->appendstate;
estate = appendstate->ps.state;
whichplan = appendstate->as_whichplan;
if (whichplan < appendstate->as_firstplan)
@ -116,7 +113,7 @@ exec_append_initialize_next(Append *node)
* If we are controlling the target relation, select the proper
* active ResultRelInfo and junk filter for this target.
*/
if (node->isTarget)
if (((Append *) appendstate->ps.plan)->isTarget)
{
Assert(whichplan < estate->es_num_result_relations);
estate->es_result_relation_info =
@ -132,9 +129,7 @@ exec_append_initialize_next(Append *node)
/* ----------------------------------------------------------------
* ExecInitAppend
*
* Begins all of the subscans of the append node, storing the
* scan structures in the 'initialized' vector of the append-state
* structure.
* Begin all of the subscans of the append node.
*
* (This is potentially wasteful, since the entire result of the
* append node may not be scanned, but this way all of the
@ -146,36 +141,31 @@ exec_append_initialize_next(Append *node)
* subplan that corresponds to the target relation being checked.
* ----------------------------------------------------------------
*/
bool
ExecInitAppend(Append *node, EState *estate, Plan *parent)
AppendState *
ExecInitAppend(Append *node, EState *estate)
{
AppendState *appendstate;
AppendState *appendstate = makeNode(AppendState);
PlanState **appendplanstates;
int nplans;
List *appendplans;
bool *initialized;
int i;
Plan *initNode;
CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
/*
* assign execution state to node and get information for append state
* Set up empty vector of subplan states
*/
node->plan.state = estate;
nplans = length(node->appendplans);
appendplans = node->appendplans;
nplans = length(appendplans);
initialized = (bool *) palloc0(nplans * sizeof(bool));
appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
/*
* create new AppendState for our append node
*/
appendstate = makeNode(AppendState);
appendstate->ps.plan = (Plan *) node;
appendstate->ps.state = estate;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
appendstate->as_initialized = initialized;
node->appendstate = appendstate;
/*
* Do we want to scan just one subplan? (Special case for
@ -212,36 +202,36 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
* append nodes still have Result slots, which hold pointers to
* tuples, so we have to initialize them.
*/
ExecInitResultTupleSlot(estate, &appendstate->cstate);
ExecInitResultTupleSlot(estate, &appendstate->ps);
/*
* call ExecInitNode on each of the plans to be executed and save the
* results into the array "initialized". Note we *must* set
* results into the array "appendplans". Note we *must* set
* estate->es_result_relation_info correctly while we initialize each
* sub-plan; ExecAssignResultTypeFromTL depends on that!
*/
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
{
appendstate->as_whichplan = i;
exec_append_initialize_next(node);
exec_append_initialize_next(appendstate);
initNode = (Plan *) nth(i, appendplans);
initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
initNode = (Plan *) nth(i, node->appendplans);
appendplanstates[i] = ExecInitNode(initNode, estate);
}
/*
* initialize tuple type
*/
ExecAssignResultTypeFromTL((Plan *) node, &appendstate->cstate);
appendstate->cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromTL(&appendstate->ps);
appendstate->ps.ps_ProjInfo = NULL;
/*
* return the result from the first subplan's initialization
*/
appendstate->as_whichplan = appendstate->as_firstplan;
exec_append_initialize_next(node);
exec_append_initialize_next(appendstate);
return TRUE;
return appendstate;
}
int
@ -264,13 +254,11 @@ ExecCountSlotsAppend(Append *node)
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecProcAppend(Append *node)
ExecProcAppend(AppendState *node)
{
EState *estate;
AppendState *appendstate;
int whichplan;
List *appendplans;
Plan *subnode;
PlanState *subnode;
TupleTableSlot *result;
TupleTableSlot *result_slot;
ScanDirection direction;
@ -278,25 +266,20 @@ ExecProcAppend(Append *node)
/*
* get information from the node
*/
appendstate = node->appendstate;
estate = node->plan.state;
estate = node->ps.state;
direction = estate->es_direction;
appendplans = node->appendplans;
whichplan = appendstate->as_whichplan;
result_slot = appendstate->cstate.cs_ResultTupleSlot;
whichplan = node->as_whichplan;
result_slot = node->ps.ps_ResultTupleSlot;
/*
* figure out which subplan we are currently processing
*/
subnode = (Plan *) nth(whichplan, appendplans);
if (subnode == NULL)
elog(DEBUG1, "ExecProcAppend: subnode is NULL");
subnode = node->appendplans[whichplan];
/*
* get a tuple from the subplan
*/
result = ExecProcNode(subnode, (Plan *) node);
result = ExecProcNode(subnode);
if (!TupIsNull(result))
{
@ -316,9 +299,9 @@ ExecProcAppend(Append *node)
* try processing again (recursively)
*/
if (ScanDirectionIsForward(direction))
appendstate->as_whichplan++;
node->as_whichplan++;
else
appendstate->as_whichplan--;
node->as_whichplan--;
/*
* return something from next node or an empty slot if all of our
@ -343,65 +326,56 @@ ExecProcAppend(Append *node)
* ----------------------------------------------------------------
*/
void
ExecEndAppend(Append *node)
ExecEndAppend(AppendState *node)
{
EState *estate;
AppendState *appendstate;
PlanState **appendplans;
int nplans;
List *appendplans;
bool *initialized;
int i;
/*
* get information from the node
*/
appendstate = node->appendstate;
estate = node->plan.state;
appendplans = node->appendplans;
nplans = appendstate->as_nplans;
initialized = appendstate->as_initialized;
nplans = node->as_nplans;
/*
* shut down each of the subscans
* shut down each of the subscans (that we've initialized)
*/
for (i = 0; i < nplans; i++)
{
if (initialized[i])
ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
if (appendplans[i])
ExecEndNode(appendplans[i]);
}
}
void
ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
{
AppendState *appendstate = node->appendstate;
int i;
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
for (i = node->as_firstplan; i <= node->as_lastplan; i++)
{
Plan *subnode;
subnode = (Plan *) nth(i, node->appendplans);
PlanState *subnode = node->appendplans[i];
/*
* ExecReScan doesn't know about my subplans, so I have to do
* changed-parameter signaling myself.
*/
if (node->plan.chgParam != NULL)
SetChangedParamList(subnode, node->plan.chgParam);
if (node->ps.chgParam != NIL)
SetChangedParamList(subnode, node->ps.chgParam);
/*
* if chgParam of subnode is not null then plan will be re-scanned
* by first ExecProcNode.
*/
if (subnode->chgParam == NULL)
if (subnode->chgParam == NIL)
{
/* make sure estate is correct for this subnode (needed??) */
appendstate->as_whichplan = i;
node->as_whichplan = i;
exec_append_initialize_next(node);
ExecReScan(subnode, exprCtxt, (Plan *) node);
ExecReScan(subnode, exprCtxt);
}
}
appendstate->as_whichplan = appendstate->as_firstplan;
node->as_whichplan = node->as_firstplan;
exec_append_initialize_next(node);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.13 2002/12/01 20:27:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.14 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -34,7 +34,7 @@
#include "utils/lsyscache.h"
static TupleTableSlot *FunctionNext(FunctionScan *node);
static TupleTableSlot *FunctionNext(FunctionScanState *node);
static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
/* ----------------------------------------------------------------
@ -48,24 +48,22 @@ static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
* ----------------------------------------------------------------
*/
static TupleTableSlot *
FunctionNext(FunctionScan *node)
FunctionNext(FunctionScanState *node)
{
TupleTableSlot *slot;
EState *estate;
ScanDirection direction;
Tuplestorestate *tuplestorestate;
FunctionScanState *scanstate;
bool should_free;
HeapTuple heapTuple;
/*
* get information from the estate and scan state
*/
scanstate = (FunctionScanState *) node->scan.scanstate;
estate = node->scan.plan.state;
estate = node->ss.ps.state;
direction = estate->es_direction;
tuplestorestate = scanstate->tuplestorestate;
tuplestorestate = node->tuplestorestate;
/*
* If first time through, read all tuples from function and put them
@ -74,13 +72,13 @@ FunctionNext(FunctionScan *node)
*/
if (tuplestorestate == NULL)
{
ExprContext *econtext = scanstate->csstate.cstate.cs_ExprContext;
ExprContext *econtext = node->ss.ps.ps_ExprContext;
TupleDesc funcTupdesc;
scanstate->tuplestorestate = tuplestorestate =
ExecMakeTableFunctionResult(scanstate->funcexpr,
node->tuplestorestate = tuplestorestate =
ExecMakeTableFunctionResult(node->funcexpr,
econtext,
scanstate->tupdesc,
node->tupdesc,
&funcTupdesc);
/*
@ -89,14 +87,14 @@ FunctionNext(FunctionScan *node)
* well do it always.
*/
if (funcTupdesc &&
tupledesc_mismatch(scanstate->tupdesc, funcTupdesc))
tupledesc_mismatch(node->tupdesc, funcTupdesc))
elog(ERROR, "Query-specified return tuple and actual function return tuple do not match");
}
/*
* Get the next tuple from tuplestore. Return NULL if no more tuples.
*/
slot = scanstate->csstate.css_ScanTupleSlot;
slot = node->ss.ss_ScanTupleSlot;
if (tuplestorestate)
heapTuple = tuplestore_getheaptuple(tuplestorestate,
ScanDirectionIsForward(direction),
@ -121,20 +119,20 @@ FunctionNext(FunctionScan *node)
*/
TupleTableSlot *
ExecFunctionScan(FunctionScan *node)
ExecFunctionScan(FunctionScanState *node)
{
/*
* use FunctionNext as access method
*/
return ExecScan(&node->scan, (ExecScanAccessMtd) FunctionNext);
return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
}
/* ----------------------------------------------------------------
* ExecInitFunctionScan
* ----------------------------------------------------------------
*/
bool
ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
FunctionScanState *
ExecInitFunctionScan(FunctionScan *node, EState *estate)
{
FunctionScanState *scanstate;
RangeTblEntry *rte;
@ -145,34 +143,40 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
/*
* FunctionScan should not have any children.
*/
Assert(outerPlan((Plan *) node) == NULL);
Assert(innerPlan((Plan *) node) == NULL);
/*
* assign the node's execution state
*/
node->scan.plan.state = estate;
Assert(outerPlan(node) == NULL);
Assert(innerPlan(node) == NULL);
/*
* create new ScanState for node
*/
scanstate = makeNode(FunctionScanState);
node->scan.scanstate = &scanstate->csstate;
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &scanstate->csstate.cstate);
ExecAssignExprContext(estate, &scanstate->ss.ps);
#define FUNCTIONSCAN_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &scanstate->csstate.cstate);
ExecInitScanTupleSlot(estate, &scanstate->csstate);
ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
ExecInitScanTupleSlot(estate, &scanstate->ss);
/*
* initialize child expressions
*/
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Node *) node->scan.plan.targetlist,
(PlanState *) scanstate);
scanstate->ss.ps.qual = (List *)
ExecInitExpr((Node *) node->scan.plan.qual,
(PlanState *) scanstate);
/*
* get info about function
@ -230,7 +234,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
elog(ERROR, "Unknown kind of return type specified for function");
scanstate->tupdesc = tupdesc;
ExecSetSlotDescriptor(scanstate->csstate.css_ScanTupleSlot,
ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
tupdesc, false);
/*
@ -239,15 +243,15 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
scanstate->tuplestorestate = NULL;
scanstate->funcexpr = rte->funcexpr;
scanstate->csstate.cstate.cs_TupFromTlist = false;
scanstate->ss.ps.ps_TupFromTlist = false;
/*
* initialize tuple type
*/
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->csstate.cstate);
ExecAssignProjectionInfo((Plan *) node, &scanstate->csstate.cstate);
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
ExecAssignProjectionInfo(&scanstate->ss.ps);
return TRUE;
return scanstate;
}
int
@ -265,39 +269,26 @@ ExecCountSlotsFunctionScan(FunctionScan *node)
* ----------------------------------------------------------------
*/
void
ExecEndFunctionScan(FunctionScan *node)
ExecEndFunctionScan(FunctionScanState *node)
{
FunctionScanState *scanstate;
EState *estate;
/*
* get information from node
*/
scanstate = (FunctionScanState *) node->scan.scanstate;
estate = node->scan.plan.state;
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&scanstate->csstate.cstate);
ExecFreeExprContext(&scanstate->csstate.cstate);
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
* clean out the tuple table
*/
ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
ExecClearTuple(scanstate->csstate.css_ScanTupleSlot);
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* Release tuplestore resources
*/
if (scanstate->tuplestorestate != NULL)
tuplestore_end(scanstate->tuplestorestate);
scanstate->tuplestorestate = NULL;
if (node->tuplestorestate != NULL)
tuplestore_end(node->tuplestorestate);
node->tuplestorestate = NULL;
}
/* ----------------------------------------------------------------
@ -307,19 +298,15 @@ ExecEndFunctionScan(FunctionScan *node)
* ----------------------------------------------------------------
*/
void
ExecFunctionMarkPos(FunctionScan *node)
ExecFunctionMarkPos(FunctionScanState *node)
{
FunctionScanState *scanstate;
scanstate = (FunctionScanState *) node->scan.scanstate;
/*
* if we haven't materialized yet, just return.
*/
if (!scanstate->tuplestorestate)
if (!node->tuplestorestate)
return;
tuplestore_markpos(scanstate->tuplestorestate);
tuplestore_markpos(node->tuplestorestate);
}
/* ----------------------------------------------------------------
@ -329,19 +316,15 @@ ExecFunctionMarkPos(FunctionScan *node)
* ----------------------------------------------------------------
*/
void
ExecFunctionRestrPos(FunctionScan *node)
ExecFunctionRestrPos(FunctionScanState *node)
{
FunctionScanState *scanstate;
scanstate = (FunctionScanState *) node->scan.scanstate;
/*
* if we haven't materialized yet, just return.
*/
if (!scanstate->tuplestorestate)
if (!node->tuplestorestate)
return;
tuplestore_restorepos(scanstate->tuplestorestate);
tuplestore_restorepos(node->tuplestorestate);
}
/* ----------------------------------------------------------------
@ -351,21 +334,14 @@ ExecFunctionRestrPos(FunctionScan *node)
* ----------------------------------------------------------------
*/
void
ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
{
FunctionScanState *scanstate;
/*
* get information from node
*/
scanstate = (FunctionScanState *) node->scan.scanstate;
ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
/*
* If we haven't materialized yet, just return.
*/
if (!scanstate->tuplestorestate)
if (!node->tuplestorestate)
return;
/*
@ -374,13 +350,13 @@ ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
* whether the function expression contains parameters and/or is
* marked volatile. FIXME soon.
*/
if (node->scan.plan.chgParam != NULL)
if (node->ss.ps.chgParam != NULL)
{
tuplestore_end(scanstate->tuplestorestate);
scanstate->tuplestorestate = NULL;
tuplestore_end(node->tuplestorestate);
node->tuplestorestate = NULL;
}
else
tuplestore_rescan(scanstate->tuplestorestate);
tuplestore_rescan(node->tuplestorestate);
}

View File

@ -15,7 +15,7 @@
* locate group boundaries.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.50 2002/11/29 21:39:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.51 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -38,12 +38,13 @@
* Return one tuple for each group of matching input tuples.
*/
TupleTableSlot *
ExecGroup(Group *node)
ExecGroup(GroupState *node)
{
GroupState *grpstate;
EState *estate;
ExprContext *econtext;
TupleDesc tupdesc;
int numCols;
AttrNumber *grpColIdx;
HeapTuple outerTuple = NULL;
HeapTuple firsttuple;
TupleTableSlot *outerslot;
@ -53,12 +54,13 @@ ExecGroup(Group *node)
/*
* get state info from node
*/
grpstate = node->grpstate;
if (grpstate->grp_done)
if (node->grp_done)
return NULL;
estate = node->plan.state;
econtext = node->grpstate->csstate.cstate.cs_ExprContext;
tupdesc = ExecGetScanType(&grpstate->csstate);
estate = node->ss.ps.state;
econtext = node->ss.ps.ps_ExprContext;
tupdesc = ExecGetScanType(&node->ss);
numCols = ((Group *) node->ss.ps.plan)->numCols;
grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
/*
* We need not call ResetExprContext here because execTuplesMatch will
@ -67,16 +69,16 @@ ExecGroup(Group *node)
/* If we don't already have first tuple of group, fetch it */
/* this should occur on the first call only */
firsttuple = grpstate->grp_firstTuple;
firsttuple = node->grp_firstTuple;
if (firsttuple == NULL)
{
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
outerslot = ExecProcNode(outerPlanState(node));
if (TupIsNull(outerslot))
{
grpstate->grp_done = TRUE;
node->grp_done = TRUE;
return NULL;
}
grpstate->grp_firstTuple = firsttuple =
node->grp_firstTuple = firsttuple =
heap_copytuple(outerslot->val);
}
@ -85,10 +87,10 @@ ExecGroup(Group *node)
*/
for (;;)
{
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
outerslot = ExecProcNode(outerPlanState(node));
if (TupIsNull(outerslot))
{
grpstate->grp_done = TRUE;
node->grp_done = TRUE;
outerTuple = NULL;
break;
}
@ -100,8 +102,8 @@ ExecGroup(Group *node)
*/
if (!execTuplesMatch(firsttuple, outerTuple,
tupdesc,
node->numCols, node->grpColIdx,
grpstate->eqfunctions,
numCols, grpColIdx,
node->eqfunctions,
econtext->ecxt_per_tuple_memory))
break;
}
@ -111,18 +113,18 @@ ExecGroup(Group *node)
* group, and store it in the result tuple slot.
*/
ExecStoreTuple(firsttuple,
grpstate->csstate.css_ScanTupleSlot,
node->ss.ss_ScanTupleSlot,
InvalidBuffer,
false);
econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
econtext->ecxt_scantuple = node->ss.ss_ScanTupleSlot;
projInfo = node->ss.ps.ps_ProjInfo;
resultSlot = ExecProject(projInfo, NULL);
/* save first tuple of next group, if we are not done yet */
if (!grpstate->grp_done)
if (!node->grp_done)
{
heap_freetuple(firsttuple);
grpstate->grp_firstTuple = heap_copytuple(outerTuple);
node->grp_firstTuple = heap_copytuple(outerTuple);
}
return resultSlot;
@ -135,65 +137,69 @@ ExecGroup(Group *node)
* planner and initializes its outer subtree
* -----------------
*/
bool
ExecInitGroup(Group *node, EState *estate, Plan *parent)
GroupState *
ExecInitGroup(Group *node, EState *estate)
{
GroupState *grpstate;
Plan *outerPlan;
/*
* assign the node's execution state
*/
node->plan.state = estate;
/*
* create state structure
*/
grpstate = makeNode(GroupState);
node->grpstate = grpstate;
grpstate->ss.ps.plan = (Plan *) node;
grpstate->ss.ps.state = estate;
grpstate->grp_firstTuple = NULL;
grpstate->grp_done = FALSE;
/*
* create expression context
*/
ExecAssignExprContext(estate, &grpstate->csstate.cstate);
ExecAssignExprContext(estate, &grpstate->ss.ps);
#define GROUP_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitScanTupleSlot(estate, &grpstate->csstate);
ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
ExecInitScanTupleSlot(estate, &grpstate->ss);
ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
/*
* initializes child nodes
* initialize child expressions
*/
outerPlan = outerPlan(node);
ExecInitNode(outerPlan, estate, (Plan *) node);
grpstate->ss.ps.targetlist = (List *)
ExecInitExpr((Node *) node->plan.targetlist,
(PlanState *) grpstate);
grpstate->ss.ps.qual = (List *)
ExecInitExpr((Node *) node->plan.qual,
(PlanState *) grpstate);
/*
* initialize child nodes
*/
outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate);
/*
* initialize tuple type.
*/
ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
/*
* Initialize tuple type for both result and scan. This node does no
* projection
*/
ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);
ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);
ExecAssignResultTypeFromTL(&grpstate->ss.ps);
ExecAssignProjectionInfo(&grpstate->ss.ps);
/*
* Precompute fmgr lookup data for inner loop
*/
grpstate->eqfunctions =
execTuplesMatchPrepare(ExecGetScanType(&grpstate->csstate),
execTuplesMatchPrepare(ExecGetScanType(&grpstate->ss),
node->numCols,
node->grpColIdx);
return TRUE;
return grpstate;
}
int
@ -208,43 +214,38 @@ ExecCountSlotsGroup(Group *node)
* -----------------------
*/
void
ExecEndGroup(Group *node)
ExecEndGroup(GroupState *node)
{
GroupState *grpstate;
Plan *outerPlan;
PlanState *outerPlan;
grpstate = node->grpstate;
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
ExecFreeProjectionInfo(&grpstate->csstate.cstate);
ExecFreeExprContext(&grpstate->csstate.cstate);
outerPlan = outerPlan(node);
ExecEndNode(outerPlan, (Plan *) node);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
/* clean up tuple table */
ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
if (grpstate->grp_firstTuple != NULL)
ExecClearTuple(node->ss.ss_ScanTupleSlot);
if (node->grp_firstTuple != NULL)
{
heap_freetuple(grpstate->grp_firstTuple);
grpstate->grp_firstTuple = NULL;
heap_freetuple(node->grp_firstTuple);
node->grp_firstTuple = NULL;
}
}
void
ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
{
GroupState *grpstate = node->grpstate;
grpstate->grp_done = FALSE;
if (grpstate->grp_firstTuple != NULL)
node->grp_done = FALSE;
if (node->grp_firstTuple != NULL)
{
heap_freetuple(grpstate->grp_firstTuple);
grpstate->grp_firstTuple = NULL;
heap_freetuple(node->grp_firstTuple);
node->grp_firstTuple = NULL;
}
if (((Plan *) node)->lefttree &&
((Plan *) node)->lefttree->chgParam == NULL)
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
if (((PlanState *) node)->lefttree &&
((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}
/*****************************************************************************

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.68 2002/11/30 00:08:15 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.69 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,11 +40,10 @@
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecHash(Hash *node)
ExecHash(HashState *node)
{
EState *estate;
HashState *hashstate;
Plan *outerNode;
PlanState *outerNode;
List *hashkeys;
HashJoinTable hashtable;
TupleTableSlot *slot;
@ -55,12 +54,10 @@ ExecHash(Hash *node)
/*
* get state info from node
*/
estate = node->ps.state;
outerNode = outerPlanState(node);
hashstate = node->hashstate;
estate = node->plan.state;
outerNode = outerPlan(node);
hashtable = hashstate->hashtable;
hashtable = node->hashtable;
if (hashtable == NULL)
elog(ERROR, "ExecHash: hash table is NULL.");
@ -79,15 +76,15 @@ ExecHash(Hash *node)
/*
* set expression context
*/
hashkeys = node->hashkeys;
econtext = hashstate->cstate.cs_ExprContext;
hashkeys = ((Hash *) node->ps.plan)->hashkeys;
econtext = node->ps.ps_ExprContext;
/*
* get all inner tuples and insert into the hash table (or temp files)
*/
for (;;)
{
slot = ExecProcNode(outerNode, (Plan *) node);
slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
break;
econtext->ecxt_innertuple = slot;
@ -108,24 +105,19 @@ ExecHash(Hash *node)
* Init routine for Hash node
* ----------------------------------------------------------------
*/
bool
ExecInitHash(Hash *node, EState *estate, Plan *parent)
HashState *
ExecInitHash(Hash *node, EState *estate)
{
HashState *hashstate;
Plan *outerPlan;
SO_printf("ExecInitHash: initializing hash node\n");
/*
* assign the node's execution state
*/
node->plan.state = estate;
/*
* create state structure
*/
hashstate = makeNode(HashState);
node->hashstate = hashstate;
hashstate->ps.plan = (Plan *) node;
hashstate->ps.state = estate;
hashstate->hashtable = NULL;
/*
@ -133,29 +125,38 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
*
* create expression context for node
*/
ExecAssignExprContext(estate, &hashstate->cstate);
ExecAssignExprContext(estate, &hashstate->ps);
#define HASH_NSLOTS 1
/*
* initialize our result slot
*/
ExecInitResultTupleSlot(estate, &hashstate->cstate);
ExecInitResultTupleSlot(estate, &hashstate->ps);
/*
* initializes child nodes
* initialize child expressions
*/
outerPlan = outerPlan(node);
ExecInitNode(outerPlan, estate, (Plan *) node);
hashstate->ps.targetlist = (List *)
ExecInitExpr((Node *) node->plan.targetlist,
(PlanState *) hashstate);
hashstate->ps.qual = (List *)
ExecInitExpr((Node *) node->plan.qual,
(PlanState *) hashstate);
/*
* initialize child nodes
*/
outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate);
/*
* initialize tuple type. no need to initialize projection info
* because this node doesn't do projections
*/
ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
hashstate->cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromOuterPlan(&hashstate->ps);
hashstate->ps.ps_ProjInfo = NULL;
return TRUE;
return hashstate;
}
int
@ -173,28 +174,22 @@ ExecCountSlotsHash(Hash *node)
* ----------------------------------------------------------------
*/
void
ExecEndHash(Hash *node)
ExecEndHash(HashState *node)
{
HashState *hashstate;
Plan *outerPlan;
/*
* get info from the hash state
*/
hashstate = node->hashstate;
PlanState *outerPlan;
/*
* free projection info. no need to free result type info because
* that came from the outer plan...
*/
ExecFreeProjectionInfo(&hashstate->cstate);
ExecFreeExprContext(&hashstate->cstate);
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
* shut down the subplan
*/
outerPlan = outerPlan(node);
ExecEndNode(outerPlan, (Plan *) node);
outerPlan = outerPlanState(node);
ExecEndNode(outerPlan);
}
@ -758,12 +753,12 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
}
void
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanHash(HashState *node, ExprContext *exprCtxt)
{
/*
* 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);
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.42 2002/11/30 00:08:15 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.43 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,8 +22,8 @@
#include "utils/memutils.h"
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
HashJoinState *hjstate);
static TupleTableSlot *ExecHashJoinOuterGetTuple(PlanState *node,
HashJoinState *hjstate);
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
BufFile *file,
TupleTableSlot *tupleSlot);
@ -41,12 +41,11 @@ static int ExecHashJoinNewBatch(HashJoinState *hjstate);
* ----------------------------------------------------------------
*/
TupleTableSlot * /* return: a tuple or NULL */
ExecHashJoin(HashJoin *node)
ExecHashJoin(HashJoinState *node)
{
HashJoinState *hjstate;
EState *estate;
Plan *outerNode;
Hash *hashNode;
PlanState *outerNode;
HashState *hashNode;
List *hjclauses;
List *outerkeys;
List *joinqual;
@ -65,37 +64,36 @@ ExecHashJoin(HashJoin *node)
/*
* get information from HashJoin node
*/
hjstate = node->hashjoinstate;
hjclauses = node->hashclauses;
estate = node->join.plan.state;
joinqual = node->join.joinqual;
otherqual = node->join.plan.qual;
hashNode = (Hash *) innerPlan(node);
outerNode = outerPlan(node);
hashPhaseDone = hjstate->hj_hashdone;
estate = node->js.ps.state;
joinqual = node->js.joinqual;
otherqual = node->js.ps.qual;
hashNode = (HashState *) innerPlanState(node);
outerNode = outerPlanState(node);
hashPhaseDone = node->hj_hashdone;
dir = estate->es_direction;
/*
* get information from HashJoin state
*/
hashtable = hjstate->hj_HashTable;
outerkeys = hjstate->hj_OuterHashKeys;
econtext = hjstate->jstate.cs_ExprContext;
hashtable = node->hj_HashTable;
outerkeys = node->hj_OuterHashKeys;
econtext = node->js.ps.ps_ExprContext;
/*
* Check to see if we're still projecting out tuples from a previous
* join tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (hjstate->jstate.cs_TupFromTlist)
if (node->js.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
hjstate->jstate.cs_TupFromTlist = false;
node->js.ps.ps_TupFromTlist = false;
}
/*
@ -116,16 +114,16 @@ ExecHashJoin(HashJoin *node)
/*
* create the hash table
*/
hashtable = ExecHashTableCreate(hashNode);
hjstate->hj_HashTable = hashtable;
hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan);
node->hj_HashTable = hashtable;
/*
* execute the Hash node, to build the hash table
*/
hashNode->hashstate->hashtable = hashtable;
innerTupleSlot = ExecProcNode((Plan *) hashNode, (Plan *) node);
hashNode->hashtable = hashtable;
innerTupleSlot = ExecProcNode((PlanState *) hashNode);
}
hjstate->hj_hashdone = true;
node->hj_hashdone = true;
/*
* Open temp files for outer batches, if needed. Note that file
@ -140,40 +138,39 @@ ExecHashJoin(HashJoin *node)
/*
* Now get an outer tuple and probe into the hash table for matches
*/
outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
outerTupleSlot = node->js.ps.ps_OuterTupleSlot;
for (;;)
{
/*
* If we don't have an outer tuple, get the next one
*/
if (hjstate->hj_NeedNewOuter)
if (node->hj_NeedNewOuter)
{
outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,
(Plan *) node,
hjstate);
node);
if (TupIsNull(outerTupleSlot))
{
/*
* when the last batch runs out, clean up and exit
*/
ExecHashTableDestroy(hashtable);
hjstate->hj_HashTable = NULL;
node->hj_HashTable = NULL;
return NULL;
}
hjstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
hjstate->hj_NeedNewOuter = false;
hjstate->hj_MatchedOuter = false;
node->hj_NeedNewOuter = false;
node->hj_MatchedOuter = false;
/*
* now we have an outer tuple, find the corresponding bucket
* for this tuple from the hash table
*/
hjstate->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
node->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
outerkeys);
hjstate->hj_CurTuple = NULL;
node->hj_CurTuple = NULL;
/*
* Now we've got an outer tuple and the corresponding hash
@ -182,7 +179,7 @@ ExecHashJoin(HashJoin *node)
*/
if (hashtable->curbatch == 0)
{
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
int batch = ExecHashJoinGetBatch(node->hj_CurBucketNo,
hashtable);
if (batch > 0)
@ -196,7 +193,7 @@ ExecHashJoin(HashJoin *node)
hashtable->outerBatchSize[batchno]++;
ExecHashJoinSaveTuple(outerTupleSlot->val,
hashtable->outerBatchFile[batchno]);
hjstate->hj_NeedNewOuter = true;
node->hj_NeedNewOuter = true;
continue; /* loop around for a new outer tuple */
}
}
@ -207,7 +204,7 @@ ExecHashJoin(HashJoin *node)
*/
for (;;)
{
curtuple = ExecScanHashBucket(hjstate,
curtuple = ExecScanHashBucket(node,
hjclauses,
econtext);
if (curtuple == NULL)
@ -217,7 +214,7 @@ ExecHashJoin(HashJoin *node)
* we've got a match, but still need to test non-hashed quals
*/
inntuple = ExecStoreTuple(curtuple,
hjstate->hj_HashTupleSlot,
node->hj_HashTupleSlot,
InvalidBuffer,
false); /* don't pfree this tuple */
econtext->ecxt_innertuple = inntuple;
@ -235,17 +232,17 @@ ExecHashJoin(HashJoin *node)
*/
if (ExecQual(joinqual, econtext, false))
{
hjstate->hj_MatchedOuter = true;
node->hj_MatchedOuter = true;
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
{
TupleTableSlot *result;
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
hjstate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -258,10 +255,10 @@ ExecHashJoin(HashJoin *node)
* whether to emit a dummy outer-join tuple. If not, loop around
* to get a new outer tuple.
*/
hjstate->hj_NeedNewOuter = true;
node->hj_NeedNewOuter = true;
if (!hjstate->hj_MatchedOuter &&
node->join.jointype == JOIN_LEFT)
if (!node->hj_MatchedOuter &&
node->js.jointype == JOIN_LEFT)
{
/*
* We are doing an outer join and there were no join matches
@ -269,7 +266,7 @@ ExecHashJoin(HashJoin *node)
* nulls for the inner tuple, and return it if it passes the
* non-join quals.
*/
econtext->ecxt_innertuple = hjstate->hj_NullInnerTupleSlot;
econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
@ -280,11 +277,11 @@ ExecHashJoin(HashJoin *node)
*/
TupleTableSlot *result;
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
hjstate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -299,47 +296,60 @@ ExecHashJoin(HashJoin *node)
* Init routine for HashJoin node.
* ----------------------------------------------------------------
*/
bool /* return: initialization status */
ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
HashJoinState *
ExecInitHashJoin(HashJoin *node, EState *estate)
{
HashJoinState *hjstate;
Plan *outerNode;
Hash *hashNode;
List *hcl;
/*
* assign the node's execution state
*/
node->join.plan.state = estate;
/*
* create state structure
*/
hjstate = makeNode(HashJoinState);
node->hashjoinstate = hjstate;
hjstate->js.ps.plan = (Plan *) node;
hjstate->js.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &hjstate->jstate);
ExecAssignExprContext(estate, &hjstate->js.ps);
/*
* initializes child nodes
* initialize child expressions
*/
outerNode = outerPlan((Plan *) node);
hashNode = (Hash *) innerPlan((Plan *) node);
hjstate->js.ps.targetlist = (List *)
ExecInitExpr((Node *) node->join.plan.targetlist,
(PlanState *) hjstate);
hjstate->js.ps.qual = (List *)
ExecInitExpr((Node *) node->join.plan.qual,
(PlanState *) hjstate);
hjstate->js.jointype = node->join.jointype;
hjstate->js.joinqual = (List *)
ExecInitExpr((Node *) node->join.joinqual,
(PlanState *) hjstate);
hjstate->hashclauses = (List *)
ExecInitExpr((Node *) node->hashclauses,
(PlanState *) hjstate);
ExecInitNode(outerNode, estate, (Plan *) node);
ExecInitNode((Plan *) hashNode, estate, (Plan *) node);
/*
* initialize child nodes
*/
outerNode = outerPlan(node);
hashNode = (Hash *) innerPlan(node);
outerPlanState(hjstate) = ExecInitNode(outerNode, estate);
innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate);
#define HASHJOIN_NSLOTS 3
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &hjstate->jstate);
ExecInitResultTupleSlot(estate, &hjstate->js.ps);
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
switch (node->join.jointype)
@ -349,7 +359,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
case JOIN_LEFT:
hjstate->hj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
ExecGetTupType((Plan *) hashNode));
ExecGetTupType(innerPlanState(hjstate)));
break;
default:
elog(ERROR, "ExecInitHashJoin: unsupported join type %d",
@ -364,8 +374,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
* the contents of the hash table. -cim 6/9/91
*/
{
HashState *hashstate = hashNode->hashstate;
TupleTableSlot *slot = hashstate->cstate.cs_ResultTupleSlot;
HashState *hashstate = (HashState *) innerPlanState(hjstate);
TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;
hjstate->hj_HashTupleSlot = slot;
}
@ -373,11 +383,11 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
/*
* initialize tuple type and projection info
*/
ExecAssignResultTypeFromTL((Plan *) node, &hjstate->jstate);
ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
ExecAssignResultTypeFromTL(&hjstate->js.ps);
ExecAssignProjectionInfo(&hjstate->js.ps);
ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
ExecGetTupType(outerNode),
ExecGetTupType(outerPlanState(hjstate)),
false);
/*
@ -402,12 +412,12 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
get_leftop(lfirst(hcl)));
}
hjstate->jstate.cs_OuterTupleSlot = NULL;
hjstate->jstate.cs_TupFromTlist = false;
hjstate->js.ps.ps_OuterTupleSlot = NULL;
hjstate->js.ps.ps_TupFromTlist = false;
hjstate->hj_NeedNewOuter = true;
hjstate->hj_MatchedOuter = false;
return TRUE;
return hjstate;
}
int
@ -425,46 +435,35 @@ ExecCountSlotsHashJoin(HashJoin *node)
* ----------------------------------------------------------------
*/
void
ExecEndHashJoin(HashJoin *node)
ExecEndHashJoin(HashJoinState *node)
{
HashJoinState *hjstate;
/*
* get info from the HashJoin state
*/
hjstate = node->hashjoinstate;
/*
* free hash table in case we end plan before all tuples are retrieved
*/
if (hjstate->hj_HashTable)
if (node->hj_HashTable)
{
ExecHashTableDestroy(hjstate->hj_HashTable);
hjstate->hj_HashTable = NULL;
ExecHashTableDestroy(node->hj_HashTable);
node->hj_HashTable = NULL;
}
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(hjstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&hjstate->jstate);
ExecFreeExprContext(&hjstate->jstate);
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
* clean up subtrees
*/
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
/*
* clean out the tuple table
*/
ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
ExecClearTuple(hjstate->hj_OuterTupleSlot);
ExecClearTuple(hjstate->hj_HashTupleSlot);
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->hj_OuterTupleSlot);
ExecClearTuple(node->hj_HashTupleSlot);
}
@ -478,7 +477,7 @@ ExecEndHashJoin(HashJoin *node)
*/
static TupleTableSlot *
ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
ExecHashJoinOuterGetTuple(PlanState *node, HashJoinState *hjstate)
{
HashJoinTable hashtable = hjstate->hj_HashTable;
int curbatch = hashtable->curbatch;
@ -486,7 +485,7 @@ ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
if (curbatch == 0)
{ /* if it is the first pass */
slot = ExecProcNode(node, parent);
slot = ExecProcNode(node);
if (!TupIsNull(slot))
return slot;
@ -611,7 +610,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
*/
ExecHashTableReset(hashtable, innerBatchSize[newbatch - 1]);
econtext = hjstate->jstate.cs_ExprContext;
econtext = hjstate->js.ps.ps_ExprContext;
innerhashkeys = hjstate->hj_InnerHashKeys;
while ((slot = ExecHashJoinGetSavedTuple(hjstate,
@ -682,39 +681,37 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
}
void
ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
{
HashJoinState *hjstate = node->hashjoinstate;
if (!hjstate->hj_hashdone)
if (!node->hj_hashdone)
return;
hjstate->hj_hashdone = false;
node->hj_hashdone = false;
/*
* Unfortunately, currently we have to destroy hashtable in all
* cases...
*/
if (hjstate->hj_HashTable)
if (node->hj_HashTable)
{
ExecHashTableDestroy(hjstate->hj_HashTable);
hjstate->hj_HashTable = NULL;
ExecHashTableDestroy(node->hj_HashTable);
node->hj_HashTable = NULL;
}
hjstate->hj_CurBucketNo = 0;
hjstate->hj_CurTuple = (HashJoinTuple) NULL;
node->hj_CurBucketNo = 0;
node->hj_CurTuple = (HashJoinTuple) NULL;
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
hjstate->jstate.cs_TupFromTlist = false;
hjstate->hj_NeedNewOuter = true;
hjstate->hj_MatchedOuter = false;
node->js.ps.ps_OuterTupleSlot = (TupleTableSlot *) NULL;
node->js.ps.ps_TupFromTlist = false;
node->hj_NeedNewOuter = true;
node->hj_MatchedOuter = 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);
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
if (((PlanState *) node)->righttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->righttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.71 2002/09/04 20:31:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.72 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,7 +40,7 @@
#define LEFT_OP 1
#define RIGHT_OP 2
static TupleTableSlot *IndexNext(IndexScan *node);
static TupleTableSlot *IndexNext(IndexScanState *node);
/* ----------------------------------------------------------------
* IndexNext
@ -65,15 +65,14 @@ static TupleTableSlot *IndexNext(IndexScan *node);
* ----------------------------------------------------------------
*/
static TupleTableSlot *
IndexNext(IndexScan *node)
IndexNext(IndexScanState *node)
{
EState *estate;
CommonScanState *scanstate;
IndexScanState *indexstate;
ExprContext *econtext;
ScanDirection direction;
IndexScanDescPtr scanDescs;
IndexScanDesc scandesc;
Index scanrelid;
HeapTuple tuple;
TupleTableSlot *slot;
int numIndices;
@ -83,21 +82,20 @@ IndexNext(IndexScan *node)
/*
* extract necessary information from index scan node
*/
estate = node->scan.plan.state;
estate = node->ss.ps.state;
direction = estate->es_direction;
if (ScanDirectionIsBackward(node->indxorderdir))
if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
{
if (ScanDirectionIsForward(direction))
direction = BackwardScanDirection;
else if (ScanDirectionIsBackward(direction))
direction = ForwardScanDirection;
}
scanstate = node->scan.scanstate;
indexstate = node->indxstate;
scanDescs = indexstate->iss_ScanDescs;
numIndices = indexstate->iss_NumIndices;
econtext = scanstate->cstate.cs_ExprContext;
slot = scanstate->css_ScanTupleSlot;
scanDescs = node->iss_ScanDescs;
numIndices = node->iss_NumIndices;
econtext = node->ss.ps.ps_ExprContext;
slot = node->ss.ss_ScanTupleSlot;
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
/*
* Check if we are evaluating PlanQual for tuple of this relation.
@ -106,15 +104,15 @@ IndexNext(IndexScan *node)
* switching in Init/ReScan plan...
*/
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
estate->es_evTuple[scanrelid - 1] != NULL)
{
List *qual;
ExecClearTuple(slot);
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
if (estate->es_evTupleNull[scanrelid - 1])
return slot; /* return empty slot */
ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
slot, InvalidBuffer, false);
/* Does the tuple meet any of the OR'd indxqual conditions? */
@ -131,7 +129,7 @@ IndexNext(IndexScan *node)
slot->val = NULL;
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
estate->es_evTupleNull[scanrelid - 1] = true;
return slot;
}
@ -144,24 +142,24 @@ IndexNext(IndexScan *node)
bBackward = ScanDirectionIsBackward(direction);
if (bBackward)
{
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
indexNumber = numIndices - node->iss_IndexPtr - 1;
if (indexNumber < 0)
{
indexNumber = 0;
indexstate->iss_IndexPtr = numIndices - 1;
node->iss_IndexPtr = numIndices - 1;
}
}
else
{
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
if ((indexNumber = node->iss_IndexPtr) < 0)
{
indexNumber = 0;
indexstate->iss_IndexPtr = 0;
node->iss_IndexPtr = 0;
}
}
while (indexNumber < numIndices)
{
scandesc = scanDescs[indexstate->iss_IndexPtr];
scandesc = scanDescs[node->iss_IndexPtr];
while ((tuple = index_getnext(scandesc, direction)) != NULL)
{
/*
@ -181,7 +179,7 @@ IndexNext(IndexScan *node)
* We do this by passing the tuple through ExecQual and
* checking for failure with all previous qualifications.
*/
if (indexstate->iss_IndexPtr > 0)
if (node->iss_IndexPtr > 0)
{
bool prev_matches = false;
int prev_index;
@ -191,7 +189,7 @@ IndexNext(IndexScan *node)
ResetExprContext(econtext);
qual = node->indxqualorig;
for (prev_index = 0;
prev_index < indexstate->iss_IndexPtr;
prev_index < node->iss_IndexPtr;
prev_index++)
{
if (ExecQual((List *) lfirst(qual), econtext, false))
@ -216,9 +214,9 @@ IndexNext(IndexScan *node)
{
indexNumber++;
if (bBackward)
indexstate->iss_IndexPtr--;
node->iss_IndexPtr--;
else
indexstate->iss_IndexPtr++;
node->iss_IndexPtr++;
}
}
@ -251,21 +249,19 @@ IndexNext(IndexScan *node)
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecIndexScan(IndexScan *node)
ExecIndexScan(IndexScanState *node)
{
IndexScanState *indexstate = node->indxstate;
/*
* If we have runtime keys and they've not already been set up, do it
* now.
*/
if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
ExecReScan((Plan *) node, NULL, NULL);
if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady)
ExecReScan((PlanState *) node, NULL);
/*
* use IndexNext as access method
*/
return ExecScan(&node->scan, (ExecScanAccessMtd) IndexNext);
return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
}
/* ----------------------------------------------------------------
@ -280,28 +276,27 @@ ExecIndexScan(IndexScan *node)
* ----------------------------------------------------------------
*/
void
ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
{
EState *estate;
IndexScanState *indexstate;
ExprContext *econtext;
int numIndices;
IndexScanDescPtr scanDescs;
ScanKey *scanKeys;
int **runtimeKeyInfo;
int *numScanKeys;
Index scanrelid;
int i;
int j;
estate = node->scan.plan.state;
indexstate = node->indxstate;
econtext = indexstate->iss_RuntimeContext; /* context for runtime
* keys */
numIndices = indexstate->iss_NumIndices;
scanDescs = indexstate->iss_ScanDescs;
scanKeys = indexstate->iss_ScanKeys;
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
numScanKeys = indexstate->iss_NumScanKeys;
estate = node->ss.ps.state;
econtext = node->iss_RuntimeContext; /* context for runtime keys */
numIndices = node->iss_NumIndices;
scanDescs = node->iss_ScanDescs;
scanKeys = node->iss_ScanKeys;
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
numScanKeys = node->iss_NumScanKeys;
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
if (econtext)
{
@ -315,7 +310,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
ExprContext *stdecontext;
econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
stdecontext = node->scan.scanstate->cstate.cs_ExprContext;
stdecontext = node->ss.ps.ps_ExprContext;
stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
}
@ -392,22 +387,22 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
}
}
indexstate->iss_RuntimeKeysReady = true;
node->iss_RuntimeKeysReady = true;
}
/* If this is re-scanning of PlanQual ... */
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
estate->es_evTuple[scanrelid - 1] != NULL)
{
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
estate->es_evTupleNull[scanrelid - 1] = false;
return;
}
/* reset index scans */
if (ScanDirectionIsBackward(node->indxorderdir))
indexstate->iss_IndexPtr = numIndices;
if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
node->iss_IndexPtr = numIndices;
else
indexstate->iss_IndexPtr = -1;
node->iss_IndexPtr = -1;
for (i = 0; i < numIndices; i++)
{
@ -427,13 +422,10 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
* ----------------------------------------------------------------
*/
void
ExecEndIndexScan(IndexScan *node)
ExecEndIndexScan(IndexScanState *node)
{
CommonScanState *scanstate;
IndexScanState *indexstate;
int **runtimeKeyInfo;
ScanKey *scanKeys;
List *indxqual;
int *numScanKeys;
int numIndices;
Relation relation;
@ -441,32 +433,25 @@ ExecEndIndexScan(IndexScan *node)
IndexScanDescPtr indexScanDescs;
int i;
scanstate = node->scan.scanstate;
indexstate = node->indxstate;
indxqual = node->indxqual;
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
/*
* extract information from the node
*/
numIndices = indexstate->iss_NumIndices;
scanKeys = indexstate->iss_ScanKeys;
numScanKeys = indexstate->iss_NumScanKeys;
indexRelationDescs = indexstate->iss_RelationDescs;
indexScanDescs = indexstate->iss_ScanDescs;
relation = scanstate->css_currentRelation;
numIndices = node->iss_NumIndices;
scanKeys = node->iss_ScanKeys;
numScanKeys = node->iss_NumScanKeys;
indexRelationDescs = node->iss_RelationDescs;
indexScanDescs = node->iss_ScanDescs;
relation = node->ss.ss_currentRelation;
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
if (indexstate->iss_RuntimeContext)
FreeExprContext(indexstate->iss_RuntimeContext);
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
if (node->iss_RuntimeContext)
FreeExprContext(node->iss_RuntimeContext);
/*
* close the index relations
@ -514,12 +499,11 @@ ExecEndIndexScan(IndexScan *node)
/*
* clear out tuple table slots
*/
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(scanstate->css_ScanTupleSlot);
pfree(scanstate);
pfree(indexstate->iss_RelationDescs);
pfree(indexstate->iss_ScanDescs);
pfree(indexstate);
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
pfree(node->iss_RelationDescs);
pfree(node->iss_ScanDescs);
pfree(node);
}
/* ----------------------------------------------------------------
@ -531,21 +515,16 @@ ExecEndIndexScan(IndexScan *node)
* ----------------------------------------------------------------
*/
void
ExecIndexMarkPos(IndexScan *node)
ExecIndexMarkPos(IndexScanState *node)
{
IndexScanState *indexstate;
IndexScanDescPtr indexScanDescs;
IndexScanDesc scanDesc;
int indexPtr;
indexstate = node->indxstate;
indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;
indexScanDescs = indexstate->iss_ScanDescs;
indexPtr = node->iss_MarkIndexPtr = node->iss_IndexPtr;
indexScanDescs = node->iss_ScanDescs;
scanDesc = indexScanDescs[indexPtr];
#ifdef NOT_USED
IndexScanMarkPosition(scanDesc);
#endif
index_markpos(scanDesc);
}
@ -560,21 +539,16 @@ ExecIndexMarkPos(IndexScan *node)
* ----------------------------------------------------------------
*/
void
ExecIndexRestrPos(IndexScan *node)
ExecIndexRestrPos(IndexScanState *node)
{
IndexScanState *indexstate;
IndexScanDescPtr indexScanDescs;
IndexScanDesc scanDesc;
int indexPtr;
indexstate = node->indxstate;
indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;
indexScanDescs = indexstate->iss_ScanDescs;
indexPtr = node->iss_IndexPtr = node->iss_MarkIndexPtr;
indexScanDescs = node->iss_ScanDescs;
scanDesc = indexScanDescs[indexPtr];
#ifdef NOT_USED
IndexScanRestorePosition(scanDesc);
#endif
index_restrpos(scanDesc);
}
@ -597,11 +571,10 @@ ExecIndexRestrPos(IndexScan *node)
* estate: the execution state initialized in InitPlan.
* ----------------------------------------------------------------
*/
bool
ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
IndexScanState *
ExecInitIndexScan(IndexScan *node, EState *estate)
{
IndexScanState *indexstate;
CommonScanState *scanstate;
List *indxqual;
List *indxid;
List *listscan;
@ -620,45 +593,52 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
Relation currentRelation;
/*
* assign execution state to node
* create state structure
*/
node->scan.plan.state = estate;
/*
* Part 1) initialize scan state
*
* create new CommonScanState for node
*/
scanstate = makeNode(CommonScanState);
node->scan.scanstate = scanstate;
indexstate = makeNode(IndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &scanstate->cstate);
ExecAssignExprContext(estate, &indexstate->ss.ps);
/*
* initialize child expressions
*/
indexstate->ss.ps.targetlist = (List *)
ExecInitExpr((Node *) node->scan.plan.targetlist,
(PlanState *) indexstate);
indexstate->ss.ps.qual = (List *)
ExecInitExpr((Node *) node->scan.plan.qual,
(PlanState *) indexstate);
indexstate->indxqual = (List *)
ExecInitExpr((Node *) node->indxqual,
(PlanState *) indexstate);
indexstate->indxqualorig = (List *)
ExecInitExpr((Node *) node->indxqualorig,
(PlanState *) indexstate);
#define INDEXSCAN_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &scanstate->cstate);
ExecInitScanTupleSlot(estate, scanstate);
ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
ExecInitScanTupleSlot(estate, &indexstate->ss);
/*
* initialize projection info. result type comes from scan desc
* below..
*/
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
ExecAssignProjectionInfo(&indexstate->ss.ps);
/*
* Part 2) initialize index scan state
*
* create new IndexScanState for node
* Initialize index-specific scan state
*/
indexstate = makeNode(IndexScanState);
indexstate->iss_NumIndices = 0;
indexstate->iss_IndexPtr = -1;
indexstate->iss_ScanKeys = NULL;
@ -669,8 +649,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
indexstate->iss_RelationDescs = NULL;
indexstate->iss_ScanDescs = NULL;
node->indxstate = indexstate;
/*
* get the index node information
*/
@ -836,7 +814,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
{
/* treat Param like a constant */
scanvalue = ExecEvalParam((Param *) leftop,
scanstate->cstate.cs_ExprContext,
indexstate->ss.ps.ps_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
@ -911,7 +889,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
{
/* treat Param like a constant */
scanvalue = ExecEvalParam((Param *) rightop,
scanstate->cstate.cs_ExprContext,
indexstate->ss.ps.ps_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
@ -976,12 +954,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
*/
if (have_runtime_keys)
{
ExprContext *stdecontext = scanstate->cstate.cs_ExprContext;
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
ExecAssignExprContext(estate, &scanstate->cstate);
ExecAssignExprContext(estate, &indexstate->ss.ps);
indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
indexstate->iss_RuntimeContext = scanstate->cstate.cs_ExprContext;
scanstate->cstate.cs_ExprContext = stdecontext;
indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
indexstate->ss.ps.ps_ExprContext = stdecontext;
}
else
{
@ -1008,14 +986,14 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
if (!RelationGetForm(currentRelation)->relhasindex)
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
indexstate->ss.ss_currentRelation = currentRelation;
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
/*
* get the scan type from the relation descriptor.
*/
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
/*
* open the index relations and initialize relation and scan
@ -1043,7 +1021,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
/*
* all done.
*/
return TRUE;
return indexstate;
}
int

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.11 2002/11/22 22:10:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.12 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -24,7 +24,7 @@
#include "executor/executor.h"
#include "executor/nodeLimit.h"
static void recompute_limits(Limit *node);
static void recompute_limits(LimitState *node);
/* ----------------------------------------------------------------
@ -35,26 +35,24 @@ static void recompute_limits(Limit *node);
* ----------------------------------------------------------------
*/
TupleTableSlot * /* return: a tuple or NULL */
ExecLimit(Limit *node)
ExecLimit(LimitState *node)
{
LimitState *limitstate;
ScanDirection direction;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
Plan *outerPlan;
PlanState *outerPlan;
/*
* get information from the node
*/
limitstate = node->limitstate;
direction = node->plan.state->es_direction;
outerPlan = outerPlan((Plan *) node);
resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot;
direction = node->ps.state->es_direction;
outerPlan = outerPlanState(node);
resultTupleSlot = node->ps.ps_ResultTupleSlot;
/*
* The main logic is a simple state machine.
*/
switch (limitstate->lstate)
switch (node->lstate)
{
case LIMIT_INITIAL:
/*
@ -71,9 +69,9 @@ ExecLimit(Limit *node)
/*
* Check for empty window; if so, treat like empty subplan.
*/
if (limitstate->count <= 0 && !limitstate->noCount)
if (node->count <= 0 && !node->noCount)
{
limitstate->lstate = LIMIT_EMPTY;
node->lstate = LIMIT_EMPTY;
return NULL;
}
/*
@ -81,24 +79,24 @@ ExecLimit(Limit *node)
*/
for (;;)
{
slot = ExecProcNode(outerPlan, (Plan *) node);
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
{
/*
* The subplan returns too few tuples for us to produce
* any output at all.
*/
limitstate->lstate = LIMIT_EMPTY;
node->lstate = LIMIT_EMPTY;
return NULL;
}
limitstate->subSlot = slot;
if (++limitstate->position > limitstate->offset)
node->subSlot = slot;
if (++node->position > node->offset)
break;
}
/*
* Okay, we have the first tuple of the window.
*/
limitstate->lstate = LIMIT_INWINDOW;
node->lstate = LIMIT_INWINDOW;
break;
case LIMIT_EMPTY:
@ -117,23 +115,23 @@ ExecLimit(Limit *node)
* advancing the subplan or the position variable; but
* change the state machine state to record having done so.
*/
if (!limitstate->noCount &&
limitstate->position >= limitstate->offset + limitstate->count)
if (!node->noCount &&
node->position >= node->offset + node->count)
{
limitstate->lstate = LIMIT_WINDOWEND;
node->lstate = LIMIT_WINDOWEND;
return NULL;
}
/*
* Get next tuple from subplan, if any.
*/
slot = ExecProcNode(outerPlan, (Plan *) node);
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
{
limitstate->lstate = LIMIT_SUBPLANEOF;
node->lstate = LIMIT_SUBPLANEOF;
return NULL;
}
limitstate->subSlot = slot;
limitstate->position++;
node->subSlot = slot;
node->position++;
}
else
{
@ -141,19 +139,19 @@ ExecLimit(Limit *node)
* Backwards scan, so check for stepping off start of window.
* As above, change only state-machine status if so.
*/
if (limitstate->position <= limitstate->offset + 1)
if (node->position <= node->offset + 1)
{
limitstate->lstate = LIMIT_WINDOWSTART;
node->lstate = LIMIT_WINDOWSTART;
return NULL;
}
/*
* Get previous tuple from subplan; there should be one!
*/
slot = ExecProcNode(outerPlan, (Plan *) node);
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
elog(ERROR, "ExecLimit: subplan failed to run backwards");
limitstate->subSlot = slot;
limitstate->position--;
node->subSlot = slot;
node->position--;
}
break;
@ -164,11 +162,11 @@ ExecLimit(Limit *node)
* Backing up from subplan EOF, so re-fetch previous tuple;
* there should be one! Note previous tuple must be in window.
*/
slot = ExecProcNode(outerPlan, (Plan *) node);
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
elog(ERROR, "ExecLimit: subplan failed to run backwards");
limitstate->subSlot = slot;
limitstate->lstate = LIMIT_INWINDOW;
node->subSlot = slot;
node->lstate = LIMIT_INWINDOW;
/* position does not change 'cause we didn't advance it before */
break;
@ -179,8 +177,8 @@ ExecLimit(Limit *node)
* Backing up from window end: simply re-return the last
* tuple fetched from the subplan.
*/
slot = limitstate->subSlot;
limitstate->lstate = LIMIT_INWINDOW;
slot = node->subSlot;
node->lstate = LIMIT_INWINDOW;
/* position does not change 'cause we didn't advance it before */
break;
@ -191,14 +189,14 @@ ExecLimit(Limit *node)
* Advancing after having backed off window start: simply
* re-return the last tuple fetched from the subplan.
*/
slot = limitstate->subSlot;
limitstate->lstate = LIMIT_INWINDOW;
slot = node->subSlot;
node->lstate = LIMIT_INWINDOW;
/* position does not change 'cause we didn't change it before */
break;
default:
elog(ERROR, "ExecLimit: impossible state %d",
(int) limitstate->lstate);
(int) node->lstate);
slot = NULL; /* keep compiler quiet */
break;
}
@ -220,55 +218,54 @@ ExecLimit(Limit *node)
* This is also a handy place to reset the current-position state info.
*/
static void
recompute_limits(Limit *node)
recompute_limits(LimitState *node)
{
LimitState *limitstate = node->limitstate;
ExprContext *econtext = limitstate->cstate.cs_ExprContext;
ExprContext *econtext = node->ps.ps_ExprContext;
bool isNull;
if (node->limitOffset)
{
limitstate->offset =
node->offset =
DatumGetInt32(ExecEvalExprSwitchContext(node->limitOffset,
econtext,
&isNull,
NULL));
/* Interpret NULL offset as no offset */
if (isNull)
limitstate->offset = 0;
else if (limitstate->offset < 0)
limitstate->offset = 0;
node->offset = 0;
else if (node->offset < 0)
node->offset = 0;
}
else
{
/* No OFFSET supplied */
limitstate->offset = 0;
node->offset = 0;
}
if (node->limitCount)
{
limitstate->noCount = false;
limitstate->count =
node->noCount = false;
node->count =
DatumGetInt32(ExecEvalExprSwitchContext(node->limitCount,
econtext,
&isNull,
NULL));
/* Interpret NULL count as no count (LIMIT ALL) */
if (isNull)
limitstate->noCount = true;
else if (limitstate->count < 0)
limitstate->count = 0;
node->noCount = true;
else if (node->count < 0)
node->count = 0;
}
else
{
/* No COUNT supplied */
limitstate->count = 0;
limitstate->noCount = true;
node->count = 0;
node->noCount = true;
}
/* Reset position to start-of-scan */
limitstate->position = 0;
limitstate->subSlot = NULL;
node->position = 0;
node->subSlot = NULL;
}
/* ----------------------------------------------------------------
@ -278,22 +275,19 @@ recompute_limits(Limit *node)
* the node's subplan.
* ----------------------------------------------------------------
*/
bool /* return: initialization status */
ExecInitLimit(Limit *node, EState *estate, Plan *parent)
LimitState *
ExecInitLimit(Limit *node, EState *estate)
{
LimitState *limitstate;
Plan *outerPlan;
/*
* assign execution state to node
*/
node->plan.state = estate;
/*
* create new LimitState for node
* create state structure
*/
limitstate = makeNode(LimitState);
node->limitstate = limitstate;
limitstate->ps.plan = (Plan *) node;
limitstate->ps.state = estate;
limitstate->lstate = LIMIT_INITIAL;
/*
@ -302,29 +296,37 @@ ExecInitLimit(Limit *node, EState *estate, Plan *parent)
* Limit nodes never call ExecQual or ExecProject, but they need an
* exprcontext anyway to evaluate the limit/offset parameters in.
*/
ExecAssignExprContext(estate, &limitstate->cstate);
ExecAssignExprContext(estate, &limitstate->ps);
/*
* initialize child expressions
*/
limitstate->limitOffset = ExecInitExpr(node->limitOffset,
(PlanState *) limitstate);
limitstate->limitCount = ExecInitExpr(node->limitCount,
(PlanState *) limitstate);
#define LIMIT_NSLOTS 1
/*
* Tuple table initialization
*/
ExecInitResultTupleSlot(estate, &limitstate->cstate);
ExecInitResultTupleSlot(estate, &limitstate->ps);
/*
* then initialize outer plan
*/
outerPlan = outerPlan((Plan *) node);
ExecInitNode(outerPlan, estate, (Plan *) node);
outerPlan = outerPlan(node);
outerPlanState(limitstate) = ExecInitNode(outerPlan, estate);
/*
* limit nodes do no projections, so initialize projection info for
* this node appropriately
*/
ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate);
limitstate->cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromOuterPlan(&limitstate->ps);
limitstate->ps.ps_ProjInfo = NULL;
return TRUE;
return limitstate;
}
int
@ -343,33 +345,29 @@ ExecCountSlotsLimit(Limit *node)
* ----------------------------------------------------------------
*/
void
ExecEndLimit(Limit *node)
ExecEndLimit(LimitState *node)
{
LimitState *limitstate = node->limitstate;
ExecFreeExprContext(&node->ps);
ExecFreeExprContext(&limitstate->cstate);
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
ExecEndNode(outerPlanState(node));
/* clean up tuple table */
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(node->ps.ps_ResultTupleSlot);
}
void
ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanLimit(LimitState *node, ExprContext *exprCtxt)
{
LimitState *limitstate = node->limitstate;
/* resetting lstate will force offset/limit recalculation */
limitstate->lstate = LIMIT_INITIAL;
node->lstate = LIMIT_INITIAL;
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(node->ps.ps_ResultTupleSlot);
/*
* 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);
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.38 2002/06/20 20:29:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -43,10 +43,9 @@
* ----------------------------------------------------------------
*/
TupleTableSlot * /* result tuple from subplan */
ExecMaterial(Material *node)
ExecMaterial(MaterialState *node)
{
EState *estate;
MaterialState *matstate;
ScanDirection dir;
Tuplestorestate *tuplestorestate;
HeapTuple heapTuple;
@ -56,10 +55,9 @@ ExecMaterial(Material *node)
/*
* get state info from node
*/
matstate = node->matstate;
estate = node->plan.state;
estate = node->ss.ps.state;
dir = estate->es_direction;
tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
/*
* If first time through, read all tuples from outer plan and pass
@ -69,7 +67,7 @@ ExecMaterial(Material *node)
if (tuplestorestate == NULL)
{
Plan *outerNode;
PlanState *outerNode;
/*
* Want to scan subplan in the forward direction while creating
@ -84,16 +82,16 @@ ExecMaterial(Material *node)
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
SortMem);
matstate->tuplestorestate = (void *) tuplestorestate;
node->tuplestorestate = (void *) tuplestorestate;
/*
* Scan the subplan and feed all the tuples to tuplestore.
*/
outerNode = outerPlan((Plan *) node);
outerNode = outerPlanState(node);
for (;;)
{
slot = ExecProcNode(outerNode, (Plan *) node);
slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
break;
@ -117,7 +115,7 @@ ExecMaterial(Material *node)
* Get the first or next tuple from tuplestore. Returns NULL if no
* more tuples.
*/
slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
heapTuple = tuplestore_getheaptuple(tuplestorestate,
ScanDirectionIsForward(dir),
&should_free);
@ -129,23 +127,20 @@ ExecMaterial(Material *node)
* ExecInitMaterial
* ----------------------------------------------------------------
*/
bool /* initialization status */
ExecInitMaterial(Material *node, EState *estate, Plan *parent)
MaterialState *
ExecInitMaterial(Material *node, EState *estate)
{
MaterialState *matstate;
Plan *outerPlan;
/*
* assign the node's execution state
*/
node->plan.state = estate;
/*
* create state structure
*/
matstate = makeNode(MaterialState);
matstate->ss.ps.plan = (Plan *) node;
matstate->ss.ps.state = estate;
matstate->tuplestorestate = NULL;
node->matstate = matstate;
/*
* Miscellaneous initialization
@ -161,24 +156,24 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
*
* material nodes only return tuples from their materialized relation.
*/
ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
ExecInitScanTupleSlot(estate, &matstate->csstate);
ExecInitResultTupleSlot(estate, &matstate->ss.ps);
ExecInitScanTupleSlot(estate, &matstate->ss);
/*
* initializes child nodes
*/
outerPlan = outerPlan((Plan *) node);
ExecInitNode(outerPlan, estate, (Plan *) node);
outerPlan = outerPlan(node);
outerPlanState(matstate) = ExecInitNode(outerPlan, estate);
/*
* initialize tuple type. no need to initialize projection info
* because this node doesn't do projections.
*/
ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
matstate->csstate.cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromOuterPlan(&matstate->ss.ps);
ExecAssignScanTypeFromOuterPlan(&matstate->ss);
matstate->ss.ps.ps_ProjInfo = NULL;
return TRUE;
return matstate;
}
int
@ -194,33 +189,24 @@ ExecCountSlotsMaterial(Material *node)
* ----------------------------------------------------------------
*/
void
ExecEndMaterial(Material *node)
ExecEndMaterial(MaterialState *node)
{
MaterialState *matstate;
Plan *outerPlan;
/*
* get info from the material state
* clean out the tuple table
*/
matstate = node->matstate;
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* shut down the subplan
*/
outerPlan = outerPlan((Plan *) node);
ExecEndNode(outerPlan, (Plan *) node);
/*
* clean out the tuple table
*/
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
ExecEndNode(outerPlanState(node));
/*
* Release tuplestore resources
*/
if (matstate->tuplestorestate != NULL)
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
matstate->tuplestorestate = NULL;
if (node->tuplestorestate != NULL)
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL;
}
/* ----------------------------------------------------------------
@ -230,17 +216,15 @@ ExecEndMaterial(Material *node)
* ----------------------------------------------------------------
*/
void
ExecMaterialMarkPos(Material *node)
ExecMaterialMarkPos(MaterialState *node)
{
MaterialState *matstate = node->matstate;
/*
* if we haven't materialized yet, just return.
*/
if (!matstate->tuplestorestate)
if (!node->tuplestorestate)
return;
tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate);
tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
}
/* ----------------------------------------------------------------
@ -250,20 +234,18 @@ ExecMaterialMarkPos(Material *node)
* ----------------------------------------------------------------
*/
void
ExecMaterialRestrPos(Material *node)
ExecMaterialRestrPos(MaterialState *node)
{
MaterialState *matstate = node->matstate;
/*
* if we haven't materialized yet, just return.
*/
if (!matstate->tuplestorestate)
if (!node->tuplestorestate)
return;
/*
* restore the scan to the previously marked position
*/
tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate);
tuplestore_restorepos((Tuplestorestate *) node->tuplestorestate);
}
/* ----------------------------------------------------------------
@ -273,19 +255,17 @@ ExecMaterialRestrPos(Material *node)
* ----------------------------------------------------------------
*/
void
ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
{
MaterialState *matstate = node->matstate;
/*
* If we haven't materialized yet, just return. If outerplan' chgParam
* is not NULL then it will be re-scanned by ExecProcNode, else - no
* reason to re-scan it at all.
*/
if (!matstate->tuplestorestate)
if (!node->tuplestorestate)
return;
ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
/*
* If subnode is to be rescanned then we forget previous stored
@ -293,11 +273,11 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
*
* Otherwise we can just rewind and rescan the stored output.
*/
if (((Plan *) node)->lefttree->chgParam != NULL)
if (((PlanState *) node)->lefttree->chgParam != NULL)
{
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
matstate->tuplestorestate = NULL;
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL;
}
else
tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate);
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.51 2002/09/04 20:31:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.52 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -340,10 +340,9 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecMergeJoin(MergeJoin *node)
ExecMergeJoin(MergeJoinState *node)
{
EState *estate;
MergeJoinState *mergestate;
ScanDirection direction;
List *innerSkipQual;
List *outerSkipQual;
@ -352,9 +351,9 @@ ExecMergeJoin(MergeJoin *node)
List *otherqual;
bool qualResult;
bool compareResult;
Plan *innerPlan;
PlanState *innerPlan;
TupleTableSlot *innerTupleSlot;
Plan *outerPlan;
PlanState *outerPlan;
TupleTableSlot *outerTupleSlot;
ExprContext *econtext;
bool doFillOuter;
@ -363,17 +362,16 @@ ExecMergeJoin(MergeJoin *node)
/*
* get information from node
*/
mergestate = node->mergestate;
estate = node->join.plan.state;
estate = node->js.ps.state;
direction = estate->es_direction;
innerPlan = innerPlan((Plan *) node);
outerPlan = outerPlan((Plan *) node);
econtext = mergestate->jstate.cs_ExprContext;
innerPlan = innerPlanState(node);
outerPlan = outerPlanState(node);
econtext = node->js.ps.ps_ExprContext;
mergeclauses = node->mergeclauses;
joinqual = node->join.joinqual;
otherqual = node->join.plan.qual;
joinqual = node->js.joinqual;
otherqual = node->js.ps.qual;
switch (node->join.jointype)
switch (node->js.jointype)
{
case JOIN_INNER:
doFillOuter = false;
@ -393,7 +391,7 @@ ExecMergeJoin(MergeJoin *node)
break;
default:
elog(ERROR, "ExecMergeJoin: unsupported join type %d",
(int) node->join.jointype);
(int) node->js.jointype);
doFillOuter = false; /* keep compiler quiet */
doFillInner = false;
break;
@ -401,13 +399,13 @@ ExecMergeJoin(MergeJoin *node)
if (ScanDirectionIsForward(direction))
{
outerSkipQual = mergestate->mj_OuterSkipQual;
innerSkipQual = mergestate->mj_InnerSkipQual;
outerSkipQual = node->mj_OuterSkipQual;
innerSkipQual = node->mj_InnerSkipQual;
}
else
{
outerSkipQual = mergestate->mj_InnerSkipQual;
innerSkipQual = mergestate->mj_OuterSkipQual;
outerSkipQual = node->mj_InnerSkipQual;
innerSkipQual = node->mj_OuterSkipQual;
}
/*
@ -415,16 +413,16 @@ ExecMergeJoin(MergeJoin *node)
* join tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (mergestate->jstate.cs_TupFromTlist)
if (node->js.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
mergestate->jstate.cs_TupFromTlist = false;
node->js.ps.ps_TupFromTlist = false;
}
/*
@ -444,9 +442,9 @@ ExecMergeJoin(MergeJoin *node)
* Note: The join states are highlighted with 32-* comments for
* improved readability.
*/
MJ_dump(mergestate);
MJ_dump(node);
switch (mergestate->mj_JoinState)
switch (node->mj_JoinState)
{
/*
* EXEC_MJ_INITIALIZE means that this is the first time
@ -459,8 +457,8 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_INITIALIZE:
MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
mergestate->mj_OuterTupleSlot = outerTupleSlot;
outerTupleSlot = ExecProcNode(outerPlan);
node->mj_OuterTupleSlot = outerTupleSlot;
if (TupIsNull(outerTupleSlot))
{
MJ_printf("ExecMergeJoin: outer subplan is empty\n");
@ -471,16 +469,16 @@ ExecMergeJoin(MergeJoin *node)
* inner tuples. We set MatchedInner = true to
* force the ENDOUTER state to advance inner.
*/
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
mergestate->mj_MatchedInner = true;
node->mj_JoinState = EXEC_MJ_ENDOUTER;
node->mj_MatchedInner = true;
break;
}
/* Otherwise we're done. */
return NULL;
}
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
mergestate->mj_InnerTupleSlot = innerTupleSlot;
innerTupleSlot = ExecProcNode(innerPlan);
node->mj_InnerTupleSlot = innerTupleSlot;
if (TupIsNull(innerTupleSlot))
{
MJ_printf("ExecMergeJoin: inner subplan is empty\n");
@ -493,8 +491,8 @@ ExecMergeJoin(MergeJoin *node)
* state to emit this tuple before advancing
* outer.
*/
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
mergestate->mj_MatchedOuter = false;
node->mj_JoinState = EXEC_MJ_ENDINNER;
node->mj_MatchedOuter = false;
break;
}
/* Otherwise we're done. */
@ -505,7 +503,7 @@ ExecMergeJoin(MergeJoin *node)
* OK, we have the initial tuples. Begin by skipping
* unmatched inner tuples.
*/
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
node->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
break;
/*
@ -519,9 +517,9 @@ ExecMergeJoin(MergeJoin *node)
ExecMarkPos(innerPlan);
MarkInnerTuple(mergestate->mj_InnerTupleSlot, mergestate);
MarkInnerTuple(node->mj_InnerTupleSlot, node);
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
node->mj_JoinState = EXEC_MJ_JOINTEST;
break;
/*
@ -538,18 +536,18 @@ ExecMergeJoin(MergeJoin *node)
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
qualResult = ExecQual(mergeclauses, econtext, false);
MJ_DEBUG_QUAL(mergeclauses, qualResult);
if (qualResult)
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
else
mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
break;
/*
@ -560,7 +558,7 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_JOINTUPLES:
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
node->mj_JoinState = EXEC_MJ_NEXTINNER;
/*
* Check the extra qual conditions to see if we actually
@ -582,8 +580,8 @@ ExecMergeJoin(MergeJoin *node)
if (qualResult)
{
mergestate->mj_MatchedOuter = true;
mergestate->mj_MatchedInner = true;
node->mj_MatchedOuter = true;
node->mj_MatchedInner = true;
qualResult = (otherqual == NIL ||
ExecQual(otherqual, econtext, false));
@ -601,12 +599,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -625,20 +623,20 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_NEXTINNER:
MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
if (doFillInner && !mergestate->mj_MatchedInner)
if (doFillInner && !node->mj_MatchedInner)
{
/*
* Generate a fake join tuple with nulls for the outer
* tuple, and return it if it passes the non-join
* quals.
*/
mergestate->mj_MatchedInner = true; /* do it only once */
node->mj_MatchedInner = true; /* do it only once */
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
outerTupleSlot = node->mj_NullOuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
@ -653,12 +651,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -668,15 +666,15 @@ ExecMergeJoin(MergeJoin *node)
/*
* now we get the next inner tuple, if any
*/
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
mergestate->mj_InnerTupleSlot = innerTupleSlot;
innerTupleSlot = ExecProcNode(innerPlan);
node->mj_InnerTupleSlot = innerTupleSlot;
MJ_DEBUG_PROC_NODE(innerTupleSlot);
mergestate->mj_MatchedInner = false;
node->mj_MatchedInner = false;
if (TupIsNull(innerTupleSlot))
mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
else
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
node->mj_JoinState = EXEC_MJ_JOINTEST;
break;
/*-------------------------------------------
@ -701,20 +699,20 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_NEXTOUTER:
MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
if (doFillOuter && !mergestate->mj_MatchedOuter)
if (doFillOuter && !node->mj_MatchedOuter)
{
/*
* Generate a fake join tuple with nulls for the inner
* tuple, and return it if it passes the non-join
* quals.
*/
mergestate->mj_MatchedOuter = true; /* do it only once */
node->mj_MatchedOuter = true; /* do it only once */
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
innerTupleSlot = node->mj_NullInnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
@ -729,12 +727,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -744,10 +742,10 @@ ExecMergeJoin(MergeJoin *node)
/*
* now we get the next outer tuple, if any
*/
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
mergestate->mj_OuterTupleSlot = outerTupleSlot;
outerTupleSlot = ExecProcNode(outerPlan);
node->mj_OuterTupleSlot = outerTupleSlot;
MJ_DEBUG_PROC_NODE(outerTupleSlot);
mergestate->mj_MatchedOuter = false;
node->mj_MatchedOuter = false;
/*
* if the outer tuple is null then we are done with the
@ -756,21 +754,21 @@ ExecMergeJoin(MergeJoin *node)
if (TupIsNull(outerTupleSlot))
{
MJ_printf("ExecMergeJoin: end of outer subplan\n");
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
if (doFillInner && !TupIsNull(innerTupleSlot))
{
/*
* Need to emit right-join tuples for remaining
* inner tuples.
*/
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
node->mj_JoinState = EXEC_MJ_ENDOUTER;
break;
}
/* Otherwise we're done. */
return NULL;
}
mergestate->mj_JoinState = EXEC_MJ_TESTOUTER;
node->mj_JoinState = EXEC_MJ_TESTOUTER;
break;
/*--------------------------------------------------------
@ -816,9 +814,9 @@ ExecMergeJoin(MergeJoin *node)
*/
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_MarkedTupleSlot;
innerTupleSlot = node->mj_MarkedTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
qualResult = ExecQual(mergeclauses, econtext, false);
@ -843,7 +841,7 @@ ExecMergeJoin(MergeJoin *node)
* the extra joinquals.
*/
ExecRestrPos(innerPlan);
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
}
else
{
@ -862,7 +860,7 @@ ExecMergeJoin(MergeJoin *node)
* larger than our marked inner tuples. So we're done.
* ----------------
*/
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
if (TupIsNull(innerTupleSlot))
{
if (doFillOuter)
@ -871,7 +869,7 @@ ExecMergeJoin(MergeJoin *node)
* Need to emit left-join tuples for remaining
* outer tuples.
*/
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
node->mj_JoinState = EXEC_MJ_ENDINNER;
break;
}
/* Otherwise we're done. */
@ -879,7 +877,7 @@ ExecMergeJoin(MergeJoin *node)
}
/* continue on to skip outer tuples */
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
}
break;
@ -913,9 +911,9 @@ ExecMergeJoin(MergeJoin *node)
*/
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
qualResult = ExecQual(mergeclauses, econtext, false);
@ -925,13 +923,13 @@ ExecMergeJoin(MergeJoin *node)
{
ExecMarkPos(innerPlan);
MarkInnerTuple(innerTupleSlot, mergestate);
MarkInnerTuple(innerTupleSlot, node);
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
break;
}
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
break;
case EXEC_MJ_SKIPOUTER_TEST:
@ -940,9 +938,9 @@ ExecMergeJoin(MergeJoin *node)
/*
* ok, now test the skip qualification
*/
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
compareResult = MergeCompare(mergeclauses,
@ -957,7 +955,7 @@ ExecMergeJoin(MergeJoin *node)
*/
if (compareResult)
{
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
break;
}
@ -973,9 +971,9 @@ ExecMergeJoin(MergeJoin *node)
MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
if (compareResult)
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
node->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
else
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
node->mj_JoinState = EXEC_MJ_JOINMARK;
break;
/*
@ -985,20 +983,20 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_SKIPOUTER_ADVANCE:
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
if (doFillOuter && !mergestate->mj_MatchedOuter)
if (doFillOuter && !node->mj_MatchedOuter)
{
/*
* Generate a fake join tuple with nulls for the inner
* tuple, and return it if it passes the non-join
* quals.
*/
mergestate->mj_MatchedOuter = true; /* do it only once */
node->mj_MatchedOuter = true; /* do it only once */
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
innerTupleSlot = node->mj_NullInnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
@ -1013,12 +1011,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -1028,10 +1026,10 @@ ExecMergeJoin(MergeJoin *node)
/*
* now we get the next outer tuple, if any
*/
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
mergestate->mj_OuterTupleSlot = outerTupleSlot;
outerTupleSlot = ExecProcNode(outerPlan);
node->mj_OuterTupleSlot = outerTupleSlot;
MJ_DEBUG_PROC_NODE(outerTupleSlot);
mergestate->mj_MatchedOuter = false;
node->mj_MatchedOuter = false;
/*
* if the outer tuple is null then we are done with the
@ -1040,14 +1038,14 @@ ExecMergeJoin(MergeJoin *node)
if (TupIsNull(outerTupleSlot))
{
MJ_printf("ExecMergeJoin: end of outer subplan\n");
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
if (doFillInner && !TupIsNull(innerTupleSlot))
{
/*
* Need to emit right-join tuples for remaining
* inner tuples.
*/
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
node->mj_JoinState = EXEC_MJ_ENDOUTER;
break;
}
/* Otherwise we're done. */
@ -1057,7 +1055,7 @@ ExecMergeJoin(MergeJoin *node)
/*
* otherwise test the new tuple against the skip qual.
*/
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
break;
/*-----------------------------------------------------------
@ -1090,9 +1088,9 @@ ExecMergeJoin(MergeJoin *node)
*/
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
qualResult = ExecQual(mergeclauses, econtext, false);
@ -1102,13 +1100,13 @@ ExecMergeJoin(MergeJoin *node)
{
ExecMarkPos(innerPlan);
MarkInnerTuple(innerTupleSlot, mergestate);
MarkInnerTuple(innerTupleSlot, node);
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
break;
}
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
break;
case EXEC_MJ_SKIPINNER_TEST:
@ -1117,9 +1115,9 @@ ExecMergeJoin(MergeJoin *node)
/*
* ok, now test the skip qualification
*/
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
compareResult = MergeCompare(mergeclauses,
@ -1134,7 +1132,7 @@ ExecMergeJoin(MergeJoin *node)
*/
if (compareResult)
{
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
break;
}
@ -1150,9 +1148,9 @@ ExecMergeJoin(MergeJoin *node)
MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
if (compareResult)
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
else
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
node->mj_JoinState = EXEC_MJ_JOINMARK;
break;
/*
@ -1162,20 +1160,20 @@ ExecMergeJoin(MergeJoin *node)
case EXEC_MJ_SKIPINNER_ADVANCE:
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
if (doFillInner && !mergestate->mj_MatchedInner)
if (doFillInner && !node->mj_MatchedInner)
{
/*
* Generate a fake join tuple with nulls for the outer
* tuple, and return it if it passes the non-join
* quals.
*/
mergestate->mj_MatchedInner = true; /* do it only once */
node->mj_MatchedInner = true; /* do it only once */
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
outerTupleSlot = node->mj_NullOuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
@ -1190,12 +1188,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -1205,10 +1203,10 @@ ExecMergeJoin(MergeJoin *node)
/*
* now we get the next inner tuple, if any
*/
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
mergestate->mj_InnerTupleSlot = innerTupleSlot;
innerTupleSlot = ExecProcNode(innerPlan);
node->mj_InnerTupleSlot = innerTupleSlot;
MJ_DEBUG_PROC_NODE(innerTupleSlot);
mergestate->mj_MatchedInner = false;
node->mj_MatchedInner = false;
/*
* if the inner tuple is null then we are done with the
@ -1217,14 +1215,14 @@ ExecMergeJoin(MergeJoin *node)
if (TupIsNull(innerTupleSlot))
{
MJ_printf("ExecMergeJoin: end of inner subplan\n");
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
if (doFillOuter && !TupIsNull(outerTupleSlot))
{
/*
* Need to emit left-join tuples for remaining
* outer tuples.
*/
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
node->mj_JoinState = EXEC_MJ_ENDINNER;
break;
}
/* Otherwise we're done. */
@ -1234,7 +1232,7 @@ ExecMergeJoin(MergeJoin *node)
/*
* otherwise test the new tuple against the skip qual.
*/
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
break;
/*
@ -1247,20 +1245,20 @@ ExecMergeJoin(MergeJoin *node)
Assert(doFillInner);
if (!mergestate->mj_MatchedInner)
if (!node->mj_MatchedInner)
{
/*
* Generate a fake join tuple with nulls for the outer
* tuple, and return it if it passes the non-join
* quals.
*/
mergestate->mj_MatchedInner = true; /* do it only once */
node->mj_MatchedInner = true; /* do it only once */
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
outerTupleSlot = node->mj_NullOuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_InnerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
@ -1275,12 +1273,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -1290,10 +1288,10 @@ ExecMergeJoin(MergeJoin *node)
/*
* now we get the next inner tuple, if any
*/
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
mergestate->mj_InnerTupleSlot = innerTupleSlot;
innerTupleSlot = ExecProcNode(innerPlan);
node->mj_InnerTupleSlot = innerTupleSlot;
MJ_DEBUG_PROC_NODE(innerTupleSlot);
mergestate->mj_MatchedInner = false;
node->mj_MatchedInner = false;
if (TupIsNull(innerTupleSlot))
{
@ -1314,20 +1312,20 @@ ExecMergeJoin(MergeJoin *node)
Assert(doFillOuter);
if (!mergestate->mj_MatchedOuter)
if (!node->mj_MatchedOuter)
{
/*
* Generate a fake join tuple with nulls for the inner
* tuple, and return it if it passes the non-join
* quals.
*/
mergestate->mj_MatchedOuter = true; /* do it only once */
node->mj_MatchedOuter = true; /* do it only once */
ResetExprContext(econtext);
outerTupleSlot = mergestate->mj_OuterTupleSlot;
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
innerTupleSlot = node->mj_NullInnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
@ -1342,12 +1340,12 @@ ExecMergeJoin(MergeJoin *node)
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(mergestate->jstate.cs_ProjInfo,
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult)
{
mergestate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -1357,10 +1355,10 @@ ExecMergeJoin(MergeJoin *node)
/*
* now we get the next outer tuple, if any
*/
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
mergestate->mj_OuterTupleSlot = outerTupleSlot;
outerTupleSlot = ExecProcNode(outerPlan);
node->mj_OuterTupleSlot = outerTupleSlot;
MJ_DEBUG_PROC_NODE(outerTupleSlot);
mergestate->mj_MatchedOuter = false;
node->mj_MatchedOuter = false;
if (TupIsNull(outerTupleSlot))
{
@ -1377,7 +1375,7 @@ ExecMergeJoin(MergeJoin *node)
*/
default:
elog(WARNING, "ExecMergeJoin: invalid join state %d, aborting",
mergestate->mj_JoinState);
node->mj_JoinState);
return NULL;
}
}
@ -1385,14 +1383,10 @@ ExecMergeJoin(MergeJoin *node)
/* ----------------------------------------------------------------
* ExecInitMergeJoin
*
* old comments
* Creates the run-time state information for the node and
* sets the relation id to contain relevant decriptors.
* ----------------------------------------------------------------
*/
bool
ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
MergeJoinState *
ExecInitMergeJoin(MergeJoin *node, EState *estate)
{
MergeJoinState *mergestate;
@ -1400,40 +1394,52 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
"initializing node");
/*
* assign the node's execution state and get the range table and
* direction from it
*/
node->join.plan.state = estate;
/*
* create new merge state for node
* create state structure
*/
mergestate = makeNode(MergeJoinState);
node->mergestate = mergestate;
mergestate->js.ps.plan = (Plan *) node;
mergestate->js.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &mergestate->jstate);
ExecAssignExprContext(estate, &mergestate->js.ps);
/*
* initialize subplans
* initialize child expressions
*/
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
mergestate->js.ps.targetlist = (List *)
ExecInitExpr((Node *) node->join.plan.targetlist,
(PlanState *) mergestate);
mergestate->js.ps.qual = (List *)
ExecInitExpr((Node *) node->join.plan.qual,
(PlanState *) mergestate);
mergestate->js.jointype = node->join.jointype;
mergestate->js.joinqual = (List *)
ExecInitExpr((Node *) node->join.joinqual,
(PlanState *) mergestate);
mergestate->mergeclauses = (List *)
ExecInitExpr((Node *) node->mergeclauses,
(PlanState *) mergestate);
/*
* initialize child nodes
*/
outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate);
innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate);
#define MERGEJOIN_NSLOTS 4
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &mergestate->jstate);
ExecInitResultTupleSlot(estate, &mergestate->js.ps);
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
ExecGetTupType(innerPlan((Plan *) node)),
ExecGetTupType(innerPlanState(mergestate)),
false);
switch (node->join.jointype)
@ -1443,12 +1449,12 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
case JOIN_LEFT:
mergestate->mj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
ExecGetTupType(innerPlan((Plan *) node)));
ExecGetTupType(innerPlanState(mergestate)));
break;
case JOIN_RIGHT:
mergestate->mj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate,
ExecGetTupType(outerPlan((Plan *) node)));
ExecGetTupType(outerPlanState(mergestate)));
/*
* Can't handle right or full join with non-nil extra
@ -1460,10 +1466,10 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
case JOIN_FULL:
mergestate->mj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate,
ExecGetTupType(outerPlan((Plan *) node)));
ExecGetTupType(outerPlanState(mergestate)));
mergestate->mj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
ExecGetTupType(innerPlan((Plan *) node)));
ExecGetTupType(innerPlanState(mergestate)));
/*
* Can't handle right or full join with non-nil extra
@ -1480,8 +1486,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
/*
* initialize tuple type and projection info
*/
ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
ExecAssignResultTypeFromTL(&mergestate->js.ps);
ExecAssignProjectionInfo(&mergestate->js.ps);
/*
* form merge skip qualifications
@ -1500,7 +1506,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
* initialize join state
*/
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
mergestate->jstate.cs_TupFromTlist = false;
mergestate->js.ps.ps_TupFromTlist = false;
mergestate->mj_MatchedOuter = false;
mergestate->mj_MatchedInner = false;
mergestate->mj_OuterTupleSlot = NULL;
@ -1512,7 +1518,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
MJ1_printf("ExecInitMergeJoin: %s\n",
"node initialized");
return TRUE;
return mergestate;
}
int
@ -1531,65 +1537,52 @@ ExecCountSlotsMergeJoin(MergeJoin *node)
* ----------------------------------------------------------------
*/
void
ExecEndMergeJoin(MergeJoin *node)
ExecEndMergeJoin(MergeJoinState *node)
{
MergeJoinState *mergestate;
MJ1_printf("ExecEndMergeJoin: %s\n",
"ending node processing");
/*
* get state information from the node
*/
mergestate = node->mergestate;
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(mergestate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&mergestate->jstate);
ExecFreeExprContext(&mergestate->jstate);
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
* shut down the subplans
*/
ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
ExecEndNode(innerPlanState(node));
ExecEndNode(outerPlanState(node));
/*
* clean out the tuple table
*/
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
ExecClearTuple(node->mj_MarkedTupleSlot);
MJ1_printf("ExecEndMergeJoin: %s\n",
"node processing ended");
}
void
ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt)
{
MergeJoinState *mergestate = node->mergestate;
ExecClearTuple(node->mj_MarkedTupleSlot);
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
mergestate->jstate.cs_TupFromTlist = false;
mergestate->mj_MatchedOuter = false;
mergestate->mj_MatchedInner = false;
mergestate->mj_OuterTupleSlot = NULL;
mergestate->mj_InnerTupleSlot = NULL;
node->mj_JoinState = EXEC_MJ_INITIALIZE;
node->js.ps.ps_TupFromTlist = false;
node->mj_MatchedOuter = false;
node->mj_MatchedInner = false;
node->mj_OuterTupleSlot = NULL;
node->mj_InnerTupleSlot = NULL;
/*
* 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);
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
if (((PlanState *) node)->righttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->righttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.26 2002/06/20 20:29:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.27 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -57,11 +57,10 @@
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecNestLoop(NestLoop *node)
ExecNestLoop(NestLoopState *node)
{
NestLoopState *nlstate;
Plan *innerPlan;
Plan *outerPlan;
PlanState *innerPlan;
PlanState *outerPlan;
TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot;
List *joinqual;
@ -73,17 +72,16 @@ ExecNestLoop(NestLoop *node)
*/
ENL1_printf("getting info from node");
nlstate = node->nlstate;
joinqual = node->join.joinqual;
otherqual = node->join.plan.qual;
outerPlan = outerPlan((Plan *) node);
innerPlan = innerPlan((Plan *) node);
econtext = nlstate->jstate.cs_ExprContext;
joinqual = node->js.joinqual;
otherqual = node->js.ps.qual;
outerPlan = outerPlanState(node);
innerPlan = innerPlanState(node);
econtext = node->js.ps.ps_ExprContext;
/*
* get the current outer tuple
*/
outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
outerTupleSlot = node->js.ps.ps_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
/*
@ -91,16 +89,16 @@ ExecNestLoop(NestLoop *node)
* join tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (nlstate->jstate.cs_TupFromTlist)
if (node->js.ps.ps_TupFromTlist)
{
TupleTableSlot *result;
ExprDoneCond isDone;
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return result;
/* Done with that source tuple... */
nlstate->jstate.cs_TupFromTlist = false;
node->js.ps.ps_TupFromTlist = false;
}
/*
@ -122,10 +120,10 @@ ExecNestLoop(NestLoop *node)
* If we don't have an outer tuple, get the next one and reset the
* inner scan.
*/
if (nlstate->nl_NeedNewOuter)
if (node->nl_NeedNewOuter)
{
ENL1_printf("getting new outer tuple");
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
outerTupleSlot = ExecProcNode(outerPlan);
/*
* if there are no more outer tuples, then the join is
@ -138,10 +136,10 @@ ExecNestLoop(NestLoop *node)
}
ENL1_printf("saving new outer tuple information");
nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
nlstate->nl_NeedNewOuter = false;
nlstate->nl_MatchedOuter = false;
node->nl_NeedNewOuter = false;
node->nl_MatchedOuter = false;
/*
* now rescan the inner plan
@ -153,7 +151,7 @@ ExecNestLoop(NestLoop *node)
* outer tuple (e.g. in index scans), that's why we pass our
* expr context.
*/
ExecReScan(innerPlan, econtext, (Plan *) node);
ExecReScan(innerPlan, econtext);
}
/*
@ -161,17 +159,17 @@ ExecNestLoop(NestLoop *node)
*/
ENL1_printf("getting new inner tuple");
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
innerTupleSlot = ExecProcNode(innerPlan);
econtext->ecxt_innertuple = innerTupleSlot;
if (TupIsNull(innerTupleSlot))
{
ENL1_printf("no inner tuple, need new outer tuple");
nlstate->nl_NeedNewOuter = true;
node->nl_NeedNewOuter = true;
if (!nlstate->nl_MatchedOuter &&
node->join.jointype == JOIN_LEFT)
if (!node->nl_MatchedOuter &&
node->js.jointype == JOIN_LEFT)
{
/*
* We are doing an outer join and there were no join
@ -179,7 +177,7 @@ ExecNestLoop(NestLoop *node)
* tuple with nulls for the inner tuple, and return it if
* it passes the non-join quals.
*/
econtext->ecxt_innertuple = nlstate->nl_NullInnerTupleSlot;
econtext->ecxt_innertuple = node->nl_NullInnerTupleSlot;
ENL1_printf("testing qualification for outer-join tuple");
@ -195,11 +193,11 @@ ExecNestLoop(NestLoop *node)
ENL1_printf("qualification succeeded, projecting tuple");
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
nlstate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -224,7 +222,7 @@ ExecNestLoop(NestLoop *node)
if (ExecQual(joinqual, econtext, false))
{
nlstate->nl_MatchedOuter = true;
node->nl_MatchedOuter = true;
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
{
@ -238,11 +236,11 @@ ExecNestLoop(NestLoop *node)
ENL1_printf("qualification succeeded, projecting tuple");
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
nlstate->jstate.cs_TupFromTlist =
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
@ -260,14 +258,10 @@ ExecNestLoop(NestLoop *node)
/* ----------------------------------------------------------------
* ExecInitNestLoop
*
* Creates the run-time state information for the nestloop node
* produced by the planner and initailizes inner and outer relations
* (child nodes).
* ----------------------------------------------------------------
*/
bool
ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
NestLoopState *
ExecInitNestLoop(NestLoop *node, EState *estate)
{
NestLoopState *nlstate;
@ -275,35 +269,45 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
"initializing node");
/*
* assign execution state to node
*/
node->join.plan.state = estate;
/*
* create new nest loop state
* create state structure
*/
nlstate = makeNode(NestLoopState);
node->nlstate = nlstate;
nlstate->js.ps.plan = (Plan *) node;
nlstate->js.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &nlstate->jstate);
ExecAssignExprContext(estate, &nlstate->js.ps);
/*
* now initialize children
* initialize child expressions
*/
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
nlstate->js.ps.targetlist = (List *)
ExecInitExpr((Node *) node->join.plan.targetlist,
(PlanState *) nlstate);
nlstate->js.ps.qual = (List *)
ExecInitExpr((Node *) node->join.plan.qual,
(PlanState *) nlstate);
nlstate->js.jointype = node->join.jointype;
nlstate->js.joinqual = (List *)
ExecInitExpr((Node *) node->join.joinqual,
(PlanState *) nlstate);
/*
* initialize child nodes
*/
outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate);
innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate);
#define NESTLOOP_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &nlstate->jstate);
ExecInitResultTupleSlot(estate, &nlstate->js.ps);
switch (node->join.jointype)
{
@ -312,7 +316,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
case JOIN_LEFT:
nlstate->nl_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
ExecGetTupType(innerPlan((Plan *) node)));
ExecGetTupType(innerPlanState(nlstate)));
break;
default:
elog(ERROR, "ExecInitNestLoop: unsupported join type %d",
@ -322,20 +326,21 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
/*
* initialize tuple type and projection info
*/
ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
ExecAssignResultTypeFromTL(&nlstate->js.ps);
ExecAssignProjectionInfo(&nlstate->js.ps);
/*
* finally, wipe the current outer tuple clean.
*/
nlstate->jstate.cs_OuterTupleSlot = NULL;
nlstate->jstate.cs_TupFromTlist = false;
nlstate->js.ps.ps_OuterTupleSlot = NULL;
nlstate->js.ps.ps_TupFromTlist = false;
nlstate->nl_NeedNewOuter = true;
nlstate->nl_MatchedOuter = false;
NL1_printf("ExecInitNestLoop: %s\n",
"node initialized");
return TRUE;
return nlstate;
}
int
@ -353,38 +358,27 @@ ExecCountSlotsNestLoop(NestLoop *node)
* ----------------------------------------------------------------
*/
void
ExecEndNestLoop(NestLoop *node)
ExecEndNestLoop(NestLoopState *node)
{
NestLoopState *nlstate;
NL1_printf("ExecEndNestLoop: %s\n",
"ending node processing");
/*
* get info from the node
*/
nlstate = node->nlstate;
/*
* Free the projection info
*
* Note: we don't ExecFreeResultType(nlstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&nlstate->jstate);
ExecFreeExprContext(&nlstate->jstate);
ExecFreeProjectionInfo(&node->js.ps);
ExecFreeExprContext(&node->js.ps);
/*
* close down subplans
*/
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
ExecEndNode(outerPlanState(node));
ExecEndNode(innerPlanState(node));
/*
* clean out the tuple table
*/
ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
NL1_printf("ExecEndNestLoop: %s\n",
"node processing ended");
@ -395,10 +389,9 @@ ExecEndNestLoop(NestLoop *node)
* ----------------------------------------------------------------
*/
void
ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt)
{
NestLoopState *nlstate = node->nlstate;
Plan *outerPlan = outerPlan((Plan *) node);
PlanState *outerPlan = outerPlanState(node);
/*
* If outerPlan->chgParam is not null then plan will be automatically
@ -408,11 +401,11 @@ ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
* run-time keys...
*/
if (outerPlan->chgParam == NULL)
ExecReScan(outerPlan, exprCtxt, (Plan *) node);
ExecReScan(outerPlan, exprCtxt);
/* let outerPlan to free its result tuple ... */
nlstate->jstate.cs_OuterTupleSlot = NULL;
nlstate->jstate.cs_TupFromTlist = false;
nlstate->nl_NeedNewOuter = true;
nlstate->nl_MatchedOuter = false;
node->js.ps.ps_OuterTupleSlot = NULL;
node->js.ps.ps_TupFromTlist = false;
node->nl_NeedNewOuter = true;
node->nl_MatchedOuter = false;
}

View File

@ -34,7 +34,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.21 2002/06/20 20:29:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.22 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -60,34 +60,29 @@
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecResult(Result *node)
ExecResult(ResultState *node)
{
ResultState *resstate;
TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
Plan *outerPlan;
PlanState *outerPlan;
ExprContext *econtext;
ExprDoneCond isDone;
/*
* initialize the result node's state
*/
resstate = node->resstate;
econtext = resstate->cstate.cs_ExprContext;
econtext = node->ps.ps_ExprContext;
/*
* check constant qualifications like (2 > 1), if not already done
*/
if (resstate->rs_checkqual)
if (node->rs_checkqual)
{
bool qualResult = ExecQual((List *) node->resconstantqual,
econtext,
false);
resstate->rs_checkqual = false;
if (qualResult == false)
node->rs_checkqual = false;
if (!qualResult)
{
resstate->rs_done = true;
node->rs_done = true;
return NULL;
}
}
@ -97,13 +92,13 @@ ExecResult(Result *node)
* scan tuple (because there is a function-returning-set in the
* projection expressions). If so, try to project another one.
*/
if (resstate->cstate.cs_TupFromTlist)
if (node->ps.ps_TupFromTlist)
{
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone == ExprMultipleResult)
return resultSlot;
/* Done with that source tuple... */
resstate->cstate.cs_TupFromTlist = false;
node->ps.ps_TupFromTlist = false;
}
/*
@ -119,9 +114,9 @@ ExecResult(Result *node)
* called, OR that we failed the constant qual check. Either way, now
* we are through.
*/
while (!resstate->rs_done)
while (!node->rs_done)
{
outerPlan = outerPlan(node);
outerPlan = outerPlanState(node);
if (outerPlan != NULL)
{
@ -129,12 +124,12 @@ ExecResult(Result *node)
* retrieve tuples from the outer plan until there are no
* more.
*/
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
outerTupleSlot = ExecProcNode(outerPlan);
if (TupIsNull(outerTupleSlot))
return NULL;
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
node->ps.ps_OuterTupleSlot = outerTupleSlot;
/*
* XXX gross hack. use outer tuple as scan tuple for
@ -149,7 +144,7 @@ ExecResult(Result *node)
* if we don't have an outer plan, then we are just generating
* the results from a constant target list. Do it only once.
*/
resstate->rs_done = true;
node->rs_done = true;
}
/*
@ -157,11 +152,11 @@ ExecResult(Result *node)
* unless the projection produces an empty set, in which case we
* must loop back to see if there are more outerPlan tuples.
*/
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
resstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return resultSlot;
}
}
@ -177,42 +172,51 @@ ExecResult(Result *node)
* (child nodes).
* ----------------------------------------------------------------
*/
bool
ExecInitResult(Result *node, EState *estate, Plan *parent)
ResultState *
ExecInitResult(Result *node, EState *estate)
{
ResultState *resstate;
/*
* assign execution state to node
*/
node->plan.state = estate;
/*
* create new ResultState for node
* create state structure
*/
resstate = makeNode(ResultState);
resstate->ps.plan = (Plan *) node;
resstate->ps.state = estate;
resstate->rs_done = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
node->resstate = resstate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &resstate->cstate);
ExecAssignExprContext(estate, &resstate->ps);
#define RESULT_NSLOTS 1
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &resstate->cstate);
ExecInitResultTupleSlot(estate, &resstate->ps);
/*
* then initialize children
* initialize child expressions
*/
ExecInitNode(outerPlan(node), estate, (Plan *) node);
resstate->ps.targetlist = (List *)
ExecInitExpr((Node *) node->plan.targetlist,
(PlanState *) resstate);
resstate->ps.qual = (List *)
ExecInitExpr((Node *) node->plan.qual,
(PlanState *) resstate);
resstate->resconstantqual = ExecInitExpr(node->resconstantqual,
(PlanState *) resstate);
/*
* initialize child nodes
*/
outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate);
/*
* we don't use inner plan
@ -222,10 +226,10 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
/*
* initialize tuple type and projection info
*/
ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
ExecAssignResultTypeFromTL(&resstate->ps);
ExecAssignProjectionInfo(&resstate->ps);
return TRUE;
return resstate;
}
int
@ -241,49 +245,37 @@ ExecCountSlotsResult(Result *node)
* ----------------------------------------------------------------
*/
void
ExecEndResult(Result *node)
ExecEndResult(ResultState *node)
{
ResultState *resstate;
resstate = node->resstate;
/*
* Free the projection info
*
* Note: we don't ExecFreeResultType(resstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&resstate->cstate);
ExecFreeExprContext(&resstate->cstate);
/*
* shut down subplans
*/
ExecEndNode(outerPlan(node), (Plan *) node);
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
* clean out the tuple table
*/
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
pfree(resstate);
node->resstate = NULL; /* XXX - new for us - er1p */
ExecClearTuple(node->ps.ps_ResultTupleSlot);
/*
* shut down subplans
*/
ExecEndNode(outerPlanState(node));
}
void
ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
{
ResultState *resstate = node->resstate;
resstate->rs_done = false;
resstate->cstate.cs_TupFromTlist = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
node->rs_done = false;
node->ps.ps_TupFromTlist = false;
node->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 &&
((Plan *) node)->lefttree->chgParam == NULL)
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
if (((PlanState *) node)->lefttree &&
((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.38 2002/11/30 05:21:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,9 +29,8 @@
#include "executor/nodeSeqscan.h"
#include "parser/parsetree.h"
static Oid InitScanRelation(SeqScan *node, EState *estate,
CommonScanState *scanstate);
static TupleTableSlot *SeqNext(SeqScan *node);
static void InitScanRelation(SeqScanState *node, EState *estate);
static TupleTableSlot *SeqNext(SeqScanState *node);
/* ----------------------------------------------------------------
* Scan Support
@ -44,11 +43,11 @@ static TupleTableSlot *SeqNext(SeqScan *node);
* ----------------------------------------------------------------
*/
static TupleTableSlot *
SeqNext(SeqScan *node)
SeqNext(SeqScanState *node)
{
HeapTuple tuple;
HeapScanDesc scandesc;
CommonScanState *scanstate;
Index scanrelid;
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
@ -56,11 +55,11 @@ SeqNext(SeqScan *node)
/*
* get information from the estate and scan state
*/
estate = node->plan.state;
scanstate = node->scanstate;
scandesc = scanstate->css_currentScanDesc;
estate = node->ps.state;
scandesc = node->ss_currentScanDesc;
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
direction = estate->es_direction;
slot = scanstate->css_ScanTupleSlot;
slot = node->ss_ScanTupleSlot;
/*
* Check if we are evaluating PlanQual for tuple of this relation.
@ -69,13 +68,13 @@ SeqNext(SeqScan *node)
* switching in Init/ReScan plan...
*/
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scanrelid - 1] != NULL)
estate->es_evTuple[scanrelid - 1] != NULL)
{
ExecClearTuple(slot);
if (estate->es_evTupleNull[node->scanrelid - 1])
if (estate->es_evTupleNull[scanrelid - 1])
return slot; /* return empty slot */
ExecStoreTuple(estate->es_evTuple[node->scanrelid - 1],
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
slot, InvalidBuffer, false);
/*
@ -85,7 +84,7 @@ SeqNext(SeqScan *node)
*/
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scanrelid - 1] = true;
estate->es_evTupleNull[scanrelid - 1] = true;
return (slot);
}
@ -124,12 +123,12 @@ SeqNext(SeqScan *node)
*/
TupleTableSlot *
ExecSeqScan(SeqScan *node)
ExecSeqScan(SeqScanState *node)
{
/*
* use SeqNext as access method
*/
return ExecScan(node, (ExecScanAccessMtd) SeqNext);
return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext);
}
/* ----------------------------------------------------------------
@ -139,9 +138,8 @@ ExecSeqScan(SeqScan *node)
* subplans of scans.
* ----------------------------------------------------------------
*/
static Oid
InitScanRelation(SeqScan *node, EState *estate,
CommonScanState *scanstate)
static void
InitScanRelation(SeqScanState *node, EState *estate)
{
Index relid;
List *rangeTable;
@ -156,7 +154,7 @@ InitScanRelation(SeqScan *node, EState *estate,
*
* We acquire AccessShareLock for the duration of the scan.
*/
relid = node->scanrelid;
relid = ((SeqScan *) node->ps.plan)->scanrelid;
rangeTable = estate->es_range_table;
rtentry = rt_fetch(relid, rangeTable);
reloid = rtentry->relid;
@ -168,12 +166,10 @@ InitScanRelation(SeqScan *node, EState *estate,
0,
NULL);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = currentScanDesc;
node->ss_currentRelation = currentRelation;
node->ss_currentScanDesc = currentScanDesc;
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
return reloid;
ExecAssignScanType(node, RelationGetDescr(currentRelation), false);
}
@ -181,59 +177,64 @@ InitScanRelation(SeqScan *node, EState *estate,
* ExecInitSeqScan
* ----------------------------------------------------------------
*/
bool
ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
SeqScanState *
ExecInitSeqScan(SeqScan *node, EState *estate)
{
CommonScanState *scanstate;
Oid reloid;
SeqScanState *scanstate;
/*
* Once upon a time it was possible to have an outerPlan of a SeqScan,
* but not any more.
*/
Assert(outerPlan((Plan *) node) == NULL);
Assert(innerPlan((Plan *) node) == NULL);
Assert(outerPlan(node) == NULL);
Assert(innerPlan(node) == NULL);
/*
* assign the node's execution state
* create state structure
*/
node->plan.state = estate;
/*
* create new CommonScanState for node
*/
scanstate = makeNode(CommonScanState);
node->scanstate = scanstate;
scanstate = makeNode(SeqScanState);
scanstate->ps.plan = (Plan *) node;
scanstate->ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &scanstate->cstate);
ExecAssignExprContext(estate, &scanstate->ps);
/*
* initialize child expressions
*/
scanstate->ps.targetlist = (List *)
ExecInitExpr((Node *) node->plan.targetlist,
(PlanState *) scanstate);
scanstate->ps.qual = (List *)
ExecInitExpr((Node *) node->plan.qual,
(PlanState *) scanstate);
#define SEQSCAN_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &scanstate->cstate);
ExecInitResultTupleSlot(estate, &scanstate->ps);
ExecInitScanTupleSlot(estate, scanstate);
/*
* initialize scan relation
*/
reloid = InitScanRelation(node, estate, scanstate);
InitScanRelation(scanstate, estate);
scanstate->cstate.cs_TupFromTlist = false;
scanstate->ps.ps_TupFromTlist = false;
/*
* initialize tuple type
*/
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
ExecAssignResultTypeFromTL(&scanstate->ps);
ExecAssignProjectionInfo(&scanstate->ps);
return TRUE;
return scanstate;
}
int
@ -251,34 +252,34 @@ ExecCountSlotsSeqScan(SeqScan *node)
* ----------------------------------------------------------------
*/
void
ExecEndSeqScan(SeqScan *node)
ExecEndSeqScan(SeqScanState *node)
{
CommonScanState *scanstate;
Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
scanstate = node->scanstate;
relation = scanstate->css_currentRelation;
scanDesc = scanstate->css_currentScanDesc;
relation = node->ss_currentRelation;
scanDesc = node->ss_currentScanDesc;
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
ExecFreeProjectionInfo(&node->ps);
ExecFreeExprContext(&node->ps);
/*
* close heap scan
*/
heap_endscan(scanDesc);
/*
* clean out the tuple table
*/
ExecClearTuple(node->ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss_ScanTupleSlot);
/*
* close the heap relation.
*
@ -288,12 +289,6 @@ ExecEndSeqScan(SeqScan *node)
* locking, however.)
*/
heap_close(relation, NoLock);
/*
* clean out the tuple table
*/
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(scanstate->css_ScanTupleSlot);
}
/* ----------------------------------------------------------------
@ -308,24 +303,24 @@ ExecEndSeqScan(SeqScan *node)
* ----------------------------------------------------------------
*/
void
ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt)
{
CommonScanState *scanstate;
EState *estate;
Index scanrelid;
HeapScanDesc scan;
scanstate = node->scanstate;
estate = node->plan.state;
estate = node->ps.state;
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
/* If this is re-scanning of PlanQual ... */
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scanrelid - 1] != NULL)
estate->es_evTuple[scanrelid - 1] != NULL)
{
estate->es_evTupleNull[node->scanrelid - 1] = false;
estate->es_evTupleNull[scanrelid - 1] = false;
return;
}
scan = scanstate->css_currentScanDesc;
scan = node->ss_currentScanDesc;
heap_rescan(scan, /* scan desc */
NULL); /* new scan keys */
@ -338,13 +333,11 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
* ----------------------------------------------------------------
*/
void
ExecSeqMarkPos(SeqScan *node)
ExecSeqMarkPos(SeqScanState *node)
{
CommonScanState *scanstate;
HeapScanDesc scan;
scanstate = node->scanstate;
scan = scanstate->css_currentScanDesc;
scan = node->ss_currentScanDesc;
heap_markpos(scan);
}
@ -355,12 +348,10 @@ ExecSeqMarkPos(SeqScan *node)
* ----------------------------------------------------------------
*/
void
ExecSeqRestrPos(SeqScan *node)
ExecSeqRestrPos(SeqScanState *node)
{
CommonScanState *scanstate;
HeapScanDesc scan;
scanstate = node->scanstate;
scan = scanstate->css_currentScanDesc;
scan = node->ss_currentScanDesc;
heap_restrpos(scan);
}

View File

@ -21,7 +21,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.6 2002/06/20 20:29:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.7 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -44,28 +44,27 @@
* ----------------------------------------------------------------
*/
TupleTableSlot * /* return: a tuple or NULL */
ExecSetOp(SetOp *node)
ExecSetOp(SetOpState *node)
{
SetOpState *setopstate;
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
Plan *outerPlan;
PlanState *outerPlan;
TupleDesc tupDesc;
/*
* get information from the node
*/
setopstate = node->setopstate;
outerPlan = outerPlan((Plan *) node);
resultTupleSlot = setopstate->cstate.cs_ResultTupleSlot;
tupDesc = ExecGetResultType(&setopstate->cstate);
outerPlan = outerPlanState(node);
resultTupleSlot = node->ps.ps_ResultTupleSlot;
tupDesc = ExecGetResultType(&node->ps);
/*
* If the previously-returned tuple needs to be returned more than
* once, keep returning it.
*/
if (setopstate->numOutput > 0)
if (node->numOutput > 0)
{
setopstate->numOutput--;
node->numOutput--;
return resultTupleSlot;
}
@ -88,15 +87,15 @@ ExecSetOp(SetOp *node)
/*
* fetch a tuple from the outer subplan, unless we already did.
*/
if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
!setopstate->subplan_done)
if (node->ps.ps_OuterTupleSlot == NULL &&
!node->subplan_done)
{
setopstate->cstate.cs_OuterTupleSlot =
ExecProcNode(outerPlan, (Plan *) node);
if (TupIsNull(setopstate->cstate.cs_OuterTupleSlot))
setopstate->subplan_done = true;
node->ps.ps_OuterTupleSlot =
ExecProcNode(outerPlan);
if (TupIsNull(node->ps.ps_OuterTupleSlot))
node->subplan_done = true;
}
inputTupleSlot = setopstate->cstate.cs_OuterTupleSlot;
inputTupleSlot = node->ps.ps_OuterTupleSlot;
if (TupIsNull(resultTupleSlot))
{
@ -104,18 +103,18 @@ ExecSetOp(SetOp *node)
* First of group: save a copy in result slot, and reset
* duplicate-counters for new group.
*/
if (setopstate->subplan_done)
if (node->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;
node->numLeft = 0;
node->numRight = 0;
endOfGroup = false;
}
else if (setopstate->subplan_done)
else if (node->subplan_done)
{
/*
* Reached end of input, so finish processing final group
@ -131,9 +130,9 @@ ExecSetOp(SetOp *node)
if (execTuplesMatch(inputTupleSlot->val,
resultTupleSlot->val,
tupDesc,
node->numCols, node->dupColIdx,
setopstate->eqfunctions,
setopstate->tempContext))
plannode->numCols, plannode->dupColIdx,
node->eqfunctions,
node->tempContext))
endOfGroup = false;
else
endOfGroup = true;
@ -146,37 +145,37 @@ ExecSetOp(SetOp *node)
* Decide how many copies (if any) to emit. This logic is
* straight from the SQL92 specification.
*/
switch (node->cmd)
switch (plannode->cmd)
{
case SETOPCMD_INTERSECT:
if (setopstate->numLeft > 0 && setopstate->numRight > 0)
setopstate->numOutput = 1;
if (node->numLeft > 0 && node->numRight > 0)
node->numOutput = 1;
else
setopstate->numOutput = 0;
node->numOutput = 0;
break;
case SETOPCMD_INTERSECT_ALL:
setopstate->numOutput =
(setopstate->numLeft < setopstate->numRight) ?
setopstate->numLeft : setopstate->numRight;
node->numOutput =
(node->numLeft < node->numRight) ?
node->numLeft : node->numRight;
break;
case SETOPCMD_EXCEPT:
if (setopstate->numLeft > 0 && setopstate->numRight == 0)
setopstate->numOutput = 1;
if (node->numLeft > 0 && node->numRight == 0)
node->numOutput = 1;
else
setopstate->numOutput = 0;
node->numOutput = 0;
break;
case SETOPCMD_EXCEPT_ALL:
setopstate->numOutput =
(setopstate->numLeft < setopstate->numRight) ?
0 : (setopstate->numLeft - setopstate->numRight);
node->numOutput =
(node->numLeft < node->numRight) ?
0 : (node->numLeft - node->numRight);
break;
default:
elog(ERROR, "ExecSetOp: bogus command code %d",
(int) node->cmd);
(int) plannode->cmd);
break;
}
/* Fall out of for-loop if we have tuples to emit */
if (setopstate->numOutput > 0)
if (node->numOutput > 0)
break;
/* Else flag that we have no current tuple, and loop around */
ExecClearTuple(resultTupleSlot);
@ -191,16 +190,16 @@ ExecSetOp(SetOp *node)
bool isNull;
flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
node->flagColIdx,
plannode->flagColIdx,
tupDesc,
&isNull));
Assert(!isNull);
if (flag)
setopstate->numRight++;
node->numRight++;
else
setopstate->numLeft++;
node->numLeft++;
/* Set flag to fetch a new input tuple, and loop around */
setopstate->cstate.cs_OuterTupleSlot = NULL;
node->ps.ps_OuterTupleSlot = NULL;
}
}
@ -208,8 +207,8 @@ ExecSetOp(SetOp *node)
* If we fall out of loop, then we need to emit at least one copy of
* resultTuple.
*/
Assert(setopstate->numOutput > 0);
setopstate->numOutput--;
Assert(node->numOutput > 0);
node->numOutput--;
return resultTupleSlot;
}
@ -220,23 +219,19 @@ ExecSetOp(SetOp *node)
* the node's subplan.
* ----------------------------------------------------------------
*/
bool /* return: initialization status */
ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
SetOpState *
ExecInitSetOp(SetOp *node, EState *estate)
{
SetOpState *setopstate;
Plan *outerPlan;
/*
* assign execution state to node
*/
node->plan.state = estate;
/*
* create new SetOpState for node
* create state structure
*/
setopstate = makeNode(SetOpState);
node->setopstate = setopstate;
setopstate->cstate.cs_OuterTupleSlot = NULL;
setopstate->ps.plan = (Plan *) node;
setopstate->ps.state = estate;
setopstate->ps.ps_OuterTupleSlot = NULL;
setopstate->subplan_done = false;
setopstate->numOutput = 0;
@ -259,30 +254,29 @@ ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
/*
* Tuple table initialization
*/
ExecInitResultTupleSlot(estate, &setopstate->cstate);
ExecInitResultTupleSlot(estate, &setopstate->ps);
/*
* then initialize outer plan
*/
outerPlan = outerPlan((Plan *) node);
ExecInitNode(outerPlan, estate, (Plan *) node);
outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate);
/*
* setop nodes do no projections, so initialize projection info for
* this node appropriately
*/
ExecAssignResultTypeFromOuterPlan((Plan *) node, &setopstate->cstate);
setopstate->cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromOuterPlan(&setopstate->ps);
setopstate->ps.ps_ProjInfo = NULL;
/*
* Precompute fmgr lookup data for inner loop
*/
setopstate->eqfunctions =
execTuplesMatchPrepare(ExecGetResultType(&setopstate->cstate),
execTuplesMatchPrepare(ExecGetResultType(&setopstate->ps),
node->numCols,
node->dupColIdx);
return TRUE;
return setopstate;
}
int
@ -301,34 +295,30 @@ ExecCountSlotsSetOp(SetOp *node)
* ----------------------------------------------------------------
*/
void
ExecEndSetOp(SetOp *node)
ExecEndSetOp(SetOpState *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;
ExecClearTuple(node->ps.ps_ResultTupleSlot);
node->ps.ps_OuterTupleSlot = NULL;
ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext);
}
void
ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
{
SetOpState *setopstate = node->setopstate;
ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
setopstate->cstate.cs_OuterTupleSlot = NULL;
setopstate->subplan_done = false;
setopstate->numOutput = 0;
ExecClearTuple(node->ps.ps_ResultTupleSlot);
node->ps.ps_OuterTupleSlot = NULL;
node->subplan_done = false;
node->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);
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.40 2002/11/13 00:39:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.41 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -88,10 +88,9 @@ ExtractSortKeys(Sort *sortnode,
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecSort(Sort *node)
ExecSort(SortState *node)
{
EState *estate;
SortState *sortstate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
HeapTuple heapTuple;
@ -104,10 +103,9 @@ ExecSort(Sort *node)
SO1_printf("ExecSort: %s\n",
"entering routine");
sortstate = node->sortstate;
estate = node->plan.state;
estate = node->ss.ps.state;
dir = estate->es_direction;
tuplesortstate = (Tuplesortstate *) sortstate->tuplesortstate;
tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
/*
* If first time through, read all tuples from outer plan and pass
@ -115,9 +113,10 @@ ExecSort(Sort *node)
* tuplesort.
*/
if (!sortstate->sort_Done)
if (!node->sort_Done)
{
Plan *outerNode;
Sort *plannode = (Sort *) node->ss.ps.plan;
PlanState *outerNode;
TupleDesc tupDesc;
Oid *sortOperators;
AttrNumber *attNums;
@ -127,8 +126,7 @@ ExecSort(Sort *node)
/*
* Want to scan subplan in the forward direction while creating
* the sorted data. (Does setting my direction actually affect
* the subplan? I bet this is useless code...)
* the sorted data.
*/
estate->es_direction = ForwardScanDirection;
@ -138,15 +136,15 @@ ExecSort(Sort *node)
SO1_printf("ExecSort: %s\n",
"calling tuplesort_begin");
outerNode = outerPlan((Plan *) node);
outerNode = outerPlanState(node);
tupDesc = ExecGetTupType(outerNode);
ExtractSortKeys(node, &sortOperators, &attNums);
ExtractSortKeys(plannode, &sortOperators, &attNums);
tuplesortstate = tuplesort_begin_heap(tupDesc, node->keycount,
tuplesortstate = tuplesort_begin_heap(tupDesc, plannode->keycount,
sortOperators, attNums,
true /* randomAccess */ );
sortstate->tuplesortstate = (void *) tuplesortstate;
node->tuplesortstate = (void *) tuplesortstate;
pfree(sortOperators);
pfree(attNums);
@ -157,7 +155,7 @@ ExecSort(Sort *node)
for (;;)
{
slot = ExecProcNode(outerNode, (Plan *) node);
slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
break;
@ -178,12 +176,12 @@ ExecSort(Sort *node)
/*
* make sure the tuple descriptor is up to date (is this needed?)
*/
ExecAssignResultType(&sortstate->csstate.cstate, tupDesc, false);
ExecAssignResultType(&node->ss.ps, tupDesc, false);
/*
* finally set the sorted flag to true
*/
sortstate->sort_Done = true;
node->sort_Done = true;
SO1_printf("ExecSort: %s\n", "sorting done");
}
@ -198,7 +196,7 @@ ExecSort(Sort *node)
ScanDirectionIsForward(dir),
&should_free);
slot = sortstate->csstate.cstate.cs_ResultTupleSlot;
slot = node->ss.ps.ps_ResultTupleSlot;
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
}
@ -209,29 +207,24 @@ ExecSort(Sort *node)
* produced by the planner and initailizes its outer subtree.
* ----------------------------------------------------------------
*/
bool
ExecInitSort(Sort *node, EState *estate, Plan *parent)
SortState *
ExecInitSort(Sort *node, EState *estate)
{
SortState *sortstate;
Plan *outerPlan;
SO1_printf("ExecInitSort: %s\n",
"initializing sort node");
/*
* assign the node's execution state
*/
node->plan.state = estate;
/*
* create state structure
*/
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
sortstate->sort_Done = false;
sortstate->tuplesortstate = NULL;
node->sortstate = sortstate;
/*
* Miscellaneous initialization
*
@ -246,27 +239,26 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
*
* sort nodes only return scan tuples from their sorted relation.
*/
ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
ExecInitScanTupleSlot(estate, &sortstate->csstate);
ExecInitResultTupleSlot(estate, &sortstate->ss.ps);
ExecInitScanTupleSlot(estate, &sortstate->ss);
/*
* initializes child nodes
*/
outerPlan = outerPlan((Plan *) node);
ExecInitNode(outerPlan, estate, (Plan *) node);
outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate);
/*
* initialize tuple type. no need to initialize projection info
* because this node doesn't do projections.
*/
ExecAssignResultTypeFromOuterPlan((Plan *) node, &sortstate->csstate.cstate);
ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
sortstate->csstate.cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromOuterPlan(&sortstate->ss.ps);
ExecAssignScanTypeFromOuterPlan(&sortstate->ss);
sortstate->ss.ps.ps_ProjInfo = NULL;
SO1_printf("ExecInitSort: %s\n",
"sort node initialized");
return TRUE;
return sortstate;
}
int
@ -282,39 +274,27 @@ ExecCountSlotsSort(Sort *node)
* ----------------------------------------------------------------
*/
void
ExecEndSort(Sort *node)
ExecEndSort(SortState *node)
{
SortState *sortstate;
Plan *outerPlan;
/*
* get info from the sort state
*/
SO1_printf("ExecEndSort: %s\n",
"shutting down sort node");
sortstate = node->sortstate;
/*
* shut down the subplan
*/
outerPlan = outerPlan((Plan *) node);
ExecEndNode(outerPlan, (Plan *) node);
/*
* clean out the tuple table
*/
ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
/*
* Release tuplesort resources
*/
if (sortstate->tuplesortstate != NULL)
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
sortstate->tuplesortstate = NULL;
pfree(sortstate);
node->sortstate = NULL;
if (node->tuplesortstate != NULL)
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
SO1_printf("ExecEndSort: %s\n",
"sort node shutdown");
@ -327,17 +307,15 @@ ExecEndSort(Sort *node)
* ----------------------------------------------------------------
*/
void
ExecSortMarkPos(Sort *node)
ExecSortMarkPos(SortState *node)
{
SortState *sortstate = node->sortstate;
/*
* if we haven't sorted yet, just return
*/
if (!sortstate->sort_Done)
if (!node->sort_Done)
return;
tuplesort_markpos((Tuplesortstate *) sortstate->tuplesortstate);
tuplesort_markpos((Tuplesortstate *) node->tuplesortstate);
}
/* ----------------------------------------------------------------
@ -347,36 +325,32 @@ ExecSortMarkPos(Sort *node)
* ----------------------------------------------------------------
*/
void
ExecSortRestrPos(Sort *node)
ExecSortRestrPos(SortState *node)
{
SortState *sortstate = node->sortstate;
/*
* if we haven't sorted yet, just return.
*/
if (!sortstate->sort_Done)
if (!node->sort_Done)
return;
/*
* restore the scan to the previously marked position
*/
tuplesort_restorepos((Tuplesortstate *) sortstate->tuplesortstate);
tuplesort_restorepos((Tuplesortstate *) node->tuplesortstate);
}
void
ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanSort(SortState *node, ExprContext *exprCtxt)
{
SortState *sortstate = node->sortstate;
/*
* If we haven't sorted yet, just return. If outerplan' chgParam is
* not NULL then it will be re-scanned by ExecProcNode, else - no
* reason to re-scan it at all.
*/
if (!sortstate->sort_Done)
if (!node->sort_Done)
return;
ExecClearTuple(sortstate->csstate.cstate.cs_ResultTupleSlot);
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
/*
* If subnode is to be rescanned then we forget previous sort results;
@ -384,12 +358,12 @@ ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent)
*
* Otherwise we can just rewind and rescan the sorted output.
*/
if (((Plan *) node)->lefttree->chgParam != NULL)
if (((PlanState *) node)->lefttree->chgParam != NULL)
{
sortstate->sort_Done = false;
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
sortstate->tuplesortstate = NULL;
node->sort_Done = false;
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
}
else
tuplesort_rescan((Tuplesortstate *) sortstate->tuplesortstate);
tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
}

View File

@ -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.34 2002/11/26 03:01:57 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.35 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -27,14 +27,15 @@
/* ----------------------------------------------------------------
* ExecSubPlan(node)
*
* ----------------------------------------------------------------
*/
Datum
ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
ExecSubPlan(SubPlanState *node, List *pvar,
ExprContext *econtext, bool *isNull)
{
Plan *plan = node->plan;
SubLink *sublink = node->sublink;
PlanState *planstate = node->planstate;
SubPlan *subplan = (SubPlan *) node->ps.plan;
SubLink *sublink = subplan->sublink;
SubLinkType subLinkType = sublink->subLinkType;
bool useor = sublink->useor;
MemoryContext oldcontext;
@ -49,15 +50,15 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
*/
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
if (node->setParam != NIL)
if (subplan->setParam != NIL)
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
/*
* Set Params of this plan from parent plan correlation Vars
*/
if (node->parParam != NIL)
if (subplan->parParam != NIL)
{
foreach(lst, node->parParam)
foreach(lst, subplan->parParam)
{
ParamExecData *prm;
@ -69,11 +70,12 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
NULL);
pvar = lnext(pvar);
}
plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
planstate->chgParam = nconc(planstate->chgParam,
listCopy(subplan->parParam));
}
Assert(pvar == NIL);
ExecReScan(plan, NULL, NULL);
ExecReScan(planstate, NULL);
/*
* For all sublink types except EXPR_SUBLINK, the result is boolean as
@ -96,9 +98,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
result = BoolGetDatum(subLinkType == ALL_SUBLINK);
*isNull = false;
for (slot = ExecProcNode(plan, NULL);
for (slot = ExecProcNode(planstate);
!TupIsNull(slot);
slot = ExecProcNode(plan, NULL))
slot = ExecProcNode(planstate))
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
@ -283,13 +285,37 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
/* ----------------------------------------------------------------
* ExecInitSubPlan
*
* ----------------------------------------------------------------
*/
bool
ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
SubPlanState *
ExecInitSubPlan(SubPlan *node, EState *estate)
{
EState *sp_estate = CreateExecutorState();
SubPlanState *subplanstate;
EState *sp_estate;
/*
* Do access checking on the rangetable entries in the subquery.
* Here, we assume the subquery is a SELECT.
*/
ExecCheckRTPerms(node->rtable, CMD_SELECT);
/*
* create state structure
*/
subplanstate = makeNode(SubPlanState);
subplanstate->ps.plan = (Plan *) node;
subplanstate->ps.state = estate;
subplanstate->needShutdown = false;
subplanstate->curTuple = NULL;
/* XXX temporary hack */
node->pstate = subplanstate;
/*
* create an EState for the subplan
*/
sp_estate = CreateExecutorState();
sp_estate->es_range_table = node->rtable;
sp_estate->es_param_list_info = estate->es_param_list_info;
@ -297,14 +323,14 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_instrument = estate->es_instrument;
node->needShutdown = false;
node->curTuple = NULL;
/*
* Start up the subplan
*/
subplanstate->planstate = ExecInitNode(node->plan, sp_estate);
if (!ExecInitNode(node->plan, sp_estate, parent))
return false;
node->needShutdown = true; /* now we need to shutdown the subplan */
subplanstate->needShutdown = true; /* now we need to shutdown the subplan */
/*
* If this plan is un-correlated or undirect correlated one and want
@ -318,7 +344,7 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
{
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = node;
prm->execPlan = subplanstate;
}
/*
@ -328,7 +354,7 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
*/
}
return true;
return subplanstate;
}
/* ----------------------------------------------------------------
@ -345,10 +371,12 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
* ----------------------------------------------------------------
*/
void
ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
{
Plan *plan = node->plan;
SubLink *sublink = node->sublink;
PlanState *planstate = node->planstate;
SubPlan *subplan = (SubPlan *) node->ps.plan;
SubLink *sublink = subplan->sublink;
EState *estate = node->ps.state;
MemoryContext oldcontext;
TupleTableSlot *slot;
List *lst;
@ -364,12 +392,12 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
sublink->subLinkType == ALL_SUBLINK)
elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
if (plan->chgParam != NULL)
ExecReScan(plan, NULL, NULL);
if (planstate->chgParam != NULL)
ExecReScan(planstate, NULL);
for (slot = ExecProcNode(plan, NULL);
for (slot = ExecProcNode(planstate);
!TupIsNull(slot);
slot = ExecProcNode(plan, NULL))
slot = ExecProcNode(planstate))
{
HeapTuple tup = slot->val;
TupleDesc tdesc = slot->ttc_tupleDescriptor;
@ -377,7 +405,7 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
if (sublink->subLinkType == EXISTS_SUBLINK)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(subplan->setParam)]);
prm->execPlan = NULL;
prm->value = BoolGetDatum(true);
@ -404,9 +432,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
heap_freetuple(node->curTuple);
node->curTuple = tup;
foreach(lst, node->setParam)
foreach(lst, subplan->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = NULL;
prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
@ -418,7 +446,7 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
{
if (sublink->subLinkType == EXISTS_SUBLINK)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(subplan->setParam)]);
prm->execPlan = NULL;
prm->value = BoolGetDatum(false);
@ -426,9 +454,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
}
else
{
foreach(lst, node->setParam)
foreach(lst, subplan->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = NULL;
prm->value = (Datum) 0;
@ -437,9 +465,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
}
}
if (plan->extParam == NULL) /* un-correlated ... */
if (planstate->plan->extParam == NULL) /* un-correlated ... */
{
ExecEndNode(plan, NULL);
ExecEndNode(planstate);
node->needShutdown = false;
}
@ -451,11 +479,11 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
* ----------------------------------------------------------------
*/
void
ExecEndSubPlan(SubPlan *node)
ExecEndSubPlan(SubPlanState *node)
{
if (node->needShutdown)
{
ExecEndNode(node->plan, NULL);
ExecEndNode(node->planstate);
node->needShutdown = false;
}
if (node->curTuple)
@ -466,33 +494,34 @@ ExecEndSubPlan(SubPlan *node)
}
void
ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
{
Plan *plan = node->plan;
PlanState *planstate = node->planstate;
SubPlan *subplan = (SubPlan *) node->ps.plan;
EState *estate = node->ps.state;
List *lst;
if (node->parParam != NULL)
if (subplan->parParam != NULL)
elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
if (node->setParam == NULL)
if (subplan->setParam == NULL)
elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
if (plan->extParam == NULL)
if (planstate->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, NULL);
* subplan->plan->chgParam is not NULL... ExecReScan (planstate, NULL);
*/
/*
* Mark this subplan's output parameters as needing recalculation
*/
foreach(lst, node->setParam)
foreach(lst, subplan->setParam)
{
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
prm->execPlan = node;
}
parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));
parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));
}

View File

@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.13 2002/06/20 20:29:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.14 2002/12/05 15:50:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -35,7 +35,7 @@
#include "parser/parsetree.h"
#include "tcop/pquery.h"
static TupleTableSlot *SubqueryNext(SubqueryScan *node);
static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
/* ----------------------------------------------------------------
* Scan Support
@ -48,9 +48,8 @@ static TupleTableSlot *SubqueryNext(SubqueryScan *node);
* ----------------------------------------------------------------
*/
static TupleTableSlot *
SubqueryNext(SubqueryScan *node)
SubqueryNext(SubqueryScanState *node)
{
SubqueryScanState *subquerystate;
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
@ -58,8 +57,7 @@ SubqueryNext(SubqueryScan *node)
/*
* get information from the estate and scan state
*/
estate = node->scan.plan.state;
subquerystate = (SubqueryScanState *) node->scan.scanstate;
estate = node->ss.ps.state;
direction = estate->es_direction;
/*
@ -70,11 +68,11 @@ SubqueryNext(SubqueryScan *node)
/*
* get the next tuple from the sub-query
*/
subquerystate->sss_SubEState->es_direction = direction;
node->sss_SubEState->es_direction = direction;
slot = ExecProcNode(node->subplan, (Plan *) node);
slot = ExecProcNode(node->subplan);
subquerystate->csstate.css_ScanTupleSlot = slot;
node->ss.ss_ScanTupleSlot = slot;
return slot;
}
@ -90,20 +88,20 @@ SubqueryNext(SubqueryScan *node)
*/
TupleTableSlot *
ExecSubqueryScan(SubqueryScan *node)
ExecSubqueryScan(SubqueryScanState *node)
{
/*
* use SubqueryNext as access method
*/
return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
return ExecScan(&node->ss, (ExecScanAccessMtd) SubqueryNext);
}
/* ----------------------------------------------------------------
* ExecInitSubqueryScan
* ----------------------------------------------------------------
*/
bool
ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
SubqueryScanState *
ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
{
SubqueryScanState *subquerystate;
RangeTblEntry *rte;
@ -112,33 +110,39 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
/*
* SubqueryScan should not have any "normal" children.
*/
Assert(outerPlan((Plan *) node) == NULL);
Assert(innerPlan((Plan *) node) == NULL);
Assert(outerPlan(node) == NULL);
Assert(innerPlan(node) == NULL);
/*
* assign the node's execution state
*/
node->scan.plan.state = estate;
/*
* create new SubqueryScanState for node
* create state structure
*/
subquerystate = makeNode(SubqueryScanState);
node->scan.scanstate = (CommonScanState *) subquerystate;
subquerystate->ss.ps.plan = (Plan *) node;
subquerystate->ss.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &subquerystate->csstate.cstate);
ExecAssignExprContext(estate, &subquerystate->ss.ps);
/*
* initialize child expressions
*/
subquerystate->ss.ps.targetlist = (List *)
ExecInitExpr((Node *) node->scan.plan.targetlist,
(PlanState *) subquerystate);
subquerystate->ss.ps.qual = (List *)
ExecInitExpr((Node *) node->scan.plan.qual,
(PlanState *) subquerystate);
#define SUBQUERYSCAN_NSLOTS 1
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
/*
* initialize subquery
@ -157,20 +161,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
sp_estate->es_tupleTable =
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
sp_estate->es_snapshot = estate->es_snapshot;
sp_estate->es_instrument = estate->es_instrument;
if (!ExecInitNode(node->subplan, sp_estate, (Plan *) node))
return false;
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
subquerystate->csstate.css_ScanTupleSlot = NULL;
subquerystate->csstate.cstate.cs_TupFromTlist = false;
subquerystate->ss.ss_ScanTupleSlot = NULL;
subquerystate->ss.ps.ps_TupFromTlist = false;
/*
* initialize tuple type
*/
ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
ExecAssignProjectionInfo(&subquerystate->ss.ps);
return TRUE;
return subquerystate;
}
int
@ -191,42 +195,31 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
* ----------------------------------------------------------------
*/
void
ExecEndSubqueryScan(SubqueryScan *node)
ExecEndSubqueryScan(SubqueryScanState *node)
{
SubqueryScanState *subquerystate;
/*
* get information from node
*/
subquerystate = (SubqueryScanState *) node->scan.scanstate;
/*
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(subquerystate) because the rule
* manager depends on the tupType returned by ExecMain(). So for now,
* this is freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&subquerystate->csstate.cstate);
ExecFreeExprContext(&subquerystate->csstate.cstate);
/*
* close down subquery
*/
ExecEndNode(node->subplan, (Plan *) node);
/*
* clean up subquery's tuple table
*/
subquerystate->csstate.css_ScanTupleSlot = NULL;
ExecDropTupleTable(subquerystate->sss_SubEState->es_tupleTable, true);
/* XXX we seem to be leaking the sub-EState... */
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
* clean out the upper tuple table
*/
ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
/*
* close down subquery
*/
ExecEndNode(node->subplan);
/*
* clean up subquery's tuple table
*/
node->ss.ss_ScanTupleSlot = NULL;
ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
/* XXX we seem to be leaking the sub-EState... */
}
/* ----------------------------------------------------------------
@ -236,27 +229,25 @@ ExecEndSubqueryScan(SubqueryScan *node)
* ----------------------------------------------------------------
*/
void
ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
{
SubqueryScanState *subquerystate;
EState *estate;
subquerystate = (SubqueryScanState *) node->scan.scanstate;
estate = node->scan.plan.state;
estate = node->ss.ps.state;
/*
* ExecReScan doesn't know about my subplan, so I have to do
* changed-parameter signaling myself.
*/
if (node->scan.plan.chgParam != NULL)
SetChangedParamList(node->subplan, node->scan.plan.chgParam);
if (node->ss.ps.chgParam != NULL)
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
*/
if (node->subplan->chgParam == NULL)
ExecReScan(node->subplan, NULL, (Plan *) node);
ExecReScan(node->subplan, NULL);
subquerystate->csstate.css_ScanTupleSlot = NULL;
node->ss.ss_ScanTupleSlot = NULL;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.27 2002/11/30 05:21:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.28 2002/12/05 15:50:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,7 +30,7 @@
#include "parser/parsetree.h"
static int TidListCreate(List *, ExprContext *, ItemPointerData[]);
static TupleTableSlot *TidNext(TidScan *node);
static TupleTableSlot *TidNext(TidScanState *node);
static int
TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
@ -65,19 +65,17 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
* ----------------------------------------------------------------
*/
static TupleTableSlot *
TidNext(TidScan *node)
TidNext(TidScanState *node)
{
EState *estate;
CommonScanState *scanstate;
TidScanState *tidstate;
ScanDirection direction;
Snapshot snapshot;
Relation heapRelation;
HeapTuple tuple;
TupleTableSlot *slot;
Index scanrelid;
Buffer buffer = InvalidBuffer;
int numTids;
bool bBackward;
int tidNumber;
ItemPointerData *tidList;
@ -85,15 +83,14 @@ TidNext(TidScan *node)
/*
* extract necessary information from tid scan node
*/
estate = node->scan.plan.state;
estate = node->ss.ps.state;
direction = estate->es_direction;
snapshot = estate->es_snapshot;
scanstate = node->scan.scanstate;
tidstate = node->tidstate;
heapRelation = scanstate->css_currentRelation;
numTids = tidstate->tss_NumTids;
tidList = tidstate->tss_TidList;
slot = scanstate->css_ScanTupleSlot;
heapRelation = node->ss.ss_currentRelation;
numTids = node->tss_NumTids;
tidList = node->tss_TidList;
slot = node->ss.ss_ScanTupleSlot;
scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
/*
* Check if we are evaluating PlanQual for tuple of this relation.
@ -102,10 +99,10 @@ TidNext(TidScan *node)
* switching in Init/ReScan plan...
*/
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
estate->es_evTuple[scanrelid - 1] != NULL)
{
ExecClearTuple(slot);
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
if (estate->es_evTupleNull[scanrelid - 1])
return slot; /* return empty slot */
/*
@ -113,15 +110,15 @@ TidNext(TidScan *node)
* list? In runtime-key case this is not certain, is it?
*/
ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
slot, InvalidBuffer, false);
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
estate->es_evTupleNull[scanrelid - 1] = true;
return (slot);
}
tuple = &(tidstate->tss_htup);
tuple = &(node->tss_htup);
/*
* ok, now that we have what we need, fetch an tid tuple. if scanning
@ -131,26 +128,26 @@ TidNext(TidScan *node)
bBackward = ScanDirectionIsBackward(direction);
if (bBackward)
{
tidNumber = numTids - tidstate->tss_TidPtr - 1;
tidNumber = numTids - node->tss_TidPtr - 1;
if (tidNumber < 0)
{
tidNumber = 0;
tidstate->tss_TidPtr = numTids - 1;
node->tss_TidPtr = numTids - 1;
}
}
else
{
if ((tidNumber = tidstate->tss_TidPtr) < 0)
if ((tidNumber = node->tss_TidPtr) < 0)
{
tidNumber = 0;
tidstate->tss_TidPtr = 0;
node->tss_TidPtr = 0;
}
}
while (tidNumber < numTids)
{
bool slot_is_valid = false;
tuple->t_self = tidList[tidstate->tss_TidPtr];
tuple->t_self = tidList[node->tss_TidPtr];
if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
{
bool prev_matches = false;
@ -181,7 +178,7 @@ TidNext(TidScan *node)
* do this by passing the tuple through ExecQual and look for
* failure with all previous qualifications.
*/
for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
for (prev_tid = 0; prev_tid < node->tss_TidPtr;
prev_tid++)
{
if (ItemPointerEquals(&tidList[prev_tid], &tuple->t_self))
@ -197,9 +194,9 @@ TidNext(TidScan *node)
}
tidNumber++;
if (bBackward)
tidstate->tss_TidPtr--;
node->tss_TidPtr--;
else
tidstate->tss_TidPtr++;
node->tss_TidPtr++;
if (slot_is_valid)
return slot;
}
@ -231,12 +228,12 @@ TidNext(TidScan *node)
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecTidScan(TidScan *node)
ExecTidScan(TidScanState *node)
{
/*
* use TidNext as access method
*/
return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
return ExecScan(&node->ss, (ExecScanAccessMtd) TidNext);
}
/* ----------------------------------------------------------------
@ -244,42 +241,30 @@ ExecTidScan(TidScan *node)
* ----------------------------------------------------------------
*/
void
ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
ExecTidReScan(TidScanState *node, ExprContext *exprCtxt)
{
EState *estate;
TidScanState *tidstate;
ItemPointerData *tidList;
Index scanrelid;
estate = node->scan.plan.state;
tidstate = node->tidstate;
tidList = tidstate->tss_TidList;
estate = node->ss.ps.state;
tidList = node->tss_TidList;
scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
/* If we are being passed an outer tuple, save it for runtime key calc */
if (exprCtxt != NULL)
node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
node->ss.ps.ps_ExprContext->ecxt_outertuple =
exprCtxt->ecxt_outertuple;
/* do runtime calc of target TIDs, if needed */
if (node->needRescan)
tidstate->tss_NumTids =
TidListCreate(node->tideval,
node->scan.scanstate->cstate.cs_ExprContext,
tidList);
/* If this is re-scanning of PlanQual ... */
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
estate->es_evTuple[scanrelid - 1] != NULL)
{
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
estate->es_evTupleNull[scanrelid - 1] = false;
return;
}
tidstate->tss_TidPtr = -1;
/*
* perhaps return something meaningful
*/
return;
node->tss_TidPtr = -1;
}
/* ----------------------------------------------------------------
@ -290,18 +275,13 @@ ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
* ----------------------------------------------------------------
*/
void
ExecEndTidScan(TidScan *node)
ExecEndTidScan(TidScanState *node)
{
CommonScanState *scanstate;
TidScanState *tidstate;
/*
* extract information from the node
*/
scanstate = node->scan.scanstate;
tidstate = node->tidstate;
if (tidstate && tidstate->tss_TidList)
pfree(tidstate->tss_TidList);
if (node && node->tss_TidList)
pfree(node->tss_TidList);
/*
* Free the projection info and the scan attribute info
@ -310,8 +290,14 @@ ExecEndTidScan(TidScan *node)
* depends on the tupType returned by ExecMain(). So for now, this is
* freed at end-transaction time. -cim 6/2/91
*/
ExecFreeProjectionInfo(&scanstate->cstate);
ExecFreeExprContext(&scanstate->cstate);
ExecFreeProjectionInfo(&node->ss.ps);
ExecFreeExprContext(&node->ss.ps);
/*
* clear out tuple table slots
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* close the heap relation.
@ -320,13 +306,7 @@ ExecEndTidScan(TidScan *node)
* ExecInitTidScan. This lock should be held till end of transaction.
* (There is a faction that considers this too much locking, however.)
*/
heap_close(scanstate->css_currentRelation, NoLock);
/*
* clear out tuple table slots
*/
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
ExecClearTuple(scanstate->css_ScanTupleSlot);
heap_close(node->ss.ss_currentRelation, NoLock);
}
/* ----------------------------------------------------------------
@ -337,12 +317,9 @@ ExecEndTidScan(TidScan *node)
* ----------------------------------------------------------------
*/
void
ExecTidMarkPos(TidScan *node)
ExecTidMarkPos(TidScanState *node)
{
TidScanState *tidstate;
tidstate = node->tidstate;
tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
node->tss_MarkTidPtr = node->tss_TidPtr;
}
/* ----------------------------------------------------------------
@ -355,12 +332,9 @@ ExecTidMarkPos(TidScan *node)
* ----------------------------------------------------------------
*/
void
ExecTidRestrPos(TidScan *node)
ExecTidRestrPos(TidScanState *node)
{
TidScanState *tidstate;
tidstate = node->tidstate;
tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
node->tss_TidPtr = node->tss_MarkTidPtr;
}
/* ----------------------------------------------------------------
@ -374,11 +348,10 @@ ExecTidRestrPos(TidScan *node)
* estate: the execution state initialized in InitPlan.
* ----------------------------------------------------------------
*/
bool
ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
TidScanState *
ExecInitTidScan(TidScan *node, EState *estate)
{
TidScanState *tidstate;
CommonScanState *scanstate;
ItemPointerData *tidList;
int numTids;
int tidPtr;
@ -390,56 +363,50 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
List *execParam = NIL;
/*
* assign execution state to node
* create state structure
*/
node->scan.plan.state = estate;
/*
* Part 1) initialize scan state
*
* create new CommonScanState for node
*/
scanstate = makeNode(CommonScanState);
node->scan.scanstate = scanstate;
tidstate = makeNode(TidScanState);
tidstate->ss.ps.plan = (Plan *) node;
tidstate->ss.ps.state = estate;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &scanstate->cstate);
ExecAssignExprContext(estate, &tidstate->ss.ps);
/*
* initialize child expressions
*/
tidstate->ss.ps.targetlist = (List *)
ExecInitExpr((Node *) node->scan.plan.targetlist,
(PlanState *) tidstate);
tidstate->ss.ps.qual = (List *)
ExecInitExpr((Node *) node->scan.plan.qual,
(PlanState *) tidstate);
#define TIDSCAN_NSLOTS 2
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &scanstate->cstate);
ExecInitScanTupleSlot(estate, scanstate);
ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
ExecInitScanTupleSlot(estate, &tidstate->ss);
/*
* initialize projection info. result type comes from scan desc
* below..
*/
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
/*
* Part 2) initialize tid scan state
*
* create new TidScanState for node
*/
tidstate = makeNode(TidScanState);
node->tidstate = tidstate;
ExecAssignProjectionInfo(&tidstate->ss.ps);
/*
* get the tid node information
*/
tidList = (ItemPointerData *) palloc(length(node->tideval) * sizeof(ItemPointerData));
numTids = 0;
if (!node->needRescan)
numTids = TidListCreate(node->tideval,
scanstate->cstate.cs_ExprContext,
tidList);
numTids = TidListCreate(node->tideval,
tidstate->ss.ps.ps_ExprContext,
tidList);
tidPtr = -1;
CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
@ -465,25 +432,25 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
currentRelation = heap_open(reloid, AccessShareLock);
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
tidstate->ss.ss_currentRelation = currentRelation;
tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
/*
* get the scan type from the relation descriptor.
*/
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation), false);
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
/*
* if there are some PARAM_EXEC in skankeys then force tid rescan on
* first scan.
*/
((Plan *) node)->chgParam = execParam;
tidstate->ss.ps.chgParam = execParam;
/*
* all done.
*/
return TRUE;
return tidstate;
}
int

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.34 2002/06/20 20:29:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.35 2002/12/05 15:50:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,7 +21,6 @@
* NOTES
* Assumes tuples returned from subplan arrive in
* sorted order.
*
*/
#include "postgres.h"
@ -39,21 +38,20 @@
* ----------------------------------------------------------------
*/
TupleTableSlot * /* return: a tuple or NULL */
ExecUnique(Unique *node)
ExecUnique(UniqueState *node)
{
UniqueState *uniquestate;
Unique *plannode = (Unique *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
Plan *outerPlan;
PlanState *outerPlan;
TupleDesc tupDesc;
/*
* get information from the node
*/
uniquestate = node->uniquestate;
outerPlan = outerPlan((Plan *) node);
resultTupleSlot = uniquestate->cstate.cs_ResultTupleSlot;
tupDesc = ExecGetResultType(&uniquestate->cstate);
outerPlan = outerPlanState(node);
resultTupleSlot = node->ps.ps_ResultTupleSlot;
tupDesc = ExecGetResultType(&node->ps);
/*
* now loop, returning only non-duplicate tuples. We assume that the
@ -64,14 +62,14 @@ ExecUnique(Unique *node)
/*
* fetch a tuple from the outer subplan
*/
slot = ExecProcNode(outerPlan, (Plan *) node);
slot = ExecProcNode(outerPlan);
if (TupIsNull(slot))
return NULL;
/*
* Always return the first tuple from the subplan.
*/
if (uniquestate->priorTuple == NULL)
if (node->priorTuple == NULL)
break;
/*
@ -79,11 +77,11 @@ ExecUnique(Unique *node)
* match. If so then we loop back and fetch another new tuple
* from the subplan.
*/
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
if (!execTuplesMatch(slot->val, node->priorTuple,
tupDesc,
node->numCols, node->uniqColIdx,
uniquestate->eqfunctions,
uniquestate->tempContext))
plannode->numCols, plannode->uniqColIdx,
node->eqfunctions,
node->tempContext))
break;
}
@ -99,11 +97,11 @@ ExecUnique(Unique *node)
* handling in execMain.c). We assume that the caller will no longer
* be interested in the current tuple after he next calls us.
*/
if (uniquestate->priorTuple != NULL)
heap_freetuple(uniquestate->priorTuple);
uniquestate->priorTuple = heap_copytuple(slot->val);
if (node->priorTuple != NULL)
heap_freetuple(node->priorTuple);
node->priorTuple = heap_copytuple(slot->val);
ExecStoreTuple(uniquestate->priorTuple,
ExecStoreTuple(node->priorTuple,
resultTupleSlot,
InvalidBuffer,
false); /* tuple does not belong to slot */
@ -118,22 +116,18 @@ ExecUnique(Unique *node)
* the node's subplan.
* ----------------------------------------------------------------
*/
bool /* return: initialization status */
ExecInitUnique(Unique *node, EState *estate, Plan *parent)
UniqueState *
ExecInitUnique(Unique *node, EState *estate)
{
UniqueState *uniquestate;
Plan *outerPlan;
/*
* assign execution state to node
*/
node->plan.state = estate;
/*
* create new UniqueState for node
* create state structure
*/
uniquestate = makeNode(UniqueState);
node->uniquestate = uniquestate;
uniquestate->ps.plan = (Plan *) node;
uniquestate->ps.state = estate;
uniquestate->priorTuple = NULL;
/*
@ -155,30 +149,29 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
/*
* Tuple table initialization
*/
ExecInitResultTupleSlot(estate, &uniquestate->cstate);
ExecInitResultTupleSlot(estate, &uniquestate->ps);
/*
* then initialize outer plan
*/
outerPlan = outerPlan((Plan *) node);
ExecInitNode(outerPlan, estate, (Plan *) node);
outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
/*
* unique nodes do no projections, so initialize projection info for
* this node appropriately
*/
ExecAssignResultTypeFromOuterPlan((Plan *) node, &uniquestate->cstate);
uniquestate->cstate.cs_ProjInfo = NULL;
ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
uniquestate->ps.ps_ProjInfo = NULL;
/*
* Precompute fmgr lookup data for inner loop
*/
uniquestate->eqfunctions =
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->cstate),
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
node->numCols,
node->uniqColIdx);
return TRUE;
return uniquestate;
}
int
@ -197,41 +190,36 @@ ExecCountSlotsUnique(Unique *node)
* ----------------------------------------------------------------
*/
void
ExecEndUnique(Unique *node)
ExecEndUnique(UniqueState *node)
{
UniqueState *uniquestate = node->uniquestate;
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
MemoryContextDelete(uniquestate->tempContext);
/* clean up tuple table */
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
if (uniquestate->priorTuple != NULL)
ExecClearTuple(node->ps.ps_ResultTupleSlot);
if (node->priorTuple != NULL)
{
heap_freetuple(uniquestate->priorTuple);
uniquestate->priorTuple = NULL;
heap_freetuple(node->priorTuple);
node->priorTuple = NULL;
}
ExecEndNode(outerPlanState(node));
MemoryContextDelete(node->tempContext);
}
void
ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
{
UniqueState *uniquestate = node->uniquestate;
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
if (uniquestate->priorTuple != NULL)
ExecClearTuple(node->ps.ps_ResultTupleSlot);
if (node->priorTuple != NULL)
{
heap_freetuple(uniquestate->priorTuple);
uniquestate->priorTuple = NULL;
heap_freetuple(node->priorTuple);
node->priorTuple = 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);
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.78 2002/11/13 00:39:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.79 2002/12/05 15:50:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -33,7 +33,7 @@ static int _SPI_connected = -1;
static int _SPI_curid = -1;
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
static int _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount);
static int _SPI_execute_plan(_SPI_plan *plan,
Datum *Values, char *Nulls, int tcount);
@ -705,9 +705,8 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
List *ptlist = spiplan->ptlist;
Query *queryTree;
Plan *planTree;
ParamListInfo paramLI;
QueryDesc *queryDesc;
EState *eState;
TupleDesc attinfo;
MemoryContext oldcontext;
Portal portal;
char portalname[64];
@ -774,28 +773,21 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
queryTree->into->relname = pstrdup(name);
queryTree->isBinary = false;
/* Create the QueryDesc object and the executor state */
queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL);
eState = CreateExecutorState();
/* If the plan has parameters, put them into the executor state */
/* If the plan has parameters, set them up */
if (spiplan->nargs > 0)
{
ParamListInfo paramLI;
paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
sizeof(ParamListInfoData));
sizeof(ParamListInfoData));
eState->es_param_list_info = paramLI;
for (k = 0; k < spiplan->nargs; paramLI++, k++)
for (k = 0; k < spiplan->nargs; k++)
{
paramLI->kind = PARAM_NUM;
paramLI->id = k + 1;
paramLI->isnull = (Nulls && Nulls[k] == 'n');
if (paramLI->isnull)
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
if (paramLI[k].isnull)
{
/* nulls just copy */
paramLI->value = Values[k];
paramLI[k].value = Values[k];
}
else
{
@ -805,20 +797,24 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
get_typlenbyval(spiplan->argtypes[k],
&paramTypLen, &paramTypByVal);
paramLI->value = datumCopy(Values[k],
paramTypByVal, paramTypLen);
paramLI[k].value = datumCopy(Values[k],
paramTypByVal, paramTypLen);
}
}
paramLI->kind = PARAM_INVALID;
paramLI[k].kind = PARAM_INVALID;
}
else
eState->es_param_list_info = NULL;
paramLI = NULL;
/* Create the QueryDesc object */
queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL,
paramLI, false);
/* Start the executor */
attinfo = ExecutorStart(queryDesc, eState);
ExecutorStart(queryDesc);
/* Put all the objects into the portal */
PortalSetQuery(portal, queryDesc, attinfo, eState, PortalCleanup);
/* Arrange to shut down the executor if portal is dropped */
PortalSetQuery(portal, queryDesc, PortalCleanup);
/* Switch back to the callers memory context */
MemoryContextSwitchTo(oldcontext);
@ -1042,7 +1038,6 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
Plan *planTree;
bool canSetResult;
QueryDesc *qdesc;
EState *state;
planTree = pg_plan_query(queryTree);
plan_list = lappend(plan_list, planTree);
@ -1089,9 +1084,9 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
else if (plan == NULL)
{
qdesc = CreateQueryDesc(queryTree, planTree,
canSetResult ? SPI : None, NULL);
state = CreateExecutorState();
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
canSetResult ? SPI : None,
NULL, NULL, false);
res = _SPI_pquery(qdesc, true, canSetResult ? tcount : 0);
if (res < 0)
return res;
CommandCounterIncrement();
@ -1099,8 +1094,9 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
canSetResult ? SPI : None, NULL);
res = _SPI_pquery(qdesc, NULL, 0);
canSetResult ? SPI : None,
NULL, NULL, false);
res = _SPI_pquery(qdesc, false, 0);
if (res < 0)
return res;
}
@ -1152,7 +1148,6 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
Plan *planTree;
bool canSetResult;
QueryDesc *qdesc;
EState *state;
planTree = lfirst(plan_list);
plan_list = lnext(plan_list);
@ -1183,30 +1178,31 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
}
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
canSetResult ? SPI : None, NULL);
state = CreateExecutorState();
ParamListInfo paramLI;
if (nargs > 0)
{
ParamListInfo paramLI;
int k;
paramLI = (ParamListInfo)
palloc0((nargs + 1) * sizeof(ParamListInfoData));
state->es_param_list_info = paramLI;
for (k = 0; k < plan->nargs; paramLI++, k++)
for (k = 0; k < plan->nargs; k++)
{
paramLI->kind = PARAM_NUM;
paramLI->id = k + 1;
paramLI->isnull = (Nulls && Nulls[k] == 'n');
paramLI->value = Values[k];
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
paramLI[k].value = Values[k];
}
paramLI->kind = PARAM_INVALID;
paramLI[k].kind = PARAM_INVALID;
}
else
state->es_param_list_info = NULL;
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
paramLI = NULL;
qdesc = CreateQueryDesc(queryTree, planTree,
canSetResult ? SPI : None,
NULL, paramLI, false);
res = _SPI_pquery(qdesc, true, canSetResult ? tcount : 0);
if (res < 0)
return res;
CommandCounterIncrement();
@ -1218,7 +1214,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
}
static int
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
_SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
{
Query *parseTree = queryDesc->parsetree;
int operation = queryDesc->operation;
@ -1262,7 +1258,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
return SPI_ERROR_OPUNKNOWN;
}
if (state == NULL) /* plan preparation, don't execute */
if (!runit) /* plan preparation, don't execute */
return res;
#ifdef SPI_EXECUTOR_STATS
@ -1270,20 +1266,20 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
ResetUsage();
#endif
ExecutorStart(queryDesc, state);
ExecutorStart(queryDesc);
/*
* Don't work currently --- need to rearrange callers so that we
* prepare the portal before doing CreateExecutorState() etc. See
* prepare the portal before doing ExecutorStart() etc. See
* pquery.c for the correct order of operations.
*/
if (isRetrieveIntoPortal)
elog(FATAL, "SPI_select: retrieve into portal not implemented");
ExecutorRun(queryDesc, state, ForwardScanDirection, (long) tcount);
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
_SPI_current->processed = state->es_processed;
save_lastoid = state->es_lastoid;
_SPI_current->processed = queryDesc->estate->es_processed;
save_lastoid = queryDesc->estate->es_lastoid;
if (operation == CMD_SELECT && queryDesc->dest == SPI)
{
@ -1291,7 +1287,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
elog(FATAL, "SPI_select: # of processed tuples check failed");
}
ExecutorEnd(queryDesc, state);
ExecutorEnd(queryDesc);
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
@ -1342,7 +1338,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
querydesc = PortalGetQueryDesc(portal);
estate = PortalGetState(portal);
estate = querydesc->estate;
/* Save the queries command destination and set it to SPI (for fetch) */
/* or None (for move) */
@ -1357,7 +1353,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
else
direction = ForwardScanDirection;
ExecutorRun(querydesc, estate, direction, (long) count);
ExecutorRun(querydesc, direction, (long) count);
if (estate->es_processed > 0)
portal->atStart = false; /* OK to back up now */
@ -1371,7 +1367,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
else
direction = BackwardScanDirection;
ExecutorRun(querydesc, estate, direction, (long) count);
ExecutorRun(querydesc, direction, (long) count);
if (estate->es_processed > 0)
portal->atEnd = false; /* OK to go forward now */