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

@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.93 2002/11/13 00:39:46 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.94 2002/12/05 15:50:30 tgl Exp $
*
*/
@ -34,17 +34,19 @@ typedef struct ExplainState
{
/* options */
bool printCost; /* print cost */
bool printNodes; /* do nodeToString() instead */
bool printAnalyze; /* print actual times */
bool printNodes; /* do nodeToString() too */
bool printAnalyze; /* print actual times */
/* other states */
List *rtable; /* range table */
} ExplainState;
static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
TupOutputState *tstate);
static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
int indent, ExplainState *es);
static double elapsed_time(struct timeval *starttime);
static void explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
int indent, ExplainState *es);
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
int scanrelid, Plan *outer_plan,
StringInfo str, int indent, ExplainState *es);
@ -116,8 +118,11 @@ static void
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
{
Plan *plan;
QueryDesc *queryDesc;
ExplainState *es;
StringInfo str;
double totaltime = 0;
struct timeval starttime;
/* planner will not cope with utility statements */
if (query->commandType == CMD_UTILITY)
@ -136,41 +141,34 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
if (plan == NULL)
return;
/* We don't support DECLARE CURSOR here */
Assert(!query->isPortal);
gettimeofday(&starttime, NULL);
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None, NULL, NULL,
stmt->analyze);
/* call ExecutorStart to prepare the plan for execution */
ExecutorStart(queryDesc);
/* Execute the plan for statistics if asked for */
if (stmt->analyze)
{
struct timeval starttime;
struct timeval endtime;
/* run the plan */
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
/*
* Set up the instrumentation for the top node. This will cascade
* during plan initialisation
*/
plan->instrument = InstrAlloc();
/* We can't clean up 'till we're done printing the stats... */
gettimeofday(&starttime, NULL);
ProcessQuery(query, plan, None, NULL);
CommandCounterIncrement();
gettimeofday(&endtime, NULL);
endtime.tv_sec -= starttime.tv_sec;
endtime.tv_usec -= starttime.tv_usec;
while (endtime.tv_usec < 0)
{
endtime.tv_usec += 1000000;
endtime.tv_sec--;
}
totaltime = (double) endtime.tv_sec +
(double) endtime.tv_usec / 1000000.0;
totaltime += elapsed_time(&starttime);
}
es = (ExplainState *) palloc0(sizeof(ExplainState));
es->printCost = true; /* default */
if (stmt->verbose)
es->printNodes = true;
es->printNodes = stmt->verbose;
es->printAnalyze = stmt->analyze;
es->rtable = query->rtable;
if (es->printNodes)
@ -193,33 +191,73 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
}
}
str = makeStringInfo();
if (es->printCost)
{
StringInfo str;
explain_outNode(str, plan, queryDesc->planstate,
NULL, 0, es);
}
str = Explain_PlanToString(plan, es);
/*
* Close down the query and free resources. Include time for this
* in the total runtime.
*/
gettimeofday(&starttime, NULL);
ExecutorEnd(queryDesc);
CommandCounterIncrement();
totaltime += elapsed_time(&starttime);
if (es->printCost)
{
if (stmt->analyze)
appendStringInfo(str, "Total runtime: %.2f msec\n",
1000.0 * totaltime);
do_text_output_multiline(tstate, str->data);
pfree(str->data);
pfree(str);
}
pfree(str->data);
pfree(str);
pfree(es);
}
/* Compute elapsed time in seconds since given gettimeofday() timestamp */
static double
elapsed_time(struct timeval *starttime)
{
struct timeval endtime;
gettimeofday(&endtime, NULL);
endtime.tv_sec -= starttime->tv_sec;
endtime.tv_usec -= starttime->tv_usec;
while (endtime.tv_usec < 0)
{
endtime.tv_usec += 1000000;
endtime.tv_sec--;
}
return (double) endtime.tv_sec +
(double) endtime.tv_usec / 1000000.0;
}
/*
* explain_outNode -
* converts a Plan node into ascii string and appends it to 'str'
*
* planstate points to the executor state node corresponding to the plan node.
* We need this to get at the instrumentation data (if any) as well as the
* list of subplans.
*
* outer_plan, if not null, references another plan node that is the outer
* side of a join with the current node. This is only interesting for
* deciphering runtime keys of an inner indexscan.
*/
static void
explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
explain_outNode(StringInfo str,
Plan *plan, PlanState *planstate,
Plan *outer_plan,
int indent, ExplainState *es)
{
List *l;
@ -410,18 +448,23 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
plan->startup_cost, plan->total_cost,
plan->plan_rows, plan->plan_width);
if (plan->instrument && plan->instrument->nloops > 0)
/*
* We have to forcibly clean up the instrumentation state because
* we haven't done ExecutorEnd yet. This is pretty grotty ...
*/
InstrEndLoop(planstate->instrument);
if (planstate->instrument && planstate->instrument->nloops > 0)
{
double nloops = plan->instrument->nloops;
double nloops = planstate->instrument->nloops;
appendStringInfo(str, " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)",
1000.0 * plan->instrument->startup / nloops,
1000.0 * plan->instrument->total / nloops,
plan->instrument->ntuples / nloops,
plan->instrument->nloops);
es->printAnalyze = true;
1000.0 * planstate->instrument->startup / nloops,
1000.0 * planstate->instrument->total / nloops,
planstate->instrument->ntuples / nloops,
planstate->instrument->nloops);
}
else if( es->printAnalyze )
else if (es->printAnalyze)
{
appendStringInfo(str, " (never executed)");
}
@ -538,6 +581,7 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
if (plan->initPlan)
{
List *saved_rtable = es->rtable;
List *pslist = planstate->initPlan;
List *lst;
for (i = 0; i < indent; i++)
@ -545,12 +589,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
appendStringInfo(str, " InitPlan\n");
foreach(lst, plan->initPlan)
{
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
SubPlan *subplan = (SubPlan *) lfirst(lst);
SubPlanState *subplanstate = (SubPlanState *) lfirst(pslist);
es->rtable = subplan->rtable;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
explain_outNode(str, subplan->plan,
subplanstate->planstate,
NULL,
indent + 4, es);
pslist = lnext(pslist);
}
es->rtable = saved_rtable;
}
@ -561,7 +611,10 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, outerPlan(plan), NULL, indent + 3, es);
explain_outNode(str, outerPlan(plan),
outerPlanState(planstate),
NULL,
indent + 3, es);
}
/* righttree */
@ -570,15 +623,20 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, innerPlan(plan), outerPlan(plan),
explain_outNode(str, innerPlan(plan),
innerPlanState(planstate),
outerPlan(plan),
indent + 3, es);
}
if (IsA(plan, Append))
{
Append *appendplan = (Append *) plan;
AppendState *appendstate = (AppendState *) planstate;
List *lst;
int j;
j = 0;
foreach(lst, appendplan->appendplans)
{
Plan *subnode = (Plan *) lfirst(lst);
@ -587,13 +645,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode, NULL, indent + 3, es);
explain_outNode(str, subnode,
appendstate->appendplans[j],
NULL,
indent + 3, es);
j++;
}
}
if (IsA(plan, SubqueryScan))
{
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
Plan *subnode = subqueryscan->subplan;
RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
es->rtable);
@ -606,13 +669,16 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode, NULL, indent + 3, es);
explain_outNode(str, subnode,
subquerystate->subplan,
NULL,
indent + 3, es);
es->rtable = saved_rtable;
}
/* subPlan-s */
if (plan->subPlan)
if (planstate->subPlan)
{
List *saved_rtable = es->rtable;
List *lst;
@ -620,29 +686,24 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " SubPlan\n");
foreach(lst, plan->subPlan)
foreach(lst, planstate->subPlan)
{
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
SubPlanState *sps = (SubPlanState *) lfirst(lst);
SubPlan *sp = (SubPlan *) sps->ps.plan;
es->rtable = sp->rtable;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
explain_outNode(str, sp->plan,
sps->planstate,
NULL,
indent + 4, es);
}
es->rtable = saved_rtable;
}
}
static StringInfo
Explain_PlanToString(Plan *plan, ExplainState *es)
{
StringInfo str = makeStringInfo();
if (plan != NULL)
explain_outNode(str, plan, NULL, 0, es);
return str;
}
/*
* Show a qualifier expression for a scan plan node
*/

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.4 2002/11/13 00:44:08 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.5 2002/12/05 15:50:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,6 +23,10 @@
/*
* PortalCleanup
*
* Clean up a portal when it's dropped. Since this mainly exists to run
* ExecutorEnd(), it should not be set as the cleanup hook until we have
* called ExecutorStart() on the portal's query.
*/
void
PortalCleanup(Portal portal)
@ -43,7 +47,7 @@ PortalCleanup(Portal portal)
/*
* tell the executor to shutdown the query
*/
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
ExecutorEnd(PortalGetQueryDesc(portal));
/*
* switch back to previous context
@ -116,7 +120,7 @@ PerformPortalFetch(char *name,
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
queryDesc = PortalGetQueryDesc(portal);
estate = PortalGetState(portal);
estate = queryDesc->estate;
/*
* If the requested destination is not the same as the query's
@ -158,7 +162,7 @@ PerformPortalFetch(char *name,
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 */
@ -172,7 +176,7 @@ PerformPortalFetch(char *name,
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 */

View File

@ -6,7 +6,7 @@
* Copyright (c) 2002, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.8 2002/11/15 00:47:22 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.9 2002/12/05 15:50:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -49,7 +49,7 @@ static void InitQueryHashTable(void);
static void StoreQuery(const char *stmt_name, List *query_list,
List *plan_list, List *argtype_list);
static QueryHashEntry *FetchQuery(const char *plan_name);
static void RunQuery(QueryDesc *qdesc, EState *state);
static void RunQuery(QueryDesc *qdesc);
/*
@ -151,15 +151,12 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
else
{
QueryDesc *qdesc;
EState *state;
if (log_executor_stats)
ResetUsage();
qdesc = CreateQueryDesc(query, plan, outputDest, NULL);
state = CreateExecutorState();
state->es_param_list_info = paramLI;
qdesc = CreateQueryDesc(query, plan, outputDest, NULL,
paramLI, false);
if (stmt->into)
{
@ -170,7 +167,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
qdesc->dest = None;
}
RunQuery(qdesc, state);
RunQuery(qdesc);
if (log_executor_stats)
ShowUsage("EXECUTOR STATISTICS");
@ -334,15 +331,11 @@ FetchQueryParams(const char *plan_name)
* Actually execute a prepared query.
*/
static void
RunQuery(QueryDesc *qdesc, EState *state)
RunQuery(QueryDesc *qdesc)
{
TupleDesc tupdesc;
tupdesc = ExecutorStart(qdesc, state);
ExecutorRun(qdesc, state, state->es_direction, 0L);
ExecutorEnd(qdesc, state);
ExecutorStart(qdesc);
ExecutorRun(qdesc, ForwardScanDirection, 0L);
ExecutorEnd(qdesc);
}
/*

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 */

View File

@ -3,27 +3,28 @@
* copyfuncs.c
* Copy functions for Postgres tree nodes.
*
* NOTE: a general convention when copying or comparing plan nodes is
* that we ignore the executor state subnode. We do not need to look
* at it because no current uses of copyObject() or equal() need to
* deal with already-executing plan trees. By leaving the state subnodes
* out, we avoid needing to write copy/compare routines for all the
* different executor state node types.
* NOTE: we currently support copying all node types found in parse and
* plan trees. We do not support copying executor state trees; there
* is no need for that, and no point in maintaining all the code that
* would be needed. We also do not support copying Path trees, mainly
* because the circular linkages between RelOptInfo and Path nodes can't
* be handled easily in a simple depth-first traversal.
*
*
* 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/nodes/copyfuncs.c,v 1.225 2002/11/30 05:21:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.226 2002/12/05 15:50:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"
@ -58,15 +59,6 @@
memcpy(newnode->fldname, from->fldname, _size); \
} while (0)
/* Special hack for fixing subplan lists of Plan nodes (ick) */
#define FIX_SUBPLAN_LINKS(subplanfldname, fldname) \
do { \
if (from->subplanfldname != NIL) \
newnode->subplanfldname = \
nconc(newnode->subplanfldname, \
pull_subplans((Node *) (newnode->fldname))); \
} while (0)
/*
* listCopy
@ -119,19 +111,13 @@ CopyPlanFields(Plan *from, Plan *newnode)
COPY_SCALAR_FIELD(total_cost);
COPY_SCALAR_FIELD(plan_rows);
COPY_SCALAR_FIELD(plan_width);
/* execution state is NOT copied */
COPY_NODE_FIELD(targetlist);
COPY_NODE_FIELD(qual);
COPY_NODE_FIELD(lefttree);
COPY_NODE_FIELD(righttree);
COPY_NODE_FIELD(initPlan);
COPY_INTLIST_FIELD(extParam);
COPY_INTLIST_FIELD(locParam);
COPY_INTLIST_FIELD(chgParam);
COPY_NODE_FIELD(initPlan);
/* subPlan list must point to subplans in the new subtree, not the old */
newnode->subPlan = NIL;
FIX_SUBPLAN_LINKS(subPlan, targetlist);
FIX_SUBPLAN_LINKS(subPlan, qual);
COPY_SCALAR_FIELD(nParamExec);
}
@ -170,9 +156,6 @@ _copyResult(Result *from)
*/
COPY_NODE_FIELD(resconstantqual);
/* subPlan list must point to subplans in the new subtree, not the old */
FIX_SUBPLAN_LINKS(plan.subPlan, resconstantqual);
return newnode;
}
@ -266,10 +249,6 @@ _copyIndexScan(IndexScan *from)
COPY_NODE_FIELD(indxqualorig);
COPY_SCALAR_FIELD(indxorderdir);
/* subPlan list must point to subplans in the new subtree, not the old */
FIX_SUBPLAN_LINKS(scan.plan.subPlan, indxqual);
FIX_SUBPLAN_LINKS(scan.plan.subPlan, indxqualorig);
return newnode;
}
@ -289,12 +268,8 @@ _copyTidScan(TidScan *from)
/*
* copy remainder of node
*/
COPY_SCALAR_FIELD(needRescan);
COPY_NODE_FIELD(tideval);
/* subPlan list must point to subplans in the new subtree, not the old */
FIX_SUBPLAN_LINKS(scan.plan.subPlan, tideval);
return newnode;
}
@ -348,9 +323,6 @@ CopyJoinFields(Join *from, Join *newnode)
COPY_SCALAR_FIELD(jointype);
COPY_NODE_FIELD(joinqual);
/* subPlan list must point to subplans in the new subtree, not the old */
FIX_SUBPLAN_LINKS(plan.subPlan, joinqual);
}
@ -406,9 +378,6 @@ _copyMergeJoin(MergeJoin *from)
*/
COPY_NODE_FIELD(mergeclauses);
/* subPlan list must point to subplans in the new subtree, not the old */
FIX_SUBPLAN_LINKS(join.plan.subPlan, mergeclauses);
return newnode;
}
@ -430,9 +399,6 @@ _copyHashJoin(HashJoin *from)
*/
COPY_NODE_FIELD(hashclauses);
/* subPlan list must point to subplans in the new subtree, not the old */
FIX_SUBPLAN_LINKS(join.plan.subPlan, hashclauses);
return newnode;
}
@ -530,6 +496,27 @@ _copyUnique(Unique *from)
return newnode;
}
/*
* _copyHash
*/
static Hash *
_copyHash(Hash *from)
{
Hash *newnode = makeNode(Hash);
/*
* copy node superclass fields
*/
CopyPlanFields((Plan *) from, (Plan *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(hashkeys);
return newnode;
}
/*
* _copySetOp
*/
@ -576,29 +563,6 @@ _copyLimit(Limit *from)
return newnode;
}
/*
* _copyHash
*/
static Hash *
_copyHash(Hash *from)
{
Hash *newnode = makeNode(Hash);
/*
* copy node superclass fields
*/
CopyPlanFields((Plan *) from, (Plan *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(hashkeys);
/* XXX could the hashkeys contain subplans? Not at present... */
return newnode;
}
static SubPlan *
_copySubPlan(SubPlan *from)
{
@ -611,10 +575,6 @@ _copySubPlan(SubPlan *from)
COPY_INTLIST_FIELD(parParam);
COPY_NODE_FIELD(sublink);
/* do not copy execution state */
newnode->needShutdown = false;
newnode->curTuple = NULL;
return newnode;
}
@ -933,313 +893,11 @@ _copyArrayRef(ArrayRef *from)
/* ****************************************************************
* relation.h copy functions
*
* XXX the code to copy RelOptInfo and Path nodes is really completely bogus,
* because it makes no attempt to deal with multiple links from RelOptInfo
* to Paths, nor with back-links from Paths to their parent RelOptInfo.
* Currently, since we never actually try to copy a RelOptInfo, this is okay.
* We don't support copying RelOptInfo, IndexOptInfo, or Path nodes.
* There are some subsidiary structs that are useful to copy, though.
* ****************************************************************
*/
/*
* _copyRelOptInfo
*/
static RelOptInfo *
_copyRelOptInfo(RelOptInfo *from)
{
RelOptInfo *newnode = makeNode(RelOptInfo);
COPY_SCALAR_FIELD(reloptkind);
COPY_INTLIST_FIELD(relids);
COPY_SCALAR_FIELD(rows);
COPY_SCALAR_FIELD(width);
COPY_NODE_FIELD(targetlist);
COPY_NODE_FIELD(pathlist);
/* XXX cheapest-path fields should point to members of pathlist? */
COPY_NODE_FIELD(cheapest_startup_path);
COPY_NODE_FIELD(cheapest_total_path);
COPY_SCALAR_FIELD(pruneable);
COPY_SCALAR_FIELD(rtekind);
COPY_NODE_FIELD(indexlist);
COPY_SCALAR_FIELD(pages);
COPY_SCALAR_FIELD(tuples);
COPY_NODE_FIELD(subplan);
COPY_SCALAR_FIELD(joinrti);
COPY_INTLIST_FIELD(joinrteids);
COPY_NODE_FIELD(baserestrictinfo);
COPY_SCALAR_FIELD(baserestrictcost);
COPY_INTLIST_FIELD(outerjoinset);
COPY_NODE_FIELD(joininfo);
COPY_INTLIST_FIELD(index_outer_relids);
COPY_NODE_FIELD(index_inner_paths);
return newnode;
}
/*
* _copyIndexOptInfo
*/
static IndexOptInfo *
_copyIndexOptInfo(IndexOptInfo *from)
{
IndexOptInfo *newnode = makeNode(IndexOptInfo);
COPY_SCALAR_FIELD(indexoid);
COPY_SCALAR_FIELD(pages);
COPY_SCALAR_FIELD(tuples);
COPY_SCALAR_FIELD(ncolumns);
COPY_SCALAR_FIELD(nkeys);
if (from->classlist)
{
/* copy the trailing zero too */
COPY_POINTER_FIELD(classlist, (from->ncolumns + 1) * sizeof(Oid));
}
if (from->indexkeys)
{
/* copy the trailing zero too */
COPY_POINTER_FIELD(indexkeys, (from->nkeys + 1) * sizeof(int));
}
if (from->ordering)
{
/* copy the trailing zero too */
COPY_POINTER_FIELD(ordering, (from->ncolumns + 1) * sizeof(Oid));
}
COPY_SCALAR_FIELD(relam);
COPY_SCALAR_FIELD(amcostestimate);
COPY_SCALAR_FIELD(indproc);
COPY_NODE_FIELD(indpred);
COPY_SCALAR_FIELD(unique);
COPY_INTLIST_FIELD(outer_relids);
COPY_NODE_FIELD(inner_paths);
return newnode;
}
/*
* CopyPathFields
*
* This function copies the fields of the Path node. It is used by
* all the copy functions for classes which inherit from Path.
*/
static void
CopyPathFields(Path *from, Path *newnode)
{
/*
* Modify the next line, since it causes the copying to cycle (i.e.
* the parent points right back here! -- JMH, 7/7/92. Old version:
* COPY_NODE_FIELD(parent);
*/
COPY_SCALAR_FIELD(parent);
COPY_SCALAR_FIELD(startup_cost);
COPY_SCALAR_FIELD(total_cost);
COPY_SCALAR_FIELD(pathtype);
COPY_NODE_FIELD(pathkeys);
}
/*
* _copyPath
*/
static Path *
_copyPath(Path *from)
{
Path *newnode = makeNode(Path);
CopyPathFields(from, newnode);
return newnode;
}
/*
* _copyIndexPath
*/
static IndexPath *
_copyIndexPath(IndexPath *from)
{
IndexPath *newnode = makeNode(IndexPath);
/*
* copy node superclass fields
*/
CopyPathFields((Path *) from, (Path *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(indexinfo);
COPY_NODE_FIELD(indexqual);
COPY_SCALAR_FIELD(indexscandir);
COPY_SCALAR_FIELD(rows);
return newnode;
}
/*
* _copyTidPath
*/
static TidPath *
_copyTidPath(TidPath *from)
{
TidPath *newnode = makeNode(TidPath);
/*
* copy node superclass fields
*/
CopyPathFields((Path *) from, (Path *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(tideval);
COPY_INTLIST_FIELD(unjoined_relids);
return newnode;
}
/*
* _copyAppendPath
*/
static AppendPath *
_copyAppendPath(AppendPath *from)
{
AppendPath *newnode = makeNode(AppendPath);
/*
* copy node superclass fields
*/
CopyPathFields((Path *) from, (Path *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(subpaths);
return newnode;
}
/*
* _copyResultPath
*/
static ResultPath *
_copyResultPath(ResultPath *from)
{
ResultPath *newnode = makeNode(ResultPath);
/*
* copy node superclass fields
*/
CopyPathFields((Path *) from, (Path *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(subpath);
COPY_NODE_FIELD(constantqual);
return newnode;
}
/*
* _copyMaterialPath
*/
static MaterialPath *
_copyMaterialPath(MaterialPath *from)
{
MaterialPath *newnode = makeNode(MaterialPath);
/*
* copy node superclass fields
*/
CopyPathFields((Path *) from, (Path *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(subpath);
return newnode;
}
/*
* CopyJoinPathFields
*
* This function copies the fields of the JoinPath node. It is used by
* all the copy functions for classes which inherit from JoinPath.
*/
static void
CopyJoinPathFields(JoinPath *from, JoinPath *newnode)
{
CopyPathFields((Path *) from, (Path *) newnode);
COPY_SCALAR_FIELD(jointype);
COPY_NODE_FIELD(outerjoinpath);
COPY_NODE_FIELD(innerjoinpath);
COPY_NODE_FIELD(joinrestrictinfo);
}
/*
* _copyNestPath
*/
static NestPath *
_copyNestPath(NestPath *from)
{
NestPath *newnode = makeNode(NestPath);
/*
* copy node superclass fields
*/
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
return newnode;
}
/*
* _copyMergePath
*/
static MergePath *
_copyMergePath(MergePath *from)
{
MergePath *newnode = makeNode(MergePath);
/*
* copy node superclass fields
*/
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(path_mergeclauses);
COPY_NODE_FIELD(outersortkeys);
COPY_NODE_FIELD(innersortkeys);
return newnode;
}
/*
* _copyHashPath
*/
static HashPath *
_copyHashPath(HashPath *from)
{
HashPath *newnode = makeNode(HashPath);
/*
* copy node superclass fields
*/
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
/*
* copy remainder of node
*/
COPY_NODE_FIELD(path_hashclauses);
return newnode;
}
/*
* _copyPathKeyItem
*/
@ -1301,21 +959,6 @@ _copyJoinInfo(JoinInfo *from)
return newnode;
}
/*
* _copyInnerIndexscanInfo
*/
static InnerIndexscanInfo *
_copyInnerIndexscanInfo(InnerIndexscanInfo *from)
{
InnerIndexscanInfo *newnode = makeNode(InnerIndexscanInfo);
COPY_INTLIST_FIELD(other_relids);
COPY_SCALAR_FIELD(isouterjoin);
COPY_NODE_FIELD(best_innerpath);
return newnode;
}
/* ****************************************************************
* parsenodes.h copy functions
* ****************************************************************
@ -1737,7 +1380,8 @@ _copyQuery(Query *from)
/*
* We do not copy the planner internal fields: base_rel_list,
* other_rel_list, join_rel_list, equi_key_list, query_pathkeys,
* hasJoinRTEs. Not entirely clear if this is right?
* hasJoinRTEs. That would get us into copying RelOptInfo/Path
* trees, which we don't want to do.
*/
return newnode;
@ -2683,15 +2327,15 @@ copyObject(void *from)
case T_Unique:
retval = _copyUnique(from);
break;
case T_Hash:
retval = _copyHash(from);
break;
case T_SetOp:
retval = _copySetOp(from);
break;
case T_Limit:
retval = _copyLimit(from);
break;
case T_Hash:
retval = _copyHash(from);
break;
case T_SubPlan:
retval = _copySubPlan(from);
break;
@ -2757,39 +2401,6 @@ copyObject(void *from)
/*
* RELATION NODES
*/
case T_RelOptInfo:
retval = _copyRelOptInfo(from);
break;
case T_IndexOptInfo:
retval = _copyIndexOptInfo(from);
break;
case T_Path:
retval = _copyPath(from);
break;
case T_IndexPath:
retval = _copyIndexPath(from);
break;
case T_TidPath:
retval = _copyTidPath(from);
break;
case T_AppendPath:
retval = _copyAppendPath(from);
break;
case T_ResultPath:
retval = _copyResultPath(from);
break;
case T_MaterialPath:
retval = _copyMaterialPath(from);
break;
case T_NestPath:
retval = _copyNestPath(from);
break;
case T_MergePath:
retval = _copyMergePath(from);
break;
case T_HashPath:
retval = _copyHashPath(from);
break;
case T_PathKeyItem:
retval = _copyPathKeyItem(from);
break;
@ -2799,9 +2410,6 @@ copyObject(void *from)
case T_JoinInfo:
retval = _copyJoinInfo(from);
break;
case T_InnerIndexscanInfo:
retval = _copyInnerIndexscanInfo(from);
break;
/*
* VALUE NODES

View File

@ -3,30 +3,30 @@
* equalfuncs.c
* Equality functions to compare node trees.
*
* NOTE: a general convention when copying or comparing plan nodes is
* that we ignore the executor state subnode. We do not need to look
* at it because no current uses of copyObject() or equal() need to
* deal with already-executing plan trees. By leaving the state subnodes
* out, we avoid needing to write copy/compare routines for all the
* different executor state node types.
* NOTE: we currently support comparing all node types found in parse
* trees. We do not support comparing executor state trees; there
* is no need for that, and no point in maintaining all the code that
* would be needed. We also do not support comparing Path trees, mainly
* because the circular linkages between RelOptInfo and Path nodes can't
* be handled easily in a simple depth-first traversal.
*
* Currently, in fact, equal() doesn't know how to compare Plan nodes
* at all, let alone their executor-state subnodes. This will probably
* need to be fixed someday, but presently there is no need to compare
* plan trees.
* Currently, in fact, equal() doesn't know how to compare Plan trees
* either. This might need to be fixed someday.
*
*
* 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/nodes/equalfuncs.c,v 1.170 2002/11/30 05:21:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.171 2002/12/05 15:50:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "utils/datum.h"
@ -369,147 +369,6 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
* Stuff from relation.h
*/
static bool
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
{
/*
* We treat RelOptInfos as equal if they refer to the same base rels
* joined in the same order. Is this appropriate/sufficient?
*/
COMPARE_INTLIST_FIELD(relids);
return true;
}
static bool
_equalIndexOptInfo(IndexOptInfo *a, IndexOptInfo *b)
{
/*
* We treat IndexOptInfos as equal if they refer to the same index. Is
* this sufficient?
*/
COMPARE_SCALAR_FIELD(indexoid);
return true;
}
static bool
_equalPath(Path *a, Path *b)
{
/* This is safe only because _equalRelOptInfo is incomplete... */
COMPARE_NODE_FIELD(parent);
/*
* do not check path costs, since they may not be set yet, and being
* float values there are roundoff error issues anyway...
*/
COMPARE_SCALAR_FIELD(pathtype);
COMPARE_NODE_FIELD(pathkeys);
return true;
}
static bool
_equalIndexPath(IndexPath *a, IndexPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
COMPARE_NODE_FIELD(indexinfo);
COMPARE_NODE_FIELD(indexqual);
COMPARE_SCALAR_FIELD(indexscandir);
/*
* Skip 'rows' because of possibility of floating-point roundoff
* error. It should be derivable from the other fields anyway.
*/
return true;
}
static bool
_equalTidPath(TidPath *a, TidPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
COMPARE_NODE_FIELD(tideval);
COMPARE_INTLIST_FIELD(unjoined_relids);
return true;
}
static bool
_equalAppendPath(AppendPath *a, AppendPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
COMPARE_NODE_FIELD(subpaths);
return true;
}
static bool
_equalResultPath(ResultPath *a, ResultPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
COMPARE_NODE_FIELD(subpath);
COMPARE_NODE_FIELD(constantqual);
return true;
}
static bool
_equalMaterialPath(MaterialPath *a, MaterialPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
COMPARE_NODE_FIELD(subpath);
return true;
}
static bool
_equalJoinPath(JoinPath *a, JoinPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
COMPARE_SCALAR_FIELD(jointype);
COMPARE_NODE_FIELD(outerjoinpath);
COMPARE_NODE_FIELD(innerjoinpath);
COMPARE_NODE_FIELD(joinrestrictinfo);
return true;
}
static bool
_equalNestPath(NestPath *a, NestPath *b)
{
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
return false;
return true;
}
static bool
_equalMergePath(MergePath *a, MergePath *b)
{
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
return false;
COMPARE_NODE_FIELD(path_mergeclauses);
COMPARE_NODE_FIELD(outersortkeys);
COMPARE_NODE_FIELD(innersortkeys);
return true;
}
static bool
_equalHashPath(HashPath *a, HashPath *b)
{
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
return false;
COMPARE_NODE_FIELD(path_hashclauses);
return true;
}
static bool
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
{
@ -547,16 +406,6 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
return true;
}
static bool
_equalInnerIndexscanInfo(InnerIndexscanInfo *a, InnerIndexscanInfo *b)
{
COMPARE_INTLIST_FIELD(other_relids);
COMPARE_SCALAR_FIELD(isouterjoin);
COMPARE_NODE_FIELD(best_innerpath);
return true;
}
/*
* Stuff from parsenodes.h
@ -1711,39 +1560,6 @@ equal(void *a, void *b)
retval = _equalJoinExpr(a, b);
break;
case T_RelOptInfo:
retval = _equalRelOptInfo(a, b);
break;
case T_IndexOptInfo:
retval = _equalIndexOptInfo(a, b);
break;
case T_Path:
retval = _equalPath(a, b);
break;
case T_IndexPath:
retval = _equalIndexPath(a, b);
break;
case T_TidPath:
retval = _equalTidPath(a, b);
break;
case T_AppendPath:
retval = _equalAppendPath(a, b);
break;
case T_ResultPath:
retval = _equalResultPath(a, b);
break;
case T_MaterialPath:
retval = _equalMaterialPath(a, b);
break;
case T_NestPath:
retval = _equalNestPath(a, b);
break;
case T_MergePath:
retval = _equalMergePath(a, b);
break;
case T_HashPath:
retval = _equalHashPath(a, b);
break;
case T_PathKeyItem:
retval = _equalPathKeyItem(a, b);
break;
@ -1753,9 +1569,6 @@ equal(void *a, void *b)
case T_JoinInfo:
retval = _equalJoinInfo(a, b);
break;
case T_InnerIndexscanInfo:
retval = _equalInnerIndexscanInfo(a, b);
break;
case T_List:
{

View File

@ -8,13 +8,13 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.185 2002/11/30 05:21:02 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.186 2002/12/05 15:50:35 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
* have an output function defined here (as well as an input function
* in readfuncs.c). For use in debugging, we also provide output
* functions for nodes that appear in raw parsetrees and plan trees.
* functions for nodes that appear in raw parsetrees, path, and plan trees.
* These nodes however need not have input functions.
*
*-------------------------------------------------------------------------
@ -24,10 +24,8 @@
#include <ctype.h>
#include "lib/stringinfo.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"
#include "parser/parse.h"
#include "utils/datum.h"
@ -385,11 +383,9 @@ _outPlanInfo(StringInfo str, Plan *node)
WRITE_NODE_FIELD(qual);
WRITE_NODE_FIELD(lefttree);
WRITE_NODE_FIELD(righttree);
WRITE_NODE_FIELD(initPlan);
WRITE_INTLIST_FIELD(extParam);
WRITE_INTLIST_FIELD(locParam);
/* chgParam is execution state too */
WRITE_NODE_FIELD(initPlan);
/* we don't write subPlan; reader must reconstruct list */
WRITE_INT_FIELD(nParamExec);
}
@ -482,7 +478,6 @@ _outTidScan(StringInfo str, TidScan *node)
_outScanInfo(str, (Scan *) node);
WRITE_BOOL_FIELD(needRescan);
WRITE_NODE_FIELD(tideval);
}
@ -930,6 +925,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
/*
* print the basic stuff of all nodes that inherit from Path
*
* Note we do NOT print the parent, else we'd be in infinite recursion
*/
static void
_outPathInfo(StringInfo str, Path *node)
@ -986,7 +983,6 @@ _outTidPath(StringInfo str, TidPath *node)
_outPathInfo(str, (Path *) node);
WRITE_NODE_FIELD(tideval);
WRITE_INTLIST_FIELD(unjoined_relids);
}
static void

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.126 2002/11/30 05:21:02 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.127 2002/12/05 15:50:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -602,9 +602,6 @@ create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
scan_relid,
best_path->tideval);
if (best_path->unjoined_relids)
scan_plan->needRescan = true;
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
return scan_plan;
@ -1302,13 +1299,11 @@ make_seqscan(List *qptlist,
Plan *plan = &node->plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scanrelid = scanrelid;
node->scanstate = (CommonScanState *) NULL;
return node;
}
@ -1326,7 +1321,6 @@ make_indexscan(List *qptlist,
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
@ -1336,7 +1330,6 @@ make_indexscan(List *qptlist,
node->indxqual = indxqual;
node->indxqualorig = indxqualorig;
node->indxorderdir = indexscandir;
node->scan.scanstate = (CommonScanState *) NULL;
return node;
}
@ -1351,16 +1344,12 @@ make_tidscan(List *qptlist,
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->tideval = copyObject(tideval); /* XXX do we really need a
* copy? */
node->needRescan = false;
node->scan.scanstate = (CommonScanState *) NULL;
node->tideval = tideval;
return node;
}
@ -1375,14 +1364,12 @@ make_subqueryscan(List *qptlist,
Plan *plan = &node->scan.plan;
copy_plan_costsize(plan, subplan);
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->subplan = subplan;
node->scan.scanstate = (CommonScanState *) NULL;
return node;
}
@ -1396,13 +1383,11 @@ make_functionscan(List *qptlist,
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->scan.scanstate = (CommonScanState *) NULL;
return node;
}
@ -1430,7 +1415,6 @@ make_append(List *appendplans, bool isTarget, List *tlist)
if (plan->plan_width < subplan->plan_width)
plan->plan_width = subplan->plan_width;
}
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = NULL;
@ -1453,7 +1437,6 @@ make_nestloop(List *tlist,
Plan *plan = &node->join.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = otherclauses;
plan->lefttree = lefttree;
@ -1477,7 +1460,6 @@ make_hashjoin(List *tlist,
Plan *plan = &node->join.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = otherclauses;
plan->lefttree = lefttree;
@ -1502,7 +1484,6 @@ make_hash(List *tlist, List *hashkeys, Plan *lefttree)
* input plan; this only affects EXPLAIN display not decisions.
*/
plan->startup_cost = plan->total_cost;
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NULL;
plan->lefttree = lefttree;
@ -1525,7 +1506,6 @@ make_mergejoin(List *tlist,
Plan *plan = &node->join.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = otherclauses;
plan->lefttree = lefttree;
@ -1557,7 +1537,6 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
lefttree->plan_width);
plan->startup_cost = sort_path.startup_cost;
plan->total_cost = sort_path.total_cost;
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
@ -1646,7 +1625,6 @@ make_material(List *tlist, Plan *lefttree)
Plan *plan = &node->plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
@ -1690,7 +1668,6 @@ make_agg(Query *root, List *tlist, List *qual,
else
plan->plan_rows = numGroups;
plan->state = (EState *) NULL;
plan->qual = qual;
plan->targetlist = tlist;
plan->lefttree = lefttree;
@ -1726,7 +1703,6 @@ make_group(Query *root,
/* One output tuple per estimated result group */
plan->plan_rows = numGroups;
plan->state = (EState *) NULL;
plan->qual = NULL;
plan->targetlist = tlist;
plan->lefttree = lefttree;
@ -1765,7 +1741,6 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
* if he has a better idea.
*/
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
@ -1824,7 +1799,6 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
if (plan->plan_rows < 1)
plan->plan_rows = 1;
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
@ -1905,7 +1879,6 @@ make_limit(List *tlist, Plan *lefttree,
}
}
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
@ -1935,13 +1908,11 @@ make_result(List *tlist,
plan->plan_width = 0; /* XXX try to be smarter? */
}
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = subplan;
plan->righttree = NULL;
node->resconstantqual = resconstantqual;
node->resstate = NULL;
return node;
}

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.83 2002/11/30 21:25:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.84 2002/12/05 15:50:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -41,6 +41,7 @@ typedef struct
} replace_vars_with_subplan_refs_context;
static void fix_expr_references(Plan *plan, Node *node);
static bool fix_expr_references_walker(Node *node, void *context);
static void set_join_references(Join *join, List *rtable);
static void set_uppernode_references(Plan *plan, Index subvarno);
static Node *join_references_mutator(Node *node,
@ -66,8 +67,6 @@ static bool fix_opids_walker(Node *node, void *context);
* for the convenience of the executor. We update Vars in upper plan nodes
* to refer to the outputs of their subplans, and we compute regproc OIDs
* for operators (ie, we look up the function that implements each op).
* We must also build lists of all the subplan nodes present in each
* plan node's expression trees.
*
* set_plan_references recursively traverses the whole plan tree.
*
@ -81,12 +80,6 @@ set_plan_references(Plan *plan, List *rtable)
if (plan == NULL)
return;
/*
* We must rebuild the plan's list of subplan nodes, since we are
* copying/mutating its expression trees.
*/
plan->subPlan = NIL;
/*
* Plan-type-specific fixes
*/
@ -107,6 +100,8 @@ set_plan_references(Plan *plan, List *rtable)
case T_TidScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
fix_expr_references(plan,
(Node *) ((TidScan *) plan)->tideval);
break;
case T_SubqueryScan:
{
@ -175,9 +170,9 @@ set_plan_references(Plan *plan, List *rtable)
* unmodified input tuples). The optimizer is lazy about
* creating really valid targetlists for them. Best to just
* leave the targetlist alone. In particular, we do not want
* to pull a subplan list for them, since we will likely end
* up with duplicate list entries for subplans that also
* appear in lower levels of the plan tree!
* to process subplans for them, since we will likely end
* up reprocessing subplans that also appear in lower levels
* of the plan tree!
*/
break;
case T_Agg:
@ -206,7 +201,7 @@ set_plan_references(Plan *plan, List *rtable)
* Append, like Sort et al, doesn't actually evaluate its
* targetlist or quals, and we haven't bothered to give it its
* own tlist copy. So, don't fix targetlist/qual. But do
* recurse into subplans.
* recurse into child plans.
*/
foreach(pl, ((Append *) plan)->appendplans)
set_plan_references((Plan *) lfirst(pl), rtable);
@ -218,24 +213,19 @@ set_plan_references(Plan *plan, List *rtable)
}
/*
* Now recurse into subplans, if any
* Now recurse into child plans and initplans, if any
*
* NOTE: it is essential that we recurse into subplans AFTER we set
* NOTE: it is essential that we recurse into child plans AFTER we set
* subplan references in this plan's tlist and quals. If we did the
* reference-adjustments bottom-up, then we would fail to match this
* plan's var nodes against the already-modified nodes of the
* subplans.
* children. Fortunately, that consideration doesn't apply to SubPlan
* nodes; else we'd need two passes over the expression trees.
*/
set_plan_references(plan->lefttree, rtable);
set_plan_references(plan->righttree, rtable);
foreach(pl, plan->initPlan)
{
SubPlan *sp = (SubPlan *) lfirst(pl);
Assert(IsA(sp, SubPlan));
set_plan_references(sp->plan, sp->rtable);
}
foreach(pl, plan->subPlan)
foreach(pl, plan->initPlan)
{
SubPlan *sp = (SubPlan *) lfirst(pl);
@ -249,13 +239,38 @@ set_plan_references(Plan *plan, List *rtable)
* Do final cleanup on expressions (targetlists or quals).
*
* This consists of looking up operator opcode info for Oper nodes
* and adding subplans to the Plan node's list of contained subplans.
* and recursively performing set_plan_references on SubPlans.
*
* The Plan argument is currently unused, but might be needed again someday.
*/
static void
fix_expr_references(Plan *plan, Node *node)
{
fix_opids(node);
plan->subPlan = nconc(plan->subPlan, pull_subplans(node));
/* This tree walk requires no special setup, so away we go... */
fix_expr_references_walker(node, NULL);
}
static bool
fix_expr_references_walker(Node *node, void *context)
{
if (node == NULL)
return false;
if (IsA(node, Expr))
{
Expr *expr = (Expr *) node;
if (expr->opType == OP_EXPR ||
expr->opType == DISTINCT_EXPR)
replace_opid((Oper *) expr->oper);
else if (expr->opType == SUBPLAN_EXPR)
{
SubPlan *sp = (SubPlan *) expr->oper;
Assert(IsA(sp, SubPlan));
set_plan_references(sp->plan, sp->rtable);
}
}
return expression_tree_walker(node, fix_expr_references_walker, context);
}
/*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.58 2002/11/30 05:21:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.59 2002/12/05 15:50:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,7 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/params.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/planmain.h"
@ -297,7 +298,7 @@ make_subplan(SubLink *slink)
switch (nodeTag(plan))
{
case T_SeqScan:
if (plan->initPlan || plan->subPlan)
if (plan->initPlan)
use_material = true;
else
{
@ -453,20 +454,13 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
}
/*
* finalize_primnode: build lists of subplans and params appearing
* in the given expression tree. NOTE: items are added to lists passed in,
* so caller must initialize lists to NIL before first call!
*
* Note: the subplan list that is constructed here and assigned to the
* plan's subPlan field will be replaced with an up-to-date list in
* set_plan_references(). We could almost dispense with building this
* subplan list at all; I believe the only place that uses it is the
* check in make_subplan to see whether a subselect has any subselects.
* finalize_primnode: build lists of params appearing
* in the given expression tree. NOTE: items are added to list passed in,
* so caller must initialize list to NIL before first call!
*/
typedef struct finalize_primnode_results
{
List *subplans; /* List of subplans found in expr */
List *paramids; /* List of PARAM_EXEC paramids found */
} finalize_primnode_results;
@ -491,8 +485,6 @@ finalize_primnode(Node *node, finalize_primnode_results *results)
SubPlan *subplan = (SubPlan *) ((Expr *) node)->oper;
List *lst;
/* Add subplan to subplans list */
results->subplans = lappend(results->subplans, subplan);
/* Check extParam list for params to add to paramids */
foreach(lst, subplan->plan->extParam)
{
@ -595,18 +587,16 @@ SS_finalize_plan(Plan *plan, List *rtable)
if (plan == NULL)
return NIL;
results.subplans = NIL; /* initialize lists to NIL */
results.paramids = NIL;
results.paramids = NIL; /* initialize list to NIL */
/*
* When we call finalize_primnode, results.paramids lists are
* automatically merged together. But when recursing to self, we have
* to do it the hard way. We want the paramids list to include params
* in subplans as well as at this level. (We don't care about finding
* subplans of subplans, though.)
* in subplans as well as at this level.
*/
/* Find params and subplans in targetlist and qual */
/* Find params in targetlist and qual */
finalize_primnode((Node *) plan->targetlist, &results);
finalize_primnode((Node *) plan->qual, &results);
@ -624,8 +614,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
/*
* we need not look at indxqualorig, since it will have the
* same param references as indxqual, and we aren't really
* concerned yet about having a complete subplan list.
* same param references as indxqual.
*/
break;
@ -704,7 +693,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
nodeTag(plan));
}
/* Process left and right subplans, if any */
/* Process left and right child plans, if any */
results.paramids = set_unioni(results.paramids,
SS_finalize_plan(plan->lefttree,
rtable));
@ -712,7 +701,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
SS_finalize_plan(plan->righttree,
rtable));
/* Now we have all the paramids and subplans */
/* Now we have all the paramids */
foreach(lst, results.paramids)
{
@ -733,7 +722,6 @@ SS_finalize_plan(Plan *plan, List *rtable)
plan->extParam = extParam;
plan->locParam = locParam;
plan->subPlan = results.subplans;
return results.paramids;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.82 2002/11/30 05:21:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.83 2002/12/05 15:50:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -385,9 +385,7 @@ create_tidscan_path(Query *root, RelOptInfo *rel, List *tideval)
pathnode->path.pathtype = T_TidScan;
pathnode->path.parent = rel;
pathnode->path.pathkeys = NIL;
pathnode->tideval = copyObject(tideval); /* is copy really
* necessary? */
pathnode->unjoined_relids = NIL;
pathnode->tideval = tideval;
cost_tidscan(&pathnode->path, root, rel, tideval);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.56 2002/11/18 01:17:39 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.57 2002/12/05 15:50:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,15 +23,16 @@
#include "utils/ps_status.h"
/* ----------------------------------------------------------------
* CreateQueryDesc
* ----------------------------------------------------------------
/*
* CreateQueryDesc
*/
QueryDesc *
CreateQueryDesc(Query *parsetree,
Plan *plantree,
CommandDest dest,
const char *portalName)
const char *portalName,
ParamListInfo params,
bool doInstrument)
{
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
@ -40,56 +41,17 @@ CreateQueryDesc(Query *parsetree,
qd->plantree = plantree; /* plan */
qd->dest = dest; /* output dest */
qd->portalName = portalName; /* name, if dest is a portal */
qd->tupDesc = NULL; /* until set by ExecutorStart */
qd->params = params; /* parameter values passed into query */
qd->doInstrument = doInstrument; /* instrumentation wanted? */
/* null these fields until set by ExecutorStart */
qd->tupDesc = NULL;
qd->estate = NULL;
qd->planstate = NULL;
return qd;
}
/* ----------------------------------------------------------------
* CreateExecutorState
*
* Note: this may someday take parameters -cim 9/18/89
* ----------------------------------------------------------------
*/
EState *
CreateExecutorState(void)
{
EState *state;
/*
* create a new executor state
*/
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_per_tuple_exprcontext = NULL;
/*
* return the executor state structure
*/
return state;
}
/* ----------------
* PreparePortal
* ----------------
@ -147,8 +109,6 @@ ProcessQuery(Query *parsetree,
Portal portal = NULL;
MemoryContext oldContext = NULL;
QueryDesc *queryDesc;
EState *state;
TupleDesc attinfo;
/*
* Check for special-case destinations
@ -193,7 +153,7 @@ ProcessQuery(Query *parsetree,
/*
* We stay in portal's memory context for now, so that query desc,
* EState, and plan startup info are also allocated in the portal
* exec state, and plan startup info are also allocated in the portal
* context.
*/
}
@ -201,17 +161,12 @@ ProcessQuery(Query *parsetree,
/*
* Now we can create the QueryDesc object.
*/
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
/*
* create a default executor state.
*/
state = CreateExecutorState();
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName, NULL, false);
/*
* call ExecStart to prepare the plan for execution
*/
attinfo = ExecutorStart(queryDesc, state);
ExecutorStart(queryDesc);
/*
* If retrieve into portal, stop now; we do not run the plan until a
@ -219,11 +174,8 @@ ProcessQuery(Query *parsetree,
*/
if (isRetrieveIntoPortal)
{
PortalSetQuery(portal,
queryDesc,
attinfo,
state,
PortalCleanup);
/* Arrange to shut down the executor if portal is dropped */
PortalSetQuery(portal, queryDesc, PortalCleanup);
/* Now we can return to caller's memory context. */
MemoryContextSwitchTo(oldContext);
@ -239,7 +191,7 @@ ProcessQuery(Query *parsetree,
* Now we get to the important call to ExecutorRun() where we actually
* run the plan..
*/
ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
/*
* Build command completion status string, if caller wants one.
@ -254,20 +206,20 @@ ProcessQuery(Query *parsetree,
strcpy(completionTag, "SELECT");
break;
case CMD_INSERT:
if (state->es_processed == 1)
lastOid = state->es_lastoid;
if (queryDesc->estate->es_processed == 1)
lastOid = queryDesc->estate->es_lastoid;
else
lastOid = InvalidOid;
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"INSERT %u %u", lastOid, state->es_processed);
"INSERT %u %u", lastOid, queryDesc->estate->es_processed);
break;
case CMD_UPDATE:
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"UPDATE %u", state->es_processed);
"UPDATE %u", queryDesc->estate->es_processed);
break;
case CMD_DELETE:
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"DELETE %u", state->es_processed);
"DELETE %u", queryDesc->estate->es_processed);
break;
default:
strcpy(completionTag, "???");
@ -278,5 +230,5 @@ ProcessQuery(Query *parsetree,
/*
* Now, we close down all the scans and free allocated resources.
*/
ExecutorEnd(queryDesc, state);
ExecutorEnd(queryDesc);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.49 2002/06/20 20:29:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.50 2002/12/05 15:50:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -149,26 +149,15 @@ GetPortalByName(char *name)
/*
* PortalSetQuery
* Attaches a "query" to portal.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal is invalid.
* BadArg if queryDesc is "invalid."
* BadArg if state is "invalid."
*/
void
PortalSetQuery(Portal portal,
QueryDesc *queryDesc,
TupleDesc attinfo,
EState *state,
void (*cleanup) (Portal portal))
{
AssertArg(PortalIsValid(portal));
AssertArg(IsA((Node *) state, EState));
portal->queryDesc = queryDesc;
portal->attinfo = attinfo;
portal->state = state;
portal->atStart = true; /* Allow fetch forward only */
portal->atEnd = false;
portal->cleanup = cleanup;
@ -212,8 +201,6 @@ CreatePortal(char *name)
/* initialize portal query */
portal->queryDesc = NULL;
portal->attinfo = NULL;
portal->state = NULL;
portal->atStart = true; /* disallow fetches until query is set */
portal->atEnd = true;
portal->cleanup = NULL;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execdesc.h,v 1.20 2002/09/04 20:31:42 momjian Exp $
* $Id: execdesc.h,v 1.21 2002/12/05 15:50:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,30 +16,38 @@
#define EXECDESC_H
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
#include "tcop/dest.h"
/* ----------------
* query descriptor:
*
* a QueryDesc encapsulates everything that the executor
* needs to execute the query
* ---------------------
*/
typedef struct QueryDesc
{
/* These fields are provided by CreateQueryDesc */
CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */
Query *parsetree;
Plan *plantree;
Query *parsetree; /* rewritten parsetree */
Plan *plantree; /* planner's output */
CommandDest dest; /* the destination output of the execution */
const char *portalName; /* name of portal, or NULL */
ParamListInfo params; /* param values being passed in */
bool doInstrument; /* TRUE requests runtime instrumentation */
TupleDesc tupDesc; /* set by ExecutorStart */
/* These fields are set by ExecutorStart */
TupleDesc tupDesc; /* descriptor for result tuples */
EState *estate; /* executor's query-wide state */
PlanState *planstate; /* tree of per-plan-node state */
} QueryDesc;
/* in pquery.c */
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
CommandDest dest, const char *portalName);
CommandDest dest, const char *portalName,
ParamListInfo params,
bool doInstrument);
#endif /* EXECDESC_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: executor.h,v 1.80 2002/12/01 20:27:32 tgl Exp $
* $Id: executor.h,v 1.81 2002/12/05 15:50:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,7 @@
#include "executor/execdesc.h"
/* ----------------
* TupIsNull
*
@ -30,9 +31,9 @@
/*
* prototypes from functions in execAmi.c
*/
extern void ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent);
extern void ExecMarkPos(Plan *node);
extern void ExecRestrPos(Plan *node);
extern void ExecReScan(PlanState *node, ExprContext *exprCtxt);
extern void ExecMarkPos(PlanState *node);
extern void ExecRestrPos(PlanState *node);
extern bool ExecSupportsMarkRestore(NodeTag plantype);
/*
@ -49,10 +50,12 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
/*
* prototypes from functions in execMain.c
*/
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
extern void ExecutorStart(QueryDesc *queryDesc);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
extern void ExecutorEnd(QueryDesc *queryDesc);
extern EState *CreateExecutorState(void);
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
@ -61,11 +64,11 @@ extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
/*
* prototypes from functions in execProcnode.c
*/
extern bool ExecInitNode(Plan *node, EState *estate, Plan *parent);
extern TupleTableSlot *ExecProcNode(Plan *node, Plan *parent);
extern PlanState *ExecInitNode(Plan *node, EState *estate);
extern TupleTableSlot *ExecProcNode(PlanState *node);
extern int ExecCountSlotsNode(Plan *node);
extern void ExecEndNode(Plan *node, Plan *parent);
extern TupleDesc ExecGetTupType(Plan *node);
extern void ExecEndNode(PlanState *node);
extern TupleDesc ExecGetTupType(PlanState *node);
/*
* prototypes from functions in execQual.c
@ -89,6 +92,7 @@ extern Datum ExecEvalExpr(Node *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
extern Datum ExecEvalExprSwitchContext(Node *expression, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
extern Node *ExecInitExpr(Node *node, PlanState *parent);
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
extern int ExecTargetListLength(List *targetlist);
extern int ExecCleanTargetListLength(List *targetlist);
@ -98,9 +102,9 @@ extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
/*
* prototypes from functions in execScan.c
*/
typedef TupleTableSlot *(*ExecScanAccessMtd) (Scan *node);
typedef TupleTableSlot *(*ExecScanAccessMtd) (ScanState *node);
extern TupleTableSlot *ExecScan(Scan *node, ExecScanAccessMtd accessMtd);
extern TupleTableSlot *ExecScan(ScanState *node, ExecScanAccessMtd accessMtd);
/*
* prototypes from functions in execTuples.c
@ -117,14 +121,13 @@ extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
TupleDesc tupdesc, bool shouldFree);
extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
extern void ExecInitResultTupleSlot(EState *estate, CommonState *commonstate);
extern void ExecInitScanTupleSlot(EState *estate,
CommonScanState *commonscanstate);
extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate);
extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate);
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
TupleDesc tupType);
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
extern void SetChangedParamList(Plan *node, List *newchg);
extern void SetChangedParamList(PlanState *node, List *newchg);
typedef struct TupOutputState
{
@ -155,21 +158,19 @@ extern void end_tup_output(TupOutputState *tstate);
* prototypes from functions in execUtils.c
*/
extern void ResetTupleCount(void);
extern void ExecAssignExprContext(EState *estate, CommonState *commonstate);
extern void ExecAssignResultType(CommonState *commonstate,
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
extern void ExecAssignResultType(PlanState *planstate,
TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignResultTypeFromOuterPlan(Plan *node,
CommonState *commonstate);
extern void ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate);
extern TupleDesc ExecGetResultType(CommonState *commonstate);
extern void ExecAssignProjectionInfo(Plan *node, CommonState *commonstate);
extern void ExecFreeProjectionInfo(CommonState *commonstate);
extern void ExecFreeExprContext(CommonState *commonstate);
extern TupleDesc ExecGetScanType(CommonScanState *csstate);
extern void ExecAssignScanType(CommonScanState *csstate,
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
extern TupleDesc ExecGetResultType(PlanState *planstate);
extern void ExecAssignProjectionInfo(PlanState *planstate);
extern void ExecFreeProjectionInfo(PlanState *planstate);
extern void ExecFreeExprContext(PlanState *planstate);
extern TupleDesc ExecGetScanType(ScanState *scanstate);
extern void ExecAssignScanType(ScanState *scanstate,
TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
CommonScanState *csstate);
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
extern ExprContext *MakeExprContext(TupleTableSlot *slot,
MemoryContext queryContext);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeAgg.h,v 1.17 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeAgg.h,v 1.18 2002/12/05 15:50:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,13 +15,13 @@
#define NODEAGG_H
#include "fmgr.h"
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecAgg(Agg *node);
extern bool ExecInitAgg(Agg *node, EState *estate, Plan *parent);
extern int ExecCountSlotsAgg(Agg *node);
extern void ExecEndAgg(Agg *node);
extern void ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent);
extern AggState *ExecInitAgg(Agg *node, EState *estate);
extern TupleTableSlot *ExecAgg(AggState *node);
extern void ExecEndAgg(AggState *node);
extern void ExecReScanAgg(AggState *node, ExprContext *exprCtxt);
extern Datum aggregate_dummy(PG_FUNCTION_ARGS);

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeAppend.h,v 1.17 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeAppend.h,v 1.18 2002/12/05 15:50:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEAPPEND_H
#define NODEAPPEND_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern bool ExecInitAppend(Append *node, EState *estate, Plan *parent);
extern int ExecCountSlotsAppend(Append *node);
extern TupleTableSlot *ExecProcAppend(Append *node);
extern void ExecEndAppend(Append *node);
extern void ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent);
extern AppendState *ExecInitAppend(Append *node, EState *estate);
extern TupleTableSlot *ExecProcAppend(AppendState *node);
extern void ExecEndAppend(AppendState *node);
extern void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt);
#endif /* NODEAPPEND_H */

View File

@ -7,21 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeFunctionscan.h,v 1.2 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeFunctionscan.h,v 1.3 2002/12/05 15:50:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEFUNCTIONSCAN_H
#define NODEFUNCTIONSCAN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecFunctionScan(FunctionScan *node);
extern void ExecEndFunctionScan(FunctionScan *node);
extern bool ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent);
extern int ExecCountSlotsFunctionScan(FunctionScan *node);
extern void ExecFunctionMarkPos(FunctionScan *node);
extern void ExecFunctionRestrPos(FunctionScan *node);
extern void ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent);
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate);
extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
extern void ExecEndFunctionScan(FunctionScanState *node);
extern void ExecFunctionMarkPos(FunctionScanState *node);
extern void ExecFunctionRestrPos(FunctionScanState *node);
extern void ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt);
#endif /* NODEFUNCTIONSCAN_H */

View File

@ -7,20 +7,20 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeGroup.h,v 1.22 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeGroup.h,v 1.23 2002/12/05 15:50:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEGROUP_H
#define NODEGROUP_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecGroup(Group *node);
extern bool ExecInitGroup(Group *node, EState *estate, Plan *parent);
extern int ExecCountSlotsGroup(Group *node);
extern void ExecEndGroup(Group *node);
extern void ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent);
extern GroupState *ExecInitGroup(Group *node, EState *estate);
extern TupleTableSlot *ExecGroup(GroupState *node);
extern void ExecEndGroup(GroupState *node);
extern void ExecReScanGroup(GroupState *node, ExprContext *exprCtxt);
extern bool execTuplesMatch(HeapTuple tuple1,
HeapTuple tuple2,

View File

@ -7,19 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeHash.h,v 1.26 2002/11/30 00:08:20 tgl Exp $
* $Id: nodeHash.h,v 1.27 2002/12/05 15:50:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEHASH_H
#define NODEHASH_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecHash(Hash *node);
extern bool ExecInitHash(Hash *node, EState *estate, Plan *parent);
extern int ExecCountSlotsHash(Hash *node);
extern void ExecEndHash(Hash *node);
extern HashState *ExecInitHash(Hash *node, EState *estate);
extern TupleTableSlot *ExecHash(HashState *node);
extern void ExecEndHash(HashState *node);
extern void ExecReScanHash(HashState *node, ExprContext *exprCtxt);
extern HashJoinTable ExecHashTableCreate(Hash *node);
extern void ExecHashTableDestroy(HashJoinTable hashtable);
extern void ExecHashTableInsert(HashJoinTable hashtable,
@ -31,7 +33,6 @@ extern int ExecHashGetBucket(HashJoinTable hashtable,
extern HeapTuple ExecScanHashBucket(HashJoinState *hjstate, List *hjclauses,
ExprContext *econtext);
extern void ExecHashTableReset(HashJoinTable hashtable, long ntuples);
extern void ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent);
extern void ExecChooseHashTableSize(double ntuples, int tupwidth,
int *virtualbuckets,
int *physicalbuckets,

View File

@ -7,20 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeHashjoin.h,v 1.23 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeHashjoin.h,v 1.24 2002/12/05 15:50:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEHASHJOIN_H
#define NODEHASHJOIN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecHashJoin(HashJoin *node);
extern bool ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent);
extern int ExecCountSlotsHashJoin(HashJoin *node);
extern void ExecEndHashJoin(HashJoin *node);
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate);
extern TupleTableSlot *ExecHashJoin(HashJoinState *node);
extern void ExecEndHashJoin(HashJoinState *node);
extern void ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt);
extern void ExecHashJoinSaveTuple(HeapTuple heapTuple, BufFile *file);
extern void ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent);
#endif /* NODEHASHJOIN_H */

View File

@ -7,22 +7,23 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeIndexscan.h,v 1.16 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeIndexscan.h,v 1.17 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEINDEXSCAN_H
#define NODEINDEXSCAN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecIndexScan(IndexScan *node);
extern void ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent);
extern void ExecEndIndexScan(IndexScan *node);
extern void ExecIndexMarkPos(IndexScan *node);
extern void ExecIndexRestrPos(IndexScan *node);
extern void ExecUpdateIndexScanKeys(IndexScan *node, ExprContext *econtext);
extern bool ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent);
extern int ExecCountSlotsIndexScan(IndexScan *node);
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate);
extern TupleTableSlot *ExecIndexScan(IndexScanState *node);
extern void ExecEndIndexScan(IndexScanState *node);
extern void ExecIndexMarkPos(IndexScanState *node);
extern void ExecIndexRestrPos(IndexScanState *node);
extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt);
extern void ExecUpdateIndexScanKeys(IndexScanState *node, ExprContext *econtext);
#endif /* NODEINDEXSCAN_H */

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeLimit.h,v 1.6 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeLimit.h,v 1.7 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODELIMIT_H
#define NODELIMIT_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecLimit(Limit *node);
extern bool ExecInitLimit(Limit *node, EState *estate, Plan *parent);
extern int ExecCountSlotsLimit(Limit *node);
extern void ExecEndLimit(Limit *node);
extern void ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent);
extern LimitState *ExecInitLimit(Limit *node, EState *estate);
extern TupleTableSlot *ExecLimit(LimitState *node);
extern void ExecEndLimit(LimitState *node);
extern void ExecReScanLimit(LimitState *node, ExprContext *exprCtxt);
#endif /* NODELIMIT_H */

View File

@ -7,21 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeMaterial.h,v 1.18 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeMaterial.h,v 1.19 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEMATERIAL_H
#define NODEMATERIAL_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecMaterial(Material *node);
extern bool ExecInitMaterial(Material *node, EState *estate, Plan *parent);
extern int ExecCountSlotsMaterial(Material *node);
extern void ExecEndMaterial(Material *node);
extern void ExecMaterialMarkPos(Material *node);
extern void ExecMaterialRestrPos(Material *node);
extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
extern MaterialState *ExecInitMaterial(Material *node, EState *estate);
extern TupleTableSlot *ExecMaterial(MaterialState *node);
extern void ExecEndMaterial(MaterialState *node);
extern void ExecMaterialMarkPos(MaterialState *node);
extern void ExecMaterialRestrPos(MaterialState *node);
extern void ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt);
#endif /* NODEMATERIAL_H */

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeMergejoin.h,v 1.17 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeMergejoin.h,v 1.18 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEMERGEJOIN_H
#define NODEMERGEJOIN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecMergeJoin(MergeJoin *node);
extern bool ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent);
extern int ExecCountSlotsMergeJoin(MergeJoin *node);
extern void ExecEndMergeJoin(MergeJoin *node);
extern void ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent);
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate);
extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node);
extern void ExecEndMergeJoin(MergeJoinState *node);
extern void ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt);
#endif /* NODEMERGEJOIN_H; */
#endif /* NODEMERGEJOIN_H */

View File

@ -7,20 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeNestloop.h,v 1.18 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeNestloop.h,v 1.19 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODENESTLOOP_H
#define NODENESTLOOP_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecNestLoop(NestLoop *node);
extern bool ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent);
extern int ExecCountSlotsNestLoop(NestLoop *node);
extern void ExecEndNestLoop(NestLoop *node);
extern void ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt,
Plan *parent);
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate);
extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
extern void ExecEndNestLoop(NestLoopState *node);
extern void ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt);
#endif /* NODENESTLOOP_H */

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeResult.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeResult.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODERESULT_H
#define NODERESULT_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecResult(Result *node);
extern bool ExecInitResult(Result *node, EState *estate, Plan *parent);
extern int ExecCountSlotsResult(Result *node);
extern void ExecEndResult(Result *node);
extern void ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent);
extern ResultState *ExecInitResult(Result *node, EState *estate);
extern TupleTableSlot *ExecResult(ResultState *node);
extern void ExecEndResult(ResultState *node);
extern void ExecReScanResult(ResultState *node, ExprContext *exprCtxt);
#endif /* NODERESULT_H */

View File

@ -7,21 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeSeqscan.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeSeqscan.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODESEQSCAN_H
#define NODESEQSCAN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecSeqScan(SeqScan *node);
extern bool ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent);
extern int ExecCountSlotsSeqScan(SeqScan *node);
extern void ExecEndSeqScan(SeqScan *node);
extern void ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent);
extern void ExecSeqMarkPos(SeqScan *node);
extern void ExecSeqRestrPos(SeqScan *node);
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate);
extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
extern void ExecEndSeqScan(SeqScanState *node);
extern void ExecSeqMarkPos(SeqScanState *node);
extern void ExecSeqRestrPos(SeqScanState *node);
extern void ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt);
#endif /* NODESEQSCAN_H */

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeSetOp.h,v 1.6 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeSetOp.h,v 1.7 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODESETOP_H
#define NODESETOP_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecSetOp(SetOp *node);
extern bool ExecInitSetOp(SetOp *node, EState *estate, Plan *parent);
extern int ExecCountSlotsSetOp(SetOp *node);
extern void ExecEndSetOp(SetOp *node);
extern void ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent);
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate);
extern TupleTableSlot *ExecSetOp(SetOpState *node);
extern void ExecEndSetOp(SetOpState *node);
extern void ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt);
#endif /* NODESETOP_H */

View File

@ -7,21 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeSort.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeSort.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODESORT_H
#define NODESORT_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecSort(Sort *node);
extern bool ExecInitSort(Sort *node, EState *estate, Plan *parent);
extern int ExecCountSlotsSort(Sort *node);
extern void ExecEndSort(Sort *node);
extern void ExecSortMarkPos(Sort *node);
extern void ExecSortRestrPos(Sort *node);
extern void ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent);
extern SortState *ExecInitSort(Sort *node, EState *estate);
extern TupleTableSlot *ExecSort(SortState *node);
extern void ExecEndSort(SortState *node);
extern void ExecSortMarkPos(SortState *node);
extern void ExecSortRestrPos(SortState *node);
extern void ExecReScanSort(SortState *node, ExprContext *exprCtxt);
#endif /* NODESORT_H */

View File

@ -2,18 +2,26 @@
*
* nodeSubplan.h
*
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeSubplan.h,v 1.12 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODESUBPLAN_H
#define NODESUBPLAN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern Datum ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext,
extern SubPlanState *ExecInitSubPlan(SubPlan *node, EState *estate);
extern Datum ExecSubPlan(SubPlanState *node, List *pvar, ExprContext *econtext,
bool *isNull);
extern bool ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent);
extern void ExecReScanSetParamPlan(SubPlan *node, Plan *parent);
extern void ExecSetParamPlan(SubPlan *node, ExprContext *econtext);
extern void ExecEndSubPlan(SubPlan *node);
extern void ExecEndSubPlan(SubPlanState *node);
extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
extern void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext);
#endif /* NODESUBPLAN_H */

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeSubqueryscan.h,v 1.6 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeSubqueryscan.h,v 1.7 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODESUBQUERYSCAN_H
#define NODESUBQUERYSCAN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecSubqueryScan(SubqueryScan *node);
extern void ExecEndSubqueryScan(SubqueryScan *node);
extern bool ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent);
extern int ExecCountSlotsSubqueryScan(SubqueryScan *node);
extern void ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent);
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate);
extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
extern void ExecEndSubqueryScan(SubqueryScanState *node);
extern void ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt);
#endif /* NODESUBQUERYSCAN_H */

View File

@ -7,22 +7,21 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeTidscan.h,v 1.10 2002/11/30 05:21:03 tgl Exp $
* $Id: nodeTidscan.h,v 1.11 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODETIDSCAN_H
#define NODETIDSCAN_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecTidScan(TidScan *node);
extern void ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent);
extern void ExecEndTidScan(TidScan *node);
extern void ExecTidMarkPos(TidScan *node);
extern void ExecTidRestrPos(TidScan *node);
extern bool ExecInitTidScan(TidScan *node, EState *estate, Plan *parent);
extern int ExecCountSlotsTidScan(TidScan *node);
extern void ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent);
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate);
extern TupleTableSlot *ExecTidScan(TidScanState *node);
extern void ExecEndTidScan(TidScanState *node);
extern void ExecTidMarkPos(TidScanState *node);
extern void ExecTidRestrPos(TidScanState *node);
extern void ExecTidReScan(TidScanState *node, ExprContext *exprCtxt);
#endif /* NODETIDSCAN_H */

View File

@ -7,19 +7,19 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodeUnique.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
* $Id: nodeUnique.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef NODEUNIQUE_H
#define NODEUNIQUE_H
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
extern TupleTableSlot *ExecUnique(Unique *node);
extern bool ExecInitUnique(Unique *node, EState *estate, Plan *parent);
extern int ExecCountSlotsUnique(Unique *node);
extern void ExecEndUnique(Unique *node);
extern void ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent);
extern UniqueState *ExecInitUnique(Unique *node, EState *estate);
extern TupleTableSlot *ExecUnique(UniqueState *node);
extern void ExecEndUnique(UniqueState *node);
extern void ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt);
#endif /* NODEUNIQUE_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execnodes.h,v 1.81 2002/11/30 00:08:20 tgl Exp $
* $Id: execnodes.h,v 1.82 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,12 +15,11 @@
#define EXECNODES_H
#include "access/relscan.h"
#include "access/sdir.h"
#include "executor/hashjoin.h"
#include "executor/tuptable.h"
#include "fmgr.h"
#include "nodes/params.h"
#include "nodes/primnodes.h"
#include "nodes/plannodes.h"
#include "utils/tuplestore.h"
@ -316,6 +315,8 @@ typedef struct EState
List *es_rowMark; /* not good place, but there is no other */
MemoryContext es_query_cxt; /* per-query context in which EState lives */
bool es_instrument; /* true requests runtime instrumentation */
/*
* this ExprContext is for per-output-tuple operations, such as
* constraint checks and index-value computations. It will be reset
@ -332,98 +333,101 @@ typedef struct EState
bool es_useEvalPlan;
} EState;
/* ----------------
* Executor Type information needed by plannodes.h
*
*| Note: the bogus classes CommonState and CommonScanState exist only
*| because our inheritance system only allows single inheritance
*| and we have to have unique slot names. Hence two or more
*| classes which want to have a common slot must ALL inherit
*| the slot from some other class. (This is a big hack to
*| allow our classes to share slot names..)
*|
*| Example:
*| the class Result and the class NestLoop nodes both want
*| a slot called "OuterTuple" so they both have to inherit
*| it from some other class. In this case they inherit
*| it from CommonState. "CommonState" and "CommonScanState" are
*| the best names I could come up with for this sort of
*| stuff.
*|
*| As a result, many classes have extra slots which they
*| don't use. These slots are denoted (unused) in the
*| comment preceding the class definition. If you
*| comes up with a better idea of a way of doing things
*| along these lines, then feel free to make your idea
*| known to me.. -cim 10/15/89
* ----------------
*/
/* ----------------------------------------------------------------
* Common Executor State Information
* Executor State Information
* ----------------------------------------------------------------
*/
/* ----------------
* CommonState information
* PlanState node
*
* Superclass for all executor node-state object types.
*
* OuterTupleSlot pointer to slot containing current "outer" tuple
* ResultTupleSlot pointer to slot in tuple table for projected tuple
* ExprContext node's expression-evaluation context
* ProjInfo info this node uses to form tuple projections
* TupFromTlist state flag used by some node types (why kept here?)
* We never actually instantiate any PlanState nodes; this is just the common
* abstract superclass for all PlanState-type nodes.
* ----------------
*/
typedef struct CommonState
typedef struct PlanState
{
NodeTag type; /* its first field is NodeTag */
TupleTableSlot *cs_OuterTupleSlot;
TupleTableSlot *cs_ResultTupleSlot;
ExprContext *cs_ExprContext;
ProjectionInfo *cs_ProjInfo;
bool cs_TupFromTlist;
} CommonState;
NodeTag type;
Plan *plan; /* associated Plan node */
/* ----------------------------------------------------------------
* Control Node State Information
* ----------------------------------------------------------------
EState *state; /* at execution time, state's of
* individual nodes point to one EState
* for the whole top-level plan */
struct Instrumentation *instrument; /* Optional runtime stats for this
* plan node */
/*
* Common structural data for all Plan types. These links to subsidiary
* state trees parallel links in the associated plan tree (except for
* the subPlan list, which does not exist in the plan tree).
*/
List *targetlist; /* target list to be computed at this node */
List *qual; /* implicitly-ANDed qual conditions */
struct PlanState *lefttree; /* input plan tree(s) */
struct PlanState *righttree;
List *initPlan; /* Init SubPlanState nodes (un-correlated
* expr subselects) */
List *subPlan; /* SubPlanState nodes in my expressions */
/*
* State for management of parameter-change-driven rescanning
*/
List *chgParam; /* integer list of IDs of changed Params */
/*
* Other run-time state needed by most if not all node types.
*/
TupleTableSlot *ps_OuterTupleSlot; /* slot for current "outer" tuple */
TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */
ExprContext *ps_ExprContext; /* node's expression-evaluation context */
ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */
bool ps_TupFromTlist; /* state flag for processing set-valued
* functions in targetlist */
} PlanState;
/* ----------------
* these are are defined to avoid confusion problems with "left"
* and "right" and "inner" and "outer". The convention is that
* the "left" plan is the "outer" plan and the "right" plan is
* the inner plan, but these make the code more readable.
* ----------------
*/
#define innerPlanState(node) (((PlanState *)(node))->righttree)
#define outerPlanState(node) (((PlanState *)(node))->lefttree)
/* ----------------
* ResultState information
*
* done flag which tells us to quit when we
* have already returned a constant tuple.
* ----------------
*/
typedef struct ResultState
{
CommonState cstate; /* its first field is NodeTag */
bool rs_done;
bool rs_checkqual;
PlanState ps; /* its first field is NodeTag */
Node *resconstantqual;
bool rs_done; /* are we done? */
bool rs_checkqual; /* do we need to check the qual? */
} ResultState;
/* ----------------
* AppendState information
*
* nplans how many plans are in the list
* whichplan which plan is being executed (0 .. n-1)
* firstplan first plan to execute (usually 0)
* lastplan last plan to execute (usually n-1)
* nplans how many plans are in the list
* initialized array of ExecInitNode() results
* ----------------
*/
typedef struct AppendState
{
CommonState cstate; /* its first field is NodeTag */
PlanState ps; /* its first field is NodeTag */
PlanState **appendplans; /* array of PlanStates for my inputs */
int as_nplans;
int as_whichplan;
int as_firstplan;
int as_lastplan;
int as_nplans;
bool *as_initialized;
} AppendState;
/* ----------------------------------------------------------------
@ -432,9 +436,9 @@ typedef struct AppendState
*/
/* ----------------
* CommonScanState information
* ScanState information
*
* CommonScanState extends CommonState for node types that represent
* ScanState extends PlanState for node types that represent
* scans of an underlying relation. It can also be used for nodes
* that scan the output of an underlying plan node --- in that case,
* only ScanTupleSlot is actually useful, and it refers to the tuple
@ -445,27 +449,23 @@ typedef struct AppendState
* ScanTupleSlot pointer to slot in tuple table holding scan tuple
* ----------------
*/
typedef struct CommonScanState
typedef struct ScanState
{
CommonState cstate; /* its first field is NodeTag */
Relation css_currentRelation;
HeapScanDesc css_currentScanDesc;
TupleTableSlot *css_ScanTupleSlot;
} CommonScanState;
PlanState ps; /* its first field is NodeTag */
Relation ss_currentRelation;
HeapScanDesc ss_currentScanDesc;
TupleTableSlot *ss_ScanTupleSlot;
} ScanState;
/*
* SeqScan uses a bare CommonScanState as its state item, since it needs
* SeqScan uses a bare ScanState as its state node, since it needs
* no additional fields.
*/
typedef ScanState SeqScanState;
/* ----------------
* IndexScanState information
*
* Note that an IndexScan node *also* has a CommonScanState state item.
* IndexScanState stores the info needed specifically for indexing.
* There's probably no good reason why this is a separate node type
* rather than an extension of CommonScanState.
*
* NumIndices number of indices in this scan
* IndexPtr current index in use
* ScanKeys Skey structures to scan index rels
@ -479,7 +479,9 @@ typedef struct CommonScanState
*/
typedef struct IndexScanState
{
NodeTag type;
ScanState ss; /* its first field is NodeTag */
List *indxqual;
List *indxqualorig;
int iss_NumIndices;
int iss_IndexPtr;
int iss_MarkIndexPtr;
@ -495,10 +497,6 @@ typedef struct IndexScanState
/* ----------------
* TidScanState information
*
* Note that a TidScan node *also* has a CommonScanState state item.
* There's probably no good reason why this is a separate node type
* rather than an extension of CommonScanState.
*
* NumTids number of tids in this scan
* TidPtr current tid in use
* TidList evaluated item pointers
@ -506,7 +504,7 @@ typedef struct IndexScanState
*/
typedef struct TidScanState
{
NodeTag type;
ScanState ss; /* its first field is NodeTag */
int tss_NumTids;
int tss_TidPtr;
int tss_MarkTidPtr;
@ -526,7 +524,8 @@ typedef struct TidScanState
*/
typedef struct SubqueryScanState
{
CommonScanState csstate; /* its first field is NodeTag */
ScanState ss; /* its first field is NodeTag */
PlanState *subplan;
EState *sss_SubEState;
} SubqueryScanState;
@ -538,12 +537,12 @@ typedef struct SubqueryScanState
*
* tupdesc expected return tuple description
* tuplestorestate private state of tuplestore.c
* funcexpr function expression being evaluated
* funcexpr state for function expression being evaluated
* ----------------
*/
typedef struct FunctionScanState
{
CommonScanState csstate; /* its first field is NodeTag */
ScanState ss; /* its first field is NodeTag */
TupleDesc tupdesc;
Tuplestorestate *tuplestorestate;
Node *funcexpr;
@ -557,11 +556,15 @@ typedef struct FunctionScanState
/* ----------------
* JoinState information
*
* Superclass for state items of join nodes.
* Currently this is the same as CommonState.
* Superclass for state nodes of join plans.
* ----------------
*/
typedef CommonState JoinState;
typedef struct JoinState
{
PlanState ps;
JoinType jointype;
List *joinqual; /* JOIN quals (in addition to ps.qual) */
} JoinState;
/* ----------------
* NestLoopState information
@ -573,7 +576,7 @@ typedef CommonState JoinState;
*/
typedef struct NestLoopState
{
JoinState jstate; /* its first field is NodeTag */
JoinState js; /* its first field is NodeTag */
bool nl_NeedNewOuter;
bool nl_MatchedOuter;
TupleTableSlot *nl_NullInnerTupleSlot;
@ -596,7 +599,8 @@ typedef struct NestLoopState
*/
typedef struct MergeJoinState
{
JoinState jstate; /* its first field is NodeTag */
JoinState js; /* its first field is NodeTag */
List *mergeclauses;
List *mj_OuterSkipQual;
List *mj_InnerSkipQual;
int mj_JoinState;
@ -630,7 +634,8 @@ typedef struct MergeJoinState
*/
typedef struct HashJoinState
{
JoinState jstate; /* its first field is NodeTag */
JoinState js; /* its first field is NodeTag */
List *hashclauses;
HashJoinTable hj_HashTable;
int hj_CurBucketNo;
HashJoinTuple hj_CurTuple;
@ -656,23 +661,46 @@ typedef struct HashJoinState
* materialize nodes are used to materialize the results
* of a subplan into a temporary file.
*
* csstate.css_ScanTupleSlot refers to output of underlying plan.
* ss.ss_ScanTupleSlot refers to output of underlying plan.
*
* tuplestorestate private state of tuplestore.c
* ----------------
*/
typedef struct MaterialState
{
CommonScanState csstate; /* its first field is NodeTag */
ScanState ss; /* its first field is NodeTag */
void *tuplestorestate;
} MaterialState;
/* ----------------
* SortState information
* ----------------
*/
typedef struct SortState
{
ScanState ss; /* its first field is NodeTag */
bool sort_Done; /* sort completed yet? */
void *tuplesortstate; /* private state of tuplesort.c */
} SortState;
/* ---------------------
* AggregateState information
* GroupState information
* -------------------------
*/
typedef struct GroupState
{
ScanState ss; /* its first field is NodeTag */
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
bool grp_done; /* indicates completion of Group scan */
} GroupState;
/* ---------------------
* AggState information
*
* csstate.css_ScanTupleSlot refers to output of underlying plan.
* ss.ss_ScanTupleSlot refers to output of underlying plan.
*
* Note: csstate.cstate.cs_ExprContext contains ecxt_aggvalues and
* Note: ss.ps.ps_ExprContext contains ecxt_aggvalues and
* ecxt_aggnulls arrays, which hold the computed agg values for the current
* input group during evaluation of an Agg node's output tuple(s). We
* create a second ExprContext, tmpcontext, in which to evaluate input
@ -687,7 +715,7 @@ typedef struct AggHashTableData *AggHashTable;
typedef struct AggState
{
CommonScanState csstate; /* its first field is NodeTag */
ScanState ss; /* its first field is NodeTag */
List *aggs; /* all Aggref nodes in targetlist & quals */
int numaggs; /* length of list (could be zero!) */
FmgrInfo *eqfunctions; /* per-grouping-field equality fns */
@ -705,32 +733,6 @@ typedef struct AggState
int next_hash_bucket; /* next chain */
} AggState;
/* ---------------------
* GroupState information
* -------------------------
*/
typedef struct GroupState
{
CommonScanState csstate; /* its first field is NodeTag */
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
bool grp_done; /* indicates completion of Group scan */
} GroupState;
/* ----------------
* SortState information
*
* sort_Done indicates whether sort has been performed yet
* tuplesortstate private state of tuplesort.c
* ----------------
*/
typedef struct SortState
{
CommonScanState csstate; /* its first field is NodeTag */
bool sort_Done;
void *tuplesortstate;
} SortState;
/* ----------------
* UniqueState information
*
@ -744,12 +746,22 @@ typedef struct SortState
*/
typedef struct UniqueState
{
CommonState cstate; /* its first field is NodeTag */
PlanState ps; /* its first field is NodeTag */
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
HeapTuple priorTuple; /* most recently returned tuple, or NULL */
MemoryContext tempContext; /* short-term context for comparisons */
} UniqueState;
/* ----------------
* HashState information
* ----------------
*/
typedef struct HashState
{
PlanState ps; /* its first field is NodeTag */
HashJoinTable hashtable; /* hash table for the hashjoin */
} HashState;
/* ----------------
* SetOpState information
*
@ -761,7 +773,7 @@ typedef struct UniqueState
*/
typedef struct SetOpState
{
CommonState cstate; /* its first field is NodeTag */
PlanState ps; /* its first field is NodeTag */
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
bool subplan_done; /* has subplan returned EOF? */
long numLeft; /* number of left-input dups of cur group */
@ -794,7 +806,9 @@ typedef enum
typedef struct LimitState
{
CommonState cstate; /* its first field is NodeTag */
PlanState ps; /* its first field is NodeTag */
Node *limitOffset; /* OFFSET parameter, or NULL if none */
Node *limitCount; /* COUNT parameter, or NULL if none */
long offset; /* current OFFSET value */
long count; /* current COUNT, if any */
bool noCount; /* if true, ignore count */
@ -803,46 +817,16 @@ typedef struct LimitState
TupleTableSlot *subSlot; /* tuple last obtained from subplan */
} LimitState;
/* ----------------
* HashState information
*
* hashtable hash table for the hashjoin
* ----------------
/* ---------------------
* SubPlanState information
* ---------------------
*/
typedef struct HashState
typedef struct SubPlanState
{
CommonState cstate; /* its first field is NodeTag */
HashJoinTable hashtable;
} HashState;
#ifdef NOT_USED
/* -----------------------
* TeeState information
* leftPlace : next item in the queue unseen by the left parent
* rightPlace : next item in the queue unseen by the right parent
* lastPlace : last item in the queue
* bufferRelname : name of the relation used as the buffer queue
* bufferRel : the relation used as the buffer queue
* mcxt : for now, tee's have their own memory context
* may be cleaned up later if portals are cleaned up
*
* initially, a Tee starts with [left/right]Place variables set to -1.
* on cleanup, queue is free'd when both leftPlace and rightPlace = -1
* -------------------------
*/
typedef struct TeeState
{
CommonState cstate; /* its first field is NodeTag */
int tee_leftPlace,
tee_rightPlace,
tee_lastPlace;
char *tee_bufferRelname;
Relation tee_bufferRel;
MemoryContext tee_mcxt;
HeapScanDesc tee_leftScanDesc,
tee_rightScanDesc;
} TeeState;
#endif
PlanState ps; /* its first field is NodeTag */
PlanState *planstate; /* subselect plan's state tree */
bool needShutdown; /* TRUE = need to shutdown subplan */
HeapTuple curTuple; /* copy of most recent tuple from subplan */
} SubPlanState;
#endif /* EXECNODES_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.125 2002/11/30 05:21:03 tgl Exp $
* $Id: nodes.h,v 1.126 2002/12/05 15:50:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -18,43 +18,84 @@
* The first field of every node is NodeTag. Each node created (with makeNode)
* will have one of the following tags as the value of its first field.
*
* Note that the number of the node tags are not contiguous. We left holes
* Note that the numbers of the node tags are not contiguous. We left holes
* here so that we can add more tags without changing the existing enum's.
* (Since node tag numbers never exist outside backend memory, there's no
* real harm in renumbering, it just costs a full rebuild ...)
*/
typedef enum NodeTag
{
T_Invalid = 0,
/*
* TAGS FOR EXECUTOR NODES (execnodes.h)
*/
T_IndexInfo = 10,
T_ResultRelInfo,
T_TupleTableSlot,
T_ExprContext,
T_ProjectionInfo,
T_JunkFilter,
T_EState,
/*
* TAGS FOR PLAN NODES (plannodes.h)
*/
T_Plan = 10,
T_Plan = 100,
T_Result,
T_Append,
T_Scan,
T_SeqScan,
T_IndexScan,
T_TidScan,
T_SubqueryScan,
T_FunctionScan,
T_Join,
T_NestLoop,
T_MergeJoin,
T_HashJoin,
T_Limit,
T_Material,
T_Sort,
T_Group,
T_Agg,
T_Unique,
T_Hash,
T_SetOp,
T_Group,
T_Limit,
T_SubPlan,
T_TidScan,
T_SubqueryScan,
T_FunctionScan,
/*
* TAGS FOR PLAN STATE NODES (execnodes.h)
*
* These should correspond one-to-one with Plan node types.
*/
T_PlanState = 200,
T_ResultState,
T_AppendState,
T_ScanState,
T_SeqScanState,
T_IndexScanState,
T_TidScanState,
T_SubqueryScanState,
T_FunctionScanState,
T_JoinState,
T_NestLoopState,
T_MergeJoinState,
T_HashJoinState,
T_MaterialState,
T_SortState,
T_GroupState,
T_AggState,
T_UniqueState,
T_HashState,
T_SetOpState,
T_LimitState,
T_SubPlanState,
/*
* TAGS FOR PRIMITIVE NODES (primnodes.h)
*/
T_Resdom = 100,
T_Resdom = 300,
T_Fjoin,
T_Expr,
T_Var,
@ -74,7 +115,7 @@ typedef enum NodeTag
/*
* TAGS FOR PLANNER NODES (relation.h)
*/
T_RelOptInfo = 200,
T_RelOptInfo = 400,
T_IndexOptInfo,
T_Path,
T_IndexPath,
@ -90,48 +131,16 @@ typedef enum NodeTag
T_JoinInfo,
T_InnerIndexscanInfo,
/*
* TAGS FOR EXECUTOR NODES (execnodes.h)
*/
T_IndexInfo = 300,
T_ResultRelInfo,
T_TupleTableSlot,
T_ExprContext,
T_ProjectionInfo,
T_JunkFilter,
T_EState,
T_CommonState,
T_ResultState,
T_AppendState,
T_CommonScanState,
T_ScanState,
T_IndexScanState,
T_JoinState,
T_NestLoopState,
T_MergeJoinState,
T_HashJoinState,
T_MaterialState,
T_AggState,
T_GroupState,
T_SortState,
T_UniqueState,
T_HashState,
T_TidScanState,
T_SubqueryScanState,
T_SetOpState,
T_LimitState,
T_FunctionScanState,
/*
* TAGS FOR MEMORY NODES (memnodes.h)
*/
T_MemoryContext = 400,
T_MemoryContext = 500,
T_AllocSetContext,
/*
* TAGS FOR VALUE NODES (pg_list.h)
*/
T_Value = 500,
T_Value = 600,
T_List,
T_Integer,
T_Float,
@ -142,7 +151,7 @@ typedef enum NodeTag
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
*/
T_Query = 600,
T_Query = 700,
T_InsertStmt,
T_DeleteStmt,
T_UpdateStmt,
@ -208,7 +217,7 @@ typedef enum NodeTag
T_ExecuteStmt,
T_DeallocateStmt,
T_A_Expr = 700,
T_A_Expr = 800,
T_ColumnRef,
T_ParamRef,
T_A_Const,
@ -248,7 +257,7 @@ typedef enum NodeTag
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
*/
T_TriggerData = 800, /* in commands/trigger.h */
T_TriggerData = 900, /* in commands/trigger.h */
T_ReturnSetInfo /* in nodes/execnodes.h */
} NodeTag;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: params.h,v 1.18 2002/11/25 21:29:42 tgl Exp $
* $Id: params.h,v 1.19 2002/12/05 15:50:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -88,7 +88,7 @@ typedef ParamListInfoData *ParamListInfo;
* array of ParamExecData records, which is referenced through
* es_param_exec_vals or ecxt_param_exec_vals.
*
* If execPlan is not NULL, it points to a SubPlan node that needs to
* If execPlan is not NULL, it points to a SubPlanState node that needs to
* be executed to produce the value. (This is done so that we can have
* lazy evaluation of InitPlans: they aren't executed until/unless a
* result value is needed.) Otherwise the value is assumed to be valid
@ -98,7 +98,7 @@ typedef ParamListInfoData *ParamListInfo;
typedef struct ParamExecData
{
void *execPlan; /* should be "SubPlan *" */
void *execPlan; /* should be "SubPlanState *" */
Datum value;
bool isnull;
} ParamExecData;

View File

@ -7,52 +7,15 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: plannodes.h,v 1.61 2002/11/30 00:08:22 tgl Exp $
* $Id: plannodes.h,v 1.62 2002/12/05 15:50:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PLANNODES_H
#define PLANNODES_H
#include "nodes/execnodes.h"
/* ----------------------------------------------------------------
* Executor State types are used in the plannode structures
* so we have to include their definitions too.
*
* Node Type node information used by executor
*
* control nodes
*
* Result ResultState resstate;
* Append AppendState appendstate;
*
* scan nodes
*
* Scan *** CommonScanState scanstate;
* IndexScan IndexScanState indxstate;
* SubqueryScan SubqueryScanState subquerystate;
* FunctionScan FunctionScanState functionstate;
*
* (*** nodes which inherit Scan also inherit scanstate)
*
* join nodes
*
* NestLoop NestLoopState nlstate;
* MergeJoin MergeJoinState mergestate;
* HashJoin HashJoinState hashjoinstate;
*
* materialize nodes
*
* Material MaterialState matstate;
* Sort SortState sortstate;
* Unique UniqueState uniquestate;
* SetOp SetOpState setopstate;
* Limit LimitState limitstate;
* Hash HashState hashstate;
*
* ----------------------------------------------------------------
*/
#include "access/sdir.h"
#include "nodes/primnodes.h"
/* ----------------------------------------------------------------
@ -62,45 +25,47 @@
/* ----------------
* Plan node
*
* All plan nodes "derive" from the Plan structure by having the
* Plan structure as the first field. This ensures that everything works
* when nodes are cast to Plan's. (node pointers are frequently cast to Plan*
* when passed around generically in the executor)
*
* We never actually instantiate any Plan nodes; this is just the common
* abstract superclass for all Plan-type nodes.
* ----------------
*/
typedef struct Plan
{
NodeTag type;
/* estimated execution costs for plan (see costsize.c for more info) */
/*
* estimated execution costs for plan (see costsize.c for more info)
*/
Cost startup_cost; /* cost expended before fetching any
* tuples */
Cost total_cost; /* total cost (assuming all tuples
* fetched) */
/*
* planner's estimate of result size (note: LIMIT, if any, is not
* considered in setting plan_rows)
* planner's estimate of result size of this plan step
*/
double plan_rows; /* number of rows plan is expected to emit */
int plan_width; /* average row width in bytes */
/*
* execution state data. Having Plan point to this, rather than the
* other way round, is 100% bogus.
* Common structural data for all Plan types.
*/
EState *state; /* at execution time, state's of
* individual nodes point to one EState
* for the whole top-level plan */
struct Instrumentation *instrument; /* Optional runtime stats for this
* plan node */
List *targetlist; /* target list to be computed at this node */
List *qual; /* implicitly-ANDed qual conditions */
struct Plan *lefttree; /* input plan tree(s) */
struct Plan *righttree;
List *initPlan; /* Init Plan nodes (un-correlated expr
* subselects) */
/*
* Common structural data for all Plan types. XXX chgParam is runtime
* data and should be in the EState, not here.
* Information for management of parameter-change-driven rescanning
*/
List *targetlist;
List *qual; /* implicitly-ANDed qual conditions */
struct Plan *lefttree;
struct Plan *righttree;
List *extParam; /* indices of _all_ _external_ PARAM_EXEC
* for this plan in global
* es_param_exec_vals. Params from
@ -108,10 +73,6 @@ typedef struct Plan
* included, but their execParam-s are
* here!!! */
List *locParam; /* someones from setParam-s */
List *chgParam; /* list of changed ones from the above */
List *initPlan; /* Init Plan nodes (un-correlated expr
* subselects) */
List *subPlan; /* Other SubPlan nodes */
/*
* We really need in some TopPlan node to store range table and
@ -134,20 +95,6 @@ typedef struct Plan
#define outerPlan(node) (((Plan *)(node))->lefttree)
/*
* ===============
* Top-level nodes
* ===============
*/
/*
* all plan nodes "derive" from the Plan structure by having the
* Plan structure as the first field. This ensures that everything works
* when nodes are cast to Plan's. (node pointers are frequently cast to Plan*
* when passed around generically in the executor)
*/
/* ----------------
* Result node -
* If no outer plan, evaluate a variable-free targetlist.
@ -163,7 +110,6 @@ typedef struct Result
{
Plan plan;
Node *resconstantqual;
ResultState *resstate;
} Result;
/* ----------------
@ -182,7 +128,6 @@ typedef struct Append
Plan plan;
List *appendplans;
bool isTarget;
AppendState *appendstate;
} Append;
/*
@ -194,7 +139,6 @@ typedef struct Scan
{
Plan plan;
Index scanrelid; /* relid is index into the range table */
CommonScanState *scanstate;
} Scan;
/* ----------------
@ -214,7 +158,6 @@ typedef struct IndexScan
List *indxqual;
List *indxqualorig;
ScanDirection indxorderdir;
IndexScanState *indxstate;
} IndexScan;
/* ----------------
@ -224,9 +167,7 @@ typedef struct IndexScan
typedef struct TidScan
{
Scan scan;
bool needRescan;
List *tideval;
TidScanState *tidstate;
} TidScan;
/* ----------------
@ -257,7 +198,6 @@ typedef struct FunctionScan
{
Scan scan;
/* no other fields needed at present */
/* scan.scanstate actually points at a FunctionScanState node */
} FunctionScan;
/*
@ -296,7 +236,6 @@ typedef struct Join
typedef struct NestLoop
{
Join join;
NestLoopState *nlstate;
} NestLoop;
/* ----------------
@ -307,7 +246,6 @@ typedef struct MergeJoin
{
Join join;
List *mergeclauses;
MergeJoinState *mergestate;
} MergeJoin;
/* ----------------
@ -318,9 +256,40 @@ typedef struct HashJoin
{
Join join;
List *hashclauses;
HashJoinState *hashjoinstate;
} HashJoin;
/* ----------------
* materialization node
* ----------------
*/
typedef struct Material
{
Plan plan;
} Material;
/* ----------------
* sort node
* ----------------
*/
typedef struct Sort
{
Plan plan;
int keycount;
} Sort;
/* ---------------
* group node -
* Used for queries with GROUP BY (but no aggregates) specified.
* The input must be presorted according to the grouping columns.
* ---------------
*/
typedef struct Group
{
Plan plan;
int numCols; /* number of grouping columns */
AttrNumber *grpColIdx; /* their indexes in the target list */
} Group;
/* ---------------
* aggregate node
*
@ -349,44 +318,8 @@ typedef struct Agg
int numCols; /* number of grouping columns */
AttrNumber *grpColIdx; /* their indexes in the target list */
long numGroups; /* estimated number of groups in input */
AggState *aggstate;
} Agg;
/* ---------------
* group node -
* Used for queries with GROUP BY (but no aggregates) specified.
* The input must be presorted according to the grouping columns.
* ---------------
*/
typedef struct Group
{
Plan plan;
int numCols; /* number of grouping columns */
AttrNumber *grpColIdx; /* their indexes in the target list */
GroupState *grpstate;
} Group;
/* ----------------
* materialization node
* ----------------
*/
typedef struct Material
{
Plan plan;
MaterialState *matstate;
} Material;
/* ----------------
* sort node
* ----------------
*/
typedef struct Sort
{
Plan plan;
int keycount;
SortState *sortstate;
} Sort;
/* ----------------
* unique node
* ----------------
@ -397,9 +330,18 @@ typedef struct Unique
int numCols; /* number of columns to check for
* uniqueness */
AttrNumber *uniqColIdx; /* indexes into the target list */
UniqueState *uniquestate;
} Unique;
/* ----------------
* hash build node
* ----------------
*/
typedef struct Hash
{
Plan plan;
List *hashkeys;
} Hash;
/* ----------------
* setop node
* ----------------
@ -420,7 +362,6 @@ typedef struct SetOp
* duplicate-ness */
AttrNumber *dupColIdx; /* indexes into the target list */
AttrNumber flagColIdx;
SetOpState *setopstate;
} SetOp;
/* ----------------
@ -432,44 +373,13 @@ typedef struct Limit
Plan plan;
Node *limitOffset; /* OFFSET parameter, or NULL if none */
Node *limitCount; /* COUNT parameter, or NULL if none */
LimitState *limitstate;
} Limit;
/* ----------------
* hash build node
* ----------------
*/
typedef struct Hash
{
Plan plan;
List *hashkeys;
HashState *hashstate;
} Hash;
#ifdef NOT_USED
/* -------------------
* Tee node information
*
* leftParent : the left parent of this node
* rightParent: the right parent of this node
* -------------------
*/
typedef struct Tee
{
Plan plan;
Plan *leftParent;
Plan *rightParent;
TeeState *teestate;
char *teeTableName; /* the name of the table to materialize
* the tee into */
List *rtentries; /* the range table for the plan below the
* Tee may be different than the parent
* plans */
} Tee;
#endif
/* ---------------------
* SubPlan node
*
* XXX Perhaps does not belong in this file? It's not really a Plan node.
* Should we make it inherit from Plan anyway?
* ---------------------
*/
typedef struct SubPlan
@ -489,12 +399,7 @@ typedef struct SubPlan
* about what to do with subselect's
* results */
/*
* Remaining fields are working state for executor; not used in
* planning
*/
bool needShutdown; /* TRUE = need to shutdown subplan */
HeapTuple curTuple; /* copy of most recent tuple from subplan */
struct SubPlanState *pstate; /* XXX TEMPORARY HACK */
} SubPlan;
#endif /* PLANNODES_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: print.h,v 1.19 2002/09/04 20:31:44 momjian Exp $
* $Id: print.h,v 1.20 2002/12/05 15:50:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,10 +15,10 @@
#define PRINT_H
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/execnodes.h"
#define nodeDisplay pprint
#define nodeDisplay(x) pprint(x)
extern void print(void *obj);
extern void pprint(void *obj);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: relation.h,v 1.72 2002/11/30 05:21:03 tgl Exp $
* $Id: relation.h,v 1.73 2002/12/05 15:50:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -377,8 +377,7 @@ typedef struct IndexPath
typedef struct TidPath
{
Path path;
List *tideval; /* qual(s) involving CTID = something */
Relids unjoined_relids; /* some rels not yet part of my Path */
List *tideval; /* qual(s) involving CTID = something */
} TidPath;
/*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pquery.h,v 1.22 2002/09/04 20:31:45 momjian Exp $
* $Id: pquery.h,v 1.23 2002/12/05 15:50:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,8 +21,6 @@
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest,
char *completionTag);
extern EState *CreateExecutorState(void);
extern Portal PreparePortal(char *portalName);
#endif /* PQUERY_H */

View File

@ -3,19 +3,16 @@
* portal.h
* POSTGRES portal definitions.
*
* A portal is an abstraction which represents the execution state of
* a running query (specifically, a CURSOR).
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: portal.h,v 1.35 2002/09/04 20:31:45 momjian Exp $
* $Id: portal.h,v 1.36 2002/12/05 15:50:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Note:
* A portal is an abstraction which represents the execution state of
* a running query (specifically, a CURSOR).
*/
#ifndef PORTAL_H
#define PORTAL_H
@ -30,8 +27,6 @@ typedef struct PortalData
char *name; /* Portal's name */
MemoryContext heap; /* subsidiary memory */
QueryDesc *queryDesc; /* Info about query associated with portal */
TupleDesc attinfo;
EState *state; /* Execution state of query */
bool atStart; /* T => fetch backwards is not allowed */
bool atEnd; /* T => fetch forwards is not allowed */
void (*cleanup) (Portal); /* Cleanup routine (optional) */
@ -47,8 +42,6 @@ typedef struct PortalData
* Access macros for Portal ... use these in preference to field access.
*/
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
#define PortalGetTupleDesc(portal) ((portal)->attinfo)
#define PortalGetState(portal) ((portal)->state)
#define PortalGetHeapMemory(portal) ((portal)->heap)
/*
@ -64,7 +57,6 @@ extern Portal CreatePortal(char *name);
extern void PortalDrop(Portal portal);
extern Portal GetPortalByName(char *name);
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
TupleDesc attinfo, EState *state,
void (*cleanup) (Portal portal));
void (*cleanup) (Portal portal));
#endif /* PORTAL_H */

View File

@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.71 2002/11/30 21:25:08 tgl Exp $
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.72 2002/12/05 15:50:39 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -3583,7 +3583,6 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
if (plan->lefttree != NULL ||
plan->righttree != NULL ||
plan->initPlan != NULL ||
plan->subPlan != NULL ||
plan->qual != NULL ||
((Result *) plan)->resconstantqual != NULL)
return;