* 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 $
*
*/
{
/* 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);
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)
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;
-
- /*
- * Set up the instrumentation for the top node. This will cascade
- * during plan initialisation
- */
- plan->instrument = InstrAlloc();
+ /* run the plan */
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L);
- gettimeofday(&starttime, NULL);
- ProcessQuery(query, plan, None, NULL);
- CommandCounterIncrement();
- gettimeofday(&endtime, NULL);
+ /* We can't clean up 'till we're done printing the stats... */
- 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)
}
}
+ 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;
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)");
}
if (plan->initPlan)
{
List *saved_rtable = es->rtable;
+ List *pslist = planstate->initPlan;
List *lst;
for (i = 0; i < indent; i++)
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;
}
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 */
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);
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);
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;
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
*/
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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)
/*
* tell the executor to shutdown the query
*/
- ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
+ ExecutorEnd(PortalGetQueryDesc(portal));
/*
* switch back to previous context
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
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 */
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/*
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)
{
qdesc->dest = None;
}
- RunQuery(qdesc, state);
+ RunQuery(qdesc);
if (log_executor_stats)
ShowUsage("EXECUTOR STATISTICS");
* 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);
}
/*
-$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
---------------------
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)
---------------------------------------------
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
#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. */
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:
return;
}
- if (node->chgParam != NULL)
+ if (node->chgParam != NIL)
{
freeList(node->chgParam);
- node->chgParam = NULL;
+ node->chgParam = NIL;
}
}
* 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;
}
* 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:
*
* 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)
* 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.
*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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,
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 */
* 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.
*
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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;
* feature.
*/
operation = queryDesc->operation;
- plan = queryDesc->plantree;
+ estate = queryDesc->estate;
dest = queryDesc->dest;
/*
result = NULL;
else
result = ExecutePlan(estate,
- plan,
+ queryDesc->planstate,
operation,
count,
direction,
* ----------------------------------------------------------------
*/
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)
{
/*
- * ExecCheckQueryPerms
- * Check access permissions for all relations referenced in a query.
+ * CreateExecutorState
*/
-static void
-ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
+EState *
+CreateExecutorState(void)
{
+ EState *state;
+
/*
- * Check RTEs in the query's primary rangetable.
+ * create a new executor state
*/
- ExecCheckRTPerms(parseTree->rtable, operation);
+ state = makeNode(EState);
/*
- * Search for subplans and APPEND nodes to check their rangetables.
+ * initialize the Executor State structure
*/
- ExecCheckPlanPerms(plan, parseTree->rtable, operation);
-}
-
-/*
- * ExecCheckPlanPerms
- * Recursively scan the plan tree to check access permissions in
- * subplans.
- */
-static void
-ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
-{
- List *subp;
+ state->es_direction = ForwardScanDirection;
+ state->es_range_table = NIL;
- 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);
+ state->es_result_relations = NULL;
+ state->es_num_result_relations = 0;
+ state->es_result_relation_info = NULL;
- ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
- ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
- }
+ state->es_junkFilter = NULL;
- /* Check lower plan nodes */
+ state->es_into_relation_descriptor = NULL;
- ExecCheckPlanPerms(plan->lefttree, rangeTable, operation);
- ExecCheckPlanPerms(plan->righttree, rangeTable, operation);
+ state->es_param_list_info = NULL;
+ state->es_param_exec_vals = NULL;
- /* Do node-type-specific checks */
+ state->es_tupleTable = NULL;
- switch (nodeTag(plan))
- {
- case T_SubqueryScan:
- {
- SubqueryScan *scan = (SubqueryScan *) plan;
- RangeTblEntry *rte;
+ state->es_query_cxt = CurrentMemoryContext;
- /* 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;
+ state->es_instrument = false;
- foreach(appendplans, app->appendplans)
- {
- ExecCheckPlanPerms((Plan *) lfirst(appendplans),
- rangeTable,
- operation);
- }
- break;
- }
+ state->es_per_tuple_exprcontext = NULL;
- default:
- break;
- }
+ /*
+ * return the executor state structure
+ */
+ return state;
}
+
/*
* ExecCheckRTPerms
* Check access permissions for all relations listed in a range table.
*/
-static void
+void
ExecCheckRTPerms(List *rangeTable, CmdType operation)
{
List *lp;
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;
*
* 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();
typedef struct evalPlanQual
{
- Plan *plan;
+ Plan *plan; /* XXX temporary */
+ PlanState *planstate;
Index rti;
EState estate;
struct evalPlanQual *free;
* 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
* 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
*/
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);
}
/*
/* 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;
estate->es_into_relation_descriptor = intoRelationDesc;
- return tupType;
+ queryDesc->tupDesc = tupType;
+ queryDesc->planstate = planstate;
}
/*
/* ----------------------------------------------------------------
* 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;
/*
* shut down the node-type-specific query processing
*/
- ExecEndNode(plan, NULL);
+ ExecEndNode(planstate);
/*
* destroy the executor "tuple" table.
*/
static TupleTableSlot *
ExecutePlan(EState *estate,
- Plan *plan,
+ PlanState *planstate,
CmdType operation,
long numberTuples,
ScanDirection direction,
{
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
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]);
/*
* 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);
if (endNode)
{
/* stop execution */
- ExecEndNode(epq->plan, NULL);
+ ExecEndNode(epq->planstate);
ExecDropTupleTable(epqstate->es_tupleTable, true);
epqstate->es_tupleTable = NULL;
}
epqstate->es_tupleTable =
ExecCreateTupleTable(estate->es_tupleTable->size);
- ExecInitNode(epq->plan, epqstate, NULL);
+ epq->planstate = ExecInitNode(epq->plan, epqstate);
return EvalPlanQualNext(estate);
}
Assert(epq->rti != 0);
lpqnext:;
- slot = ExecProcNode(epq->plan, NULL);
+ slot = ExecProcNode(epq->planstate);
/*
* No more tuples for this PQ. Continue previous one.
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]);
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)
* "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
* * 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
* 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"
#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"
#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"
*
* 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))
{
* 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);
+ result = (PlanState *) ExecInitSort((Sort *) node, estate);
break;
- case T_Unique:
- result = ExecInitUnique((Unique *) node, estate, parent);
+ case T_Group:
+ result = (PlanState *) ExecInitGroup((Group *) node, estate);
break;
- case T_SetOp:
- result = ExecInitSetOp((SetOp *) node, estate, parent);
+ case T_Agg:
+ result = (PlanState *) ExecInitAgg((Agg *) node, estate);
break;
- case T_Limit:
- result = ExecInitLimit((Limit *) node, estate, parent);
+ case T_Unique:
+ result = (PlanState *) ExecInitUnique((Unique *) node, estate);
break;
- case T_Group:
- result = ExecInitGroup((Group *) node, estate, parent);
+ case T_Hash:
+ result = (PlanState *) ExecInitHash((Hash *) node, estate);
break;
- case T_Agg:
- result = ExecInitAgg((Agg *) node, estate, parent);
+ 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;
}
/* ----------------------------------------------------------------
* 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;
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);
/*
* 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:
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))
case T_MergeJoin:
return ExecCountSlotsMergeJoin((MergeJoin *) node);
- case T_Hash:
- return ExecCountSlotsHash((Hash *) node);
-
case T_HashJoin:
return ExecCountSlotsHashJoin((HashJoin *) 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;
}
* ----------------------------------------------------------------
*/
void
-ExecEndNode(Plan *node, Plan *parent)
+ExecEndNode(PlanState *node)
{
List *subp;
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))
/*
* 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);
- break;
-
- case T_MergeJoin:
- ExecEndMergeJoin((MergeJoin *) node);
+ case T_NestLoopState:
+ ExecEndNestLoop((NestLoopState *) node);
break;
- case T_Hash:
- ExecEndHash((Hash *) node);
+ case T_MergeJoinState:
+ ExecEndMergeJoin((MergeJoinState *) 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:
(int) nodeTag(node));
break;
}
-
- if (node->instrument)
- InstrEndLoop(node->instrument);
}
* ----------------------------------------------------------------
*/
TupleDesc
-ExecGetTupType(Plan *node)
+ExecGetTupType(PlanState *node)
{
TupleTableSlot *slot;
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
}
+/*
+ * 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
* ----------------------------------------------------------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecScan(Scan *node,
+ExecScan(ScanState *node,
ExecScanAccessMtd accessMtd) /* function returning a tuple */
{
- CommonScanState *scanstate;
EState *estate;
ExprContext *econtext;
List *qual;
/*
* 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;
}
/*
if (TupIsNull(slot))
{
return ExecStoreTuple(NULL,
- scanstate->cstate.cs_ProjInfo->pi_slot,
+ node->ps.ps_ProjInfo->pi_slot,
InvalidBuffer,
true);
}
* 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;
}
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------
*/
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;
}
/* ----------------
* ----------------
*/
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;
}
/* ----------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------
*/
void
-ExecAssignExprContext(EState *estate, CommonState *commonstate)
+ExecAssignExprContext(EState *estate, PlanState *planstate)
{
ExprContext *econtext = makeNode(ExprContext);
econtext->ecxt_aggnulls = NULL;
econtext->ecxt_callbacks = NULL;
- commonstate->cs_ExprContext = econtext;
+ planstate->ps_ExprContext = econtext;
}
/* ----------------
* ----------------
*/
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);
}
* ----------------
*/
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);
}
/* ----------------
* ----------------
*/
void
-ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
+ExecAssignResultTypeFromTL(PlanState *planstate)
{
ResultRelInfo *ri;
bool hasoid = false;
* 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;
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);
}
/* ----------------
* ----------------
*/
TupleDesc
-ExecGetResultType(CommonState *commonstate)
+ExecGetResultType(PlanState *planstate)
{
- TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
+ TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
return slot->ttc_tupleDescriptor;
}
* ----------------
*/
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;
}
* ----------------
*/
void
-ExecFreeProjectionInfo(CommonState *commonstate)
+ExecFreeProjectionInfo(PlanState *planstate)
{
ProjectionInfo *projInfo;
* 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;
pfree(projInfo->pi_tupValue);
pfree(projInfo);
- commonstate->cs_ProjInfo = NULL;
+ planstate->ps_ProjInfo = NULL;
}
/* ----------------
* ----------------
*/
void
-ExecFreeExprContext(CommonState *commonstate)
+ExecFreeExprContext(PlanState *planstate)
{
ExprContext *econtext;
* 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;
*/
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
pfree(econtext);
- commonstate->cs_ExprContext = NULL;
+ planstate->ps_ExprContext = NULL;
}
/* ----------------------------------------------------------------
* ----------------
*/
TupleDesc
-ExecGetScanType(CommonScanState *csstate)
+ExecGetScanType(ScanState *scanstate)
{
- TupleTableSlot *slot = csstate->css_ScanTupleSlot;
+ TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
return slot->ttc_tupleDescriptor;
}
* ----------------
*/
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);
}
* ----------------
*/
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);
}
}
void
-SetChangedParamList(Plan *node, List *newchg)
+SetChangedParamList(PlanState *node, List *newchg)
{
List *nl;
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))
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
- * 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
{
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)
* 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;
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);
Query *queryTree = lfirst(qtl_item);
Plan *planTree;
execution_state *newes;
- EState *estate;
planTree = pg_plan_query(queryTree);
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;
}
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)
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 *
/* 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 *
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;
/*
* execution now.
*/
if (!fcinfo->flinfo->fn_retset)
- {
postquel_end(es);
- es->status = F_EXEC_DONE;
- }
return value;
}
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)
}
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.
*/
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)
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
{
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.
* 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;
* 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;
* 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);
}
* 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;
/*
* 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
{
*/
if (aggstate->grp_firstTuple == NULL)
{
- outerslot = ExecProcNode(outerPlan, (Plan *) node);
+ outerslot = ExecProcNode(outerPlan);
if (!TupIsNull(outerslot))
{
/*
/* 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 */
* Otherwise, return the tuple.
*/
}
- while (!ExecQual(node->plan.qual, econtext, false));
+ while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
return resultSlot;
}
* 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;
/*
* 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;
*/
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);
* 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;
/*
* 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
{
* Otherwise, return the tuple.
*/
}
- while (!ExecQual(node->plan.qual, econtext, false));
+ while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
return resultSlot;
}
* planner and initializes its outer subtree
* -----------------
*/
-bool
-ExecInitAgg(Agg *node, EState *estate, Plan *parent)
+AggState *
+ExecInitAgg(Agg *node, EState *estate)
{
AggState *aggstate;
AggStatePerAgg peragg;
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;
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
/*
* 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);
if (node->aggstrategy == AGG_HASHED)
{
- build_hash_table(node);
+ build_hash_table(aggstate);
aggstate->table_filled = false;
}
else
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);
}
ReleaseSysCache(aggTuple);
}
- return TRUE;
+ return aggstate;
}
static Datum
}
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);
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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)
* 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 =
/* ----------------------------------------------------------------
* 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
* 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
* 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
* ----------------------------------------------------------------
*/
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;
/*
* 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))
{
* 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
* ----------------------------------------------------------------
*/
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "utils/lsyscache.h"
-static TupleTableSlot *FunctionNext(FunctionScan *node);
+static TupleTableSlot *FunctionNext(FunctionScanState *node);
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
*/
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);
/*
* 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),
*/
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;
/*
* 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
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);
/*
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
* ----------------------------------------------------------------
*/
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;
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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;
/*
* 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);
}
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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;
/*
* 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
/* 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);
}
*/
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;
}
*/
if (!execTuplesMatch(firsttuple, outerTuple,
tupdesc,
- node->numCols, node->grpColIdx,
- grpstate->eqfunctions,
+ numCols, grpColIdx,
+ node->eqfunctions,
econtext->ecxt_per_tuple_memory))
break;
}
* 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;
* 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);
+
+ /*
+ * initialize child expressions
+ */
+ grpstate->ss.ps.targetlist = (List *)
+ ExecInitExpr((Node *) node->plan.targetlist,
+ (PlanState *) grpstate);
+ grpstate->ss.ps.qual = (List *)
+ ExecInitExpr((Node *) node->plan.qual,
+ (PlanState *) grpstate);
/*
- * initializes child nodes
+ * initialize child nodes
*/
- outerPlan = outerPlan(node);
- ExecInitNode(outerPlan, estate, (Plan *) node);
+ 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
* -----------------------
*/
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);
}
/*****************************************************************************
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecHash(Hash *node)
+ExecHash(HashState *node)
{
EState *estate;
- HashState *hashstate;
- Plan *outerNode;
+ PlanState *outerNode;
List *hashkeys;
HashJoinTable hashtable;
TupleTableSlot *slot;
/*
* 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.");
/*
* 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;
* 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;
/*
*
* 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
* ----------------------------------------------------------------
*/
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);
}
}
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
* ----------------------------------------------------------------
*/
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;
/*
* 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;
}
/*
/*
* 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
/*
* 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
*/
if (hashtable->curbatch == 0)
{
- int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
+ int batch = ExecHashJoinGetBatch(node->hj_CurBucketNo,
hashtable);
if (batch > 0)
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 */
}
}
*/
for (;;)
{
- curtuple = ExecScanHashBucket(hjstate,
+ curtuple = ExecScanHashBucket(node,
hjclauses,
econtext);
if (curtuple == NULL)
* 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;
*/
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;
}
* 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
* 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))
{
*/
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;
}
* 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);
+
+ /*
+ * initialize child expressions
+ */
+ 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);
/*
- * initializes child nodes
+ * initialize child nodes
*/
- outerNode = outerPlan((Plan *) node);
- hashNode = (Hash *) innerPlan((Plan *) node);
+ outerNode = outerPlan(node);
+ hashNode = (Hash *) innerPlan(node);
- ExecInitNode(outerNode, estate, (Plan *) node);
- ExecInitNode((Plan *) hashNode, estate, (Plan *) 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)
case JOIN_LEFT:
hjstate->hj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
- ExecGetTupType((Plan *) hashNode));
+ ExecGetTupType(innerPlanState(hjstate)));
break;
default:
elog(ERROR, "ExecInitHashJoin: unsupported join type %d",
* 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;
}
/*
* 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);
/*
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
* ----------------------------------------------------------------
*/
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);
}
*/
static TupleTableSlot *
-ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
+ExecHashJoinOuterGetTuple(PlanState *node, HashJoinState *hjstate)
{
HashJoinTable hashtable = hjstate->hj_HashTable;
int curbatch = hashtable->curbatch;
if (curbatch == 0)
{ /* if it is the first pass */
- slot = ExecProcNode(node, parent);
+ slot = ExecProcNode(node);
if (!TupIsNull(slot))
return slot;
*/
ExecHashTableReset(hashtable, innerBatchSize[newbatch - 1]);
- econtext = hjstate->jstate.cs_ExprContext;
+ econtext = hjstate->js.ps.ps_ExprContext;
innerhashkeys = hjstate->hj_InnerHashKeys;
while ((slot = ExecHashJoinGetSavedTuple(hjstate,
}
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#define LEFT_OP 1
#define RIGHT_OP 2
-static TupleTableSlot *IndexNext(IndexScan *node);
+static TupleTableSlot *IndexNext(IndexScanState *node);
/* ----------------------------------------------------------------
* IndexNext
* ----------------------------------------------------------------
*/
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;
/*
* 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.
* 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? */
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;
}
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)
{
/*
* 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;
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))
{
indexNumber++;
if (bBackward)
- indexstate->iss_IndexPtr--;
+ node->iss_IndexPtr--;
else
- indexstate->iss_IndexPtr++;
+ node->iss_IndexPtr++;
}
}
* ----------------------------------------------------------------
*/
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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)
{
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;
}
}
}
- 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++)
{
* ----------------------------------------------------------------
*/
void
-ExecEndIndexScan(IndexScan *node)
+ExecEndIndexScan(IndexScanState *node)
{
- CommonScanState *scanstate;
- IndexScanState *indexstate;
int **runtimeKeyInfo;
ScanKey *scanKeys;
- List *indxqual;
int *numScanKeys;
int numIndices;
Relation relation;
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
/*
* 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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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);
}
* ----------------------------------------------------------------
*/
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);
}
* 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;
Relation currentRelation;
/*
- * assign execution state to node
+ * create state structure
*/
- node->scan.plan.state = estate;
+ indexstate = makeNode(IndexScanState);
+ indexstate->ss.ps.plan = (Plan *) node;
+ indexstate->ss.ps.state = estate;
/*
- * Part 1) initialize scan state
+ * Miscellaneous initialization
*
- * create new CommonScanState for node
+ * create expression context for node
*/
- scanstate = makeNode(CommonScanState);
- node->scan.scanstate = scanstate;
+ ExecAssignExprContext(estate, &indexstate->ss.ps);
/*
- * Miscellaneous initialization
- *
- * create expression context for node
+ * initialize child expressions
*/
- ExecAssignExprContext(estate, &scanstate->cstate);
+ 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;
indexstate->iss_RelationDescs = NULL;
indexstate->iss_ScanDescs = NULL;
- node->indxstate = indexstate;
-
/*
* get the index node information
*/
{
/* treat Param like a constant */
scanvalue = ExecEvalParam((Param *) leftop,
- scanstate->cstate.cs_ExprContext,
+ indexstate->ss.ps.ps_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
{
/* treat Param like a constant */
scanvalue = ExecEvalParam((Param *) rightop,
- scanstate->cstate.cs_ExprContext,
+ indexstate->ss.ps.ps_ExprContext,
&isnull);
if (isnull)
flags |= SK_ISNULL;
*/
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
{
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
/*
* all done.
*/
- return TRUE;
+ return indexstate;
}
int
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "executor/executor.h"
#include "executor/nodeLimit.h"
-static void recompute_limits(Limit *node);
+static void recompute_limits(LimitState *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:
/*
/*
* 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;
}
/*
*/
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:
* 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
{
* 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;
* 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;
* 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;
* 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;
}
* 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;
}
/* ----------------------------------------------------------------
* 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;
/*
* 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
* ----------------------------------------------------------------
*/
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot * /* result tuple from subplan */
-ExecMaterial(Material *node)
+ExecMaterial(MaterialState *node)
{
EState *estate;
- MaterialState *matstate;
ScanDirection dir;
Tuplestorestate *tuplestorestate;
HeapTuple heapTuple;
/*
* 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
if (tuplestorestate == NULL)
{
- Plan *outerNode;
+ PlanState *outerNode;
/*
* Want to scan subplan in the forward direction while creating
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;
* 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);
* 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
*
* 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
* ----------------------------------------------------------------
*/
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;
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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
*
* 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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecMergeJoin(MergeJoin *node)
+ExecMergeJoin(MergeJoinState *node)
{
EState *estate;
- MergeJoinState *mergestate;
ScanDirection direction;
List *innerSkipQual;
List *outerSkipQual;
List *otherqual;
bool qualResult;
bool compareResult;
- Plan *innerPlan;
+ PlanState *innerPlan;
TupleTableSlot *innerTupleSlot;
- Plan *outerPlan;
+ PlanState *outerPlan;
TupleTableSlot *outerTupleSlot;
ExprContext *econtext;
bool doFillOuter;
/*
* 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;
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;
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;
}
/*
* 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;
}
/*
* 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
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");
* 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");
* 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. */
* 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;
/*
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;
/*
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;
/*
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
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));
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;
}
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))
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;
}
/*
* 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;
/*-------------------------------------------
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))
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;
}
/*
* 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
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;
/*--------------------------------------------------------
*/
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);
* the extra joinquals.
*/
ExecRestrPos(innerPlan);
- mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ node->mj_JoinState = EXEC_MJ_JOINTUPLES;
}
else
{
* larger than our marked inner tuples. So we're done.
* ----------------
*/
- innerTupleSlot = mergestate->mj_InnerTupleSlot;
+ innerTupleSlot = node->mj_InnerTupleSlot;
if (TupIsNull(innerTupleSlot))
{
if (doFillOuter)
* 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. */
}
/* continue on to skip outer tuples */
- mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
+ node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
}
break;
*/
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);
{
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:
/*
* 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,
*/
if (compareResult)
{
- mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
+ node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
break;
}
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;
/*
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))
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;
}
/*
* 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
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. */
/*
* otherwise test the new tuple against the skip qual.
*/
- mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
+ node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
break;
/*-----------------------------------------------------------
*/
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);
{
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:
/*
* 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,
*/
if (compareResult)
{
- mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
+ node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
break;
}
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;
/*
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))
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;
}
/*
* 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
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. */
/*
* otherwise test the new tuple against the skip qual.
*/
- mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
+ node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
break;
/*
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))
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;
}
/*
* 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))
{
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))
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;
}
/*
* 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))
{
*/
default:
elog(WARNING, "ExecMergeJoin: invalid join state %d, aborting",
- mergestate->mj_JoinState);
+ node->mj_JoinState);
return NULL;
}
}
/* ----------------------------------------------------------------
* 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;
"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 child expressions
+ */
+ 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 subplans
+ * initialize child nodes
*/
- ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
- ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
+ 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)
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
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
/*
* 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
* 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;
MJ1_printf("ExecInitMergeJoin: %s\n",
"node initialized");
- return TRUE;
+ return mergestate;
}
int
* ----------------------------------------------------------------
*/
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(mergestate->mj_MarkedTupleSlot);
+ ExecClearTuple(node->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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecNestLoop(NestLoop *node)
+ExecNestLoop(NestLoopState *node)
{
- NestLoopState *nlstate;
- Plan *innerPlan;
- Plan *outerPlan;
+ PlanState *innerPlan;
+ PlanState *outerPlan;
TupleTableSlot *outerTupleSlot;
TupleTableSlot *innerTupleSlot;
List *joinqual;
*/
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;
/*
* 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;
}
/*
* 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
}
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
* outer tuple (e.g. in index scans), that's why we pass our
* expr context.
*/
- ExecReScan(innerPlan, econtext, (Plan *) node);
+ ExecReScan(innerPlan, econtext);
}
/*
*/
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
* 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");
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;
}
if (ExecQual(joinqual, econtext, false))
{
- nlstate->nl_MatchedOuter = true;
+ node->nl_MatchedOuter = true;
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
{
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;
}
/* ----------------------------------------------------------------
* 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;
"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)
{
case JOIN_LEFT:
nlstate->nl_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate,
- ExecGetTupType(innerPlan((Plan *) node)));
+ ExecGetTupType(innerPlanState(nlstate)));
break;
default:
elog(ERROR, "ExecInitNestLoop: unsupported join type %d",
/*
* 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
* ----------------------------------------------------------------
*/
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");
* ----------------------------------------------------------------
*/
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
* 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;
}
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
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;
}
}
* 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;
}
/*
* 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)
{
* 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
* 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;
}
/*
* 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;
}
}
* (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
/*
* 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
* ----------------------------------------------------------------
*/
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);
+ ExecFreeProjectionInfo(&node->ps);
+ ExecFreeExprContext(&node->ps);
/*
- * shut down subplans
+ * clean out the tuple table
*/
- ExecEndNode(outerPlan(node), (Plan *) node);
+ ExecClearTuple(node->ps.ps_ResultTupleSlot);
/*
- * clean out the tuple table
+ * shut down subplans
*/
- ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
- pfree(resstate);
- node->resstate = NULL; /* XXX - new for us - er1p */
+ 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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-SeqNext(SeqScan *node)
+SeqNext(SeqScanState *node)
{
HeapTuple tuple;
HeapScanDesc scandesc;
- CommonScanState *scanstate;
+ Index scanrelid;
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
/*
* 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.
* 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);
/*
*/
/* Flag for the next call that no more tuples */
- estate->es_evTupleNull[node->scanrelid - 1] = true;
+ estate->es_evTupleNull[scanrelid - 1] = true;
return (slot);
}
*/
TupleTableSlot *
-ExecSeqScan(SeqScan *node)
+ExecSeqScan(SeqScanState *node)
{
/*
* use SeqNext as access method
*/
- return ExecScan(node, (ExecScanAccessMtd) SeqNext);
+ return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext);
}
/* ----------------------------------------------------------------
* subplans of scans.
* ----------------------------------------------------------------
*/
-static Oid
-InitScanRelation(SeqScan *node, EState *estate,
- CommonScanState *scanstate)
+static void
+InitScanRelation(SeqScanState *node, EState *estate)
{
Index relid;
List *rangeTable;
*
* 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;
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);
}
* 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);
-
- /*
- * assign the node's execution state
- */
- node->plan.state = estate;
+ Assert(outerPlan(node) == NULL);
+ Assert(innerPlan(node) == NULL);
/*
- * create new CommonScanState for node
+ * create state structure
*/
- 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
* ----------------------------------------------------------------
*/
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.
*
* locking, however.)
*/
heap_close(relation, NoLock);
-
- /*
- * clean out the tuple table
- */
- ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
- ExecClearTuple(scanstate->css_ScanTupleSlot);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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 */
* ----------------------------------------------------------------
*/
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);
}
* ----------------------------------------------------------------
*/
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
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;
}
/*
* 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))
{
* 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
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;
* 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);
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;
}
}
* 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;
}
* 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;
/*
* 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
* ----------------------------------------------------------------
*/
void
-ExecEndSetOp(SetOp *node)
+ExecEndSetOp(SetOpState *node)
{
- SetOpState *setopstate = node->setopstate;
-
- ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
+ /* clean up tuple table */
+ ExecClearTuple(node->ps.ps_ResultTupleSlot);
+ node->ps.ps_OuterTupleSlot = NULL;
- MemoryContextDelete(setopstate->tempContext);
+ ExecEndNode(outerPlanState(node));
- /* clean up tuple table */
- ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
- setopstate->cstate.cs_OuterTupleSlot = NULL;
+ 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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecSort(Sort *node)
+ExecSort(SortState *node)
{
EState *estate;
- SortState *sortstate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
HeapTuple heapTuple;
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
* 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;
/*
* 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;
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);
for (;;)
{
- slot = ExecProcNode(outerNode, (Plan *) node);
+ slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
break;
/*
* 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");
}
ScanDirectionIsForward(dir),
&should_free);
- slot = sortstate->csstate.cstate.cs_ResultTupleSlot;
+ slot = node->ss.ps.ps_ResultTupleSlot;
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
}
* 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
*
*
* 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
* ----------------------------------------------------------------
*/
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
+ * clean out the tuple table
*/
- outerPlan = outerPlan((Plan *) node);
- ExecEndNode(outerPlan, (Plan *) node);
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
- * clean out the tuple table
+ * shut down the subplan
*/
- ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
+ 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");
* ----------------------------------------------------------------
*/
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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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;
*
* 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);
}
* 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 $
*
*-------------------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* 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;
*/
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;
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
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;
/* ----------------------------------------------------------------
* 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;
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;
-
- if (!ExecInitNode(node->plan, sp_estate, parent))
- return false;
+ /*
+ * Start up the subplan
+ */
+ subplanstate->planstate = ExecInitNode(node->plan, sp_estate);
- 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
{
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
- prm->execPlan = node;
+ prm->execPlan = subplanstate;
}
/*
*/
}
- return true;
+ return subplanstate;
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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;
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;
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);
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));
{
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);
}
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;
}
}
- if (plan->extParam == NULL) /* un-correlated ... */
+ if (planstate->plan->extParam == NULL) /* un-correlated ... */
{
- ExecEndNode(plan, NULL);
+ ExecEndNode(planstate);
node->needShutdown = false;
}
* ----------------------------------------------------------------
*/
void
-ExecEndSubPlan(SubPlan *node)
+ExecEndSubPlan(SubPlanState *node)
{
if (node->needShutdown)
{
- ExecEndNode(node->plan, NULL);
+ ExecEndNode(node->planstate);
node->needShutdown = false;
}
if (node->curTuple)
}
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));
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "parser/parsetree.h"
#include "tcop/pquery.h"
-static TupleTableSlot *SubqueryNext(SubqueryScan *node);
+static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
/* ----------------------------------------------------------------
* Scan Support
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-SubqueryNext(SubqueryScan *node)
+SubqueryNext(SubqueryScanState *node)
{
- SubqueryScanState *subquerystate;
EState *estate;
ScanDirection direction;
TupleTableSlot *slot;
/*
* 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;
/*
/*
* 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;
}
*/
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;
/*
* 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
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
* ----------------------------------------------------------------
*/
void
-ExecEndSubqueryScan(SubqueryScan *node)
+ExecEndSubqueryScan(SubqueryScanState *node)
{
- SubqueryScanState *subquerystate;
-
/*
- * get information from node
+ * Free the projection info and the scan attribute info
*/
- subquerystate = (SubqueryScanState *) node->scan.scanstate;
+ ExecFreeProjectionInfo(&node->ss.ps);
+ ExecFreeExprContext(&node->ss.ps);
/*
- * 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
+ * clean out the upper tuple table
*/
- ExecFreeProjectionInfo(&subquerystate->csstate.cstate);
- ExecFreeExprContext(&subquerystate->csstate.cstate);
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
/*
* close down subquery
*/
- ExecEndNode(node->subplan, (Plan *) node);
+ ExecEndNode(node->subplan);
/*
* clean up subquery's tuple table
*/
- subquerystate->csstate.css_ScanTupleSlot = NULL;
- ExecDropTupleTable(subquerystate->sss_SubEState->es_tupleTable, true);
+ node->ss.ss_ScanTupleSlot = NULL;
+ ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
/* XXX we seem to be leaking the sub-EState... */
-
- /*
- * clean out the upper tuple table
- */
- ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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[])
* ----------------------------------------------------------------
*/
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;
/*
* 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.
* 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 */
/*
* 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
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;
* 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))
}
tidNumber++;
if (bBackward)
- tidstate->tss_TidPtr--;
+ node->tss_TidPtr--;
else
- tidstate->tss_TidPtr++;
+ node->tss_TidPtr++;
if (slot_is_valid)
return slot;
}
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecTidScan(TidScan *node)
+ExecTidScan(TidScanState *node)
{
/*
* use TidNext as access method
*/
- return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
+ return ExecScan(&node->ss, (ExecScanAccessMtd) TidNext);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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;
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
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
* 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.
* 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);
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
void
-ExecTidMarkPos(TidScan *node)
+ExecTidMarkPos(TidScanState *node)
{
- TidScanState *tidstate;
-
- tidstate = node->tidstate;
- tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
+ node->tss_MarkTidPtr = node->tss_TidPtr;
}
/* ----------------------------------------------------------------
* ----------------------------------------------------------------
*/
void
-ExecTidRestrPos(TidScan *node)
+ExecTidRestrPos(TidScanState *node)
{
- TidScanState *tidstate;
-
- tidstate = node->tidstate;
- tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
+ node->tss_TidPtr = node->tss_MarkTidPtr;
}
/* ----------------------------------------------------------------
* 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;
List *execParam = NIL;
/*
- * assign execution state to node
+ * create state structure
*/
- node->scan.plan.state = estate;
+ tidstate = makeNode(TidScanState);
+ tidstate->ss.ps.plan = (Plan *) node;
+ tidstate->ss.ps.state = estate;
/*
- * Part 1) initialize scan state
+ * Miscellaneous initialization
*
- * create new CommonScanState for node
+ * create expression context for node
*/
- scanstate = makeNode(CommonScanState);
- node->scan.scanstate = scanstate;
+ ExecAssignExprContext(estate, &tidstate->ss.ps);
/*
- * Miscellaneous initialization
- *
- * create expression context for node
+ * initialize child expressions
*/
- ExecAssignExprContext(estate, &scanstate->cstate);
+ 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);
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* NOTES
* Assumes tuples returned from subplan arrive in
* sorted order.
- *
*/
#include "postgres.h"
* ----------------------------------------------------------------
*/
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
/*
* 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;
/*
* 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;
}
* 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 */
* 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;
/*
/*
* 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
* ----------------------------------------------------------------
*/
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);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
List *ptlist = spiplan->ptlist;
Query *queryTree;
Plan *planTree;
+ ParamListInfo paramLI;
QueryDesc *queryDesc;
- EState *eState;
- TupleDesc attinfo;
MemoryContext oldcontext;
Portal portal;
char portalname[64];
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
{
get_typlenbyval(spiplan->argtypes[k],
¶mTypLen, ¶mTypByVal);
- 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);
Plan *planTree;
bool canSetResult;
QueryDesc *qdesc;
- EState *state;
planTree = pg_plan_query(queryTree);
plan_list = lappend(plan_list, planTree);
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();
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;
}
Plan *planTree;
bool canSetResult;
QueryDesc *qdesc;
- EState *state;
planTree = lfirst(plan_list);
plan_list = lnext(plan_list);
}
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();
}
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;
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
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)
{
elog(FATAL, "SPI_select: # of processed tuples check failed");
}
- ExecutorEnd(queryDesc, state);
+ ExecutorEnd(queryDesc);
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
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) */
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 */
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 */
* 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"
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
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);
}
*/
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;
}
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;
}
/*
* 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;
}
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);
}
*/
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;
}
*/
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;
}
}
/*
- * _copySetOp
+ * _copyHash
*/
-static SetOp *
-_copySetOp(SetOp *from)
+static Hash *
+_copyHash(Hash *from)
{
- SetOp *newnode = makeNode(SetOp);
+ Hash *newnode = makeNode(Hash);
/*
* copy node superclass fields
/*
* copy remainder of node
*/
- COPY_SCALAR_FIELD(cmd);
- COPY_SCALAR_FIELD(numCols);
- COPY_POINTER_FIELD(dupColIdx, from->numCols * sizeof(AttrNumber));
- COPY_SCALAR_FIELD(flagColIdx);
+ COPY_NODE_FIELD(hashkeys);
return newnode;
}
/*
- * _copyLimit
+ * _copySetOp
*/
-static Limit *
-_copyLimit(Limit *from)
+static SetOp *
+_copySetOp(SetOp *from)
{
- Limit *newnode = makeNode(Limit);
+ SetOp *newnode = makeNode(SetOp);
/*
* copy node superclass fields
/*
* copy remainder of node
*/
- COPY_NODE_FIELD(limitOffset);
- COPY_NODE_FIELD(limitCount);
+ COPY_SCALAR_FIELD(cmd);
+ COPY_SCALAR_FIELD(numCols);
+ COPY_POINTER_FIELD(dupColIdx, from->numCols * sizeof(AttrNumber));
+ COPY_SCALAR_FIELD(flagColIdx);
return newnode;
}
/*
- * _copyHash
+ * _copyLimit
*/
-static Hash *
-_copyHash(Hash *from)
+static Limit *
+_copyLimit(Limit *from)
{
- Hash *newnode = makeNode(Hash);
+ Limit *newnode = makeNode(Limit);
/*
* copy node superclass fields
/*
* copy remainder of node
*/
- COPY_NODE_FIELD(hashkeys);
-
- /* XXX could the hashkeys contain subplans? Not at present... */
+ COPY_NODE_FIELD(limitOffset);
+ COPY_NODE_FIELD(limitCount);
return newnode;
}
COPY_INTLIST_FIELD(parParam);
COPY_NODE_FIELD(sublink);
- /* do not copy execution state */
- newnode->needShutdown = false;
- newnode->curTuple = NULL;
-
return newnode;
}
/* ****************************************************************
* 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
*/
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
* ****************************************************************
/*
* 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;
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;
/*
* 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;
case T_JoinInfo:
retval = _copyJoinInfo(from);
break;
- case T_InnerIndexscanInfo:
- retval = _copyInnerIndexscanInfo(from);
- break;
/*
* VALUE NODES
* 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"
* 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)
{
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
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;
case T_JoinInfo:
retval = _equalJoinInfo(a, b);
break;
- case T_InnerIndexscanInfo:
- retval = _equalInnerIndexscanInfo(a, b);
- break;
case T_List:
{
*
*
* 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.
*
*-------------------------------------------------------------------------
#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"
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);
}
_outScanInfo(str, (Scan *) node);
- WRITE_BOOL_FIELD(needRescan);
WRITE_NODE_FIELD(tideval);
}
/*
* 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)
_outPathInfo(str, (Path *) node);
WRITE_NODE_FIELD(tideval);
- WRITE_INTLIST_FIELD(unjoined_relids);
}
static void
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
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;
}
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
- plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
node->indxqual = indxqual;
node->indxqualorig = indxqualorig;
node->indxorderdir = indexscandir;
- node->scan.scanstate = (CommonScanState *) NULL;
return node;
}
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;
}
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;
}
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;
}
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;
Plan *plan = &node->join.plan;
/* cost should be inserted by caller */
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = otherclauses;
plan->lefttree = lefttree;
Plan *plan = &node->join.plan;
/* cost should be inserted by caller */
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = otherclauses;
plan->lefttree = 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;
Plan *plan = &node->join.plan;
/* cost should be inserted by caller */
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = otherclauses;
plan->lefttree = lefttree;
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;
Plan *plan = &node->plan;
/* cost should be inserted by caller */
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
else
plan->plan_rows = numGroups;
- plan->state = (EState *) NULL;
plan->qual = qual;
plan->targetlist = tlist;
plan->lefttree = lefttree;
/* One output tuple per estimated result group */
plan->plan_rows = numGroups;
- plan->state = (EState *) NULL;
plan->qual = NULL;
plan->targetlist = tlist;
plan->lefttree = lefttree;
* if he has a better idea.
*/
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
if (plan->plan_rows < 1)
plan->plan_rows = 1;
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
}
}
- plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;
plan->lefttree = lefttree;
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
} 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,
* 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.
*
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
*/
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:
{
* 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:
* 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);
}
/*
- * 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);
* 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);
}
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
switch (nodeTag(plan))
{
case T_SeqScan:
- if (plan->initPlan || plan->subPlan)
+ if (plan->initPlan)
use_material = true;
else
{
}
/*
- * 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;
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)
{
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);
/*
* 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;
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));
SS_finalize_plan(plan->righttree,
rtable));
- /* Now we have all the paramids and subplans */
+ /* Now we have all the paramids */
foreach(lst, results.paramids)
{
plan->extParam = extParam;
plan->locParam = locParam;
- plan->subPlan = results.subplans;
return results.paramids;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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));
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 */
-
- 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;
+ qd->params = params; /* parameter values passed into query */
+ qd->doInstrument = doInstrument; /* instrumentation wanted? */
- state->es_per_tuple_exprcontext = NULL;
+ /* null these fields until set by ExecutorStart */
+ qd->tupDesc = NULL;
+ qd->estate = NULL;
+ qd->planstate = NULL;
- /*
- * return the executor state structure
- */
- return state;
+ return qd;
}
/* ----------------
Portal portal = NULL;
MemoryContext oldContext = NULL;
QueryDesc *queryDesc;
- EState *state;
- TupleDesc attinfo;
/*
* Check for special-case destinations
/*
* 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.
*/
}
/*
* 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
*/
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);
* 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.
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, "???");
/*
* Now, we close down all the scans and free allocated resources.
*/
- ExecutorEnd(queryDesc, state);
+ ExecutorEnd(queryDesc);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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;
/* 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;
* 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 $
*
*-------------------------------------------------------------------------
*/
#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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "executor/execdesc.h"
+
/* ----------------
* TupIsNull
*
/*
* 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);
/*
/*
* 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,
/*
* 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
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);
/*
* 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
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
{
* 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);
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
* 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 */
* 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 */
* 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,
* 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,
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,
* 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 */
* 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 */
* 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 */
* 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 */
* 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 */
* 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 */
* 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 */
* 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 */
* 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 */
* 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 */
*
* 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 */
* 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 */
* 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 */
* 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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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
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
- *
- * Superclass for all executor node-state object types.
+ * PlanState node
*
- * 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;
/* ----------------------------------------------------------------
*/
/* ----------------
- * 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
* 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
*/
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;
/* ----------------
* 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
*/
typedef struct TidScanState
{
- NodeTag type;
+ ScanState ss; /* its first field is NodeTag */
int tss_NumTids;
int tss_TidPtr;
int tss_MarkTidPtr;
*/
typedef struct SubqueryScanState
{
- CommonScanState csstate; /* its first field is NodeTag */
+ ScanState ss; /* its first field is NodeTag */
+ PlanState *subplan;
EState *sss_SubEState;
} 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;
/* ----------------
* 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
*/
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;
*/
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;
*/
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;
* 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
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 */
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
*
*/
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
*
*/
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 */
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 */
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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,
/*
* TAGS FOR PLANNER NODES (relation.h)
*/
- T_RelOptInfo = 200,
+ T_RelOptInfo = 400,
T_IndexOptInfo,
T_Path,
T_IndexPath,
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,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
*/
- T_Query = 600,
+ T_Query = 700,
T_InsertStmt,
T_DeleteStmt,
T_UpdateStmt,
T_ExecuteStmt,
T_DeallocateStmt,
- T_A_Expr = 700,
+ T_A_Expr = 800,
T_ColumnRef,
T_ParamRef,
T_A_Const,
/*
* 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;
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
typedef struct ParamExecData
{
- void *execPlan; /* should be "SubPlan *" */
+ void *execPlan; /* should be "SubPlanState *" */
Datum value;
bool isnull;
} ParamExecData;
* 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"
/* ----------------------------------------------------------------
/* ----------------
* 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
* 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
#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.
{
Plan plan;
Node *resconstantqual;
- ResultState *resstate;
} Result;
/* ----------------
Plan plan;
List *appendplans;
bool isTarget;
- AppendState *appendstate;
} Append;
/*
{
Plan plan;
Index scanrelid; /* relid is index into the range table */
- CommonScanState *scanstate;
} Scan;
/* ----------------
List *indxqual;
List *indxqualorig;
ScanDirection indxorderdir;
- IndexScanState *indxstate;
} IndexScan;
/* ----------------
typedef struct TidScan
{
Scan scan;
- bool needRescan;
List *tideval;
- TidScanState *tidstate;
} TidScan;
/* ----------------
{
Scan scan;
/* no other fields needed at present */
- /* scan.scanstate actually points at a FunctionScanState node */
} FunctionScan;
/*
typedef struct NestLoop
{
Join join;
- NestLoopState *nlstate;
} NestLoop;
/* ----------------
{
Join join;
List *mergeclauses;
- MergeJoinState *mergestate;
} MergeJoin;
/* ----------------
{
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
*
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
* ----------------
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
* ----------------
* duplicate-ness */
AttrNumber *dupColIdx; /* indexes into the target list */
AttrNumber flagColIdx;
- SetOpState *setopstate;
} SetOp;
/* ----------------
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
* 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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest,
char *completionTag);
-extern EState *CreateExecutorState(void);
-
extern Portal PreparePortal(char *portalName);
#endif /* PQUERY_H */
* 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
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) */
* 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)
/*
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 */
* 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.
*
if (plan->lefttree != NULL ||
plan->righttree != NULL ||
plan->initPlan != NULL ||
- plan->subPlan != NULL ||
plan->qual != NULL ||
((Result *) plan)->resconstantqual != NULL)
return;