Phase 1 of read-only-plans project: cause executor state nodes to point
to plan nodes, not vice-versa. All executor state nodes now inherit from struct PlanState. Copying of plan trees has been simplified by not storing a list of SubPlans in Plan nodes (eliminating duplicate links). The executor still needs such a list, but it can build it during ExecutorStart since it has to scan the plan tree anyway. No initdb forced since no stored-on-disk structures changed, but you will need a full recompile because of node-numbering changes.
This commit is contained in:
parent
0f3b83edfa
commit
1fd0c59e25
|
@ -5,7 +5,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.93 2002/11/13 00:39:46 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.94 2002/12/05 15:50:30 tgl Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -34,17 +34,19 @@ typedef struct ExplainState
|
|||
{
|
||||
/* options */
|
||||
bool printCost; /* print cost */
|
||||
bool printNodes; /* do nodeToString() instead */
|
||||
bool printAnalyze; /* print actual times */
|
||||
bool printNodes; /* do nodeToString() too */
|
||||
bool printAnalyze; /* print actual times */
|
||||
/* other states */
|
||||
List *rtable; /* range table */
|
||||
} ExplainState;
|
||||
|
||||
static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
|
||||
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
|
||||
TupOutputState *tstate);
|
||||
static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
||||
int indent, ExplainState *es);
|
||||
static double elapsed_time(struct timeval *starttime);
|
||||
static void explain_outNode(StringInfo str,
|
||||
Plan *plan, PlanState *planstate,
|
||||
Plan *outer_plan,
|
||||
int indent, ExplainState *es);
|
||||
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
|
||||
int scanrelid, Plan *outer_plan,
|
||||
StringInfo str, int indent, ExplainState *es);
|
||||
|
@ -116,8 +118,11 @@ static void
|
|||
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
||||
{
|
||||
Plan *plan;
|
||||
QueryDesc *queryDesc;
|
||||
ExplainState *es;
|
||||
StringInfo str;
|
||||
double totaltime = 0;
|
||||
struct timeval starttime;
|
||||
|
||||
/* planner will not cope with utility statements */
|
||||
if (query->commandType == CMD_UTILITY)
|
||||
|
@ -136,41 +141,34 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
|||
if (plan == NULL)
|
||||
return;
|
||||
|
||||
/* We don't support DECLARE CURSOR here */
|
||||
Assert(!query->isPortal);
|
||||
|
||||
gettimeofday(&starttime, NULL);
|
||||
|
||||
/* Create a QueryDesc requesting no output */
|
||||
queryDesc = CreateQueryDesc(query, plan, None, NULL, NULL,
|
||||
stmt->analyze);
|
||||
|
||||
/* call ExecutorStart to prepare the plan for execution */
|
||||
ExecutorStart(queryDesc);
|
||||
|
||||
/* Execute the plan for statistics if asked for */
|
||||
if (stmt->analyze)
|
||||
{
|
||||
struct timeval starttime;
|
||||
struct timeval endtime;
|
||||
/* run the plan */
|
||||
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
|
||||
|
||||
/*
|
||||
* Set up the instrumentation for the top node. This will cascade
|
||||
* during plan initialisation
|
||||
*/
|
||||
plan->instrument = InstrAlloc();
|
||||
/* We can't clean up 'till we're done printing the stats... */
|
||||
|
||||
gettimeofday(&starttime, NULL);
|
||||
ProcessQuery(query, plan, None, NULL);
|
||||
CommandCounterIncrement();
|
||||
gettimeofday(&endtime, NULL);
|
||||
|
||||
endtime.tv_sec -= starttime.tv_sec;
|
||||
endtime.tv_usec -= starttime.tv_usec;
|
||||
while (endtime.tv_usec < 0)
|
||||
{
|
||||
endtime.tv_usec += 1000000;
|
||||
endtime.tv_sec--;
|
||||
}
|
||||
totaltime = (double) endtime.tv_sec +
|
||||
(double) endtime.tv_usec / 1000000.0;
|
||||
totaltime += elapsed_time(&starttime);
|
||||
}
|
||||
|
||||
es = (ExplainState *) palloc0(sizeof(ExplainState));
|
||||
|
||||
es->printCost = true; /* default */
|
||||
|
||||
if (stmt->verbose)
|
||||
es->printNodes = true;
|
||||
|
||||
es->printNodes = stmt->verbose;
|
||||
es->printAnalyze = stmt->analyze;
|
||||
es->rtable = query->rtable;
|
||||
|
||||
if (es->printNodes)
|
||||
|
@ -193,33 +191,73 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
|||
}
|
||||
}
|
||||
|
||||
str = makeStringInfo();
|
||||
|
||||
if (es->printCost)
|
||||
{
|
||||
StringInfo str;
|
||||
explain_outNode(str, plan, queryDesc->planstate,
|
||||
NULL, 0, es);
|
||||
}
|
||||
|
||||
str = Explain_PlanToString(plan, es);
|
||||
/*
|
||||
* Close down the query and free resources. Include time for this
|
||||
* in the total runtime.
|
||||
*/
|
||||
gettimeofday(&starttime, NULL);
|
||||
|
||||
ExecutorEnd(queryDesc);
|
||||
CommandCounterIncrement();
|
||||
|
||||
totaltime += elapsed_time(&starttime);
|
||||
|
||||
if (es->printCost)
|
||||
{
|
||||
if (stmt->analyze)
|
||||
appendStringInfo(str, "Total runtime: %.2f msec\n",
|
||||
1000.0 * totaltime);
|
||||
do_text_output_multiline(tstate, str->data);
|
||||
pfree(str->data);
|
||||
pfree(str);
|
||||
}
|
||||
|
||||
pfree(str->data);
|
||||
pfree(str);
|
||||
pfree(es);
|
||||
}
|
||||
|
||||
/* Compute elapsed time in seconds since given gettimeofday() timestamp */
|
||||
static double
|
||||
elapsed_time(struct timeval *starttime)
|
||||
{
|
||||
struct timeval endtime;
|
||||
|
||||
gettimeofday(&endtime, NULL);
|
||||
|
||||
endtime.tv_sec -= starttime->tv_sec;
|
||||
endtime.tv_usec -= starttime->tv_usec;
|
||||
while (endtime.tv_usec < 0)
|
||||
{
|
||||
endtime.tv_usec += 1000000;
|
||||
endtime.tv_sec--;
|
||||
}
|
||||
return (double) endtime.tv_sec +
|
||||
(double) endtime.tv_usec / 1000000.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* explain_outNode -
|
||||
* converts a Plan node into ascii string and appends it to 'str'
|
||||
*
|
||||
* planstate points to the executor state node corresponding to the plan node.
|
||||
* We need this to get at the instrumentation data (if any) as well as the
|
||||
* list of subplans.
|
||||
*
|
||||
* outer_plan, if not null, references another plan node that is the outer
|
||||
* side of a join with the current node. This is only interesting for
|
||||
* deciphering runtime keys of an inner indexscan.
|
||||
*/
|
||||
static void
|
||||
explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
||||
explain_outNode(StringInfo str,
|
||||
Plan *plan, PlanState *planstate,
|
||||
Plan *outer_plan,
|
||||
int indent, ExplainState *es)
|
||||
{
|
||||
List *l;
|
||||
|
@ -410,18 +448,23 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
plan->startup_cost, plan->total_cost,
|
||||
plan->plan_rows, plan->plan_width);
|
||||
|
||||
if (plan->instrument && plan->instrument->nloops > 0)
|
||||
/*
|
||||
* We have to forcibly clean up the instrumentation state because
|
||||
* we haven't done ExecutorEnd yet. This is pretty grotty ...
|
||||
*/
|
||||
InstrEndLoop(planstate->instrument);
|
||||
|
||||
if (planstate->instrument && planstate->instrument->nloops > 0)
|
||||
{
|
||||
double nloops = plan->instrument->nloops;
|
||||
double nloops = planstate->instrument->nloops;
|
||||
|
||||
appendStringInfo(str, " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)",
|
||||
1000.0 * plan->instrument->startup / nloops,
|
||||
1000.0 * plan->instrument->total / nloops,
|
||||
plan->instrument->ntuples / nloops,
|
||||
plan->instrument->nloops);
|
||||
es->printAnalyze = true;
|
||||
1000.0 * planstate->instrument->startup / nloops,
|
||||
1000.0 * planstate->instrument->total / nloops,
|
||||
planstate->instrument->ntuples / nloops,
|
||||
planstate->instrument->nloops);
|
||||
}
|
||||
else if( es->printAnalyze )
|
||||
else if (es->printAnalyze)
|
||||
{
|
||||
appendStringInfo(str, " (never executed)");
|
||||
}
|
||||
|
@ -538,6 +581,7 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
if (plan->initPlan)
|
||||
{
|
||||
List *saved_rtable = es->rtable;
|
||||
List *pslist = planstate->initPlan;
|
||||
List *lst;
|
||||
|
||||
for (i = 0; i < indent; i++)
|
||||
|
@ -545,12 +589,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
appendStringInfo(str, " InitPlan\n");
|
||||
foreach(lst, plan->initPlan)
|
||||
{
|
||||
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
|
||||
SubPlan *subplan = (SubPlan *) lfirst(lst);
|
||||
SubPlanState *subplanstate = (SubPlanState *) lfirst(pslist);
|
||||
|
||||
es->rtable = subplan->rtable;
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
|
||||
explain_outNode(str, subplan->plan,
|
||||
subplanstate->planstate,
|
||||
NULL,
|
||||
indent + 4, es);
|
||||
pslist = lnext(pslist);
|
||||
}
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
|
@ -561,7 +611,10 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, outerPlan(plan), NULL, indent + 3, es);
|
||||
explain_outNode(str, outerPlan(plan),
|
||||
outerPlanState(planstate),
|
||||
NULL,
|
||||
indent + 3, es);
|
||||
}
|
||||
|
||||
/* righttree */
|
||||
|
@ -570,15 +623,20 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, innerPlan(plan), outerPlan(plan),
|
||||
explain_outNode(str, innerPlan(plan),
|
||||
innerPlanState(planstate),
|
||||
outerPlan(plan),
|
||||
indent + 3, es);
|
||||
}
|
||||
|
||||
if (IsA(plan, Append))
|
||||
{
|
||||
Append *appendplan = (Append *) plan;
|
||||
AppendState *appendstate = (AppendState *) planstate;
|
||||
List *lst;
|
||||
int j;
|
||||
|
||||
j = 0;
|
||||
foreach(lst, appendplan->appendplans)
|
||||
{
|
||||
Plan *subnode = (Plan *) lfirst(lst);
|
||||
|
@ -587,13 +645,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
|
||||
explain_outNode(str, subnode, NULL, indent + 3, es);
|
||||
explain_outNode(str, subnode,
|
||||
appendstate->appendplans[j],
|
||||
NULL,
|
||||
indent + 3, es);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsA(plan, SubqueryScan))
|
||||
{
|
||||
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
|
||||
SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
|
||||
Plan *subnode = subqueryscan->subplan;
|
||||
RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
|
||||
es->rtable);
|
||||
|
@ -606,13 +669,16 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
|
||||
explain_outNode(str, subnode, NULL, indent + 3, es);
|
||||
explain_outNode(str, subnode,
|
||||
subquerystate->subplan,
|
||||
NULL,
|
||||
indent + 3, es);
|
||||
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
|
||||
/* subPlan-s */
|
||||
if (plan->subPlan)
|
||||
if (planstate->subPlan)
|
||||
{
|
||||
List *saved_rtable = es->rtable;
|
||||
List *lst;
|
||||
|
@ -620,29 +686,24 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " SubPlan\n");
|
||||
foreach(lst, plan->subPlan)
|
||||
foreach(lst, planstate->subPlan)
|
||||
{
|
||||
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
|
||||
SubPlanState *sps = (SubPlanState *) lfirst(lst);
|
||||
SubPlan *sp = (SubPlan *) sps->ps.plan;
|
||||
|
||||
es->rtable = sp->rtable;
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
|
||||
explain_outNode(str, sp->plan,
|
||||
sps->planstate,
|
||||
NULL,
|
||||
indent + 4, es);
|
||||
}
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
}
|
||||
|
||||
static StringInfo
|
||||
Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||
{
|
||||
StringInfo str = makeStringInfo();
|
||||
|
||||
if (plan != NULL)
|
||||
explain_outNode(str, plan, NULL, 0, es);
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a qualifier expression for a scan plan node
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.4 2002/11/13 00:44:08 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.5 2002/12/05 15:50:30 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -23,6 +23,10 @@
|
|||
|
||||
/*
|
||||
* PortalCleanup
|
||||
*
|
||||
* Clean up a portal when it's dropped. Since this mainly exists to run
|
||||
* ExecutorEnd(), it should not be set as the cleanup hook until we have
|
||||
* called ExecutorStart() on the portal's query.
|
||||
*/
|
||||
void
|
||||
PortalCleanup(Portal portal)
|
||||
|
@ -43,7 +47,7 @@ PortalCleanup(Portal portal)
|
|||
/*
|
||||
* tell the executor to shutdown the query
|
||||
*/
|
||||
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
|
||||
ExecutorEnd(PortalGetQueryDesc(portal));
|
||||
|
||||
/*
|
||||
* switch back to previous context
|
||||
|
@ -116,7 +120,7 @@ PerformPortalFetch(char *name,
|
|||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
queryDesc = PortalGetQueryDesc(portal);
|
||||
estate = PortalGetState(portal);
|
||||
estate = queryDesc->estate;
|
||||
|
||||
/*
|
||||
* If the requested destination is not the same as the query's
|
||||
|
@ -158,7 +162,7 @@ PerformPortalFetch(char *name,
|
|||
else
|
||||
direction = ForwardScanDirection;
|
||||
|
||||
ExecutorRun(queryDesc, estate, direction, (long) count);
|
||||
ExecutorRun(queryDesc, direction, (long) count);
|
||||
|
||||
if (estate->es_processed > 0)
|
||||
portal->atStart = false; /* OK to back up now */
|
||||
|
@ -172,7 +176,7 @@ PerformPortalFetch(char *name,
|
|||
else
|
||||
direction = BackwardScanDirection;
|
||||
|
||||
ExecutorRun(queryDesc, estate, direction, (long) count);
|
||||
ExecutorRun(queryDesc, direction, (long) count);
|
||||
|
||||
if (estate->es_processed > 0)
|
||||
portal->atEnd = false; /* OK to go forward now */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Copyright (c) 2002, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.8 2002/11/15 00:47:22 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.9 2002/12/05 15:50:30 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -49,7 +49,7 @@ static void InitQueryHashTable(void);
|
|||
static void StoreQuery(const char *stmt_name, List *query_list,
|
||||
List *plan_list, List *argtype_list);
|
||||
static QueryHashEntry *FetchQuery(const char *plan_name);
|
||||
static void RunQuery(QueryDesc *qdesc, EState *state);
|
||||
static void RunQuery(QueryDesc *qdesc);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -151,15 +151,12 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
|||
else
|
||||
{
|
||||
QueryDesc *qdesc;
|
||||
EState *state;
|
||||
|
||||
if (log_executor_stats)
|
||||
ResetUsage();
|
||||
|
||||
qdesc = CreateQueryDesc(query, plan, outputDest, NULL);
|
||||
state = CreateExecutorState();
|
||||
|
||||
state->es_param_list_info = paramLI;
|
||||
qdesc = CreateQueryDesc(query, plan, outputDest, NULL,
|
||||
paramLI, false);
|
||||
|
||||
if (stmt->into)
|
||||
{
|
||||
|
@ -170,7 +167,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
|||
qdesc->dest = None;
|
||||
}
|
||||
|
||||
RunQuery(qdesc, state);
|
||||
RunQuery(qdesc);
|
||||
|
||||
if (log_executor_stats)
|
||||
ShowUsage("EXECUTOR STATISTICS");
|
||||
|
@ -334,15 +331,11 @@ FetchQueryParams(const char *plan_name)
|
|||
* Actually execute a prepared query.
|
||||
*/
|
||||
static void
|
||||
RunQuery(QueryDesc *qdesc, EState *state)
|
||||
RunQuery(QueryDesc *qdesc)
|
||||
{
|
||||
TupleDesc tupdesc;
|
||||
|
||||
tupdesc = ExecutorStart(qdesc, state);
|
||||
|
||||
ExecutorRun(qdesc, state, state->es_direction, 0L);
|
||||
|
||||
ExecutorEnd(qdesc, state);
|
||||
ExecutorStart(qdesc);
|
||||
ExecutorRun(qdesc, ForwardScanDirection, 0L);
|
||||
ExecutorEnd(qdesc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.1 2001/05/15 00:35:50 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.2 2002/12/05 15:50:30 tgl Exp $
|
||||
|
||||
The Postgres Executor
|
||||
---------------------
|
||||
|
@ -39,6 +39,27 @@ delivered by the plan tree.
|
|||
XXX a great deal more documentation needs to be written here...
|
||||
|
||||
|
||||
Plan Trees and State Trees
|
||||
--------------------------
|
||||
|
||||
The plan tree delivered by the planner contains a tree of Plan nodes (struct
|
||||
types derived from struct Plan). Each Plan node may have expression trees
|
||||
associated with it, to represent its target list, qualification conditions,
|
||||
etc. During executor startup we build a parallel tree of identical structure
|
||||
containing executor state nodes --- every plan and expression node type has
|
||||
a corresponding executor state node type. Each node in the state tree has a
|
||||
pointer to its corresponding node in the plan tree, plus executor state data
|
||||
as needed to implement that node type. This arrangement allows the plan
|
||||
tree to be completely read-only as far as the executor is concerned: all data
|
||||
that is modified during execution is in the state tree. Read-only plan trees
|
||||
make life much simpler for plan caching and reuse.
|
||||
|
||||
Altogether there are four classes of nodes used in these trees: Plan nodes,
|
||||
their corresponding PlanState nodes, Expr nodes, and their corresponding
|
||||
ExprState nodes. (Actually, there are also List nodes, which are used as
|
||||
"glue" in all four kinds of tree.)
|
||||
|
||||
|
||||
EvalPlanQual (READ COMMITTED update checking)
|
||||
---------------------------------------------
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execAmi.c,v 1.65 2002/11/30 05:21:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.66 2002/12/05 15:50:30 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -19,12 +19,12 @@
|
|||
#include "executor/instrument.h"
|
||||
#include "executor/nodeAgg.h"
|
||||
#include "executor/nodeAppend.h"
|
||||
#include "executor/nodeFunctionscan.h"
|
||||
#include "executor/nodeGroup.h"
|
||||
#include "executor/nodeGroup.h"
|
||||
#include "executor/nodeHash.h"
|
||||
#include "executor/nodeHashjoin.h"
|
||||
#include "executor/nodeIndexscan.h"
|
||||
#include "executor/nodeTidscan.h"
|
||||
#include "executor/nodeLimit.h"
|
||||
#include "executor/nodeMaterial.h"
|
||||
#include "executor/nodeMergejoin.h"
|
||||
|
@ -35,45 +35,45 @@
|
|||
#include "executor/nodeSort.h"
|
||||
#include "executor/nodeSubplan.h"
|
||||
#include "executor/nodeSubqueryscan.h"
|
||||
#include "executor/nodeFunctionscan.h"
|
||||
#include "executor/nodeTidscan.h"
|
||||
#include "executor/nodeUnique.h"
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecReScan
|
||||
*
|
||||
* XXX this should be extended to cope with all the node types..
|
||||
*
|
||||
* takes the new expression context as an argument, so that
|
||||
* index scans needn't have their scan keys updated separately
|
||||
* - marcel 09/20/94
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScan(PlanState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
/* If collecting timing stats, update them */
|
||||
if (node->instrument)
|
||||
InstrEndLoop(node->instrument);
|
||||
|
||||
if (node->chgParam != NULL) /* Wow! */
|
||||
/* If we have changed parameters, propagate that info */
|
||||
if (node->chgParam != NIL)
|
||||
{
|
||||
List *lst;
|
||||
|
||||
foreach(lst, node->initPlan)
|
||||
{
|
||||
Plan *splan = ((SubPlan *) lfirst(lst))->plan;
|
||||
PlanState *splan = ((SubPlanState *) lfirst(lst))->planstate;
|
||||
|
||||
if (splan->extParam != NULL) /* don't care about child
|
||||
if (splan->plan->extParam != NIL) /* don't care about child
|
||||
* locParam */
|
||||
SetChangedParamList(splan, node->chgParam);
|
||||
if (splan->chgParam != NULL)
|
||||
ExecReScanSetParamPlan((SubPlan *) lfirst(lst), node);
|
||||
if (splan->chgParam != NIL)
|
||||
ExecReScanSetParamPlan((SubPlanState *) lfirst(lst), node);
|
||||
}
|
||||
foreach(lst, node->subPlan)
|
||||
{
|
||||
Plan *splan = ((SubPlan *) lfirst(lst))->plan;
|
||||
PlanState *splan = ((SubPlanState *) lfirst(lst))->planstate;
|
||||
|
||||
if (splan->extParam != NULL)
|
||||
if (splan->plan->extParam != NIL)
|
||||
SetChangedParamList(splan, node->chgParam);
|
||||
}
|
||||
/* Well. Now set chgParam for left/right trees. */
|
||||
|
@ -85,76 +85,76 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
|
||||
case T_ResultState:
|
||||
ExecReScanResult((ResultState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
|
||||
case T_AppendState:
|
||||
ExecReScanAppend((AppendState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
ExecTidReScan((TidScan *) node, exprCtxt, parent);
|
||||
case T_SeqScanState:
|
||||
ExecSeqReScan((SeqScanState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_SubqueryScan:
|
||||
ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
|
||||
case T_IndexScanState:
|
||||
ExecIndexReScan((IndexScanState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
ExecFunctionReScan((FunctionScan *) node, exprCtxt, parent);
|
||||
case T_TidScanState:
|
||||
ExecTidReScan((TidScanState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Material:
|
||||
ExecMaterialReScan((Material *) node, exprCtxt, parent);
|
||||
case T_SubqueryScanState:
|
||||
ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_NestLoop:
|
||||
ExecReScanNestLoop((NestLoop *) node, exprCtxt, parent);
|
||||
case T_FunctionScanState:
|
||||
ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_HashJoin:
|
||||
ExecReScanHashJoin((HashJoin *) node, exprCtxt, parent);
|
||||
case T_NestLoopState:
|
||||
ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
ExecReScanHash((Hash *) node, exprCtxt, parent);
|
||||
case T_MergeJoinState:
|
||||
ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Agg:
|
||||
ExecReScanAgg((Agg *) node, exprCtxt, parent);
|
||||
case T_HashJoinState:
|
||||
ExecReScanHashJoin((HashJoinState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Group:
|
||||
ExecReScanGroup((Group *) node, exprCtxt, parent);
|
||||
case T_MaterialState:
|
||||
ExecMaterialReScan((MaterialState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Result:
|
||||
ExecReScanResult((Result *) node, exprCtxt, parent);
|
||||
case T_SortState:
|
||||
ExecReScanSort((SortState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Unique:
|
||||
ExecReScanUnique((Unique *) node, exprCtxt, parent);
|
||||
case T_GroupState:
|
||||
ExecReScanGroup((GroupState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_SetOp:
|
||||
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
|
||||
case T_AggState:
|
||||
ExecReScanAgg((AggState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Limit:
|
||||
ExecReScanLimit((Limit *) node, exprCtxt, parent);
|
||||
case T_UniqueState:
|
||||
ExecReScanUnique((UniqueState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
||||
case T_HashState:
|
||||
ExecReScanHash((HashState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_MergeJoin:
|
||||
ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
|
||||
case T_SetOpState:
|
||||
ExecReScanSetOp((SetOpState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
case T_Append:
|
||||
ExecReScanAppend((Append *) node, exprCtxt, parent);
|
||||
case T_LimitState:
|
||||
ExecReScanLimit((LimitState *) node, exprCtxt);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -163,10 +163,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
return;
|
||||
}
|
||||
|
||||
if (node->chgParam != NULL)
|
||||
if (node->chgParam != NIL)
|
||||
{
|
||||
freeList(node->chgParam);
|
||||
node->chgParam = NULL;
|
||||
node->chgParam = NIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,37 +176,37 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
* Marks the current scan position.
|
||||
*/
|
||||
void
|
||||
ExecMarkPos(Plan *node)
|
||||
ExecMarkPos(PlanState *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
ExecSeqMarkPos((SeqScan *) node);
|
||||
case T_SeqScanState:
|
||||
ExecSeqMarkPos((SeqScanState *) node);
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
ExecIndexMarkPos((IndexScan *) node);
|
||||
case T_IndexScanState:
|
||||
ExecIndexMarkPos((IndexScanState *) node);
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
ExecTidMarkPos((TidScan *) node);
|
||||
case T_TidScanState:
|
||||
ExecTidMarkPos((TidScanState *) node);
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
ExecFunctionMarkPos((FunctionScan *) node);
|
||||
case T_FunctionScanState:
|
||||
ExecFunctionMarkPos((FunctionScanState *) node);
|
||||
break;
|
||||
|
||||
case T_Material:
|
||||
ExecMaterialMarkPos((Material *) node);
|
||||
case T_MaterialState:
|
||||
ExecMaterialMarkPos((MaterialState *) node);
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
ExecSortMarkPos((Sort *) node);
|
||||
case T_SortState:
|
||||
ExecSortMarkPos((SortState *) node);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* don't make hard error unless caller asks to restore... */
|
||||
elog(LOG, "ExecMarkPos: node type %d not supported",
|
||||
elog(DEBUG1, "ExecMarkPos: node type %d not supported",
|
||||
nodeTag(node));
|
||||
break;
|
||||
}
|
||||
|
@ -218,32 +218,32 @@ ExecMarkPos(Plan *node)
|
|||
* restores the scan position previously saved with ExecMarkPos()
|
||||
*/
|
||||
void
|
||||
ExecRestrPos(Plan *node)
|
||||
ExecRestrPos(PlanState *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
ExecSeqRestrPos((SeqScan *) node);
|
||||
case T_SeqScanState:
|
||||
ExecSeqRestrPos((SeqScanState *) node);
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
ExecIndexRestrPos((IndexScan *) node);
|
||||
case T_IndexScanState:
|
||||
ExecIndexRestrPos((IndexScanState *) node);
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
ExecTidRestrPos((TidScan *) node);
|
||||
case T_TidScanState:
|
||||
ExecTidRestrPos((TidScanState *) node);
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
ExecFunctionRestrPos((FunctionScan *) node);
|
||||
case T_FunctionScanState:
|
||||
ExecFunctionRestrPos((FunctionScanState *) node);
|
||||
break;
|
||||
|
||||
case T_Material:
|
||||
ExecMaterialRestrPos((Material *) node);
|
||||
case T_MaterialState:
|
||||
ExecMaterialRestrPos((MaterialState *) node);
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
ExecSortRestrPos((Sort *) node);
|
||||
case T_SortState:
|
||||
ExecSortRestrPos((SortState *) node);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -258,6 +258,7 @@ ExecRestrPos(Plan *node)
|
|||
*
|
||||
* XXX Ideally, all plan node types would support mark/restore, and this
|
||||
* wouldn't be needed. For now, this had better match the routines above.
|
||||
* But note the test is on Plan nodetype, not PlanState nodetype.
|
||||
*/
|
||||
bool
|
||||
ExecSupportsMarkRestore(NodeTag plantype)
|
||||
|
|
|
@ -12,10 +12,9 @@
|
|||
* ExecutorRun() and ExecutorEnd()
|
||||
*
|
||||
* These three procedures are the external interfaces to the executor.
|
||||
* In each case, the query descriptor and the execution state is required
|
||||
* as arguments
|
||||
* In each case, the query descriptor is required as an argument.
|
||||
*
|
||||
* ExecutorStart() must be called at the beginning of any execution of any
|
||||
* ExecutorStart() must be called at the beginning of execution of any
|
||||
* query plan and ExecutorEnd() should always be called at the end of
|
||||
* execution of a plan.
|
||||
*
|
||||
|
@ -27,7 +26,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.189 2002/12/05 04:04:42 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.190 2002/12/05 15:50:30 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -48,16 +47,13 @@
|
|||
|
||||
|
||||
/* decls for local routines only used within this module */
|
||||
static TupleDesc InitPlan(CmdType operation,
|
||||
Query *parseTree,
|
||||
Plan *plan,
|
||||
EState *estate);
|
||||
static void InitPlan(QueryDesc *queryDesc);
|
||||
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||
Index resultRelationIndex,
|
||||
List *rangeTable,
|
||||
CmdType operation);
|
||||
static void EndPlan(Plan *plan, EState *estate);
|
||||
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
|
||||
static void EndPlan(PlanState *planstate, EState *estate);
|
||||
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
|
||||
CmdType operation,
|
||||
long numberTuples,
|
||||
ScanDirection direction,
|
||||
|
@ -73,11 +69,6 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
|
|||
EState *estate);
|
||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||
static void EndEvalPlanQual(EState *estate);
|
||||
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
|
||||
Plan *plan);
|
||||
static void ExecCheckPlanPerms(Plan *plan, List *rangeTable,
|
||||
CmdType operation);
|
||||
static void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
||||
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
||||
|
||||
/* end of local decls */
|
||||
|
@ -89,26 +80,40 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
|||
* This routine must be called at the beginning of any execution of any
|
||||
* query plan
|
||||
*
|
||||
* returns a TupleDesc which describes the attributes of the tuples to
|
||||
* be returned by the query. (Same value is saved in queryDesc)
|
||||
* Takes a QueryDesc previously created by CreateQueryDesc (it's not real
|
||||
* clear why we bother to separate the two functions, but...). The tupDesc
|
||||
* field of the QueryDesc is filled in to describe the tuples that will be
|
||||
* returned, and the internal fields (estate and planstate) are set up.
|
||||
*
|
||||
* XXX this will change soon:
|
||||
* NB: the CurrentMemoryContext when this is called must be the context
|
||||
* to be used as the per-query context for the query plan. ExecutorRun()
|
||||
* and ExecutorEnd() must be called in this same memory context.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleDesc
|
||||
ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
||||
void
|
||||
ExecutorStart(QueryDesc *queryDesc)
|
||||
{
|
||||
TupleDesc result;
|
||||
EState *estate;
|
||||
|
||||
/* sanity checks */
|
||||
/* sanity checks: queryDesc must not be started already */
|
||||
Assert(queryDesc != NULL);
|
||||
Assert(queryDesc->estate == NULL);
|
||||
|
||||
/*
|
||||
* Build EState, fill with parameters from queryDesc
|
||||
*/
|
||||
estate = CreateExecutorState();
|
||||
queryDesc->estate = estate;
|
||||
|
||||
estate->es_param_list_info = queryDesc->params;
|
||||
|
||||
if (queryDesc->plantree->nParamExec > 0)
|
||||
estate->es_param_exec_vals = (ParamExecData *)
|
||||
palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
|
||||
|
||||
estate->es_instrument = queryDesc->doInstrument;
|
||||
|
||||
/*
|
||||
* Make our own private copy of the current query snapshot data.
|
||||
*
|
||||
|
@ -119,16 +124,9 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||
estate->es_snapshot = CopyQuerySnapshot();
|
||||
|
||||
/*
|
||||
* Initialize the plan
|
||||
* Initialize the plan state tree
|
||||
*/
|
||||
result = InitPlan(queryDesc->operation,
|
||||
queryDesc->parsetree,
|
||||
queryDesc->plantree,
|
||||
estate);
|
||||
|
||||
queryDesc->tupDesc = result;
|
||||
|
||||
return result;
|
||||
InitPlan(queryDesc);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -150,11 +148,11 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
||||
ExecutorRun(QueryDesc *queryDesc,
|
||||
ScanDirection direction, long count)
|
||||
{
|
||||
CmdType operation;
|
||||
Plan *plan;
|
||||
EState *estate;
|
||||
CommandDest dest;
|
||||
DestReceiver *destfunc;
|
||||
TupleTableSlot *result;
|
||||
|
@ -169,7 +167,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
|||
* feature.
|
||||
*/
|
||||
operation = queryDesc->operation;
|
||||
plan = queryDesc->plantree;
|
||||
estate = queryDesc->estate;
|
||||
dest = queryDesc->dest;
|
||||
|
||||
/*
|
||||
|
@ -189,7 +187,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
|||
result = NULL;
|
||||
else
|
||||
result = ExecutePlan(estate,
|
||||
plan,
|
||||
queryDesc->planstate,
|
||||
operation,
|
||||
count,
|
||||
direction,
|
||||
|
@ -211,12 +209,16 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
|
||||
ExecutorEnd(QueryDesc *queryDesc)
|
||||
{
|
||||
EState *estate;
|
||||
|
||||
/* sanity checks */
|
||||
Assert(queryDesc != NULL);
|
||||
|
||||
EndPlan(queryDesc->plantree, estate);
|
||||
estate = queryDesc->estate;
|
||||
|
||||
EndPlan(queryDesc->planstate, estate);
|
||||
|
||||
if (estate->es_snapshot != NULL)
|
||||
{
|
||||
|
@ -235,97 +237,55 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
|
|||
|
||||
|
||||
/*
|
||||
* ExecCheckQueryPerms
|
||||
* Check access permissions for all relations referenced in a query.
|
||||
* CreateExecutorState
|
||||
*/
|
||||
static void
|
||||
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
|
||||
EState *
|
||||
CreateExecutorState(void)
|
||||
{
|
||||
/*
|
||||
* Check RTEs in the query's primary rangetable.
|
||||
*/
|
||||
ExecCheckRTPerms(parseTree->rtable, operation);
|
||||
EState *state;
|
||||
|
||||
/*
|
||||
* Search for subplans and APPEND nodes to check their rangetables.
|
||||
* create a new executor state
|
||||
*/
|
||||
ExecCheckPlanPerms(plan, parseTree->rtable, operation);
|
||||
state = makeNode(EState);
|
||||
|
||||
/*
|
||||
* initialize the Executor State structure
|
||||
*/
|
||||
state->es_direction = ForwardScanDirection;
|
||||
state->es_range_table = NIL;
|
||||
|
||||
state->es_result_relations = NULL;
|
||||
state->es_num_result_relations = 0;
|
||||
state->es_result_relation_info = NULL;
|
||||
|
||||
state->es_junkFilter = NULL;
|
||||
|
||||
state->es_into_relation_descriptor = NULL;
|
||||
|
||||
state->es_param_list_info = NULL;
|
||||
state->es_param_exec_vals = NULL;
|
||||
|
||||
state->es_tupleTable = NULL;
|
||||
|
||||
state->es_query_cxt = CurrentMemoryContext;
|
||||
|
||||
state->es_instrument = false;
|
||||
|
||||
state->es_per_tuple_exprcontext = NULL;
|
||||
|
||||
/*
|
||||
* return the executor state structure
|
||||
*/
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecCheckPlanPerms
|
||||
* Recursively scan the plan tree to check access permissions in
|
||||
* subplans.
|
||||
*/
|
||||
static void
|
||||
ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
|
||||
{
|
||||
List *subp;
|
||||
|
||||
if (plan == NULL)
|
||||
return;
|
||||
|
||||
/* Check subplans, which we assume are plain SELECT queries */
|
||||
|
||||
foreach(subp, plan->initPlan)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
|
||||
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
|
||||
ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
|
||||
}
|
||||
foreach(subp, plan->subPlan)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
|
||||
ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
|
||||
ExecCheckPlanPerms(subplan->plan, subplan->rtable, CMD_SELECT);
|
||||
}
|
||||
|
||||
/* Check lower plan nodes */
|
||||
|
||||
ExecCheckPlanPerms(plan->lefttree, rangeTable, operation);
|
||||
ExecCheckPlanPerms(plan->righttree, rangeTable, operation);
|
||||
|
||||
/* Do node-type-specific checks */
|
||||
|
||||
switch (nodeTag(plan))
|
||||
{
|
||||
case T_SubqueryScan:
|
||||
{
|
||||
SubqueryScan *scan = (SubqueryScan *) plan;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/* Recursively check the subquery */
|
||||
rte = rt_fetch(scan->scan.scanrelid, rangeTable);
|
||||
Assert(rte->rtekind == RTE_SUBQUERY);
|
||||
ExecCheckQueryPerms(operation, rte->subquery, scan->subplan);
|
||||
break;
|
||||
}
|
||||
case T_Append:
|
||||
{
|
||||
Append *app = (Append *) plan;
|
||||
List *appendplans;
|
||||
|
||||
foreach(appendplans, app->appendplans)
|
||||
{
|
||||
ExecCheckPlanPerms((Plan *) lfirst(appendplans),
|
||||
rangeTable,
|
||||
operation);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecCheckRTPerms
|
||||
* Check access permissions for all relations listed in a range table.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
ExecCheckRTPerms(List *rangeTable, CmdType operation)
|
||||
{
|
||||
List *lp;
|
||||
|
@ -350,11 +310,18 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
|||
AclResult aclcheck_result;
|
||||
|
||||
/*
|
||||
* Only plain-relation RTEs need to be checked here. Subquery RTEs
|
||||
* will be checked when ExecCheckPlanPerms finds the SubqueryScan
|
||||
* node, and function RTEs are checked by init_fcache when the
|
||||
* function is prepared for execution. Join and special RTEs need no
|
||||
* checks.
|
||||
* If it's a subquery, recursively examine its rangetable.
|
||||
*/
|
||||
if (rte->rtekind == RTE_SUBQUERY)
|
||||
{
|
||||
ExecCheckRTPerms(rte->subquery->rtable, operation);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, only plain-relation RTEs need to be checked here.
|
||||
* Function RTEs are checked by init_fcache when the function is prepared
|
||||
* for execution. Join and special RTEs need no checks.
|
||||
*/
|
||||
if (rte->rtekind != RTE_RELATION)
|
||||
return;
|
||||
|
@ -367,7 +334,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
|||
*
|
||||
* Note: GetUserId() is presently fast enough that there's no harm in
|
||||
* calling it separately for each RTE. If that stops being true, we
|
||||
* could call it once in ExecCheckQueryPerms and pass the userid down
|
||||
* could call it once in ExecCheckRTPerms and pass the userid down
|
||||
* from there. But for now, no need for the extra clutter.
|
||||
*/
|
||||
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
|
||||
|
@ -428,7 +395,8 @@ typedef struct execRowMark
|
|||
|
||||
typedef struct evalPlanQual
|
||||
{
|
||||
Plan *plan;
|
||||
Plan *plan; /* XXX temporary */
|
||||
PlanState *planstate;
|
||||
Index rti;
|
||||
EState estate;
|
||||
struct evalPlanQual *free;
|
||||
|
@ -441,17 +409,24 @@ typedef struct evalPlanQual
|
|||
* and start up the rule manager
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static TupleDesc
|
||||
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
static void
|
||||
InitPlan(QueryDesc *queryDesc)
|
||||
{
|
||||
CmdType operation = queryDesc->operation;
|
||||
Query *parseTree = queryDesc->parsetree;
|
||||
Plan *plan = queryDesc->plantree;
|
||||
EState *estate = queryDesc->estate;
|
||||
PlanState *planstate;
|
||||
List *rangeTable;
|
||||
Relation intoRelationDesc;
|
||||
TupleDesc tupType;
|
||||
|
||||
/*
|
||||
* Do permissions checks.
|
||||
* Do permissions checks. It's sufficient to examine the query's
|
||||
* top rangetable here --- subplan RTEs will be checked during
|
||||
* ExecInitSubPlan().
|
||||
*/
|
||||
ExecCheckQueryPerms(operation, parseTree, plan);
|
||||
ExecCheckRTPerms(parseTree->rtable, operation);
|
||||
|
||||
/*
|
||||
* get information from query descriptor
|
||||
|
@ -575,14 +550,14 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||
* query tree. This opens files, allocates storage and leaves us
|
||||
* ready to start processing tuples.
|
||||
*/
|
||||
ExecInitNode(plan, estate, NULL);
|
||||
planstate = ExecInitNode(plan, estate);
|
||||
|
||||
/*
|
||||
* Get the tuple descriptor describing the type of tuples to return.
|
||||
* (this is especially important if we are creating a relation with
|
||||
* "SELECT INTO")
|
||||
*/
|
||||
tupType = ExecGetTupType(plan); /* tuple descriptor */
|
||||
tupType = ExecGetTupType(planstate);
|
||||
|
||||
/*
|
||||
* Initialize the junk filter if needed. SELECT and INSERT queries
|
||||
|
@ -627,26 +602,29 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||
*/
|
||||
if (parseTree->resultRelations != NIL)
|
||||
{
|
||||
List *subplans;
|
||||
PlanState **appendplans;
|
||||
int as_nplans;
|
||||
ResultRelInfo *resultRelInfo;
|
||||
int i;
|
||||
|
||||
/* Top plan had better be an Append here. */
|
||||
Assert(IsA(plan, Append));
|
||||
Assert(((Append *) plan)->isTarget);
|
||||
subplans = ((Append *) plan)->appendplans;
|
||||
Assert(length(subplans) == estate->es_num_result_relations);
|
||||
Assert(IsA(planstate, AppendState));
|
||||
appendplans = ((AppendState *) planstate)->appendplans;
|
||||
as_nplans = ((AppendState *) planstate)->as_nplans;
|
||||
Assert(as_nplans == estate->es_num_result_relations);
|
||||
resultRelInfo = estate->es_result_relations;
|
||||
while (subplans != NIL)
|
||||
for (i = 0; i < as_nplans; i++)
|
||||
{
|
||||
Plan *subplan = (Plan *) lfirst(subplans);
|
||||
PlanState *subplan = appendplans[i];
|
||||
JunkFilter *j;
|
||||
|
||||
j = ExecInitJunkFilter(subplan->targetlist,
|
||||
j = ExecInitJunkFilter(subplan->plan->targetlist,
|
||||
ExecGetTupType(subplan),
|
||||
ExecAllocTableSlot(estate->es_tupleTable));
|
||||
resultRelInfo->ri_junkFilter = j;
|
||||
resultRelInfo++;
|
||||
subplans = lnext(subplans);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -661,7 +639,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||
/* Normal case with just one JunkFilter */
|
||||
JunkFilter *j;
|
||||
|
||||
j = ExecInitJunkFilter(plan->targetlist,
|
||||
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
||||
tupType,
|
||||
ExecAllocTableSlot(estate->es_tupleTable));
|
||||
estate->es_junkFilter = j;
|
||||
|
@ -755,7 +733,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||
|
||||
estate->es_into_relation_descriptor = intoRelationDesc;
|
||||
|
||||
return tupType;
|
||||
queryDesc->tupDesc = tupType;
|
||||
queryDesc->planstate = planstate;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -816,11 +795,11 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
|
|||
/* ----------------------------------------------------------------
|
||||
* EndPlan
|
||||
*
|
||||
* Cleans up the query plan -- closes files and free up storages
|
||||
* Cleans up the query plan -- closes files and frees up storage
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
EndPlan(Plan *plan, EState *estate)
|
||||
EndPlan(PlanState *planstate, EState *estate)
|
||||
{
|
||||
ResultRelInfo *resultRelInfo;
|
||||
int i;
|
||||
|
@ -835,7 +814,7 @@ EndPlan(Plan *plan, EState *estate)
|
|||
/*
|
||||
* shut down the node-type-specific query processing
|
||||
*/
|
||||
ExecEndNode(plan, NULL);
|
||||
ExecEndNode(planstate);
|
||||
|
||||
/*
|
||||
* destroy the executor "tuple" table.
|
||||
|
@ -902,7 +881,7 @@ EndPlan(Plan *plan, EState *estate)
|
|||
*/
|
||||
static TupleTableSlot *
|
||||
ExecutePlan(EState *estate,
|
||||
Plan *plan,
|
||||
PlanState *planstate,
|
||||
CmdType operation,
|
||||
long numberTuples,
|
||||
ScanDirection direction,
|
||||
|
@ -964,10 +943,10 @@ lnext: ;
|
|||
{
|
||||
slot = EvalPlanQualNext(estate);
|
||||
if (TupIsNull(slot))
|
||||
slot = ExecProcNode(plan, NULL);
|
||||
slot = ExecProcNode(planstate);
|
||||
}
|
||||
else
|
||||
slot = ExecProcNode(plan, NULL);
|
||||
slot = ExecProcNode(planstate);
|
||||
|
||||
/*
|
||||
* if the tuple is null, then we assume there is nothing more to
|
||||
|
@ -1765,7 +1744,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
|||
oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
|
||||
Assert(oldepq->rti != 0);
|
||||
/* stop execution */
|
||||
ExecEndNode(epq->plan, NULL);
|
||||
ExecEndNode(epq->planstate);
|
||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||
epqstate->es_tupleTable = NULL;
|
||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
||||
|
@ -1793,10 +1772,8 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
|||
|
||||
/*
|
||||
* Each stack level has its own copy of the plan tree. This
|
||||
* is wasteful, but necessary as long as plan nodes point to
|
||||
* exec state nodes rather than vice versa. Note that
|
||||
* copyfuncs.c doesn't attempt to copy the exec state nodes,
|
||||
* which is a good thing in this situation.
|
||||
* is wasteful, but necessary until plan trees are fully
|
||||
* read-only.
|
||||
*/
|
||||
newepq->plan = copyObject(estate->es_origPlan);
|
||||
|
||||
|
@ -1858,7 +1835,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
|||
if (endNode)
|
||||
{
|
||||
/* stop execution */
|
||||
ExecEndNode(epq->plan, NULL);
|
||||
ExecEndNode(epq->planstate);
|
||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||
epqstate->es_tupleTable = NULL;
|
||||
}
|
||||
|
@ -1886,7 +1863,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
|||
epqstate->es_tupleTable =
|
||||
ExecCreateTupleTable(estate->es_tupleTable->size);
|
||||
|
||||
ExecInitNode(epq->plan, epqstate, NULL);
|
||||
epq->planstate = ExecInitNode(epq->plan, epqstate);
|
||||
|
||||
return EvalPlanQualNext(estate);
|
||||
}
|
||||
|
@ -1902,7 +1879,7 @@ EvalPlanQualNext(EState *estate)
|
|||
Assert(epq->rti != 0);
|
||||
|
||||
lpqnext:;
|
||||
slot = ExecProcNode(epq->plan, NULL);
|
||||
slot = ExecProcNode(epq->planstate);
|
||||
|
||||
/*
|
||||
* No more tuples for this PQ. Continue previous one.
|
||||
|
@ -1910,7 +1887,7 @@ lpqnext:;
|
|||
if (TupIsNull(slot))
|
||||
{
|
||||
/* stop execution */
|
||||
ExecEndNode(epq->plan, NULL);
|
||||
ExecEndNode(epq->planstate);
|
||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||
epqstate->es_tupleTable = NULL;
|
||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
||||
|
@ -1951,7 +1928,7 @@ EndEvalPlanQual(EState *estate)
|
|||
for (;;)
|
||||
{
|
||||
/* stop execution */
|
||||
ExecEndNode(epq->plan, NULL);
|
||||
ExecEndNode(epq->planstate);
|
||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||
epqstate->es_tupleTable = NULL;
|
||||
if (epqstate->es_evTuple[epq->rti - 1] != NULL)
|
||||
|
|
|
@ -5,23 +5,23 @@
|
|||
* "get a tuple", and "cleanup" routines for the given node type.
|
||||
* If the node has children, then it will presumably call ExecInitNode,
|
||||
* ExecProcNode, or ExecEndNode on its subnodes and do the appropriate
|
||||
* processing..
|
||||
* processing.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.30 2002/06/20 20:29:27 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.31 2002/12/05 15:50:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
* ExecCountSlotsNode - count tuple slots needed by plan tree
|
||||
* ExecInitNode - initialize a plan node and its subplans
|
||||
* ExecProcNode - get a tuple by executing the plan node
|
||||
* ExecEndNode - shut down a plan node and its subplans
|
||||
* ExecCountSlotsNode - count tuple slots needed by plan tree
|
||||
* ExecGetTupType - get result tuple type of a plan node
|
||||
*
|
||||
* NOTES
|
||||
|
@ -53,10 +53,12 @@
|
|||
* * ExecInitNode() notices that it is looking at a nest loop and
|
||||
* as the code below demonstrates, it calls ExecInitNestLoop().
|
||||
* Eventually this calls ExecInitNode() on the right and left subplans
|
||||
* and so forth until the entire plan is initialized.
|
||||
* and so forth until the entire plan is initialized. The result
|
||||
* of ExecInitNode() is a plan state tree built with the same structure
|
||||
* as the underlying plan tree.
|
||||
*
|
||||
* * Then when ExecRun() is called, it calls ExecutePlan() which
|
||||
* calls ExecProcNode() repeatedly on the top node of the plan.
|
||||
* * Then when ExecRun() is called, it calls ExecutePlan() which calls
|
||||
* ExecProcNode() repeatedly on the top node of the plan state tree.
|
||||
* Each time this happens, ExecProcNode() will end up calling
|
||||
* ExecNestLoop(), which calls ExecProcNode() on its subplans.
|
||||
* Each of these subplans is a sequential scan so ExecSeqScan() is
|
||||
|
@ -73,7 +75,6 @@
|
|||
* ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
|
||||
* their work to the appopriate node support routines which may
|
||||
* in turn call these routines themselves on their subplans.
|
||||
*
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
|
@ -81,11 +82,11 @@
|
|||
#include "executor/instrument.h"
|
||||
#include "executor/nodeAgg.h"
|
||||
#include "executor/nodeAppend.h"
|
||||
#include "executor/nodeFunctionscan.h"
|
||||
#include "executor/nodeGroup.h"
|
||||
#include "executor/nodeHash.h"
|
||||
#include "executor/nodeHashjoin.h"
|
||||
#include "executor/nodeIndexscan.h"
|
||||
#include "executor/nodeTidscan.h"
|
||||
#include "executor/nodeLimit.h"
|
||||
#include "executor/nodeMaterial.h"
|
||||
#include "executor/nodeMergejoin.h"
|
||||
|
@ -96,7 +97,7 @@
|
|||
#include "executor/nodeSort.h"
|
||||
#include "executor/nodeSubplan.h"
|
||||
#include "executor/nodeSubqueryscan.h"
|
||||
#include "executor/nodeFunctionscan.h"
|
||||
#include "executor/nodeTidscan.h"
|
||||
#include "executor/nodeUnique.h"
|
||||
#include "miscadmin.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
|
@ -109,32 +110,23 @@
|
|||
*
|
||||
* Initial States:
|
||||
* 'node' is the plan produced by the query planner
|
||||
* 'estate' is the shared execution state for the query tree
|
||||
*
|
||||
* returns TRUE/FALSE on whether the plan was successfully initialized
|
||||
* Returns a PlanState node corresponding to the given Plan node.
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
||||
PlanState *
|
||||
ExecInitNode(Plan *node, EState *estate)
|
||||
{
|
||||
bool result;
|
||||
PlanState *result;
|
||||
List *subps;
|
||||
List *subp;
|
||||
|
||||
/*
|
||||
* do nothing when we get to the end of a leaf on tree.
|
||||
*/
|
||||
if (node == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Set up instrumentation for this node if the parent has it */
|
||||
if (!node->instrument && parent && parent->instrument)
|
||||
node->instrument = InstrAlloc();
|
||||
|
||||
foreach(subp, node->initPlan)
|
||||
{
|
||||
result = ExecInitSubPlan((SubPlan *) lfirst(subp), estate, node);
|
||||
if (result == FALSE)
|
||||
return FALSE;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
|
@ -142,104 +134,124 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||
* control nodes
|
||||
*/
|
||||
case T_Result:
|
||||
result = ExecInitResult((Result *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitResult((Result *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Append:
|
||||
result = ExecInitAppend((Append *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitAppend((Append *) node, estate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* scan nodes
|
||||
*/
|
||||
case T_SeqScan:
|
||||
result = ExecInitSeqScan((SeqScan *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitSeqScan((SeqScan *) node, estate);
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
result = ExecInitIndexScan((IndexScan *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitIndexScan((IndexScan *) node, estate);
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
result = ExecInitTidScan((TidScan *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitTidScan((TidScan *) node, estate);
|
||||
break;
|
||||
|
||||
case T_SubqueryScan:
|
||||
result = ExecInitSubqueryScan((SubqueryScan *) node, estate,
|
||||
parent);
|
||||
result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node, estate);
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
result = ExecInitFunctionScan((FunctionScan *) node, estate,
|
||||
parent);
|
||||
result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node, estate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* join nodes
|
||||
*/
|
||||
case T_NestLoop:
|
||||
result = ExecInitNestLoop((NestLoop *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitNestLoop((NestLoop *) node, estate);
|
||||
break;
|
||||
|
||||
case T_MergeJoin:
|
||||
result = ExecInitMergeJoin((MergeJoin *) node, estate, parent);
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
result = ExecInitHash((Hash *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node, estate);
|
||||
break;
|
||||
|
||||
case T_HashJoin:
|
||||
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitHashJoin((HashJoin *) node, estate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* materialization nodes
|
||||
*/
|
||||
case T_Material:
|
||||
result = ExecInitMaterial((Material *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitMaterial((Material *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
result = ExecInitSort((Sort *) node, estate, parent);
|
||||
break;
|
||||
|
||||
case T_Unique:
|
||||
result = ExecInitUnique((Unique *) node, estate, parent);
|
||||
break;
|
||||
|
||||
case T_SetOp:
|
||||
result = ExecInitSetOp((SetOp *) node, estate, parent);
|
||||
break;
|
||||
|
||||
case T_Limit:
|
||||
result = ExecInitLimit((Limit *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitSort((Sort *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Group:
|
||||
result = ExecInitGroup((Group *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitGroup((Group *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Agg:
|
||||
result = ExecInitAgg((Agg *) node, estate, parent);
|
||||
result = (PlanState *) ExecInitAgg((Agg *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Unique:
|
||||
result = (PlanState *) ExecInitUnique((Unique *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
result = (PlanState *) ExecInitHash((Hash *) node, estate);
|
||||
break;
|
||||
|
||||
case T_SetOp:
|
||||
result = (PlanState *) ExecInitSetOp((SetOp *) node, estate);
|
||||
break;
|
||||
|
||||
case T_Limit:
|
||||
result = (PlanState *) ExecInitLimit((Limit *) node, estate);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "ExecInitNode: node type %d unsupported",
|
||||
(int) nodeTag(node));
|
||||
result = FALSE;
|
||||
result = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
if (result != FALSE)
|
||||
/*
|
||||
* Initialize any initPlans present in this node. The planner put
|
||||
* them in a separate list for us.
|
||||
*/
|
||||
subps = NIL;
|
||||
foreach(subp, node->initPlan)
|
||||
{
|
||||
foreach(subp, node->subPlan)
|
||||
{
|
||||
result = ExecInitSubPlan((SubPlan *) lfirst(subp), estate, node);
|
||||
if (result == FALSE)
|
||||
return FALSE;
|
||||
}
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
|
||||
Assert(IsA(subplan, SubPlan));
|
||||
subps = lappend(subps, ExecInitSubPlan(subplan, estate));
|
||||
}
|
||||
result->initPlan = subps;
|
||||
|
||||
/*
|
||||
* Initialize any subPlans present in this node. These were found
|
||||
* by ExecInitExpr during initialization of the PlanState.
|
||||
*/
|
||||
subps = NIL;
|
||||
foreach(subp, result->subPlan)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
|
||||
Assert(IsA(subplan, SubPlan));
|
||||
subps = lappend(subps, ExecInitSubPlan(subplan, estate));
|
||||
}
|
||||
result->subPlan = subps;
|
||||
|
||||
/* Set up instrumentation for this node if requested */
|
||||
if (estate->es_instrument)
|
||||
result->instrument = InstrAlloc();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -248,12 +260,11 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||
/* ----------------------------------------------------------------
|
||||
* ExecProcNode
|
||||
*
|
||||
* Initial States:
|
||||
* the query tree must be initialized once by calling ExecInit.
|
||||
* Execute the given node to return a(nother) tuple.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecProcNode(Plan *node, Plan *parent)
|
||||
ExecProcNode(PlanState *node)
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
|
||||
|
@ -265,8 +276,8 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
if (node->chgParam != NULL) /* something changed */
|
||||
ExecReScan(node, NULL, parent); /* let ReScan handle this */
|
||||
if (node->chgParam != NIL) /* something changed */
|
||||
ExecReScan(node, NULL); /* let ReScan handle this */
|
||||
|
||||
if (node->instrument)
|
||||
InstrStartNode(node->instrument);
|
||||
|
@ -276,85 +287,85 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||
/*
|
||||
* control nodes
|
||||
*/
|
||||
case T_Result:
|
||||
result = ExecResult((Result *) node);
|
||||
case T_ResultState:
|
||||
result = ExecResult((ResultState *) node);
|
||||
break;
|
||||
|
||||
case T_Append:
|
||||
result = ExecProcAppend((Append *) node);
|
||||
case T_AppendState:
|
||||
result = ExecProcAppend((AppendState *) node);
|
||||
break;
|
||||
|
||||
/*
|
||||
* scan nodes
|
||||
*/
|
||||
case T_SeqScan:
|
||||
result = ExecSeqScan((SeqScan *) node);
|
||||
case T_SeqScanState:
|
||||
result = ExecSeqScan((SeqScanState *) node);
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
result = ExecIndexScan((IndexScan *) node);
|
||||
case T_IndexScanState:
|
||||
result = ExecIndexScan((IndexScanState *) node);
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
result = ExecTidScan((TidScan *) node);
|
||||
case T_TidScanState:
|
||||
result = ExecTidScan((TidScanState *) node);
|
||||
break;
|
||||
|
||||
case T_SubqueryScan:
|
||||
result = ExecSubqueryScan((SubqueryScan *) node);
|
||||
case T_SubqueryScanState:
|
||||
result = ExecSubqueryScan((SubqueryScanState *) node);
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
result = ExecFunctionScan((FunctionScan *) node);
|
||||
case T_FunctionScanState:
|
||||
result = ExecFunctionScan((FunctionScanState *) node);
|
||||
break;
|
||||
|
||||
/*
|
||||
* join nodes
|
||||
*/
|
||||
case T_NestLoop:
|
||||
result = ExecNestLoop((NestLoop *) node);
|
||||
case T_NestLoopState:
|
||||
result = ExecNestLoop((NestLoopState *) node);
|
||||
break;
|
||||
|
||||
case T_MergeJoin:
|
||||
result = ExecMergeJoin((MergeJoin *) node);
|
||||
case T_MergeJoinState:
|
||||
result = ExecMergeJoin((MergeJoinState *) node);
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
result = ExecHash((Hash *) node);
|
||||
break;
|
||||
|
||||
case T_HashJoin:
|
||||
result = ExecHashJoin((HashJoin *) node);
|
||||
case T_HashJoinState:
|
||||
result = ExecHashJoin((HashJoinState *) node);
|
||||
break;
|
||||
|
||||
/*
|
||||
* materialization nodes
|
||||
*/
|
||||
case T_Material:
|
||||
result = ExecMaterial((Material *) node);
|
||||
case T_MaterialState:
|
||||
result = ExecMaterial((MaterialState *) node);
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
result = ExecSort((Sort *) node);
|
||||
case T_SortState:
|
||||
result = ExecSort((SortState *) node);
|
||||
break;
|
||||
|
||||
case T_Unique:
|
||||
result = ExecUnique((Unique *) node);
|
||||
case T_GroupState:
|
||||
result = ExecGroup((GroupState *) node);
|
||||
break;
|
||||
|
||||
case T_SetOp:
|
||||
result = ExecSetOp((SetOp *) node);
|
||||
case T_AggState:
|
||||
result = ExecAgg((AggState *) node);
|
||||
break;
|
||||
|
||||
case T_Limit:
|
||||
result = ExecLimit((Limit *) node);
|
||||
case T_UniqueState:
|
||||
result = ExecUnique((UniqueState *) node);
|
||||
break;
|
||||
|
||||
case T_Group:
|
||||
result = ExecGroup((Group *) node);
|
||||
case T_HashState:
|
||||
result = ExecHash((HashState *) node);
|
||||
break;
|
||||
|
||||
case T_Agg:
|
||||
result = ExecAgg((Agg *) node);
|
||||
case T_SetOpState:
|
||||
result = ExecSetOp((SetOpState *) node);
|
||||
break;
|
||||
|
||||
case T_LimitState:
|
||||
result = ExecLimit((LimitState *) node);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -370,10 +381,16 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ExecCountSlotsNode - count up the number of tuple table slots needed
|
||||
*
|
||||
* Note that this scans a Plan tree, not a PlanState tree, because we
|
||||
* haven't built the PlanState tree yet ...
|
||||
*/
|
||||
int
|
||||
ExecCountSlotsNode(Plan *node)
|
||||
{
|
||||
if (node == (Plan *) NULL)
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
|
||||
switch (nodeTag(node))
|
||||
|
@ -414,9 +431,6 @@ ExecCountSlotsNode(Plan *node)
|
|||
case T_MergeJoin:
|
||||
return ExecCountSlotsMergeJoin((MergeJoin *) node);
|
||||
|
||||
case T_Hash:
|
||||
return ExecCountSlotsHash((Hash *) node);
|
||||
|
||||
case T_HashJoin:
|
||||
return ExecCountSlotsHashJoin((HashJoin *) node);
|
||||
|
||||
|
@ -429,26 +443,30 @@ ExecCountSlotsNode(Plan *node)
|
|||
case T_Sort:
|
||||
return ExecCountSlotsSort((Sort *) node);
|
||||
|
||||
case T_Group:
|
||||
return ExecCountSlotsGroup((Group *) node);
|
||||
|
||||
case T_Agg:
|
||||
return ExecCountSlotsAgg((Agg *) node);
|
||||
|
||||
case T_Unique:
|
||||
return ExecCountSlotsUnique((Unique *) node);
|
||||
|
||||
case T_Hash:
|
||||
return ExecCountSlotsHash((Hash *) node);
|
||||
|
||||
case T_SetOp:
|
||||
return ExecCountSlotsSetOp((SetOp *) node);
|
||||
|
||||
case T_Limit:
|
||||
return ExecCountSlotsLimit((Limit *) node);
|
||||
|
||||
case T_Group:
|
||||
return ExecCountSlotsGroup((Group *) node);
|
||||
|
||||
case T_Agg:
|
||||
return ExecCountSlotsAgg((Agg *) node);
|
||||
|
||||
default:
|
||||
elog(ERROR, "ExecCountSlotsNode: node type %d unsupported",
|
||||
(int) nodeTag(node));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -464,7 +482,7 @@ ExecCountSlotsNode(Plan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndNode(Plan *node, Plan *parent)
|
||||
ExecEndNode(PlanState *node)
|
||||
{
|
||||
List *subp;
|
||||
|
||||
|
@ -474,14 +492,19 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||
if (node == NULL)
|
||||
return;
|
||||
|
||||
if (node->instrument)
|
||||
InstrEndLoop(node->instrument);
|
||||
|
||||
/* Clean up initPlans and subPlans */
|
||||
foreach(subp, node->initPlan)
|
||||
ExecEndSubPlan((SubPlan *) lfirst(subp));
|
||||
ExecEndSubPlan((SubPlanState *) lfirst(subp));
|
||||
foreach(subp, node->subPlan)
|
||||
ExecEndSubPlan((SubPlan *) lfirst(subp));
|
||||
if (node->chgParam != NULL)
|
||||
ExecEndSubPlan((SubPlanState *) lfirst(subp));
|
||||
|
||||
if (node->chgParam != NIL)
|
||||
{
|
||||
freeList(node->chgParam);
|
||||
node->chgParam = NULL;
|
||||
node->chgParam = NIL;
|
||||
}
|
||||
|
||||
switch (nodeTag(node))
|
||||
|
@ -489,85 +512,85 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||
/*
|
||||
* control nodes
|
||||
*/
|
||||
case T_Result:
|
||||
ExecEndResult((Result *) node);
|
||||
case T_ResultState:
|
||||
ExecEndResult((ResultState *) node);
|
||||
break;
|
||||
|
||||
case T_Append:
|
||||
ExecEndAppend((Append *) node);
|
||||
case T_AppendState:
|
||||
ExecEndAppend((AppendState *) node);
|
||||
break;
|
||||
|
||||
/*
|
||||
* scan nodes
|
||||
*/
|
||||
case T_SeqScan:
|
||||
ExecEndSeqScan((SeqScan *) node);
|
||||
case T_SeqScanState:
|
||||
ExecEndSeqScan((SeqScanState *) node);
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
ExecEndIndexScan((IndexScan *) node);
|
||||
case T_IndexScanState:
|
||||
ExecEndIndexScan((IndexScanState *) node);
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
ExecEndTidScan((TidScan *) node);
|
||||
case T_TidScanState:
|
||||
ExecEndTidScan((TidScanState *) node);
|
||||
break;
|
||||
|
||||
case T_SubqueryScan:
|
||||
ExecEndSubqueryScan((SubqueryScan *) node);
|
||||
case T_SubqueryScanState:
|
||||
ExecEndSubqueryScan((SubqueryScanState *) node);
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
ExecEndFunctionScan((FunctionScan *) node);
|
||||
case T_FunctionScanState:
|
||||
ExecEndFunctionScan((FunctionScanState *) node);
|
||||
break;
|
||||
|
||||
/*
|
||||
* join nodes
|
||||
*/
|
||||
case T_NestLoop:
|
||||
ExecEndNestLoop((NestLoop *) node);
|
||||
case T_NestLoopState:
|
||||
ExecEndNestLoop((NestLoopState *) node);
|
||||
break;
|
||||
|
||||
case T_MergeJoin:
|
||||
ExecEndMergeJoin((MergeJoin *) node);
|
||||
case T_MergeJoinState:
|
||||
ExecEndMergeJoin((MergeJoinState *) node);
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
ExecEndHash((Hash *) node);
|
||||
break;
|
||||
|
||||
case T_HashJoin:
|
||||
ExecEndHashJoin((HashJoin *) node);
|
||||
case T_HashJoinState:
|
||||
ExecEndHashJoin((HashJoinState *) node);
|
||||
break;
|
||||
|
||||
/*
|
||||
* materialization nodes
|
||||
*/
|
||||
case T_Material:
|
||||
ExecEndMaterial((Material *) node);
|
||||
case T_MaterialState:
|
||||
ExecEndMaterial((MaterialState *) node);
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
ExecEndSort((Sort *) node);
|
||||
case T_SortState:
|
||||
ExecEndSort((SortState *) node);
|
||||
break;
|
||||
|
||||
case T_Unique:
|
||||
ExecEndUnique((Unique *) node);
|
||||
case T_GroupState:
|
||||
ExecEndGroup((GroupState *) node);
|
||||
break;
|
||||
|
||||
case T_SetOp:
|
||||
ExecEndSetOp((SetOp *) node);
|
||||
case T_AggState:
|
||||
ExecEndAgg((AggState *) node);
|
||||
break;
|
||||
|
||||
case T_Limit:
|
||||
ExecEndLimit((Limit *) node);
|
||||
case T_UniqueState:
|
||||
ExecEndUnique((UniqueState *) node);
|
||||
break;
|
||||
|
||||
case T_Group:
|
||||
ExecEndGroup((Group *) node);
|
||||
case T_HashState:
|
||||
ExecEndHash((HashState *) node);
|
||||
break;
|
||||
|
||||
case T_Agg:
|
||||
ExecEndAgg((Agg *) node);
|
||||
case T_SetOpState:
|
||||
ExecEndSetOp((SetOpState *) node);
|
||||
break;
|
||||
|
||||
case T_LimitState:
|
||||
ExecEndLimit((LimitState *) node);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -575,9 +598,6 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||
(int) nodeTag(node));
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->instrument)
|
||||
InstrEndLoop(node->instrument);
|
||||
}
|
||||
|
||||
|
||||
|
@ -592,7 +612,7 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleDesc
|
||||
ExecGetTupType(Plan *node)
|
||||
ExecGetTupType(PlanState *node)
|
||||
{
|
||||
TupleTableSlot *slot;
|
||||
|
||||
|
@ -601,147 +621,147 @@ ExecGetTupType(Plan *node)
|
|||
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_Result:
|
||||
case T_ResultState:
|
||||
{
|
||||
ResultState *resstate = ((Result *) node)->resstate;
|
||||
ResultState *resstate = (ResultState *) node;
|
||||
|
||||
slot = resstate->cstate.cs_ResultTupleSlot;
|
||||
slot = resstate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_SeqScan:
|
||||
case T_AppendState:
|
||||
{
|
||||
CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
|
||||
AppendState *appendstate = (AppendState *) node;
|
||||
|
||||
slot = scanstate->cstate.cs_ResultTupleSlot;
|
||||
slot = appendstate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_NestLoop:
|
||||
case T_SeqScanState:
|
||||
{
|
||||
NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
|
||||
SeqScanState *scanstate = (SeqScanState *) node;
|
||||
|
||||
slot = nlstate->jstate.cs_ResultTupleSlot;
|
||||
slot = scanstate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Append:
|
||||
case T_IndexScanState:
|
||||
{
|
||||
AppendState *appendstate = ((Append *) node)->appendstate;
|
||||
IndexScanState *scanstate = (IndexScanState *) node;
|
||||
|
||||
slot = appendstate->cstate.cs_ResultTupleSlot;
|
||||
slot = scanstate->ss.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_IndexScan:
|
||||
case T_TidScanState:
|
||||
{
|
||||
CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
|
||||
TidScanState *scanstate = (TidScanState *) node;
|
||||
|
||||
slot = scanstate->cstate.cs_ResultTupleSlot;
|
||||
slot = scanstate->ss.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_TidScan:
|
||||
case T_SubqueryScanState:
|
||||
{
|
||||
CommonScanState *scanstate = ((TidScan *) node)->scan.scanstate;
|
||||
SubqueryScanState *scanstate = (SubqueryScanState *) node;
|
||||
|
||||
slot = scanstate->cstate.cs_ResultTupleSlot;
|
||||
slot = scanstate->ss.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_SubqueryScan:
|
||||
case T_FunctionScanState:
|
||||
{
|
||||
CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
|
||||
FunctionScanState *scanstate = (FunctionScanState *) node;
|
||||
|
||||
slot = scanstate->cstate.cs_ResultTupleSlot;
|
||||
slot = scanstate->ss.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_FunctionScan:
|
||||
case T_NestLoopState:
|
||||
{
|
||||
CommonScanState *scanstate = ((FunctionScan *) node)->scan.scanstate;
|
||||
NestLoopState *nlstate = (NestLoopState *) node;
|
||||
|
||||
slot = scanstate->cstate.cs_ResultTupleSlot;
|
||||
slot = nlstate->js.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Material:
|
||||
case T_MergeJoinState:
|
||||
{
|
||||
MaterialState *matstate = ((Material *) node)->matstate;
|
||||
MergeJoinState *mergestate = (MergeJoinState *) node;
|
||||
|
||||
slot = matstate->csstate.css_ScanTupleSlot;
|
||||
slot = mergestate->js.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Sort:
|
||||
case T_HashJoinState:
|
||||
{
|
||||
SortState *sortstate = ((Sort *) node)->sortstate;
|
||||
HashJoinState *hashjoinstate = (HashJoinState *) node;
|
||||
|
||||
slot = sortstate->csstate.css_ScanTupleSlot;
|
||||
slot = hashjoinstate->js.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Agg:
|
||||
case T_MaterialState:
|
||||
{
|
||||
AggState *aggstate = ((Agg *) node)->aggstate;
|
||||
MaterialState *matstate = (MaterialState *) node;
|
||||
|
||||
slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
|
||||
slot = matstate->ss.ss_ScanTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Group:
|
||||
case T_SortState:
|
||||
{
|
||||
GroupState *grpstate = ((Group *) node)->grpstate;
|
||||
SortState *sortstate = (SortState *) node;
|
||||
|
||||
slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
|
||||
slot = sortstate->ss.ss_ScanTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
case T_GroupState:
|
||||
{
|
||||
HashState *hashstate = ((Hash *) node)->hashstate;
|
||||
GroupState *grpstate = (GroupState *) node;
|
||||
|
||||
slot = hashstate->cstate.cs_ResultTupleSlot;
|
||||
slot = grpstate->ss.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Unique:
|
||||
case T_AggState:
|
||||
{
|
||||
UniqueState *uniquestate = ((Unique *) node)->uniquestate;
|
||||
AggState *aggstate = (AggState *) node;
|
||||
|
||||
slot = uniquestate->cstate.cs_ResultTupleSlot;
|
||||
slot = aggstate->ss.ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_SetOp:
|
||||
case T_UniqueState:
|
||||
{
|
||||
SetOpState *setopstate = ((SetOp *) node)->setopstate;
|
||||
UniqueState *uniquestate = (UniqueState *) node;
|
||||
|
||||
slot = setopstate->cstate.cs_ResultTupleSlot;
|
||||
slot = uniquestate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_Limit:
|
||||
case T_HashState:
|
||||
{
|
||||
LimitState *limitstate = ((Limit *) node)->limitstate;
|
||||
HashState *hashstate = (HashState *) node;
|
||||
|
||||
slot = limitstate->cstate.cs_ResultTupleSlot;
|
||||
slot = hashstate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_MergeJoin:
|
||||
case T_SetOpState:
|
||||
{
|
||||
MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
|
||||
SetOpState *setopstate = (SetOpState *) node;
|
||||
|
||||
slot = mergestate->jstate.cs_ResultTupleSlot;
|
||||
slot = setopstate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_HashJoin:
|
||||
case T_LimitState:
|
||||
{
|
||||
HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
|
||||
LimitState *limitstate = (LimitState *) node;
|
||||
|
||||
slot = hashjoinstate->jstate.cs_ResultTupleSlot;
|
||||
slot = limitstate->ps.ps_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.112 2002/12/01 20:27:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.113 2002/12/05 15:50:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1766,7 +1766,8 @@ ExecEvalExpr(Node *expression,
|
|||
isNull, isDone);
|
||||
break;
|
||||
case SUBPLAN_EXPR:
|
||||
retDatum = ExecSubPlan((SubPlan *) expr->oper,
|
||||
/* XXX temporary hack to find exec state node */
|
||||
retDatum = ExecSubPlan(((SubPlan *) expr->oper)->pstate,
|
||||
expr->args, econtext,
|
||||
isNull);
|
||||
break;
|
||||
|
@ -1850,6 +1851,169 @@ ExecEvalExprSwitchContext(Node *expression,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* ExecInitExpr: prepare an expression tree for execution
|
||||
*
|
||||
* 'node' is the root of the expression tree to examine
|
||||
* 'parent' is the PlanState node that owns the expression,
|
||||
* or NULL if we are preparing an expression that is not associated
|
||||
* with a plan. (If so, it can't have Aggrefs or SubPlans.)
|
||||
*
|
||||
* Soon this will generate an expression state tree paralleling the given
|
||||
* expression tree. Right now, it just searches the expression tree for
|
||||
* Aggref and SubPlan nodes.
|
||||
*/
|
||||
Node *
|
||||
ExecInitExpr(Node *node, PlanState *parent)
|
||||
{
|
||||
List *temp;
|
||||
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_Var:
|
||||
break;
|
||||
case T_Const:
|
||||
break;
|
||||
case T_Param:
|
||||
break;
|
||||
case T_Aggref:
|
||||
if (parent && IsA(parent, AggState))
|
||||
{
|
||||
AggState *aggstate = (AggState *) parent;
|
||||
int naggs;
|
||||
|
||||
aggstate->aggs = lcons(node, aggstate->aggs);
|
||||
naggs = ++aggstate->numaggs;
|
||||
|
||||
ExecInitExpr(((Aggref *) node)->target, parent);
|
||||
|
||||
/*
|
||||
* Complain if the aggregate's argument contains any
|
||||
* aggregates; nested agg functions are semantically
|
||||
* nonsensical. (This probably was caught earlier,
|
||||
* but we defend against it here anyway.)
|
||||
*/
|
||||
if (naggs != aggstate->numaggs)
|
||||
elog(ERROR, "Aggregate function calls may not be nested");
|
||||
}
|
||||
else
|
||||
elog(ERROR, "ExecInitExpr: Aggref not expected here");
|
||||
break;
|
||||
case T_ArrayRef:
|
||||
{
|
||||
ArrayRef *aref = (ArrayRef *) node;
|
||||
|
||||
ExecInitExpr((Node *) aref->refupperindexpr, parent);
|
||||
ExecInitExpr((Node *) aref->reflowerindexpr, parent);
|
||||
ExecInitExpr(aref->refexpr, parent);
|
||||
ExecInitExpr(aref->refassgnexpr, parent);
|
||||
}
|
||||
break;
|
||||
case T_Expr:
|
||||
{
|
||||
Expr *expr = (Expr *) node;
|
||||
|
||||
switch (expr->opType)
|
||||
{
|
||||
case OP_EXPR:
|
||||
break;
|
||||
case FUNC_EXPR:
|
||||
break;
|
||||
case OR_EXPR:
|
||||
break;
|
||||
case AND_EXPR:
|
||||
break;
|
||||
case NOT_EXPR:
|
||||
break;
|
||||
case DISTINCT_EXPR:
|
||||
break;
|
||||
case SUBPLAN_EXPR:
|
||||
if (parent)
|
||||
{
|
||||
SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
|
||||
|
||||
/*
|
||||
* Here we just add the SubPlan nodes to
|
||||
* parent->subPlan. Later they will be expanded
|
||||
* to SubPlanState nodes.
|
||||
*/
|
||||
parent->subPlan = lcons(expr->oper,
|
||||
parent->subPlan);
|
||||
|
||||
/* Must recurse into oper list too */
|
||||
Assert(IsA(sublink, SubLink));
|
||||
if (sublink->lefthand)
|
||||
elog(ERROR, "ExecInitExpr: sublink has not been transformed");
|
||||
ExecInitExpr((Node *) sublink->oper, parent);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "ExecInitExpr: SubPlan not expected here");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecInitExpr: unknown expression type %d",
|
||||
expr->opType);
|
||||
break;
|
||||
}
|
||||
/* for all Expr node types, examine args list */
|
||||
ExecInitExpr((Node *) expr->args, parent);
|
||||
}
|
||||
break;
|
||||
case T_FieldSelect:
|
||||
ExecInitExpr(((FieldSelect *) node)->arg, parent);
|
||||
break;
|
||||
case T_RelabelType:
|
||||
ExecInitExpr(((RelabelType *) node)->arg, parent);
|
||||
break;
|
||||
case T_CaseExpr:
|
||||
{
|
||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||
|
||||
foreach(temp, caseexpr->args)
|
||||
{
|
||||
CaseWhen *when = (CaseWhen *) lfirst(temp);
|
||||
|
||||
Assert(IsA(when, CaseWhen));
|
||||
ExecInitExpr(when->expr, parent);
|
||||
ExecInitExpr(when->result, parent);
|
||||
}
|
||||
/* caseexpr->arg should be null, but we'll check it anyway */
|
||||
ExecInitExpr(caseexpr->arg, parent);
|
||||
ExecInitExpr(caseexpr->defresult, parent);
|
||||
}
|
||||
break;
|
||||
case T_NullTest:
|
||||
ExecInitExpr(((NullTest *) node)->arg, parent);
|
||||
break;
|
||||
case T_BooleanTest:
|
||||
ExecInitExpr(((BooleanTest *) node)->arg, parent);
|
||||
break;
|
||||
case T_ConstraintTest:
|
||||
ExecInitExpr(((ConstraintTest *) node)->arg, parent);
|
||||
ExecInitExpr(((ConstraintTest *) node)->check_expr, parent);
|
||||
break;
|
||||
case T_ConstraintTestValue:
|
||||
break;
|
||||
case T_List:
|
||||
foreach(temp, (List *) node)
|
||||
{
|
||||
ExecInitExpr((Node *) lfirst(temp), parent);
|
||||
}
|
||||
break;
|
||||
case T_TargetEntry:
|
||||
ExecInitExpr(((TargetEntry *) node)->expr, parent);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecInitExpr: unknown expression type %d",
|
||||
nodeTag(node));
|
||||
break;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecQual / ExecTargetList / ExecProject
|
||||
* ----------------------------------------------------------------
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.21 2002/09/02 02:47:02 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.22 2002/12/05 15:50:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -44,10 +44,9 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecScan(Scan *node,
|
||||
ExecScan(ScanState *node,
|
||||
ExecScanAccessMtd accessMtd) /* function returning a tuple */
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
EState *estate;
|
||||
ExprContext *econtext;
|
||||
List *qual;
|
||||
|
@ -57,23 +56,22 @@ ExecScan(Scan *node,
|
|||
/*
|
||||
* Fetch data from node
|
||||
*/
|
||||
estate = node->plan.state;
|
||||
scanstate = node->scanstate;
|
||||
econtext = scanstate->cstate.cs_ExprContext;
|
||||
qual = node->plan.qual;
|
||||
estate = node->ps.state;
|
||||
econtext = node->ps.ps_ExprContext;
|
||||
qual = node->ps.qual;
|
||||
|
||||
/*
|
||||
* Check to see if we're still projecting out tuples from a previous
|
||||
* scan tuple (because there is a function-returning-set in the
|
||||
* projection expressions). If so, try to project another one.
|
||||
*/
|
||||
if (scanstate->cstate.cs_TupFromTlist)
|
||||
if (node->ps.ps_TupFromTlist)
|
||||
{
|
||||
resultSlot = ExecProject(scanstate->cstate.cs_ProjInfo, &isDone);
|
||||
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
return resultSlot;
|
||||
/* Done with that source tuple... */
|
||||
scanstate->cstate.cs_TupFromTlist = false;
|
||||
node->ps.ps_TupFromTlist = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -104,7 +102,7 @@ ExecScan(Scan *node,
|
|||
if (TupIsNull(slot))
|
||||
{
|
||||
return ExecStoreTuple(NULL,
|
||||
scanstate->cstate.cs_ProjInfo->pi_slot,
|
||||
node->ps.ps_ProjInfo->pi_slot,
|
||||
InvalidBuffer,
|
||||
true);
|
||||
}
|
||||
|
@ -130,10 +128,10 @@ ExecScan(Scan *node,
|
|||
* return it --- unless we find we can project no tuples from
|
||||
* this scan tuple, in which case continue scan.
|
||||
*/
|
||||
resultSlot = ExecProject(scanstate->cstate.cs_ProjInfo, &isDone);
|
||||
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
scanstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
|
||||
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
|
||||
return resultSlot;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.60 2002/09/28 20:00:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -483,11 +483,11 @@ ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
|
||||
ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
|
||||
{
|
||||
INIT_SLOT_DEFS;
|
||||
INIT_SLOT_ALLOC;
|
||||
commonstate->cs_ResultTupleSlot = slot;
|
||||
planstate->ps_ResultTupleSlot = slot;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -495,11 +495,11 @@ ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecInitScanTupleSlot(EState *estate, CommonScanState *commonscanstate)
|
||||
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
|
||||
{
|
||||
INIT_SLOT_DEFS;
|
||||
INIT_SLOT_ALLOC;
|
||||
commonscanstate->css_ScanTupleSlot = slot;
|
||||
scanstate->ss_ScanTupleSlot = slot;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.90 2002/09/04 20:31:18 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.91 2002/12/05 15:50:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -142,7 +142,7 @@ DisplayTupleCount(FILE *statfp)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignExprContext(EState *estate, CommonState *commonstate)
|
||||
ExecAssignExprContext(EState *estate, PlanState *planstate)
|
||||
{
|
||||
ExprContext *econtext = makeNode(ExprContext);
|
||||
|
||||
|
@ -166,7 +166,7 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
|
|||
econtext->ecxt_aggnulls = NULL;
|
||||
econtext->ecxt_callbacks = NULL;
|
||||
|
||||
commonstate->cs_ExprContext = econtext;
|
||||
planstate->ps_ExprContext = econtext;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -259,10 +259,10 @@ MakePerTupleExprContext(EState *estate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignResultType(CommonState *commonstate,
|
||||
ExecAssignResultType(PlanState *planstate,
|
||||
TupleDesc tupDesc, bool shouldFree)
|
||||
{
|
||||
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
|
||||
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
|
||||
|
||||
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
|
||||
}
|
||||
|
@ -272,15 +272,15 @@ ExecAssignResultType(CommonState *commonstate,
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
|
||||
ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
|
||||
{
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlan = outerPlanState(planstate);
|
||||
tupDesc = ExecGetTupType(outerPlan);
|
||||
|
||||
ExecAssignResultType(commonstate, tupDesc, false);
|
||||
ExecAssignResultType(planstate, tupDesc, false);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -288,7 +288,7 @@ ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
|
||||
ExecAssignResultTypeFromTL(PlanState *planstate)
|
||||
{
|
||||
ResultRelInfo *ri;
|
||||
bool hasoid = false;
|
||||
|
@ -311,7 +311,7 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
|
|||
* each of the child plans of the topmost Append plan. So, this is
|
||||
* ugly but it works, for now ...
|
||||
*/
|
||||
ri = node->state->es_result_relation_info;
|
||||
ri = planstate->state->es_result_relation_info;
|
||||
if (ri != NULL)
|
||||
{
|
||||
Relation rel = ri->ri_RelationDesc;
|
||||
|
@ -320,8 +320,13 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
|
|||
hasoid = rel->rd_rel->relhasoids;
|
||||
}
|
||||
|
||||
tupDesc = ExecTypeFromTL(node->targetlist, hasoid);
|
||||
ExecAssignResultType(commonstate, tupDesc, true);
|
||||
/*
|
||||
* XXX Some plan nodes don't bother to set up planstate->targetlist,
|
||||
* so use the underlying plan's targetlist instead. This will probably
|
||||
* need to be fixed later.
|
||||
*/
|
||||
tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
|
||||
ExecAssignResultType(planstate, tupDesc, true);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -329,9 +334,9 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
TupleDesc
|
||||
ExecGetResultType(CommonState *commonstate)
|
||||
ExecGetResultType(PlanState *planstate)
|
||||
{
|
||||
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
|
||||
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
|
||||
|
||||
return slot->ttc_tupleDescriptor;
|
||||
}
|
||||
|
@ -342,23 +347,23 @@ ExecGetResultType(CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
|
||||
ExecAssignProjectionInfo(PlanState *planstate)
|
||||
{
|
||||
ProjectionInfo *projInfo;
|
||||
List *targetList;
|
||||
int len;
|
||||
|
||||
targetList = node->targetlist;
|
||||
targetList = planstate->targetlist;
|
||||
len = ExecTargetListLength(targetList);
|
||||
|
||||
projInfo = makeNode(ProjectionInfo);
|
||||
projInfo->pi_targetlist = targetList;
|
||||
projInfo->pi_len = len;
|
||||
projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
|
||||
projInfo->pi_exprContext = commonstate->cs_ExprContext;
|
||||
projInfo->pi_slot = commonstate->cs_ResultTupleSlot;
|
||||
projInfo->pi_exprContext = planstate->ps_ExprContext;
|
||||
projInfo->pi_slot = planstate->ps_ResultTupleSlot;
|
||||
|
||||
commonstate->cs_ProjInfo = projInfo;
|
||||
planstate->ps_ProjInfo = projInfo;
|
||||
}
|
||||
|
||||
|
||||
|
@ -367,7 +372,7 @@ ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecFreeProjectionInfo(CommonState *commonstate)
|
||||
ExecFreeProjectionInfo(PlanState *planstate)
|
||||
{
|
||||
ProjectionInfo *projInfo;
|
||||
|
||||
|
@ -375,7 +380,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||
* get projection info. if NULL then this node has none so we just
|
||||
* return.
|
||||
*/
|
||||
projInfo = commonstate->cs_ProjInfo;
|
||||
projInfo = planstate->ps_ProjInfo;
|
||||
if (projInfo == NULL)
|
||||
return;
|
||||
|
||||
|
@ -386,7 +391,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||
pfree(projInfo->pi_tupValue);
|
||||
|
||||
pfree(projInfo);
|
||||
commonstate->cs_ProjInfo = NULL;
|
||||
planstate->ps_ProjInfo = NULL;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -394,7 +399,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecFreeExprContext(CommonState *commonstate)
|
||||
ExecFreeExprContext(PlanState *planstate)
|
||||
{
|
||||
ExprContext *econtext;
|
||||
|
||||
|
@ -402,7 +407,7 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||
* get expression context. if NULL then this node has none so we just
|
||||
* return.
|
||||
*/
|
||||
econtext = commonstate->cs_ExprContext;
|
||||
econtext = planstate->ps_ExprContext;
|
||||
if (econtext == NULL)
|
||||
return;
|
||||
|
||||
|
@ -416,7 +421,7 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||
*/
|
||||
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
||||
pfree(econtext);
|
||||
commonstate->cs_ExprContext = NULL;
|
||||
planstate->ps_ExprContext = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -434,9 +439,9 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||
* ----------------
|
||||
*/
|
||||
TupleDesc
|
||||
ExecGetScanType(CommonScanState *csstate)
|
||||
ExecGetScanType(ScanState *scanstate)
|
||||
{
|
||||
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
|
||||
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
|
||||
|
||||
return slot->ttc_tupleDescriptor;
|
||||
}
|
||||
|
@ -446,10 +451,10 @@ ExecGetScanType(CommonScanState *csstate)
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignScanType(CommonScanState *csstate,
|
||||
ExecAssignScanType(ScanState *scanstate,
|
||||
TupleDesc tupDesc, bool shouldFree)
|
||||
{
|
||||
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
|
||||
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
|
||||
|
||||
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
|
||||
}
|
||||
|
@ -459,15 +464,15 @@ ExecAssignScanType(CommonScanState *csstate,
|
|||
* ----------------
|
||||
*/
|
||||
void
|
||||
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
|
||||
ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
|
||||
{
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlan = outerPlanState(scanstate);
|
||||
tupDesc = ExecGetTupType(outerPlan);
|
||||
|
||||
ExecAssignScanType(csstate, tupDesc, false);
|
||||
ExecAssignScanType(scanstate, tupDesc, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -718,7 +723,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||
}
|
||||
|
||||
void
|
||||
SetChangedParamList(Plan *node, List *newchg)
|
||||
SetChangedParamList(PlanState *node, List *newchg)
|
||||
{
|
||||
List *nl;
|
||||
|
||||
|
@ -727,8 +732,8 @@ SetChangedParamList(Plan *node, List *newchg)
|
|||
int paramId = lfirsti(nl);
|
||||
|
||||
/* if this node doesn't depend on a param ... */
|
||||
if (!intMember(paramId, node->extParam) &&
|
||||
!intMember(paramId, node->locParam))
|
||||
if (!intMember(paramId, node->plan->extParam) &&
|
||||
!intMember(paramId, node->plan->locParam))
|
||||
continue;
|
||||
/* if this param is already in list of changed ones ... */
|
||||
if (intMember(paramId, node->chgParam))
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.60 2002/11/13 00:39:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.61 2002/12/05 15:50:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -28,7 +28,9 @@
|
|||
|
||||
|
||||
/*
|
||||
* We have an execution_state record for each query in a function.
|
||||
* We have an execution_state record for each query in a function. Each
|
||||
* record contains a querytree and plantree for its query. If the query
|
||||
* is currently in F_EXEC_RUN state then there's a QueryDesc too.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
|
@ -37,10 +39,11 @@ typedef enum
|
|||
|
||||
typedef struct local_es
|
||||
{
|
||||
QueryDesc *qd;
|
||||
EState *estate;
|
||||
struct local_es *next;
|
||||
ExecStatus status;
|
||||
Query *query;
|
||||
Plan *plan;
|
||||
QueryDesc *qd; /* null unless status == RUN */
|
||||
} execution_state;
|
||||
|
||||
#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *) NULL)
|
||||
|
@ -62,6 +65,8 @@ typedef struct
|
|||
* we end execution of the function and
|
||||
* free stuff */
|
||||
|
||||
ParamListInfo paramLI; /* Param list representing current args */
|
||||
|
||||
/* head of linked list of execution_state records */
|
||||
execution_state *func_state;
|
||||
} SQLFunctionCache;
|
||||
|
@ -73,10 +78,11 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
|
|||
static execution_state *init_execution_state(char *src,
|
||||
Oid *argOidVect, int nargs);
|
||||
static void init_sql_fcache(FmgrInfo *finfo);
|
||||
static void postquel_start(execution_state *es);
|
||||
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
|
||||
static TupleTableSlot *postquel_getnext(execution_state *es);
|
||||
static void postquel_end(execution_state *es);
|
||||
static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo);
|
||||
static void postquel_sub_params(SQLFunctionCachePtr fcache,
|
||||
FunctionCallInfo fcinfo);
|
||||
static Datum postquel_execute(execution_state *es,
|
||||
FunctionCallInfo fcinfo,
|
||||
SQLFunctionCachePtr fcache);
|
||||
|
@ -101,7 +107,6 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
|
|||
Query *queryTree = lfirst(qtl_item);
|
||||
Plan *planTree;
|
||||
execution_state *newes;
|
||||
EState *estate;
|
||||
|
||||
planTree = pg_plan_query(queryTree);
|
||||
|
||||
|
@ -113,29 +118,9 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
|
|||
|
||||
newes->next = NULL;
|
||||
newes->status = F_EXEC_START;
|
||||
newes->qd = CreateQueryDesc(queryTree, planTree, None, NULL);
|
||||
newes->estate = estate = CreateExecutorState();
|
||||
|
||||
if (nargs > 0)
|
||||
{
|
||||
int i;
|
||||
ParamListInfo paramLI;
|
||||
|
||||
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
||||
|
||||
estate->es_param_list_info = paramLI;
|
||||
|
||||
for (i = 0; i < nargs; paramLI++, i++)
|
||||
{
|
||||
paramLI->kind = PARAM_NUM;
|
||||
paramLI->id = i + 1;
|
||||
paramLI->isnull = false;
|
||||
paramLI->value = (Datum) NULL;
|
||||
}
|
||||
paramLI->kind = PARAM_INVALID;
|
||||
}
|
||||
else
|
||||
estate->es_param_list_info = (ParamListInfo) NULL;
|
||||
newes->query = queryTree;
|
||||
newes->plan = planTree;
|
||||
newes->qd = NULL;
|
||||
|
||||
preves = newes;
|
||||
}
|
||||
|
@ -219,6 +204,10 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||
else
|
||||
fcache->funcSlot = NULL;
|
||||
|
||||
/*
|
||||
* Parse and plan the queries. We need the argument info to pass
|
||||
* to the parser.
|
||||
*/
|
||||
nargs = procedureStruct->pronargs;
|
||||
|
||||
if (nargs > 0)
|
||||
|
@ -252,15 +241,18 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||
|
||||
|
||||
static void
|
||||
postquel_start(execution_state *es)
|
||||
postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
|
||||
{
|
||||
/*
|
||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
*/
|
||||
if (es->qd->operation == CMD_UTILITY)
|
||||
return;
|
||||
ExecutorStart(es->qd, es->estate);
|
||||
Assert(es->qd == NULL);
|
||||
es->qd = CreateQueryDesc(es->query, es->plan,
|
||||
None, NULL,
|
||||
fcache->paramLI, false);
|
||||
|
||||
/* Utility commands don't need Executor. */
|
||||
if (es->qd->operation != CMD_UTILITY)
|
||||
ExecutorStart(es->qd);
|
||||
|
||||
es->status = F_EXEC_RUN;
|
||||
}
|
||||
|
||||
static TupleTableSlot *
|
||||
|
@ -282,40 +274,52 @@ postquel_getnext(execution_state *es)
|
|||
/* If it's not the last command, just run it to completion */
|
||||
count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L;
|
||||
|
||||
return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count);
|
||||
return ExecutorRun(es->qd, ForwardScanDirection, count);
|
||||
}
|
||||
|
||||
static void
|
||||
postquel_end(execution_state *es)
|
||||
{
|
||||
/*
|
||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
*/
|
||||
if (es->qd->operation == CMD_UTILITY)
|
||||
return;
|
||||
ExecutorEnd(es->qd, es->estate);
|
||||
/* Utility commands don't need Executor. */
|
||||
if (es->qd->operation != CMD_UTILITY)
|
||||
ExecutorEnd(es->qd);
|
||||
|
||||
pfree(es->qd);
|
||||
es->qd = NULL;
|
||||
|
||||
es->status = F_EXEC_DONE;
|
||||
}
|
||||
|
||||
/* Build ParamListInfo array representing current arguments */
|
||||
static void
|
||||
postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo)
|
||||
postquel_sub_params(SQLFunctionCachePtr fcache,
|
||||
FunctionCallInfo fcinfo)
|
||||
{
|
||||
EState *estate;
|
||||
ParamListInfo paramLI;
|
||||
int nargs = fcinfo->nargs;
|
||||
|
||||
estate = es->estate;
|
||||
paramLI = estate->es_param_list_info;
|
||||
|
||||
while (paramLI->kind != PARAM_INVALID)
|
||||
if (nargs > 0)
|
||||
{
|
||||
if (paramLI->kind == PARAM_NUM)
|
||||
int i;
|
||||
|
||||
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
||||
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
Assert(paramLI->id <= fcinfo->nargs);
|
||||
paramLI->value = fcinfo->arg[paramLI->id - 1];
|
||||
paramLI->isnull = fcinfo->argnull[paramLI->id - 1];
|
||||
paramLI[i].kind = PARAM_NUM;
|
||||
paramLI[i].id = i + 1;
|
||||
paramLI[i].value = fcinfo->arg[i];
|
||||
paramLI[i].isnull = fcinfo->argnull[i];
|
||||
}
|
||||
paramLI++;
|
||||
paramLI[nargs].kind = PARAM_INVALID;
|
||||
}
|
||||
else
|
||||
paramLI = (ParamListInfo) NULL;
|
||||
|
||||
if (fcache->paramLI)
|
||||
pfree(fcache->paramLI);
|
||||
|
||||
fcache->paramLI = paramLI;
|
||||
}
|
||||
|
||||
static TupleTableSlot *
|
||||
|
@ -359,27 +363,14 @@ postquel_execute(execution_state *es,
|
|||
TupleTableSlot *slot;
|
||||
Datum value;
|
||||
|
||||
/*
|
||||
* It's more right place to do it (before
|
||||
* postquel_start->ExecutorStart). Now
|
||||
* ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
|
||||
* note: I HOPE we can do it here). - vadim 01/22/97
|
||||
*/
|
||||
if (fcinfo->nargs > 0)
|
||||
postquel_sub_params(es, fcinfo);
|
||||
|
||||
if (es->status == F_EXEC_START)
|
||||
{
|
||||
postquel_start(es);
|
||||
es->status = F_EXEC_RUN;
|
||||
}
|
||||
postquel_start(es, fcache);
|
||||
|
||||
slot = postquel_getnext(es);
|
||||
|
||||
if (TupIsNull(slot))
|
||||
{
|
||||
postquel_end(es);
|
||||
es->status = F_EXEC_DONE;
|
||||
fcinfo->isnull = true;
|
||||
|
||||
/*
|
||||
|
@ -438,10 +429,7 @@ postquel_execute(execution_state *es,
|
|||
* execution now.
|
||||
*/
|
||||
if (!fcinfo->flinfo->fn_retset)
|
||||
{
|
||||
postquel_end(es);
|
||||
es->status = F_EXEC_DONE;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -471,7 +459,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
|||
oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
|
||||
|
||||
/*
|
||||
* Initialize fcache and execution state if first time through.
|
||||
* Initialize fcache (build plans) if first time through.
|
||||
*/
|
||||
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
|
||||
if (fcache == NULL)
|
||||
|
@ -481,6 +469,13 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
|||
}
|
||||
es = fcache->func_state;
|
||||
|
||||
/*
|
||||
* Convert params to appropriate format if starting a fresh execution.
|
||||
* (If continuing execution, we can re-use prior params.)
|
||||
*/
|
||||
if (es && es->status == F_EXEC_START)
|
||||
postquel_sub_params(fcache, fcinfo);
|
||||
|
||||
/*
|
||||
* Find first unfinished query in function.
|
||||
*/
|
||||
|
@ -506,7 +501,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
|||
if (es == (execution_state *) NULL)
|
||||
{
|
||||
/*
|
||||
* Reset the execution states to start over again
|
||||
* Reset the execution states to start over again on next call.
|
||||
*/
|
||||
es = fcache->func_state;
|
||||
while (es)
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.97 2002/11/29 21:39:11 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.98 2002/12/05 15:50:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -212,11 +212,12 @@ static void finalize_aggregate(AggState *aggstate,
|
|||
AggStatePerAgg peraggstate,
|
||||
AggStatePerGroup pergroupstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
static void build_hash_table(Agg *node);
|
||||
static AggHashEntry lookup_hash_entry(Agg *node, TupleTableSlot *slot);
|
||||
static TupleTableSlot *agg_retrieve_direct(Agg *node);
|
||||
static void agg_fill_hash_table(Agg *node);
|
||||
static TupleTableSlot *agg_retrieve_hash_table(Agg *node);
|
||||
static void build_hash_table(AggState *aggstate);
|
||||
static AggHashEntry lookup_hash_entry(AggState *aggstate,
|
||||
TupleTableSlot *slot);
|
||||
static TupleTableSlot *agg_retrieve_direct(AggState *aggstate);
|
||||
static void agg_fill_hash_table(AggState *aggstate);
|
||||
static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
|
||||
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
|
||||
|
||||
|
||||
|
@ -521,7 +522,7 @@ finalize_aggregate(AggState *aggstate,
|
|||
{
|
||||
MemoryContext oldContext;
|
||||
|
||||
oldContext = MemoryContextSwitchTo(aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory);
|
||||
oldContext = MemoryContextSwitchTo(aggstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory);
|
||||
|
||||
/*
|
||||
* Apply the agg's finalfn if one is provided, else return transValue.
|
||||
|
@ -572,9 +573,9 @@ finalize_aggregate(AggState *aggstate,
|
|||
* The hash table always lives in the aggcontext memory context.
|
||||
*/
|
||||
static void
|
||||
build_hash_table(Agg *node)
|
||||
build_hash_table(AggState *aggstate)
|
||||
{
|
||||
AggState *aggstate = node->aggstate;
|
||||
Agg *node = (Agg *) aggstate->ss.ps.plan;
|
||||
AggHashTable hashtable;
|
||||
Size tabsize;
|
||||
|
||||
|
@ -596,9 +597,9 @@ build_hash_table(Agg *node)
|
|||
* When called, CurrentMemoryContext should be the per-query context.
|
||||
*/
|
||||
static AggHashEntry
|
||||
lookup_hash_entry(Agg *node, TupleTableSlot *slot)
|
||||
lookup_hash_entry(AggState *aggstate, TupleTableSlot *slot)
|
||||
{
|
||||
AggState *aggstate = node->aggstate;
|
||||
Agg *node = (Agg *) aggstate->ss.ps.plan;
|
||||
AggHashTable hashtable = aggstate->hashtable;
|
||||
MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
||||
HeapTuple tuple = slot->val;
|
||||
|
@ -684,16 +685,14 @@ lookup_hash_entry(Agg *node, TupleTableSlot *slot)
|
|||
* the result tuple.
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecAgg(Agg *node)
|
||||
ExecAgg(AggState *node)
|
||||
{
|
||||
AggState *aggstate = node->aggstate;
|
||||
|
||||
if (aggstate->agg_done)
|
||||
if (node->agg_done)
|
||||
return NULL;
|
||||
|
||||
if (node->aggstrategy == AGG_HASHED)
|
||||
if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
|
||||
{
|
||||
if (!aggstate->table_filled)
|
||||
if (!node->table_filled)
|
||||
agg_fill_hash_table(node);
|
||||
return agg_retrieve_hash_table(node);
|
||||
}
|
||||
|
@ -707,10 +706,10 @@ ExecAgg(Agg *node)
|
|||
* ExecAgg for non-hashed case
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
agg_retrieve_direct(Agg *node)
|
||||
agg_retrieve_direct(AggState *aggstate)
|
||||
{
|
||||
AggState *aggstate;
|
||||
Plan *outerPlan;
|
||||
Agg *node = (Agg *) aggstate->ss.ps.plan;
|
||||
PlanState *outerPlan;
|
||||
ExprContext *econtext;
|
||||
ExprContext *tmpcontext;
|
||||
ProjectionInfo *projInfo;
|
||||
|
@ -726,22 +725,21 @@ agg_retrieve_direct(Agg *node)
|
|||
/*
|
||||
* get state info from node
|
||||
*/
|
||||
aggstate = node->aggstate;
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlan = outerPlanState(aggstate);
|
||||
/* econtext is the per-output-tuple expression context */
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
econtext = aggstate->ss.ps.ps_ExprContext;
|
||||
aggvalues = econtext->ecxt_aggvalues;
|
||||
aggnulls = econtext->ecxt_aggnulls;
|
||||
/* tmpcontext is the per-input-tuple expression context */
|
||||
tmpcontext = aggstate->tmpcontext;
|
||||
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
|
||||
projInfo = aggstate->ss.ps.ps_ProjInfo;
|
||||
peragg = aggstate->peragg;
|
||||
pergroup = aggstate->pergroup;
|
||||
firstSlot = aggstate->csstate.css_ScanTupleSlot;
|
||||
firstSlot = aggstate->ss.ss_ScanTupleSlot;
|
||||
|
||||
/*
|
||||
* We loop retrieving groups until we find one matching
|
||||
* node->plan.qual
|
||||
* aggstate->ss.ps.qual
|
||||
*/
|
||||
do
|
||||
{
|
||||
|
@ -754,7 +752,7 @@ agg_retrieve_direct(Agg *node)
|
|||
*/
|
||||
if (aggstate->grp_firstTuple == NULL)
|
||||
{
|
||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
outerslot = ExecProcNode(outerPlan);
|
||||
if (!TupIsNull(outerslot))
|
||||
{
|
||||
/*
|
||||
|
@ -810,7 +808,7 @@ agg_retrieve_direct(Agg *node)
|
|||
/* Reset per-input-tuple context after each tuple */
|
||||
ResetExprContext(tmpcontext);
|
||||
|
||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
outerslot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(outerslot))
|
||||
{
|
||||
/* no more outer-plan tuples available */
|
||||
|
@ -917,7 +915,7 @@ agg_retrieve_direct(Agg *node)
|
|||
* Otherwise, return the tuple.
|
||||
*/
|
||||
}
|
||||
while (!ExecQual(node->plan.qual, econtext, false));
|
||||
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
|
||||
|
||||
return resultSlot;
|
||||
}
|
||||
|
@ -926,10 +924,9 @@ agg_retrieve_direct(Agg *node)
|
|||
* ExecAgg for hashed case: phase 1, read input and build hash table
|
||||
*/
|
||||
static void
|
||||
agg_fill_hash_table(Agg *node)
|
||||
agg_fill_hash_table(AggState *aggstate)
|
||||
{
|
||||
AggState *aggstate;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
ExprContext *tmpcontext;
|
||||
AggHashEntry entry;
|
||||
TupleTableSlot *outerslot;
|
||||
|
@ -937,8 +934,7 @@ agg_fill_hash_table(Agg *node)
|
|||
/*
|
||||
* get state info from node
|
||||
*/
|
||||
aggstate = node->aggstate;
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlan = outerPlanState(aggstate);
|
||||
/* tmpcontext is the per-input-tuple expression context */
|
||||
tmpcontext = aggstate->tmpcontext;
|
||||
|
||||
|
@ -948,14 +944,14 @@ agg_fill_hash_table(Agg *node)
|
|||
*/
|
||||
for (;;)
|
||||
{
|
||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
outerslot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(outerslot))
|
||||
break;
|
||||
/* set up for advance_aggregates call */
|
||||
tmpcontext->ecxt_scantuple = outerslot;
|
||||
|
||||
/* Find or build hashtable entry for this tuple's group */
|
||||
entry = lookup_hash_entry(node, outerslot);
|
||||
entry = lookup_hash_entry(aggstate, outerslot);
|
||||
|
||||
/* Advance the aggregates */
|
||||
advance_aggregates(aggstate, entry->pergroup);
|
||||
|
@ -974,9 +970,8 @@ agg_fill_hash_table(Agg *node)
|
|||
* ExecAgg for hashed case: phase 2, retrieving groups from hash table
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
agg_retrieve_hash_table(Agg *node)
|
||||
agg_retrieve_hash_table(AggState *aggstate)
|
||||
{
|
||||
AggState *aggstate;
|
||||
ExprContext *econtext;
|
||||
ProjectionInfo *projInfo;
|
||||
Datum *aggvalues;
|
||||
|
@ -992,19 +987,18 @@ agg_retrieve_hash_table(Agg *node)
|
|||
/*
|
||||
* get state info from node
|
||||
*/
|
||||
aggstate = node->aggstate;
|
||||
/* econtext is the per-output-tuple expression context */
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
econtext = aggstate->ss.ps.ps_ExprContext;
|
||||
aggvalues = econtext->ecxt_aggvalues;
|
||||
aggnulls = econtext->ecxt_aggnulls;
|
||||
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
|
||||
projInfo = aggstate->ss.ps.ps_ProjInfo;
|
||||
peragg = aggstate->peragg;
|
||||
hashtable = aggstate->hashtable;
|
||||
firstSlot = aggstate->csstate.css_ScanTupleSlot;
|
||||
firstSlot = aggstate->ss.ss_ScanTupleSlot;
|
||||
|
||||
/*
|
||||
* We loop retrieving groups until we find one matching
|
||||
* node->plan.qual
|
||||
* We loop retrieving groups until we find one satisfying
|
||||
* aggstate->ss.ps.qual
|
||||
*/
|
||||
do
|
||||
{
|
||||
|
@ -1071,7 +1065,7 @@ agg_retrieve_hash_table(Agg *node)
|
|||
* Otherwise, return the tuple.
|
||||
*/
|
||||
}
|
||||
while (!ExecQual(node->plan.qual, econtext, false));
|
||||
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
|
||||
|
||||
return resultSlot;
|
||||
}
|
||||
|
@ -1083,8 +1077,8 @@ agg_retrieve_hash_table(Agg *node)
|
|||
* planner and initializes its outer subtree
|
||||
* -----------------
|
||||
*/
|
||||
bool
|
||||
ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
AggState *
|
||||
ExecInitAgg(Agg *node, EState *estate)
|
||||
{
|
||||
AggState *aggstate;
|
||||
AggStatePerAgg peragg;
|
||||
|
@ -1094,16 +1088,15 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
aggno;
|
||||
List *alist;
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
aggstate = makeNode(AggState);
|
||||
node->aggstate = aggstate;
|
||||
aggstate->ss.ps.plan = (Plan *) node;
|
||||
aggstate->ss.ps.state = estate;
|
||||
|
||||
aggstate->aggs = NIL;
|
||||
aggstate->numaggs = 0;
|
||||
aggstate->eqfunctions = NULL;
|
||||
aggstate->peragg = NULL;
|
||||
aggstate->agg_done = false;
|
||||
|
@ -1111,38 +1104,14 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
aggstate->grp_firstTuple = NULL;
|
||||
aggstate->hashtable = NULL;
|
||||
|
||||
/*
|
||||
* find aggregates in targetlist and quals
|
||||
*
|
||||
* Note: pull_agg_clauses also checks that no aggs contain other agg
|
||||
* calls in their arguments. This would make no sense under SQL
|
||||
* semantics anyway (and it's forbidden by the spec). Because that is
|
||||
* true, we don't need to worry about evaluating the aggs in any
|
||||
* particular order.
|
||||
*/
|
||||
aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
|
||||
pull_agg_clause((Node *) node->plan.qual));
|
||||
aggstate->numaggs = numaggs = length(aggstate->aggs);
|
||||
if (numaggs <= 0)
|
||||
{
|
||||
/*
|
||||
* This is not an error condition: we might be using the Agg node just
|
||||
* to do hash-based grouping. Even in the regular case,
|
||||
* constant-expression simplification could optimize away all of the
|
||||
* Aggrefs in the targetlist and qual. So keep going, but force local
|
||||
* copy of numaggs positive so that palloc()s below don't choke.
|
||||
*/
|
||||
numaggs = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create expression contexts. We need two, one for per-input-tuple
|
||||
* processing and one for per-output-tuple processing. We cheat a little
|
||||
* by using ExecAssignExprContext() to build both.
|
||||
*/
|
||||
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
|
||||
aggstate->tmpcontext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
|
||||
ExecAssignExprContext(estate, &aggstate->ss.ps);
|
||||
aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
|
||||
ExecAssignExprContext(estate, &aggstate->ss.ps);
|
||||
|
||||
/*
|
||||
* We also need a long-lived memory context for holding hashtable
|
||||
|
@ -1163,14 +1132,64 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &aggstate->csstate);
|
||||
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
||||
ExecInitScanTupleSlot(estate, &aggstate->ss);
|
||||
ExecInitResultTupleSlot(estate, &aggstate->ss.ps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*
|
||||
* Note: ExecInitExpr finds Aggrefs for us, and also checks that no aggs
|
||||
* contain other agg calls in their arguments. This would make no sense
|
||||
* under SQL semantics anyway (and it's forbidden by the spec). Because
|
||||
* that is true, we don't need to worry about evaluating the aggs in any
|
||||
* particular order.
|
||||
*/
|
||||
aggstate->ss.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->plan.targetlist,
|
||||
(PlanState *) aggstate);
|
||||
aggstate->ss.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->plan.qual,
|
||||
(PlanState *) aggstate);
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlanState(aggstate) = ExecInitNode(outerPlan, estate);
|
||||
|
||||
/*
|
||||
* initialize source tuple type.
|
||||
*/
|
||||
ExecAssignScanTypeFromOuterPlan(&aggstate->ss);
|
||||
|
||||
/*
|
||||
* Initialize result tuple type and projection info.
|
||||
*/
|
||||
ExecAssignResultTypeFromTL(&aggstate->ss.ps);
|
||||
ExecAssignProjectionInfo(&aggstate->ss.ps);
|
||||
|
||||
/*
|
||||
* get the count of aggregates in targetlist and quals
|
||||
*/
|
||||
numaggs = aggstate->numaggs;
|
||||
Assert(numaggs == length(aggstate->aggs));
|
||||
if (numaggs <= 0)
|
||||
{
|
||||
/*
|
||||
* This is not an error condition: we might be using the Agg node just
|
||||
* to do hash-based grouping. Even in the regular case,
|
||||
* constant-expression simplification could optimize away all of the
|
||||
* Aggrefs in the targetlist and qual. So keep going, but force local
|
||||
* copy of numaggs positive so that palloc()s below don't choke.
|
||||
*/
|
||||
numaggs = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up aggregate-result storage in the output expr context, and also
|
||||
* allocate my private per-agg working storage
|
||||
*/
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
econtext = aggstate->ss.ps.ps_ExprContext;
|
||||
econtext->ecxt_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
|
||||
econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * numaggs);
|
||||
|
||||
|
@ -1179,7 +1198,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
|
||||
if (node->aggstrategy == AGG_HASHED)
|
||||
{
|
||||
build_hash_table(node);
|
||||
build_hash_table(aggstate);
|
||||
aggstate->table_filled = false;
|
||||
}
|
||||
else
|
||||
|
@ -1190,30 +1209,13 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
aggstate->pergroup = pergroup;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlan = outerPlan(node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
|
||||
/*
|
||||
* initialize source tuple type.
|
||||
*/
|
||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
|
||||
|
||||
/*
|
||||
* Initialize result tuple type and projection info.
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &aggstate->csstate.cstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &aggstate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* If we are grouping, precompute fmgr lookup data for inner loop
|
||||
*/
|
||||
if (node->numCols > 0)
|
||||
{
|
||||
aggstate->eqfunctions =
|
||||
execTuplesMatchPrepare(ExecGetScanType(&aggstate->csstate),
|
||||
execTuplesMatchPrepare(ExecGetScanType(&aggstate->ss),
|
||||
node->numCols,
|
||||
node->grpColIdx);
|
||||
}
|
||||
|
@ -1330,7 +1332,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
ReleaseSysCache(aggTuple);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return aggstate;
|
||||
}
|
||||
|
||||
static Datum
|
||||
|
@ -1372,84 +1374,82 @@ ExecCountSlotsAgg(Agg *node)
|
|||
}
|
||||
|
||||
void
|
||||
ExecEndAgg(Agg *node)
|
||||
ExecEndAgg(AggState *node)
|
||||
{
|
||||
AggState *aggstate = node->aggstate;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
int aggno;
|
||||
|
||||
/* Make sure we have closed any open tuplesorts */
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
for (aggno = 0; aggno < node->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
|
||||
AggStatePerAgg peraggstate = &node->peragg[aggno];
|
||||
|
||||
if (peraggstate->sortstate)
|
||||
tuplesort_end(peraggstate->sortstate);
|
||||
}
|
||||
|
||||
ExecFreeProjectionInfo(&aggstate->csstate.cstate);
|
||||
ExecFreeProjectionInfo(&node->ss.ps);
|
||||
|
||||
/*
|
||||
* Free both the expr contexts.
|
||||
*/
|
||||
ExecFreeExprContext(&aggstate->csstate.cstate);
|
||||
aggstate->csstate.cstate.cs_ExprContext = aggstate->tmpcontext;
|
||||
ExecFreeExprContext(&aggstate->csstate.cstate);
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
node->ss.ps.ps_ExprContext = node->tmpcontext;
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
|
||||
MemoryContextDelete(aggstate->aggcontext);
|
||||
MemoryContextDelete(node->aggcontext);
|
||||
|
||||
outerPlan = outerPlan(node);
|
||||
ExecEndNode(outerPlan, (Plan *) node);
|
||||
outerPlan = outerPlanState(node);
|
||||
ExecEndNode(outerPlan);
|
||||
|
||||
/* clean up tuple table */
|
||||
ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
|
||||
if (aggstate->grp_firstTuple != NULL)
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
if (node->grp_firstTuple != NULL)
|
||||
{
|
||||
heap_freetuple(aggstate->grp_firstTuple);
|
||||
aggstate->grp_firstTuple = NULL;
|
||||
heap_freetuple(node->grp_firstTuple);
|
||||
node->grp_firstTuple = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
AggState *aggstate = node->aggstate;
|
||||
ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
ExprContext *econtext = node->ss.ps.ps_ExprContext;
|
||||
int aggno;
|
||||
|
||||
/* Make sure we have closed any open tuplesorts */
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
for (aggno = 0; aggno < node->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
|
||||
AggStatePerAgg peraggstate = &node->peragg[aggno];
|
||||
|
||||
if (peraggstate->sortstate)
|
||||
tuplesort_end(peraggstate->sortstate);
|
||||
peraggstate->sortstate = NULL;
|
||||
}
|
||||
|
||||
aggstate->agg_done = false;
|
||||
if (aggstate->grp_firstTuple != NULL)
|
||||
node->agg_done = false;
|
||||
if (node->grp_firstTuple != NULL)
|
||||
{
|
||||
heap_freetuple(aggstate->grp_firstTuple);
|
||||
aggstate->grp_firstTuple = NULL;
|
||||
heap_freetuple(node->grp_firstTuple);
|
||||
node->grp_firstTuple = NULL;
|
||||
}
|
||||
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * aggstate->numaggs);
|
||||
MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * aggstate->numaggs);
|
||||
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
|
||||
MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * node->numaggs);
|
||||
|
||||
MemoryContextReset(aggstate->aggcontext);
|
||||
MemoryContextReset(node->aggcontext);
|
||||
|
||||
if (node->aggstrategy == AGG_HASHED)
|
||||
if (((Agg *) node->ss.ps.plan)->aggstrategy == AGG_HASHED)
|
||||
{
|
||||
build_hash_table(node);
|
||||
aggstate->table_filled = false;
|
||||
node->table_filled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree->chgParam == NIL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.50 2002/11/13 00:39:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.51 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -62,30 +62,27 @@
|
|||
#include "executor/nodeAppend.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
static bool exec_append_initialize_next(Append *node);
|
||||
static bool exec_append_initialize_next(AppendState *appendstate);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* exec_append_initialize_next
|
||||
*
|
||||
* Sets up the append node state (i.e. the append state node)
|
||||
* for the "next" scan.
|
||||
* Sets up the append state node for the "next" scan.
|
||||
*
|
||||
* Returns t iff there is a "next" scan to process.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static bool
|
||||
exec_append_initialize_next(Append *node)
|
||||
exec_append_initialize_next(AppendState *appendstate)
|
||||
{
|
||||
EState *estate;
|
||||
AppendState *appendstate;
|
||||
int whichplan;
|
||||
|
||||
/*
|
||||
* get information from the append node
|
||||
*/
|
||||
estate = node->plan.state;
|
||||
appendstate = node->appendstate;
|
||||
estate = appendstate->ps.state;
|
||||
whichplan = appendstate->as_whichplan;
|
||||
|
||||
if (whichplan < appendstate->as_firstplan)
|
||||
|
@ -116,7 +113,7 @@ exec_append_initialize_next(Append *node)
|
|||
* If we are controlling the target relation, select the proper
|
||||
* active ResultRelInfo and junk filter for this target.
|
||||
*/
|
||||
if (node->isTarget)
|
||||
if (((Append *) appendstate->ps.plan)->isTarget)
|
||||
{
|
||||
Assert(whichplan < estate->es_num_result_relations);
|
||||
estate->es_result_relation_info =
|
||||
|
@ -132,9 +129,7 @@ exec_append_initialize_next(Append *node)
|
|||
/* ----------------------------------------------------------------
|
||||
* ExecInitAppend
|
||||
*
|
||||
* Begins all of the subscans of the append node, storing the
|
||||
* scan structures in the 'initialized' vector of the append-state
|
||||
* structure.
|
||||
* Begin all of the subscans of the append node.
|
||||
*
|
||||
* (This is potentially wasteful, since the entire result of the
|
||||
* append node may not be scanned, but this way all of the
|
||||
|
@ -146,36 +141,31 @@ exec_append_initialize_next(Append *node)
|
|||
* subplan that corresponds to the target relation being checked.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
||||
AppendState *
|
||||
ExecInitAppend(Append *node, EState *estate)
|
||||
{
|
||||
AppendState *appendstate;
|
||||
AppendState *appendstate = makeNode(AppendState);
|
||||
PlanState **appendplanstates;
|
||||
int nplans;
|
||||
List *appendplans;
|
||||
bool *initialized;
|
||||
int i;
|
||||
Plan *initNode;
|
||||
|
||||
CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
|
||||
|
||||
/*
|
||||
* assign execution state to node and get information for append state
|
||||
* Set up empty vector of subplan states
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
nplans = length(node->appendplans);
|
||||
|
||||
appendplans = node->appendplans;
|
||||
nplans = length(appendplans);
|
||||
|
||||
initialized = (bool *) palloc0(nplans * sizeof(bool));
|
||||
appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
|
||||
|
||||
/*
|
||||
* create new AppendState for our append node
|
||||
*/
|
||||
appendstate = makeNode(AppendState);
|
||||
appendstate->ps.plan = (Plan *) node;
|
||||
appendstate->ps.state = estate;
|
||||
appendstate->appendplans = appendplanstates;
|
||||
appendstate->as_nplans = nplans;
|
||||
appendstate->as_initialized = initialized;
|
||||
|
||||
node->appendstate = appendstate;
|
||||
|
||||
/*
|
||||
* Do we want to scan just one subplan? (Special case for
|
||||
|
@ -212,36 +202,36 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
|||
* append nodes still have Result slots, which hold pointers to
|
||||
* tuples, so we have to initialize them.
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &appendstate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &appendstate->ps);
|
||||
|
||||
/*
|
||||
* call ExecInitNode on each of the plans to be executed and save the
|
||||
* results into the array "initialized". Note we *must* set
|
||||
* results into the array "appendplans". Note we *must* set
|
||||
* estate->es_result_relation_info correctly while we initialize each
|
||||
* sub-plan; ExecAssignResultTypeFromTL depends on that!
|
||||
*/
|
||||
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
|
||||
{
|
||||
appendstate->as_whichplan = i;
|
||||
exec_append_initialize_next(node);
|
||||
exec_append_initialize_next(appendstate);
|
||||
|
||||
initNode = (Plan *) nth(i, appendplans);
|
||||
initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
|
||||
initNode = (Plan *) nth(i, node->appendplans);
|
||||
appendplanstates[i] = ExecInitNode(initNode, estate);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize tuple type
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &appendstate->cstate);
|
||||
appendstate->cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromTL(&appendstate->ps);
|
||||
appendstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
* return the result from the first subplan's initialization
|
||||
*/
|
||||
appendstate->as_whichplan = appendstate->as_firstplan;
|
||||
exec_append_initialize_next(node);
|
||||
exec_append_initialize_next(appendstate);
|
||||
|
||||
return TRUE;
|
||||
return appendstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -264,13 +254,11 @@ ExecCountSlotsAppend(Append *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecProcAppend(Append *node)
|
||||
ExecProcAppend(AppendState *node)
|
||||
{
|
||||
EState *estate;
|
||||
AppendState *appendstate;
|
||||
int whichplan;
|
||||
List *appendplans;
|
||||
Plan *subnode;
|
||||
PlanState *subnode;
|
||||
TupleTableSlot *result;
|
||||
TupleTableSlot *result_slot;
|
||||
ScanDirection direction;
|
||||
|
@ -278,25 +266,20 @@ ExecProcAppend(Append *node)
|
|||
/*
|
||||
* get information from the node
|
||||
*/
|
||||
appendstate = node->appendstate;
|
||||
estate = node->plan.state;
|
||||
estate = node->ps.state;
|
||||
direction = estate->es_direction;
|
||||
appendplans = node->appendplans;
|
||||
whichplan = appendstate->as_whichplan;
|
||||
result_slot = appendstate->cstate.cs_ResultTupleSlot;
|
||||
whichplan = node->as_whichplan;
|
||||
result_slot = node->ps.ps_ResultTupleSlot;
|
||||
|
||||
/*
|
||||
* figure out which subplan we are currently processing
|
||||
*/
|
||||
subnode = (Plan *) nth(whichplan, appendplans);
|
||||
|
||||
if (subnode == NULL)
|
||||
elog(DEBUG1, "ExecProcAppend: subnode is NULL");
|
||||
subnode = node->appendplans[whichplan];
|
||||
|
||||
/*
|
||||
* get a tuple from the subplan
|
||||
*/
|
||||
result = ExecProcNode(subnode, (Plan *) node);
|
||||
result = ExecProcNode(subnode);
|
||||
|
||||
if (!TupIsNull(result))
|
||||
{
|
||||
|
@ -316,9 +299,9 @@ ExecProcAppend(Append *node)
|
|||
* try processing again (recursively)
|
||||
*/
|
||||
if (ScanDirectionIsForward(direction))
|
||||
appendstate->as_whichplan++;
|
||||
node->as_whichplan++;
|
||||
else
|
||||
appendstate->as_whichplan--;
|
||||
node->as_whichplan--;
|
||||
|
||||
/*
|
||||
* return something from next node or an empty slot if all of our
|
||||
|
@ -343,65 +326,56 @@ ExecProcAppend(Append *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndAppend(Append *node)
|
||||
ExecEndAppend(AppendState *node)
|
||||
{
|
||||
EState *estate;
|
||||
AppendState *appendstate;
|
||||
PlanState **appendplans;
|
||||
int nplans;
|
||||
List *appendplans;
|
||||
bool *initialized;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* get information from the node
|
||||
*/
|
||||
appendstate = node->appendstate;
|
||||
estate = node->plan.state;
|
||||
appendplans = node->appendplans;
|
||||
nplans = appendstate->as_nplans;
|
||||
initialized = appendstate->as_initialized;
|
||||
nplans = node->as_nplans;
|
||||
|
||||
/*
|
||||
* shut down each of the subscans
|
||||
* shut down each of the subscans (that we've initialized)
|
||||
*/
|
||||
for (i = 0; i < nplans; i++)
|
||||
{
|
||||
if (initialized[i])
|
||||
ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
|
||||
if (appendplans[i])
|
||||
ExecEndNode(appendplans[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
AppendState *appendstate = node->appendstate;
|
||||
int i;
|
||||
|
||||
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
|
||||
for (i = node->as_firstplan; i <= node->as_lastplan; i++)
|
||||
{
|
||||
Plan *subnode;
|
||||
|
||||
subnode = (Plan *) nth(i, node->appendplans);
|
||||
PlanState *subnode = node->appendplans[i];
|
||||
|
||||
/*
|
||||
* ExecReScan doesn't know about my subplans, so I have to do
|
||||
* changed-parameter signaling myself.
|
||||
*/
|
||||
if (node->plan.chgParam != NULL)
|
||||
SetChangedParamList(subnode, node->plan.chgParam);
|
||||
if (node->ps.chgParam != NIL)
|
||||
SetChangedParamList(subnode, node->ps.chgParam);
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned
|
||||
* by first ExecProcNode.
|
||||
*/
|
||||
if (subnode->chgParam == NULL)
|
||||
if (subnode->chgParam == NIL)
|
||||
{
|
||||
/* make sure estate is correct for this subnode (needed??) */
|
||||
appendstate->as_whichplan = i;
|
||||
node->as_whichplan = i;
|
||||
exec_append_initialize_next(node);
|
||||
ExecReScan(subnode, exprCtxt, (Plan *) node);
|
||||
ExecReScan(subnode, exprCtxt);
|
||||
}
|
||||
}
|
||||
appendstate->as_whichplan = appendstate->as_firstplan;
|
||||
node->as_whichplan = node->as_firstplan;
|
||||
exec_append_initialize_next(node);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.13 2002/12/01 20:27:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.14 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -34,7 +34,7 @@
|
|||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
static TupleTableSlot *FunctionNext(FunctionScan *node);
|
||||
static TupleTableSlot *FunctionNext(FunctionScanState *node);
|
||||
static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -48,24 +48,22 @@ static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
FunctionNext(FunctionScan *node)
|
||||
FunctionNext(FunctionScanState *node)
|
||||
{
|
||||
TupleTableSlot *slot;
|
||||
EState *estate;
|
||||
ScanDirection direction;
|
||||
Tuplestorestate *tuplestorestate;
|
||||
FunctionScanState *scanstate;
|
||||
bool should_free;
|
||||
HeapTuple heapTuple;
|
||||
|
||||
/*
|
||||
* get information from the estate and scan state
|
||||
*/
|
||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
||||
estate = node->scan.plan.state;
|
||||
estate = node->ss.ps.state;
|
||||
direction = estate->es_direction;
|
||||
|
||||
tuplestorestate = scanstate->tuplestorestate;
|
||||
tuplestorestate = node->tuplestorestate;
|
||||
|
||||
/*
|
||||
* If first time through, read all tuples from function and put them
|
||||
|
@ -74,13 +72,13 @@ FunctionNext(FunctionScan *node)
|
|||
*/
|
||||
if (tuplestorestate == NULL)
|
||||
{
|
||||
ExprContext *econtext = scanstate->csstate.cstate.cs_ExprContext;
|
||||
ExprContext *econtext = node->ss.ps.ps_ExprContext;
|
||||
TupleDesc funcTupdesc;
|
||||
|
||||
scanstate->tuplestorestate = tuplestorestate =
|
||||
ExecMakeTableFunctionResult(scanstate->funcexpr,
|
||||
node->tuplestorestate = tuplestorestate =
|
||||
ExecMakeTableFunctionResult(node->funcexpr,
|
||||
econtext,
|
||||
scanstate->tupdesc,
|
||||
node->tupdesc,
|
||||
&funcTupdesc);
|
||||
|
||||
/*
|
||||
|
@ -89,14 +87,14 @@ FunctionNext(FunctionScan *node)
|
|||
* well do it always.
|
||||
*/
|
||||
if (funcTupdesc &&
|
||||
tupledesc_mismatch(scanstate->tupdesc, funcTupdesc))
|
||||
tupledesc_mismatch(node->tupdesc, funcTupdesc))
|
||||
elog(ERROR, "Query-specified return tuple and actual function return tuple do not match");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next tuple from tuplestore. Return NULL if no more tuples.
|
||||
*/
|
||||
slot = scanstate->csstate.css_ScanTupleSlot;
|
||||
slot = node->ss.ss_ScanTupleSlot;
|
||||
if (tuplestorestate)
|
||||
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
||||
ScanDirectionIsForward(direction),
|
||||
|
@ -121,20 +119,20 @@ FunctionNext(FunctionScan *node)
|
|||
*/
|
||||
|
||||
TupleTableSlot *
|
||||
ExecFunctionScan(FunctionScan *node)
|
||||
ExecFunctionScan(FunctionScanState *node)
|
||||
{
|
||||
/*
|
||||
* use FunctionNext as access method
|
||||
*/
|
||||
return ExecScan(&node->scan, (ExecScanAccessMtd) FunctionNext);
|
||||
return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitFunctionScan
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
||||
FunctionScanState *
|
||||
ExecInitFunctionScan(FunctionScan *node, EState *estate)
|
||||
{
|
||||
FunctionScanState *scanstate;
|
||||
RangeTblEntry *rte;
|
||||
|
@ -145,34 +143,40 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* FunctionScan should not have any children.
|
||||
*/
|
||||
Assert(outerPlan((Plan *) node) == NULL);
|
||||
Assert(innerPlan((Plan *) node) == NULL);
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->scan.plan.state = estate;
|
||||
Assert(outerPlan(node) == NULL);
|
||||
Assert(innerPlan(node) == NULL);
|
||||
|
||||
/*
|
||||
* create new ScanState for node
|
||||
*/
|
||||
scanstate = makeNode(FunctionScanState);
|
||||
node->scan.scanstate = &scanstate->csstate;
|
||||
scanstate->ss.ps.plan = (Plan *) node;
|
||||
scanstate->ss.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &scanstate->csstate.cstate);
|
||||
ExecAssignExprContext(estate, &scanstate->ss.ps);
|
||||
|
||||
#define FUNCTIONSCAN_NSLOTS 2
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &scanstate->csstate.cstate);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->csstate);
|
||||
ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
|
||||
ExecInitScanTupleSlot(estate, &scanstate->ss);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*/
|
||||
scanstate->ss.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.targetlist,
|
||||
(PlanState *) scanstate);
|
||||
scanstate->ss.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.qual,
|
||||
(PlanState *) scanstate);
|
||||
|
||||
/*
|
||||
* get info about function
|
||||
|
@ -230,7 +234,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
|||
elog(ERROR, "Unknown kind of return type specified for function");
|
||||
|
||||
scanstate->tupdesc = tupdesc;
|
||||
ExecSetSlotDescriptor(scanstate->csstate.css_ScanTupleSlot,
|
||||
ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
|
||||
tupdesc, false);
|
||||
|
||||
/*
|
||||
|
@ -239,15 +243,15 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
|||
scanstate->tuplestorestate = NULL;
|
||||
scanstate->funcexpr = rte->funcexpr;
|
||||
|
||||
scanstate->csstate.cstate.cs_TupFromTlist = false;
|
||||
scanstate->ss.ps.ps_TupFromTlist = false;
|
||||
|
||||
/*
|
||||
* initialize tuple type
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->csstate.cstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->csstate.cstate);
|
||||
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
|
||||
ExecAssignProjectionInfo(&scanstate->ss.ps);
|
||||
|
||||
return TRUE;
|
||||
return scanstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -265,39 +269,26 @@ ExecCountSlotsFunctionScan(FunctionScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndFunctionScan(FunctionScan *node)
|
||||
ExecEndFunctionScan(FunctionScanState *node)
|
||||
{
|
||||
FunctionScanState *scanstate;
|
||||
EState *estate;
|
||||
|
||||
/*
|
||||
* get information from node
|
||||
*/
|
||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
||||
estate = node->scan.plan.state;
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&scanstate->csstate.cstate);
|
||||
ExecFreeExprContext(&scanstate->csstate.cstate);
|
||||
ExecFreeProjectionInfo(&node->ss.ps);
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(scanstate->csstate.css_ScanTupleSlot);
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
|
||||
/*
|
||||
* Release tuplestore resources
|
||||
*/
|
||||
if (scanstate->tuplestorestate != NULL)
|
||||
tuplestore_end(scanstate->tuplestorestate);
|
||||
scanstate->tuplestorestate = NULL;
|
||||
if (node->tuplestorestate != NULL)
|
||||
tuplestore_end(node->tuplestorestate);
|
||||
node->tuplestorestate = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -307,19 +298,15 @@ ExecEndFunctionScan(FunctionScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecFunctionMarkPos(FunctionScan *node)
|
||||
ExecFunctionMarkPos(FunctionScanState *node)
|
||||
{
|
||||
FunctionScanState *scanstate;
|
||||
|
||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
||||
|
||||
/*
|
||||
* if we haven't materialized yet, just return.
|
||||
*/
|
||||
if (!scanstate->tuplestorestate)
|
||||
if (!node->tuplestorestate)
|
||||
return;
|
||||
|
||||
tuplestore_markpos(scanstate->tuplestorestate);
|
||||
tuplestore_markpos(node->tuplestorestate);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -329,19 +316,15 @@ ExecFunctionMarkPos(FunctionScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecFunctionRestrPos(FunctionScan *node)
|
||||
ExecFunctionRestrPos(FunctionScanState *node)
|
||||
{
|
||||
FunctionScanState *scanstate;
|
||||
|
||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
||||
|
||||
/*
|
||||
* if we haven't materialized yet, just return.
|
||||
*/
|
||||
if (!scanstate->tuplestorestate)
|
||||
if (!node->tuplestorestate)
|
||||
return;
|
||||
|
||||
tuplestore_restorepos(scanstate->tuplestorestate);
|
||||
tuplestore_restorepos(node->tuplestorestate);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -351,21 +334,14 @@ ExecFunctionRestrPos(FunctionScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
FunctionScanState *scanstate;
|
||||
|
||||
/*
|
||||
* get information from node
|
||||
*/
|
||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
||||
|
||||
ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* If we haven't materialized yet, just return.
|
||||
*/
|
||||
if (!scanstate->tuplestorestate)
|
||||
if (!node->tuplestorestate)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -374,13 +350,13 @@ ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
* whether the function expression contains parameters and/or is
|
||||
* marked volatile. FIXME soon.
|
||||
*/
|
||||
if (node->scan.plan.chgParam != NULL)
|
||||
if (node->ss.ps.chgParam != NULL)
|
||||
{
|
||||
tuplestore_end(scanstate->tuplestorestate);
|
||||
scanstate->tuplestorestate = NULL;
|
||||
tuplestore_end(node->tuplestorestate);
|
||||
node->tuplestorestate = NULL;
|
||||
}
|
||||
else
|
||||
tuplestore_rescan(scanstate->tuplestorestate);
|
||||
tuplestore_rescan(node->tuplestorestate);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* locate group boundaries.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.50 2002/11/29 21:39:11 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.51 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -38,12 +38,13 @@
|
|||
* Return one tuple for each group of matching input tuples.
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecGroup(Group *node)
|
||||
ExecGroup(GroupState *node)
|
||||
{
|
||||
GroupState *grpstate;
|
||||
EState *estate;
|
||||
ExprContext *econtext;
|
||||
TupleDesc tupdesc;
|
||||
int numCols;
|
||||
AttrNumber *grpColIdx;
|
||||
HeapTuple outerTuple = NULL;
|
||||
HeapTuple firsttuple;
|
||||
TupleTableSlot *outerslot;
|
||||
|
@ -53,12 +54,13 @@ ExecGroup(Group *node)
|
|||
/*
|
||||
* get state info from node
|
||||
*/
|
||||
grpstate = node->grpstate;
|
||||
if (grpstate->grp_done)
|
||||
if (node->grp_done)
|
||||
return NULL;
|
||||
estate = node->plan.state;
|
||||
econtext = node->grpstate->csstate.cstate.cs_ExprContext;
|
||||
tupdesc = ExecGetScanType(&grpstate->csstate);
|
||||
estate = node->ss.ps.state;
|
||||
econtext = node->ss.ps.ps_ExprContext;
|
||||
tupdesc = ExecGetScanType(&node->ss);
|
||||
numCols = ((Group *) node->ss.ps.plan)->numCols;
|
||||
grpColIdx = ((Group *) node->ss.ps.plan)->grpColIdx;
|
||||
|
||||
/*
|
||||
* We need not call ResetExprContext here because execTuplesMatch will
|
||||
|
@ -67,16 +69,16 @@ ExecGroup(Group *node)
|
|||
|
||||
/* If we don't already have first tuple of group, fetch it */
|
||||
/* this should occur on the first call only */
|
||||
firsttuple = grpstate->grp_firstTuple;
|
||||
firsttuple = node->grp_firstTuple;
|
||||
if (firsttuple == NULL)
|
||||
{
|
||||
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
|
||||
outerslot = ExecProcNode(outerPlanState(node));
|
||||
if (TupIsNull(outerslot))
|
||||
{
|
||||
grpstate->grp_done = TRUE;
|
||||
node->grp_done = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
grpstate->grp_firstTuple = firsttuple =
|
||||
node->grp_firstTuple = firsttuple =
|
||||
heap_copytuple(outerslot->val);
|
||||
}
|
||||
|
||||
|
@ -85,10 +87,10 @@ ExecGroup(Group *node)
|
|||
*/
|
||||
for (;;)
|
||||
{
|
||||
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
|
||||
outerslot = ExecProcNode(outerPlanState(node));
|
||||
if (TupIsNull(outerslot))
|
||||
{
|
||||
grpstate->grp_done = TRUE;
|
||||
node->grp_done = TRUE;
|
||||
outerTuple = NULL;
|
||||
break;
|
||||
}
|
||||
|
@ -100,8 +102,8 @@ ExecGroup(Group *node)
|
|||
*/
|
||||
if (!execTuplesMatch(firsttuple, outerTuple,
|
||||
tupdesc,
|
||||
node->numCols, node->grpColIdx,
|
||||
grpstate->eqfunctions,
|
||||
numCols, grpColIdx,
|
||||
node->eqfunctions,
|
||||
econtext->ecxt_per_tuple_memory))
|
||||
break;
|
||||
}
|
||||
|
@ -111,18 +113,18 @@ ExecGroup(Group *node)
|
|||
* group, and store it in the result tuple slot.
|
||||
*/
|
||||
ExecStoreTuple(firsttuple,
|
||||
grpstate->csstate.css_ScanTupleSlot,
|
||||
node->ss.ss_ScanTupleSlot,
|
||||
InvalidBuffer,
|
||||
false);
|
||||
econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
|
||||
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
||||
econtext->ecxt_scantuple = node->ss.ss_ScanTupleSlot;
|
||||
projInfo = node->ss.ps.ps_ProjInfo;
|
||||
resultSlot = ExecProject(projInfo, NULL);
|
||||
|
||||
/* save first tuple of next group, if we are not done yet */
|
||||
if (!grpstate->grp_done)
|
||||
if (!node->grp_done)
|
||||
{
|
||||
heap_freetuple(firsttuple);
|
||||
grpstate->grp_firstTuple = heap_copytuple(outerTuple);
|
||||
node->grp_firstTuple = heap_copytuple(outerTuple);
|
||||
}
|
||||
|
||||
return resultSlot;
|
||||
|
@ -135,65 +137,69 @@ ExecGroup(Group *node)
|
|||
* planner and initializes its outer subtree
|
||||
* -----------------
|
||||
*/
|
||||
bool
|
||||
ExecInitGroup(Group *node, EState *estate, Plan *parent)
|
||||
GroupState *
|
||||
ExecInitGroup(Group *node, EState *estate)
|
||||
{
|
||||
GroupState *grpstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
grpstate = makeNode(GroupState);
|
||||
node->grpstate = grpstate;
|
||||
grpstate->ss.ps.plan = (Plan *) node;
|
||||
grpstate->ss.ps.state = estate;
|
||||
grpstate->grp_firstTuple = NULL;
|
||||
grpstate->grp_done = FALSE;
|
||||
|
||||
/*
|
||||
* create expression context
|
||||
*/
|
||||
ExecAssignExprContext(estate, &grpstate->csstate.cstate);
|
||||
ExecAssignExprContext(estate, &grpstate->ss.ps);
|
||||
|
||||
#define GROUP_NSLOTS 2
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitScanTupleSlot(estate, &grpstate->csstate);
|
||||
ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
|
||||
ExecInitScanTupleSlot(estate, &grpstate->ss);
|
||||
ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
|
||||
|
||||
/*
|
||||
* initializes child nodes
|
||||
* initialize child expressions
|
||||
*/
|
||||
outerPlan = outerPlan(node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
grpstate->ss.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->plan.targetlist,
|
||||
(PlanState *) grpstate);
|
||||
grpstate->ss.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->plan.qual,
|
||||
(PlanState *) grpstate);
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlanState(grpstate) = ExecInitNode(outerPlan(node), estate);
|
||||
|
||||
/*
|
||||
* initialize tuple type.
|
||||
*/
|
||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
|
||||
ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
|
||||
|
||||
/*
|
||||
* Initialize tuple type for both result and scan. This node does no
|
||||
* projection
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);
|
||||
ExecAssignResultTypeFromTL(&grpstate->ss.ps);
|
||||
ExecAssignProjectionInfo(&grpstate->ss.ps);
|
||||
|
||||
/*
|
||||
* Precompute fmgr lookup data for inner loop
|
||||
*/
|
||||
grpstate->eqfunctions =
|
||||
execTuplesMatchPrepare(ExecGetScanType(&grpstate->csstate),
|
||||
execTuplesMatchPrepare(ExecGetScanType(&grpstate->ss),
|
||||
node->numCols,
|
||||
node->grpColIdx);
|
||||
|
||||
return TRUE;
|
||||
return grpstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -208,43 +214,38 @@ ExecCountSlotsGroup(Group *node)
|
|||
* -----------------------
|
||||
*/
|
||||
void
|
||||
ExecEndGroup(Group *node)
|
||||
ExecEndGroup(GroupState *node)
|
||||
{
|
||||
GroupState *grpstate;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
|
||||
grpstate = node->grpstate;
|
||||
ExecFreeProjectionInfo(&node->ss.ps);
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
|
||||
ExecFreeProjectionInfo(&grpstate->csstate.cstate);
|
||||
ExecFreeExprContext(&grpstate->csstate.cstate);
|
||||
|
||||
outerPlan = outerPlan(node);
|
||||
ExecEndNode(outerPlan, (Plan *) node);
|
||||
outerPlan = outerPlanState(node);
|
||||
ExecEndNode(outerPlan);
|
||||
|
||||
/* clean up tuple table */
|
||||
ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
|
||||
if (grpstate->grp_firstTuple != NULL)
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
if (node->grp_firstTuple != NULL)
|
||||
{
|
||||
heap_freetuple(grpstate->grp_firstTuple);
|
||||
grpstate->grp_firstTuple = NULL;
|
||||
heap_freetuple(node->grp_firstTuple);
|
||||
node->grp_firstTuple = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
GroupState *grpstate = node->grpstate;
|
||||
|
||||
grpstate->grp_done = FALSE;
|
||||
if (grpstate->grp_firstTuple != NULL)
|
||||
node->grp_done = FALSE;
|
||||
if (node->grp_firstTuple != NULL)
|
||||
{
|
||||
heap_freetuple(grpstate->grp_firstTuple);
|
||||
grpstate->grp_firstTuple = NULL;
|
||||
heap_freetuple(node->grp_firstTuple);
|
||||
node->grp_firstTuple = NULL;
|
||||
}
|
||||
|
||||
if (((Plan *) node)->lefttree &&
|
||||
((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree &&
|
||||
((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.68 2002/11/30 00:08:15 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.69 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -40,11 +40,10 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecHash(Hash *node)
|
||||
ExecHash(HashState *node)
|
||||
{
|
||||
EState *estate;
|
||||
HashState *hashstate;
|
||||
Plan *outerNode;
|
||||
PlanState *outerNode;
|
||||
List *hashkeys;
|
||||
HashJoinTable hashtable;
|
||||
TupleTableSlot *slot;
|
||||
|
@ -55,12 +54,10 @@ ExecHash(Hash *node)
|
|||
/*
|
||||
* get state info from node
|
||||
*/
|
||||
estate = node->ps.state;
|
||||
outerNode = outerPlanState(node);
|
||||
|
||||
hashstate = node->hashstate;
|
||||
estate = node->plan.state;
|
||||
outerNode = outerPlan(node);
|
||||
|
||||
hashtable = hashstate->hashtable;
|
||||
hashtable = node->hashtable;
|
||||
if (hashtable == NULL)
|
||||
elog(ERROR, "ExecHash: hash table is NULL.");
|
||||
|
||||
|
@ -79,15 +76,15 @@ ExecHash(Hash *node)
|
|||
/*
|
||||
* set expression context
|
||||
*/
|
||||
hashkeys = node->hashkeys;
|
||||
econtext = hashstate->cstate.cs_ExprContext;
|
||||
hashkeys = ((Hash *) node->ps.plan)->hashkeys;
|
||||
econtext = node->ps.ps_ExprContext;
|
||||
|
||||
/*
|
||||
* get all inner tuples and insert into the hash table (or temp files)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
slot = ExecProcNode(outerNode, (Plan *) node);
|
||||
slot = ExecProcNode(outerNode);
|
||||
if (TupIsNull(slot))
|
||||
break;
|
||||
econtext->ecxt_innertuple = slot;
|
||||
|
@ -108,24 +105,19 @@ ExecHash(Hash *node)
|
|||
* Init routine for Hash node
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitHash(Hash *node, EState *estate, Plan *parent)
|
||||
HashState *
|
||||
ExecInitHash(Hash *node, EState *estate)
|
||||
{
|
||||
HashState *hashstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
SO_printf("ExecInitHash: initializing hash node\n");
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
hashstate = makeNode(HashState);
|
||||
node->hashstate = hashstate;
|
||||
hashstate->ps.plan = (Plan *) node;
|
||||
hashstate->ps.state = estate;
|
||||
hashstate->hashtable = NULL;
|
||||
|
||||
/*
|
||||
|
@ -133,29 +125,38 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
|
|||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &hashstate->cstate);
|
||||
ExecAssignExprContext(estate, &hashstate->ps);
|
||||
|
||||
#define HASH_NSLOTS 1
|
||||
|
||||
/*
|
||||
* initialize our result slot
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &hashstate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &hashstate->ps);
|
||||
|
||||
/*
|
||||
* initializes child nodes
|
||||
* initialize child expressions
|
||||
*/
|
||||
outerPlan = outerPlan(node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
hashstate->ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->plan.targetlist,
|
||||
(PlanState *) hashstate);
|
||||
hashstate->ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->plan.qual,
|
||||
(PlanState *) hashstate);
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate);
|
||||
|
||||
/*
|
||||
* initialize tuple type. no need to initialize projection info
|
||||
* because this node doesn't do projections
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
|
||||
hashstate->cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromOuterPlan(&hashstate->ps);
|
||||
hashstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
return TRUE;
|
||||
return hashstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -173,28 +174,22 @@ ExecCountSlotsHash(Hash *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndHash(Hash *node)
|
||||
ExecEndHash(HashState *node)
|
||||
{
|
||||
HashState *hashstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* get info from the hash state
|
||||
*/
|
||||
hashstate = node->hashstate;
|
||||
PlanState *outerPlan;
|
||||
|
||||
/*
|
||||
* free projection info. no need to free result type info because
|
||||
* that came from the outer plan...
|
||||
*/
|
||||
ExecFreeProjectionInfo(&hashstate->cstate);
|
||||
ExecFreeExprContext(&hashstate->cstate);
|
||||
ExecFreeProjectionInfo(&node->ps);
|
||||
ExecFreeExprContext(&node->ps);
|
||||
|
||||
/*
|
||||
* shut down the subplan
|
||||
*/
|
||||
outerPlan = outerPlan(node);
|
||||
ExecEndNode(outerPlan, (Plan *) node);
|
||||
outerPlan = outerPlanState(node);
|
||||
ExecEndNode(outerPlan);
|
||||
}
|
||||
|
||||
|
||||
|
@ -758,12 +753,12 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
|||
}
|
||||
|
||||
void
|
||||
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanHash(HashState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.42 2002/11/30 00:08:15 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.43 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -22,8 +22,8 @@
|
|||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
||||
HashJoinState *hjstate);
|
||||
static TupleTableSlot *ExecHashJoinOuterGetTuple(PlanState *node,
|
||||
HashJoinState *hjstate);
|
||||
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||
BufFile *file,
|
||||
TupleTableSlot *tupleSlot);
|
||||
|
@ -41,12 +41,11 @@ static int ExecHashJoinNewBatch(HashJoinState *hjstate);
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot * /* return: a tuple or NULL */
|
||||
ExecHashJoin(HashJoin *node)
|
||||
ExecHashJoin(HashJoinState *node)
|
||||
{
|
||||
HashJoinState *hjstate;
|
||||
EState *estate;
|
||||
Plan *outerNode;
|
||||
Hash *hashNode;
|
||||
PlanState *outerNode;
|
||||
HashState *hashNode;
|
||||
List *hjclauses;
|
||||
List *outerkeys;
|
||||
List *joinqual;
|
||||
|
@ -65,37 +64,36 @@ ExecHashJoin(HashJoin *node)
|
|||
/*
|
||||
* get information from HashJoin node
|
||||
*/
|
||||
hjstate = node->hashjoinstate;
|
||||
hjclauses = node->hashclauses;
|
||||
estate = node->join.plan.state;
|
||||
joinqual = node->join.joinqual;
|
||||
otherqual = node->join.plan.qual;
|
||||
hashNode = (Hash *) innerPlan(node);
|
||||
outerNode = outerPlan(node);
|
||||
hashPhaseDone = hjstate->hj_hashdone;
|
||||
estate = node->js.ps.state;
|
||||
joinqual = node->js.joinqual;
|
||||
otherqual = node->js.ps.qual;
|
||||
hashNode = (HashState *) innerPlanState(node);
|
||||
outerNode = outerPlanState(node);
|
||||
hashPhaseDone = node->hj_hashdone;
|
||||
dir = estate->es_direction;
|
||||
|
||||
/*
|
||||
* get information from HashJoin state
|
||||
*/
|
||||
hashtable = hjstate->hj_HashTable;
|
||||
outerkeys = hjstate->hj_OuterHashKeys;
|
||||
econtext = hjstate->jstate.cs_ExprContext;
|
||||
hashtable = node->hj_HashTable;
|
||||
outerkeys = node->hj_OuterHashKeys;
|
||||
econtext = node->js.ps.ps_ExprContext;
|
||||
|
||||
/*
|
||||
* Check to see if we're still projecting out tuples from a previous
|
||||
* join tuple (because there is a function-returning-set in the
|
||||
* projection expressions). If so, try to project another one.
|
||||
*/
|
||||
if (hjstate->jstate.cs_TupFromTlist)
|
||||
if (node->js.ps.ps_TupFromTlist)
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
|
||||
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
return result;
|
||||
/* Done with that source tuple... */
|
||||
hjstate->jstate.cs_TupFromTlist = false;
|
||||
node->js.ps.ps_TupFromTlist = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -116,16 +114,16 @@ ExecHashJoin(HashJoin *node)
|
|||
/*
|
||||
* create the hash table
|
||||
*/
|
||||
hashtable = ExecHashTableCreate(hashNode);
|
||||
hjstate->hj_HashTable = hashtable;
|
||||
hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan);
|
||||
node->hj_HashTable = hashtable;
|
||||
|
||||
/*
|
||||
* execute the Hash node, to build the hash table
|
||||
*/
|
||||
hashNode->hashstate->hashtable = hashtable;
|
||||
innerTupleSlot = ExecProcNode((Plan *) hashNode, (Plan *) node);
|
||||
hashNode->hashtable = hashtable;
|
||||
innerTupleSlot = ExecProcNode((PlanState *) hashNode);
|
||||
}
|
||||
hjstate->hj_hashdone = true;
|
||||
node->hj_hashdone = true;
|
||||
|
||||
/*
|
||||
* Open temp files for outer batches, if needed. Note that file
|
||||
|
@ -140,40 +138,39 @@ ExecHashJoin(HashJoin *node)
|
|||
/*
|
||||
* Now get an outer tuple and probe into the hash table for matches
|
||||
*/
|
||||
outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
|
||||
outerTupleSlot = node->js.ps.ps_OuterTupleSlot;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
* If we don't have an outer tuple, get the next one
|
||||
*/
|
||||
if (hjstate->hj_NeedNewOuter)
|
||||
if (node->hj_NeedNewOuter)
|
||||
{
|
||||
outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,
|
||||
(Plan *) node,
|
||||
hjstate);
|
||||
node);
|
||||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
/*
|
||||
* when the last batch runs out, clean up and exit
|
||||
*/
|
||||
ExecHashTableDestroy(hashtable);
|
||||
hjstate->hj_HashTable = NULL;
|
||||
node->hj_HashTable = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hjstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
|
||||
node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
hjstate->hj_NeedNewOuter = false;
|
||||
hjstate->hj_MatchedOuter = false;
|
||||
node->hj_NeedNewOuter = false;
|
||||
node->hj_MatchedOuter = false;
|
||||
|
||||
/*
|
||||
* now we have an outer tuple, find the corresponding bucket
|
||||
* for this tuple from the hash table
|
||||
*/
|
||||
hjstate->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
||||
node->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
||||
outerkeys);
|
||||
hjstate->hj_CurTuple = NULL;
|
||||
node->hj_CurTuple = NULL;
|
||||
|
||||
/*
|
||||
* Now we've got an outer tuple and the corresponding hash
|
||||
|
@ -182,7 +179,7 @@ ExecHashJoin(HashJoin *node)
|
|||
*/
|
||||
if (hashtable->curbatch == 0)
|
||||
{
|
||||
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
|
||||
int batch = ExecHashJoinGetBatch(node->hj_CurBucketNo,
|
||||
hashtable);
|
||||
|
||||
if (batch > 0)
|
||||
|
@ -196,7 +193,7 @@ ExecHashJoin(HashJoin *node)
|
|||
hashtable->outerBatchSize[batchno]++;
|
||||
ExecHashJoinSaveTuple(outerTupleSlot->val,
|
||||
hashtable->outerBatchFile[batchno]);
|
||||
hjstate->hj_NeedNewOuter = true;
|
||||
node->hj_NeedNewOuter = true;
|
||||
continue; /* loop around for a new outer tuple */
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +204,7 @@ ExecHashJoin(HashJoin *node)
|
|||
*/
|
||||
for (;;)
|
||||
{
|
||||
curtuple = ExecScanHashBucket(hjstate,
|
||||
curtuple = ExecScanHashBucket(node,
|
||||
hjclauses,
|
||||
econtext);
|
||||
if (curtuple == NULL)
|
||||
|
@ -217,7 +214,7 @@ ExecHashJoin(HashJoin *node)
|
|||
* we've got a match, but still need to test non-hashed quals
|
||||
*/
|
||||
inntuple = ExecStoreTuple(curtuple,
|
||||
hjstate->hj_HashTupleSlot,
|
||||
node->hj_HashTupleSlot,
|
||||
InvalidBuffer,
|
||||
false); /* don't pfree this tuple */
|
||||
econtext->ecxt_innertuple = inntuple;
|
||||
|
@ -235,17 +232,17 @@ ExecHashJoin(HashJoin *node)
|
|||
*/
|
||||
if (ExecQual(joinqual, econtext, false))
|
||||
{
|
||||
hjstate->hj_MatchedOuter = true;
|
||||
node->hj_MatchedOuter = true;
|
||||
|
||||
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
|
||||
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
hjstate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -258,10 +255,10 @@ ExecHashJoin(HashJoin *node)
|
|||
* whether to emit a dummy outer-join tuple. If not, loop around
|
||||
* to get a new outer tuple.
|
||||
*/
|
||||
hjstate->hj_NeedNewOuter = true;
|
||||
node->hj_NeedNewOuter = true;
|
||||
|
||||
if (!hjstate->hj_MatchedOuter &&
|
||||
node->join.jointype == JOIN_LEFT)
|
||||
if (!node->hj_MatchedOuter &&
|
||||
node->js.jointype == JOIN_LEFT)
|
||||
{
|
||||
/*
|
||||
* We are doing an outer join and there were no join matches
|
||||
|
@ -269,7 +266,7 @@ ExecHashJoin(HashJoin *node)
|
|||
* nulls for the inner tuple, and return it if it passes the
|
||||
* non-join quals.
|
||||
*/
|
||||
econtext->ecxt_innertuple = hjstate->hj_NullInnerTupleSlot;
|
||||
econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
@ -280,11 +277,11 @@ ExecHashJoin(HashJoin *node)
|
|||
*/
|
||||
TupleTableSlot *result;
|
||||
|
||||
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
hjstate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -299,47 +296,60 @@ ExecHashJoin(HashJoin *node)
|
|||
* Init routine for HashJoin node.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool /* return: initialization status */
|
||||
ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
||||
HashJoinState *
|
||||
ExecInitHashJoin(HashJoin *node, EState *estate)
|
||||
{
|
||||
HashJoinState *hjstate;
|
||||
Plan *outerNode;
|
||||
Hash *hashNode;
|
||||
List *hcl;
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->join.plan.state = estate;
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
hjstate = makeNode(HashJoinState);
|
||||
node->hashjoinstate = hjstate;
|
||||
hjstate->js.ps.plan = (Plan *) node;
|
||||
hjstate->js.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &hjstate->jstate);
|
||||
ExecAssignExprContext(estate, &hjstate->js.ps);
|
||||
|
||||
/*
|
||||
* initializes child nodes
|
||||
* initialize child expressions
|
||||
*/
|
||||
outerNode = outerPlan((Plan *) node);
|
||||
hashNode = (Hash *) innerPlan((Plan *) node);
|
||||
hjstate->js.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->join.plan.targetlist,
|
||||
(PlanState *) hjstate);
|
||||
hjstate->js.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->join.plan.qual,
|
||||
(PlanState *) hjstate);
|
||||
hjstate->js.jointype = node->join.jointype;
|
||||
hjstate->js.joinqual = (List *)
|
||||
ExecInitExpr((Node *) node->join.joinqual,
|
||||
(PlanState *) hjstate);
|
||||
hjstate->hashclauses = (List *)
|
||||
ExecInitExpr((Node *) node->hashclauses,
|
||||
(PlanState *) hjstate);
|
||||
|
||||
ExecInitNode(outerNode, estate, (Plan *) node);
|
||||
ExecInitNode((Plan *) hashNode, estate, (Plan *) node);
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerNode = outerPlan(node);
|
||||
hashNode = (Hash *) innerPlan(node);
|
||||
|
||||
outerPlanState(hjstate) = ExecInitNode(outerNode, estate);
|
||||
innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate);
|
||||
|
||||
#define HASHJOIN_NSLOTS 3
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &hjstate->jstate);
|
||||
ExecInitResultTupleSlot(estate, &hjstate->js.ps);
|
||||
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
|
||||
|
||||
switch (node->join.jointype)
|
||||
|
@ -349,7 +359,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||
case JOIN_LEFT:
|
||||
hjstate->hj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType((Plan *) hashNode));
|
||||
ExecGetTupType(innerPlanState(hjstate)));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecInitHashJoin: unsupported join type %d",
|
||||
|
@ -364,8 +374,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||
* the contents of the hash table. -cim 6/9/91
|
||||
*/
|
||||
{
|
||||
HashState *hashstate = hashNode->hashstate;
|
||||
TupleTableSlot *slot = hashstate->cstate.cs_ResultTupleSlot;
|
||||
HashState *hashstate = (HashState *) innerPlanState(hjstate);
|
||||
TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;
|
||||
|
||||
hjstate->hj_HashTupleSlot = slot;
|
||||
}
|
||||
|
@ -373,11 +383,11 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* initialize tuple type and projection info
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &hjstate->jstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
|
||||
ExecAssignResultTypeFromTL(&hjstate->js.ps);
|
||||
ExecAssignProjectionInfo(&hjstate->js.ps);
|
||||
|
||||
ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
|
||||
ExecGetTupType(outerNode),
|
||||
ExecGetTupType(outerPlanState(hjstate)),
|
||||
false);
|
||||
|
||||
/*
|
||||
|
@ -402,12 +412,12 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||
get_leftop(lfirst(hcl)));
|
||||
}
|
||||
|
||||
hjstate->jstate.cs_OuterTupleSlot = NULL;
|
||||
hjstate->jstate.cs_TupFromTlist = false;
|
||||
hjstate->js.ps.ps_OuterTupleSlot = NULL;
|
||||
hjstate->js.ps.ps_TupFromTlist = false;
|
||||
hjstate->hj_NeedNewOuter = true;
|
||||
hjstate->hj_MatchedOuter = false;
|
||||
|
||||
return TRUE;
|
||||
return hjstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -425,46 +435,35 @@ ExecCountSlotsHashJoin(HashJoin *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndHashJoin(HashJoin *node)
|
||||
ExecEndHashJoin(HashJoinState *node)
|
||||
{
|
||||
HashJoinState *hjstate;
|
||||
|
||||
/*
|
||||
* get info from the HashJoin state
|
||||
*/
|
||||
hjstate = node->hashjoinstate;
|
||||
|
||||
/*
|
||||
* free hash table in case we end plan before all tuples are retrieved
|
||||
*/
|
||||
if (hjstate->hj_HashTable)
|
||||
if (node->hj_HashTable)
|
||||
{
|
||||
ExecHashTableDestroy(hjstate->hj_HashTable);
|
||||
hjstate->hj_HashTable = NULL;
|
||||
ExecHashTableDestroy(node->hj_HashTable);
|
||||
node->hj_HashTable = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(hjstate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&hjstate->jstate);
|
||||
ExecFreeExprContext(&hjstate->jstate);
|
||||
ExecFreeProjectionInfo(&node->js.ps);
|
||||
ExecFreeExprContext(&node->js.ps);
|
||||
|
||||
/*
|
||||
* clean up subtrees
|
||||
*/
|
||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode(outerPlanState(node));
|
||||
ExecEndNode(innerPlanState(node));
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(hjstate->hj_OuterTupleSlot);
|
||||
ExecClearTuple(hjstate->hj_HashTupleSlot);
|
||||
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||
ExecClearTuple(node->hj_OuterTupleSlot);
|
||||
ExecClearTuple(node->hj_HashTupleSlot);
|
||||
|
||||
}
|
||||
|
||||
|
@ -478,7 +477,7 @@ ExecEndHashJoin(HashJoin *node)
|
|||
*/
|
||||
|
||||
static TupleTableSlot *
|
||||
ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
||||
ExecHashJoinOuterGetTuple(PlanState *node, HashJoinState *hjstate)
|
||||
{
|
||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||
int curbatch = hashtable->curbatch;
|
||||
|
@ -486,7 +485,7 @@ ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
|||
|
||||
if (curbatch == 0)
|
||||
{ /* if it is the first pass */
|
||||
slot = ExecProcNode(node, parent);
|
||||
slot = ExecProcNode(node);
|
||||
if (!TupIsNull(slot))
|
||||
return slot;
|
||||
|
||||
|
@ -611,7 +610,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
|||
*/
|
||||
ExecHashTableReset(hashtable, innerBatchSize[newbatch - 1]);
|
||||
|
||||
econtext = hjstate->jstate.cs_ExprContext;
|
||||
econtext = hjstate->js.ps.ps_ExprContext;
|
||||
innerhashkeys = hjstate->hj_InnerHashKeys;
|
||||
|
||||
while ((slot = ExecHashJoinGetSavedTuple(hjstate,
|
||||
|
@ -682,39 +681,37 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
|
|||
}
|
||||
|
||||
void
|
||||
ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
HashJoinState *hjstate = node->hashjoinstate;
|
||||
|
||||
if (!hjstate->hj_hashdone)
|
||||
if (!node->hj_hashdone)
|
||||
return;
|
||||
|
||||
hjstate->hj_hashdone = false;
|
||||
node->hj_hashdone = false;
|
||||
|
||||
/*
|
||||
* Unfortunately, currently we have to destroy hashtable in all
|
||||
* cases...
|
||||
*/
|
||||
if (hjstate->hj_HashTable)
|
||||
if (node->hj_HashTable)
|
||||
{
|
||||
ExecHashTableDestroy(hjstate->hj_HashTable);
|
||||
hjstate->hj_HashTable = NULL;
|
||||
ExecHashTableDestroy(node->hj_HashTable);
|
||||
node->hj_HashTable = NULL;
|
||||
}
|
||||
|
||||
hjstate->hj_CurBucketNo = 0;
|
||||
hjstate->hj_CurTuple = (HashJoinTuple) NULL;
|
||||
node->hj_CurBucketNo = 0;
|
||||
node->hj_CurTuple = (HashJoinTuple) NULL;
|
||||
|
||||
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
|
||||
hjstate->jstate.cs_TupFromTlist = false;
|
||||
hjstate->hj_NeedNewOuter = true;
|
||||
hjstate->hj_MatchedOuter = false;
|
||||
node->js.ps.ps_OuterTupleSlot = (TupleTableSlot *) NULL;
|
||||
node->js.ps.ps_TupFromTlist = false;
|
||||
node->hj_NeedNewOuter = true;
|
||||
node->hj_MatchedOuter = false;
|
||||
|
||||
/*
|
||||
* if chgParam of subnodes is not null then plans will be re-scanned
|
||||
* by first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((Plan *) node)->righttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->righttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
if (((PlanState *) node)->righttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->righttree, exprCtxt);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.71 2002/09/04 20:31:18 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.72 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -40,7 +40,7 @@
|
|||
#define LEFT_OP 1
|
||||
#define RIGHT_OP 2
|
||||
|
||||
static TupleTableSlot *IndexNext(IndexScan *node);
|
||||
static TupleTableSlot *IndexNext(IndexScanState *node);
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* IndexNext
|
||||
|
@ -65,15 +65,14 @@ static TupleTableSlot *IndexNext(IndexScan *node);
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
IndexNext(IndexScan *node)
|
||||
IndexNext(IndexScanState *node)
|
||||
{
|
||||
EState *estate;
|
||||
CommonScanState *scanstate;
|
||||
IndexScanState *indexstate;
|
||||
ExprContext *econtext;
|
||||
ScanDirection direction;
|
||||
IndexScanDescPtr scanDescs;
|
||||
IndexScanDesc scandesc;
|
||||
Index scanrelid;
|
||||
HeapTuple tuple;
|
||||
TupleTableSlot *slot;
|
||||
int numIndices;
|
||||
|
@ -83,21 +82,20 @@ IndexNext(IndexScan *node)
|
|||
/*
|
||||
* extract necessary information from index scan node
|
||||
*/
|
||||
estate = node->scan.plan.state;
|
||||
estate = node->ss.ps.state;
|
||||
direction = estate->es_direction;
|
||||
if (ScanDirectionIsBackward(node->indxorderdir))
|
||||
if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
|
||||
{
|
||||
if (ScanDirectionIsForward(direction))
|
||||
direction = BackwardScanDirection;
|
||||
else if (ScanDirectionIsBackward(direction))
|
||||
direction = ForwardScanDirection;
|
||||
}
|
||||
scanstate = node->scan.scanstate;
|
||||
indexstate = node->indxstate;
|
||||
scanDescs = indexstate->iss_ScanDescs;
|
||||
numIndices = indexstate->iss_NumIndices;
|
||||
econtext = scanstate->cstate.cs_ExprContext;
|
||||
slot = scanstate->css_ScanTupleSlot;
|
||||
scanDescs = node->iss_ScanDescs;
|
||||
numIndices = node->iss_NumIndices;
|
||||
econtext = node->ss.ps.ps_ExprContext;
|
||||
slot = node->ss.ss_ScanTupleSlot;
|
||||
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||
|
@ -106,15 +104,15 @@ IndexNext(IndexScan *node)
|
|||
* switching in Init/ReScan plan...
|
||||
*/
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||
{
|
||||
List *qual;
|
||||
|
||||
ExecClearTuple(slot);
|
||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
||||
if (estate->es_evTupleNull[scanrelid - 1])
|
||||
return slot; /* return empty slot */
|
||||
|
||||
ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
|
||||
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
|
||||
slot, InvalidBuffer, false);
|
||||
|
||||
/* Does the tuple meet any of the OR'd indxqual conditions? */
|
||||
|
@ -131,7 +129,7 @@ IndexNext(IndexScan *node)
|
|||
slot->val = NULL;
|
||||
|
||||
/* Flag for the next call that no more tuples */
|
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
||||
estate->es_evTupleNull[scanrelid - 1] = true;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
@ -144,24 +142,24 @@ IndexNext(IndexScan *node)
|
|||
bBackward = ScanDirectionIsBackward(direction);
|
||||
if (bBackward)
|
||||
{
|
||||
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
|
||||
indexNumber = numIndices - node->iss_IndexPtr - 1;
|
||||
if (indexNumber < 0)
|
||||
{
|
||||
indexNumber = 0;
|
||||
indexstate->iss_IndexPtr = numIndices - 1;
|
||||
node->iss_IndexPtr = numIndices - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
|
||||
if ((indexNumber = node->iss_IndexPtr) < 0)
|
||||
{
|
||||
indexNumber = 0;
|
||||
indexstate->iss_IndexPtr = 0;
|
||||
node->iss_IndexPtr = 0;
|
||||
}
|
||||
}
|
||||
while (indexNumber < numIndices)
|
||||
{
|
||||
scandesc = scanDescs[indexstate->iss_IndexPtr];
|
||||
scandesc = scanDescs[node->iss_IndexPtr];
|
||||
while ((tuple = index_getnext(scandesc, direction)) != NULL)
|
||||
{
|
||||
/*
|
||||
|
@ -181,7 +179,7 @@ IndexNext(IndexScan *node)
|
|||
* We do this by passing the tuple through ExecQual and
|
||||
* checking for failure with all previous qualifications.
|
||||
*/
|
||||
if (indexstate->iss_IndexPtr > 0)
|
||||
if (node->iss_IndexPtr > 0)
|
||||
{
|
||||
bool prev_matches = false;
|
||||
int prev_index;
|
||||
|
@ -191,7 +189,7 @@ IndexNext(IndexScan *node)
|
|||
ResetExprContext(econtext);
|
||||
qual = node->indxqualorig;
|
||||
for (prev_index = 0;
|
||||
prev_index < indexstate->iss_IndexPtr;
|
||||
prev_index < node->iss_IndexPtr;
|
||||
prev_index++)
|
||||
{
|
||||
if (ExecQual((List *) lfirst(qual), econtext, false))
|
||||
|
@ -216,9 +214,9 @@ IndexNext(IndexScan *node)
|
|||
{
|
||||
indexNumber++;
|
||||
if (bBackward)
|
||||
indexstate->iss_IndexPtr--;
|
||||
node->iss_IndexPtr--;
|
||||
else
|
||||
indexstate->iss_IndexPtr++;
|
||||
node->iss_IndexPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,21 +249,19 @@ IndexNext(IndexScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecIndexScan(IndexScan *node)
|
||||
ExecIndexScan(IndexScanState *node)
|
||||
{
|
||||
IndexScanState *indexstate = node->indxstate;
|
||||
|
||||
/*
|
||||
* If we have runtime keys and they've not already been set up, do it
|
||||
* now.
|
||||
*/
|
||||
if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
|
||||
ExecReScan((Plan *) node, NULL, NULL);
|
||||
if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady)
|
||||
ExecReScan((PlanState *) node, NULL);
|
||||
|
||||
/*
|
||||
* use IndexNext as access method
|
||||
*/
|
||||
return ExecScan(&node->scan, (ExecScanAccessMtd) IndexNext);
|
||||
return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -280,28 +276,27 @@ ExecIndexScan(IndexScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
EState *estate;
|
||||
IndexScanState *indexstate;
|
||||
ExprContext *econtext;
|
||||
int numIndices;
|
||||
IndexScanDescPtr scanDescs;
|
||||
ScanKey *scanKeys;
|
||||
int **runtimeKeyInfo;
|
||||
int *numScanKeys;
|
||||
Index scanrelid;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
estate = node->scan.plan.state;
|
||||
indexstate = node->indxstate;
|
||||
econtext = indexstate->iss_RuntimeContext; /* context for runtime
|
||||
* keys */
|
||||
numIndices = indexstate->iss_NumIndices;
|
||||
scanDescs = indexstate->iss_ScanDescs;
|
||||
scanKeys = indexstate->iss_ScanKeys;
|
||||
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
|
||||
numScanKeys = indexstate->iss_NumScanKeys;
|
||||
estate = node->ss.ps.state;
|
||||
econtext = node->iss_RuntimeContext; /* context for runtime keys */
|
||||
numIndices = node->iss_NumIndices;
|
||||
scanDescs = node->iss_ScanDescs;
|
||||
scanKeys = node->iss_ScanKeys;
|
||||
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
|
||||
numScanKeys = node->iss_NumScanKeys;
|
||||
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||
|
||||
if (econtext)
|
||||
{
|
||||
|
@ -315,7 +310,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
ExprContext *stdecontext;
|
||||
|
||||
econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
|
||||
stdecontext = node->scan.scanstate->cstate.cs_ExprContext;
|
||||
stdecontext = node->ss.ps.ps_ExprContext;
|
||||
stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
|
||||
}
|
||||
|
||||
|
@ -392,22 +387,22 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
}
|
||||
}
|
||||
|
||||
indexstate->iss_RuntimeKeysReady = true;
|
||||
node->iss_RuntimeKeysReady = true;
|
||||
}
|
||||
|
||||
/* If this is re-scanning of PlanQual ... */
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||
{
|
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
|
||||
estate->es_evTupleNull[scanrelid - 1] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* reset index scans */
|
||||
if (ScanDirectionIsBackward(node->indxorderdir))
|
||||
indexstate->iss_IndexPtr = numIndices;
|
||||
if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
|
||||
node->iss_IndexPtr = numIndices;
|
||||
else
|
||||
indexstate->iss_IndexPtr = -1;
|
||||
node->iss_IndexPtr = -1;
|
||||
|
||||
for (i = 0; i < numIndices; i++)
|
||||
{
|
||||
|
@ -427,13 +422,10 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndIndexScan(IndexScan *node)
|
||||
ExecEndIndexScan(IndexScanState *node)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
IndexScanState *indexstate;
|
||||
int **runtimeKeyInfo;
|
||||
ScanKey *scanKeys;
|
||||
List *indxqual;
|
||||
int *numScanKeys;
|
||||
int numIndices;
|
||||
Relation relation;
|
||||
|
@ -441,32 +433,25 @@ ExecEndIndexScan(IndexScan *node)
|
|||
IndexScanDescPtr indexScanDescs;
|
||||
int i;
|
||||
|
||||
scanstate = node->scan.scanstate;
|
||||
indexstate = node->indxstate;
|
||||
indxqual = node->indxqual;
|
||||
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
|
||||
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
|
||||
|
||||
/*
|
||||
* extract information from the node
|
||||
*/
|
||||
numIndices = indexstate->iss_NumIndices;
|
||||
scanKeys = indexstate->iss_ScanKeys;
|
||||
numScanKeys = indexstate->iss_NumScanKeys;
|
||||
indexRelationDescs = indexstate->iss_RelationDescs;
|
||||
indexScanDescs = indexstate->iss_ScanDescs;
|
||||
relation = scanstate->css_currentRelation;
|
||||
numIndices = node->iss_NumIndices;
|
||||
scanKeys = node->iss_ScanKeys;
|
||||
numScanKeys = node->iss_NumScanKeys;
|
||||
indexRelationDescs = node->iss_RelationDescs;
|
||||
indexScanDescs = node->iss_ScanDescs;
|
||||
relation = node->ss.ss_currentRelation;
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
||||
ExecFreeExprContext(&scanstate->cstate);
|
||||
if (indexstate->iss_RuntimeContext)
|
||||
FreeExprContext(indexstate->iss_RuntimeContext);
|
||||
ExecFreeProjectionInfo(&node->ss.ps);
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
if (node->iss_RuntimeContext)
|
||||
FreeExprContext(node->iss_RuntimeContext);
|
||||
|
||||
/*
|
||||
* close the index relations
|
||||
|
@ -514,12 +499,11 @@ ExecEndIndexScan(IndexScan *node)
|
|||
/*
|
||||
* clear out tuple table slots
|
||||
*/
|
||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||||
pfree(scanstate);
|
||||
pfree(indexstate->iss_RelationDescs);
|
||||
pfree(indexstate->iss_ScanDescs);
|
||||
pfree(indexstate);
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
pfree(node->iss_RelationDescs);
|
||||
pfree(node->iss_ScanDescs);
|
||||
pfree(node);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -531,21 +515,16 @@ ExecEndIndexScan(IndexScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecIndexMarkPos(IndexScan *node)
|
||||
ExecIndexMarkPos(IndexScanState *node)
|
||||
{
|
||||
IndexScanState *indexstate;
|
||||
IndexScanDescPtr indexScanDescs;
|
||||
IndexScanDesc scanDesc;
|
||||
int indexPtr;
|
||||
|
||||
indexstate = node->indxstate;
|
||||
indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;
|
||||
indexScanDescs = indexstate->iss_ScanDescs;
|
||||
indexPtr = node->iss_MarkIndexPtr = node->iss_IndexPtr;
|
||||
indexScanDescs = node->iss_ScanDescs;
|
||||
scanDesc = indexScanDescs[indexPtr];
|
||||
|
||||
#ifdef NOT_USED
|
||||
IndexScanMarkPosition(scanDesc);
|
||||
#endif
|
||||
index_markpos(scanDesc);
|
||||
}
|
||||
|
||||
|
@ -560,21 +539,16 @@ ExecIndexMarkPos(IndexScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecIndexRestrPos(IndexScan *node)
|
||||
ExecIndexRestrPos(IndexScanState *node)
|
||||
{
|
||||
IndexScanState *indexstate;
|
||||
IndexScanDescPtr indexScanDescs;
|
||||
IndexScanDesc scanDesc;
|
||||
int indexPtr;
|
||||
|
||||
indexstate = node->indxstate;
|
||||
indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;
|
||||
indexScanDescs = indexstate->iss_ScanDescs;
|
||||
indexPtr = node->iss_IndexPtr = node->iss_MarkIndexPtr;
|
||||
indexScanDescs = node->iss_ScanDescs;
|
||||
scanDesc = indexScanDescs[indexPtr];
|
||||
|
||||
#ifdef NOT_USED
|
||||
IndexScanRestorePosition(scanDesc);
|
||||
#endif
|
||||
index_restrpos(scanDesc);
|
||||
}
|
||||
|
||||
|
@ -597,11 +571,10 @@ ExecIndexRestrPos(IndexScan *node)
|
|||
* estate: the execution state initialized in InitPlan.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
IndexScanState *
|
||||
ExecInitIndexScan(IndexScan *node, EState *estate)
|
||||
{
|
||||
IndexScanState *indexstate;
|
||||
CommonScanState *scanstate;
|
||||
List *indxqual;
|
||||
List *indxid;
|
||||
List *listscan;
|
||||
|
@ -620,45 +593,52 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
Relation currentRelation;
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
* create state structure
|
||||
*/
|
||||
node->scan.plan.state = estate;
|
||||
|
||||
/*
|
||||
* Part 1) initialize scan state
|
||||
*
|
||||
* create new CommonScanState for node
|
||||
*/
|
||||
scanstate = makeNode(CommonScanState);
|
||||
node->scan.scanstate = scanstate;
|
||||
indexstate = makeNode(IndexScanState);
|
||||
indexstate->ss.ps.plan = (Plan *) node;
|
||||
indexstate->ss.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||
ExecAssignExprContext(estate, &indexstate->ss.ps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*/
|
||||
indexstate->ss.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.targetlist,
|
||||
(PlanState *) indexstate);
|
||||
indexstate->ss.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.qual,
|
||||
(PlanState *) indexstate);
|
||||
indexstate->indxqual = (List *)
|
||||
ExecInitExpr((Node *) node->indxqual,
|
||||
(PlanState *) indexstate);
|
||||
indexstate->indxqualorig = (List *)
|
||||
ExecInitExpr((Node *) node->indxqualorig,
|
||||
(PlanState *) indexstate);
|
||||
|
||||
#define INDEXSCAN_NSLOTS 2
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||||
ExecInitScanTupleSlot(estate, scanstate);
|
||||
ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
|
||||
ExecInitScanTupleSlot(estate, &indexstate->ss);
|
||||
|
||||
/*
|
||||
* initialize projection info. result type comes from scan desc
|
||||
* below..
|
||||
*/
|
||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
||||
ExecAssignProjectionInfo(&indexstate->ss.ps);
|
||||
|
||||
/*
|
||||
* Part 2) initialize index scan state
|
||||
*
|
||||
* create new IndexScanState for node
|
||||
* Initialize index-specific scan state
|
||||
*/
|
||||
indexstate = makeNode(IndexScanState);
|
||||
indexstate->iss_NumIndices = 0;
|
||||
indexstate->iss_IndexPtr = -1;
|
||||
indexstate->iss_ScanKeys = NULL;
|
||||
|
@ -669,8 +649,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
indexstate->iss_RelationDescs = NULL;
|
||||
indexstate->iss_ScanDescs = NULL;
|
||||
|
||||
node->indxstate = indexstate;
|
||||
|
||||
/*
|
||||
* get the index node information
|
||||
*/
|
||||
|
@ -836,7 +814,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
{
|
||||
/* treat Param like a constant */
|
||||
scanvalue = ExecEvalParam((Param *) leftop,
|
||||
scanstate->cstate.cs_ExprContext,
|
||||
indexstate->ss.ps.ps_ExprContext,
|
||||
&isnull);
|
||||
if (isnull)
|
||||
flags |= SK_ISNULL;
|
||||
|
@ -911,7 +889,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
{
|
||||
/* treat Param like a constant */
|
||||
scanvalue = ExecEvalParam((Param *) rightop,
|
||||
scanstate->cstate.cs_ExprContext,
|
||||
indexstate->ss.ps.ps_ExprContext,
|
||||
&isnull);
|
||||
if (isnull)
|
||||
flags |= SK_ISNULL;
|
||||
|
@ -976,12 +954,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
*/
|
||||
if (have_runtime_keys)
|
||||
{
|
||||
ExprContext *stdecontext = scanstate->cstate.cs_ExprContext;
|
||||
ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
|
||||
|
||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||
ExecAssignExprContext(estate, &indexstate->ss.ps);
|
||||
indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
|
||||
indexstate->iss_RuntimeContext = scanstate->cstate.cs_ExprContext;
|
||||
scanstate->cstate.cs_ExprContext = stdecontext;
|
||||
indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
|
||||
indexstate->ss.ps.ps_ExprContext = stdecontext;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1008,14 +986,14 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
if (!RelationGetForm(currentRelation)->relhasindex)
|
||||
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
|
||||
|
||||
scanstate->css_currentRelation = currentRelation;
|
||||
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
|
||||
indexstate->ss.ss_currentRelation = currentRelation;
|
||||
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
||||
|
||||
/*
|
||||
* get the scan type from the relation descriptor.
|
||||
*/
|
||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
||||
ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
|
||||
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
|
||||
|
||||
/*
|
||||
* open the index relations and initialize relation and scan
|
||||
|
@ -1043,7 +1021,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* all done.
|
||||
*/
|
||||
return TRUE;
|
||||
return indexstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.11 2002/11/22 22:10:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.12 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -24,7 +24,7 @@
|
|||
#include "executor/executor.h"
|
||||
#include "executor/nodeLimit.h"
|
||||
|
||||
static void recompute_limits(Limit *node);
|
||||
static void recompute_limits(LimitState *node);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -35,26 +35,24 @@ static void recompute_limits(Limit *node);
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot * /* return: a tuple or NULL */
|
||||
ExecLimit(Limit *node)
|
||||
ExecLimit(LimitState *node)
|
||||
{
|
||||
LimitState *limitstate;
|
||||
ScanDirection direction;
|
||||
TupleTableSlot *resultTupleSlot;
|
||||
TupleTableSlot *slot;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
|
||||
/*
|
||||
* get information from the node
|
||||
*/
|
||||
limitstate = node->limitstate;
|
||||
direction = node->plan.state->es_direction;
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot;
|
||||
direction = node->ps.state->es_direction;
|
||||
outerPlan = outerPlanState(node);
|
||||
resultTupleSlot = node->ps.ps_ResultTupleSlot;
|
||||
|
||||
/*
|
||||
* The main logic is a simple state machine.
|
||||
*/
|
||||
switch (limitstate->lstate)
|
||||
switch (node->lstate)
|
||||
{
|
||||
case LIMIT_INITIAL:
|
||||
/*
|
||||
|
@ -71,9 +69,9 @@ ExecLimit(Limit *node)
|
|||
/*
|
||||
* Check for empty window; if so, treat like empty subplan.
|
||||
*/
|
||||
if (limitstate->count <= 0 && !limitstate->noCount)
|
||||
if (node->count <= 0 && !node->noCount)
|
||||
{
|
||||
limitstate->lstate = LIMIT_EMPTY;
|
||||
node->lstate = LIMIT_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
|
@ -81,24 +79,24 @@ ExecLimit(Limit *node)
|
|||
*/
|
||||
for (;;)
|
||||
{
|
||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
slot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(slot))
|
||||
{
|
||||
/*
|
||||
* The subplan returns too few tuples for us to produce
|
||||
* any output at all.
|
||||
*/
|
||||
limitstate->lstate = LIMIT_EMPTY;
|
||||
node->lstate = LIMIT_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
limitstate->subSlot = slot;
|
||||
if (++limitstate->position > limitstate->offset)
|
||||
node->subSlot = slot;
|
||||
if (++node->position > node->offset)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Okay, we have the first tuple of the window.
|
||||
*/
|
||||
limitstate->lstate = LIMIT_INWINDOW;
|
||||
node->lstate = LIMIT_INWINDOW;
|
||||
break;
|
||||
|
||||
case LIMIT_EMPTY:
|
||||
|
@ -117,23 +115,23 @@ ExecLimit(Limit *node)
|
|||
* advancing the subplan or the position variable; but
|
||||
* change the state machine state to record having done so.
|
||||
*/
|
||||
if (!limitstate->noCount &&
|
||||
limitstate->position >= limitstate->offset + limitstate->count)
|
||||
if (!node->noCount &&
|
||||
node->position >= node->offset + node->count)
|
||||
{
|
||||
limitstate->lstate = LIMIT_WINDOWEND;
|
||||
node->lstate = LIMIT_WINDOWEND;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Get next tuple from subplan, if any.
|
||||
*/
|
||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
slot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(slot))
|
||||
{
|
||||
limitstate->lstate = LIMIT_SUBPLANEOF;
|
||||
node->lstate = LIMIT_SUBPLANEOF;
|
||||
return NULL;
|
||||
}
|
||||
limitstate->subSlot = slot;
|
||||
limitstate->position++;
|
||||
node->subSlot = slot;
|
||||
node->position++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -141,19 +139,19 @@ ExecLimit(Limit *node)
|
|||
* Backwards scan, so check for stepping off start of window.
|
||||
* As above, change only state-machine status if so.
|
||||
*/
|
||||
if (limitstate->position <= limitstate->offset + 1)
|
||||
if (node->position <= node->offset + 1)
|
||||
{
|
||||
limitstate->lstate = LIMIT_WINDOWSTART;
|
||||
node->lstate = LIMIT_WINDOWSTART;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Get previous tuple from subplan; there should be one!
|
||||
*/
|
||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
slot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(slot))
|
||||
elog(ERROR, "ExecLimit: subplan failed to run backwards");
|
||||
limitstate->subSlot = slot;
|
||||
limitstate->position--;
|
||||
node->subSlot = slot;
|
||||
node->position--;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -164,11 +162,11 @@ ExecLimit(Limit *node)
|
|||
* Backing up from subplan EOF, so re-fetch previous tuple;
|
||||
* there should be one! Note previous tuple must be in window.
|
||||
*/
|
||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
slot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(slot))
|
||||
elog(ERROR, "ExecLimit: subplan failed to run backwards");
|
||||
limitstate->subSlot = slot;
|
||||
limitstate->lstate = LIMIT_INWINDOW;
|
||||
node->subSlot = slot;
|
||||
node->lstate = LIMIT_INWINDOW;
|
||||
/* position does not change 'cause we didn't advance it before */
|
||||
break;
|
||||
|
||||
|
@ -179,8 +177,8 @@ ExecLimit(Limit *node)
|
|||
* Backing up from window end: simply re-return the last
|
||||
* tuple fetched from the subplan.
|
||||
*/
|
||||
slot = limitstate->subSlot;
|
||||
limitstate->lstate = LIMIT_INWINDOW;
|
||||
slot = node->subSlot;
|
||||
node->lstate = LIMIT_INWINDOW;
|
||||
/* position does not change 'cause we didn't advance it before */
|
||||
break;
|
||||
|
||||
|
@ -191,14 +189,14 @@ ExecLimit(Limit *node)
|
|||
* Advancing after having backed off window start: simply
|
||||
* re-return the last tuple fetched from the subplan.
|
||||
*/
|
||||
slot = limitstate->subSlot;
|
||||
limitstate->lstate = LIMIT_INWINDOW;
|
||||
slot = node->subSlot;
|
||||
node->lstate = LIMIT_INWINDOW;
|
||||
/* position does not change 'cause we didn't change it before */
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "ExecLimit: impossible state %d",
|
||||
(int) limitstate->lstate);
|
||||
(int) node->lstate);
|
||||
slot = NULL; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
@ -220,55 +218,54 @@ ExecLimit(Limit *node)
|
|||
* This is also a handy place to reset the current-position state info.
|
||||
*/
|
||||
static void
|
||||
recompute_limits(Limit *node)
|
||||
recompute_limits(LimitState *node)
|
||||
{
|
||||
LimitState *limitstate = node->limitstate;
|
||||
ExprContext *econtext = limitstate->cstate.cs_ExprContext;
|
||||
ExprContext *econtext = node->ps.ps_ExprContext;
|
||||
bool isNull;
|
||||
|
||||
if (node->limitOffset)
|
||||
{
|
||||
limitstate->offset =
|
||||
node->offset =
|
||||
DatumGetInt32(ExecEvalExprSwitchContext(node->limitOffset,
|
||||
econtext,
|
||||
&isNull,
|
||||
NULL));
|
||||
/* Interpret NULL offset as no offset */
|
||||
if (isNull)
|
||||
limitstate->offset = 0;
|
||||
else if (limitstate->offset < 0)
|
||||
limitstate->offset = 0;
|
||||
node->offset = 0;
|
||||
else if (node->offset < 0)
|
||||
node->offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No OFFSET supplied */
|
||||
limitstate->offset = 0;
|
||||
node->offset = 0;
|
||||
}
|
||||
|
||||
if (node->limitCount)
|
||||
{
|
||||
limitstate->noCount = false;
|
||||
limitstate->count =
|
||||
node->noCount = false;
|
||||
node->count =
|
||||
DatumGetInt32(ExecEvalExprSwitchContext(node->limitCount,
|
||||
econtext,
|
||||
&isNull,
|
||||
NULL));
|
||||
/* Interpret NULL count as no count (LIMIT ALL) */
|
||||
if (isNull)
|
||||
limitstate->noCount = true;
|
||||
else if (limitstate->count < 0)
|
||||
limitstate->count = 0;
|
||||
node->noCount = true;
|
||||
else if (node->count < 0)
|
||||
node->count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No COUNT supplied */
|
||||
limitstate->count = 0;
|
||||
limitstate->noCount = true;
|
||||
node->count = 0;
|
||||
node->noCount = true;
|
||||
}
|
||||
|
||||
/* Reset position to start-of-scan */
|
||||
limitstate->position = 0;
|
||||
limitstate->subSlot = NULL;
|
||||
node->position = 0;
|
||||
node->subSlot = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -278,22 +275,19 @@ recompute_limits(Limit *node)
|
|||
* the node's subplan.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool /* return: initialization status */
|
||||
ExecInitLimit(Limit *node, EState *estate, Plan *parent)
|
||||
LimitState *
|
||||
ExecInitLimit(Limit *node, EState *estate)
|
||||
{
|
||||
LimitState *limitstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new LimitState for node
|
||||
* create state structure
|
||||
*/
|
||||
limitstate = makeNode(LimitState);
|
||||
node->limitstate = limitstate;
|
||||
limitstate->ps.plan = (Plan *) node;
|
||||
limitstate->ps.state = estate;
|
||||
|
||||
limitstate->lstate = LIMIT_INITIAL;
|
||||
|
||||
/*
|
||||
|
@ -302,29 +296,37 @@ ExecInitLimit(Limit *node, EState *estate, Plan *parent)
|
|||
* Limit nodes never call ExecQual or ExecProject, but they need an
|
||||
* exprcontext anyway to evaluate the limit/offset parameters in.
|
||||
*/
|
||||
ExecAssignExprContext(estate, &limitstate->cstate);
|
||||
ExecAssignExprContext(estate, &limitstate->ps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*/
|
||||
limitstate->limitOffset = ExecInitExpr(node->limitOffset,
|
||||
(PlanState *) limitstate);
|
||||
limitstate->limitCount = ExecInitExpr(node->limitCount,
|
||||
(PlanState *) limitstate);
|
||||
|
||||
#define LIMIT_NSLOTS 1
|
||||
|
||||
/*
|
||||
* Tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &limitstate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &limitstate->ps);
|
||||
|
||||
/*
|
||||
* then initialize outer plan
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlanState(limitstate) = ExecInitNode(outerPlan, estate);
|
||||
|
||||
/*
|
||||
* limit nodes do no projections, so initialize projection info for
|
||||
* this node appropriately
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate);
|
||||
limitstate->cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromOuterPlan(&limitstate->ps);
|
||||
limitstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
return TRUE;
|
||||
return limitstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -343,33 +345,29 @@ ExecCountSlotsLimit(Limit *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndLimit(Limit *node)
|
||||
ExecEndLimit(LimitState *node)
|
||||
{
|
||||
LimitState *limitstate = node->limitstate;
|
||||
ExecFreeExprContext(&node->ps);
|
||||
|
||||
ExecFreeExprContext(&limitstate->cstate);
|
||||
|
||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode(outerPlanState(node));
|
||||
|
||||
/* clean up tuple table */
|
||||
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanLimit(LimitState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
LimitState *limitstate = node->limitstate;
|
||||
|
||||
/* resetting lstate will force offset/limit recalculation */
|
||||
limitstate->lstate = LIMIT_INITIAL;
|
||||
node->lstate = LIMIT_INITIAL;
|
||||
|
||||
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.38 2002/06/20 20:29:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -43,10 +43,9 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot * /* result tuple from subplan */
|
||||
ExecMaterial(Material *node)
|
||||
ExecMaterial(MaterialState *node)
|
||||
{
|
||||
EState *estate;
|
||||
MaterialState *matstate;
|
||||
ScanDirection dir;
|
||||
Tuplestorestate *tuplestorestate;
|
||||
HeapTuple heapTuple;
|
||||
|
@ -56,10 +55,9 @@ ExecMaterial(Material *node)
|
|||
/*
|
||||
* get state info from node
|
||||
*/
|
||||
matstate = node->matstate;
|
||||
estate = node->plan.state;
|
||||
estate = node->ss.ps.state;
|
||||
dir = estate->es_direction;
|
||||
tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
|
||||
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
|
||||
|
||||
/*
|
||||
* If first time through, read all tuples from outer plan and pass
|
||||
|
@ -69,7 +67,7 @@ ExecMaterial(Material *node)
|
|||
|
||||
if (tuplestorestate == NULL)
|
||||
{
|
||||
Plan *outerNode;
|
||||
PlanState *outerNode;
|
||||
|
||||
/*
|
||||
* Want to scan subplan in the forward direction while creating
|
||||
|
@ -84,16 +82,16 @@ ExecMaterial(Material *node)
|
|||
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
||||
SortMem);
|
||||
|
||||
matstate->tuplestorestate = (void *) tuplestorestate;
|
||||
node->tuplestorestate = (void *) tuplestorestate;
|
||||
|
||||
/*
|
||||
* Scan the subplan and feed all the tuples to tuplestore.
|
||||
*/
|
||||
outerNode = outerPlan((Plan *) node);
|
||||
outerNode = outerPlanState(node);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
slot = ExecProcNode(outerNode, (Plan *) node);
|
||||
slot = ExecProcNode(outerNode);
|
||||
|
||||
if (TupIsNull(slot))
|
||||
break;
|
||||
|
@ -117,7 +115,7 @@ ExecMaterial(Material *node)
|
|||
* Get the first or next tuple from tuplestore. Returns NULL if no
|
||||
* more tuples.
|
||||
*/
|
||||
slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
|
||||
slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
|
||||
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
||||
ScanDirectionIsForward(dir),
|
||||
&should_free);
|
||||
|
@ -129,23 +127,20 @@ ExecMaterial(Material *node)
|
|||
* ExecInitMaterial
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool /* initialization status */
|
||||
ExecInitMaterial(Material *node, EState *estate, Plan *parent)
|
||||
MaterialState *
|
||||
ExecInitMaterial(Material *node, EState *estate)
|
||||
{
|
||||
MaterialState *matstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
matstate = makeNode(MaterialState);
|
||||
matstate->ss.ps.plan = (Plan *) node;
|
||||
matstate->ss.ps.state = estate;
|
||||
|
||||
matstate->tuplestorestate = NULL;
|
||||
node->matstate = matstate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
|
@ -161,24 +156,24 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
|
|||
*
|
||||
* material nodes only return tuples from their materialized relation.
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
|
||||
ExecInitScanTupleSlot(estate, &matstate->csstate);
|
||||
ExecInitResultTupleSlot(estate, &matstate->ss.ps);
|
||||
ExecInitScanTupleSlot(estate, &matstate->ss);
|
||||
|
||||
/*
|
||||
* initializes child nodes
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlanState(matstate) = ExecInitNode(outerPlan, estate);
|
||||
|
||||
/*
|
||||
* initialize tuple type. no need to initialize projection info
|
||||
* because this node doesn't do projections.
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
|
||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
|
||||
matstate->csstate.cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromOuterPlan(&matstate->ss.ps);
|
||||
ExecAssignScanTypeFromOuterPlan(&matstate->ss);
|
||||
matstate->ss.ps.ps_ProjInfo = NULL;
|
||||
|
||||
return TRUE;
|
||||
return matstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -194,33 +189,24 @@ ExecCountSlotsMaterial(Material *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndMaterial(Material *node)
|
||||
ExecEndMaterial(MaterialState *node)
|
||||
{
|
||||
MaterialState *matstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* get info from the material state
|
||||
* clean out the tuple table
|
||||
*/
|
||||
matstate = node->matstate;
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
|
||||
/*
|
||||
* shut down the subplan
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecEndNode(outerPlan, (Plan *) node);
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
|
||||
ExecEndNode(outerPlanState(node));
|
||||
|
||||
/*
|
||||
* Release tuplestore resources
|
||||
*/
|
||||
if (matstate->tuplestorestate != NULL)
|
||||
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
||||
matstate->tuplestorestate = NULL;
|
||||
if (node->tuplestorestate != NULL)
|
||||
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
||||
node->tuplestorestate = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -230,17 +216,15 @@ ExecEndMaterial(Material *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecMaterialMarkPos(Material *node)
|
||||
ExecMaterialMarkPos(MaterialState *node)
|
||||
{
|
||||
MaterialState *matstate = node->matstate;
|
||||
|
||||
/*
|
||||
* if we haven't materialized yet, just return.
|
||||
*/
|
||||
if (!matstate->tuplestorestate)
|
||||
if (!node->tuplestorestate)
|
||||
return;
|
||||
|
||||
tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate);
|
||||
tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -250,20 +234,18 @@ ExecMaterialMarkPos(Material *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecMaterialRestrPos(Material *node)
|
||||
ExecMaterialRestrPos(MaterialState *node)
|
||||
{
|
||||
MaterialState *matstate = node->matstate;
|
||||
|
||||
/*
|
||||
* if we haven't materialized yet, just return.
|
||||
*/
|
||||
if (!matstate->tuplestorestate)
|
||||
if (!node->tuplestorestate)
|
||||
return;
|
||||
|
||||
/*
|
||||
* restore the scan to the previously marked position
|
||||
*/
|
||||
tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate);
|
||||
tuplestore_restorepos((Tuplestorestate *) node->tuplestorestate);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -273,19 +255,17 @@ ExecMaterialRestrPos(Material *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
MaterialState *matstate = node->matstate;
|
||||
|
||||
/*
|
||||
* If we haven't materialized yet, just return. If outerplan' chgParam
|
||||
* is not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||
* reason to re-scan it at all.
|
||||
*/
|
||||
if (!matstate->tuplestorestate)
|
||||
if (!node->tuplestorestate)
|
||||
return;
|
||||
|
||||
ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* If subnode is to be rescanned then we forget previous stored
|
||||
|
@ -293,11 +273,11 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
|||
*
|
||||
* Otherwise we can just rewind and rescan the stored output.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam != NULL)
|
||||
if (((PlanState *) node)->lefttree->chgParam != NULL)
|
||||
{
|
||||
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
||||
matstate->tuplestorestate = NULL;
|
||||
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
||||
node->tuplestorestate = NULL;
|
||||
}
|
||||
else
|
||||
tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate);
|
||||
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.51 2002/09/04 20:31:18 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.52 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -340,10 +340,9 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecMergeJoin(MergeJoin *node)
|
||||
ExecMergeJoin(MergeJoinState *node)
|
||||
{
|
||||
EState *estate;
|
||||
MergeJoinState *mergestate;
|
||||
ScanDirection direction;
|
||||
List *innerSkipQual;
|
||||
List *outerSkipQual;
|
||||
|
@ -352,9 +351,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
List *otherqual;
|
||||
bool qualResult;
|
||||
bool compareResult;
|
||||
Plan *innerPlan;
|
||||
PlanState *innerPlan;
|
||||
TupleTableSlot *innerTupleSlot;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
TupleTableSlot *outerTupleSlot;
|
||||
ExprContext *econtext;
|
||||
bool doFillOuter;
|
||||
|
@ -363,17 +362,16 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* get information from node
|
||||
*/
|
||||
mergestate = node->mergestate;
|
||||
estate = node->join.plan.state;
|
||||
estate = node->js.ps.state;
|
||||
direction = estate->es_direction;
|
||||
innerPlan = innerPlan((Plan *) node);
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
econtext = mergestate->jstate.cs_ExprContext;
|
||||
innerPlan = innerPlanState(node);
|
||||
outerPlan = outerPlanState(node);
|
||||
econtext = node->js.ps.ps_ExprContext;
|
||||
mergeclauses = node->mergeclauses;
|
||||
joinqual = node->join.joinqual;
|
||||
otherqual = node->join.plan.qual;
|
||||
joinqual = node->js.joinqual;
|
||||
otherqual = node->js.ps.qual;
|
||||
|
||||
switch (node->join.jointype)
|
||||
switch (node->js.jointype)
|
||||
{
|
||||
case JOIN_INNER:
|
||||
doFillOuter = false;
|
||||
|
@ -393,7 +391,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecMergeJoin: unsupported join type %d",
|
||||
(int) node->join.jointype);
|
||||
(int) node->js.jointype);
|
||||
doFillOuter = false; /* keep compiler quiet */
|
||||
doFillInner = false;
|
||||
break;
|
||||
|
@ -401,13 +399,13 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
if (ScanDirectionIsForward(direction))
|
||||
{
|
||||
outerSkipQual = mergestate->mj_OuterSkipQual;
|
||||
innerSkipQual = mergestate->mj_InnerSkipQual;
|
||||
outerSkipQual = node->mj_OuterSkipQual;
|
||||
innerSkipQual = node->mj_InnerSkipQual;
|
||||
}
|
||||
else
|
||||
{
|
||||
outerSkipQual = mergestate->mj_InnerSkipQual;
|
||||
innerSkipQual = mergestate->mj_OuterSkipQual;
|
||||
outerSkipQual = node->mj_InnerSkipQual;
|
||||
innerSkipQual = node->mj_OuterSkipQual;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -415,16 +413,16 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* join tuple (because there is a function-returning-set in the
|
||||
* projection expressions). If so, try to project another one.
|
||||
*/
|
||||
if (mergestate->jstate.cs_TupFromTlist)
|
||||
if (node->js.ps.ps_TupFromTlist)
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
ExprDoneCond isDone;
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
return result;
|
||||
/* Done with that source tuple... */
|
||||
mergestate->jstate.cs_TupFromTlist = false;
|
||||
node->js.ps.ps_TupFromTlist = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -444,9 +442,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* Note: The join states are highlighted with 32-* comments for
|
||||
* improved readability.
|
||||
*/
|
||||
MJ_dump(mergestate);
|
||||
MJ_dump(node);
|
||||
|
||||
switch (mergestate->mj_JoinState)
|
||||
switch (node->mj_JoinState)
|
||||
{
|
||||
/*
|
||||
* EXEC_MJ_INITIALIZE means that this is the first time
|
||||
|
@ -459,8 +457,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||
case EXEC_MJ_INITIALIZE:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
|
||||
|
||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||
outerTupleSlot = ExecProcNode(outerPlan);
|
||||
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
MJ_printf("ExecMergeJoin: outer subplan is empty\n");
|
||||
|
@ -471,16 +469,16 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* inner tuples. We set MatchedInner = true to
|
||||
* force the ENDOUTER state to advance inner.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||
mergestate->mj_MatchedInner = true;
|
||||
node->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||
node->mj_MatchedInner = true;
|
||||
break;
|
||||
}
|
||||
/* Otherwise we're done. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||
innerTupleSlot = ExecProcNode(innerPlan);
|
||||
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||
if (TupIsNull(innerTupleSlot))
|
||||
{
|
||||
MJ_printf("ExecMergeJoin: inner subplan is empty\n");
|
||||
|
@ -493,8 +491,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* state to emit this tuple before advancing
|
||||
* outer.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
node->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
node->mj_MatchedOuter = false;
|
||||
break;
|
||||
}
|
||||
/* Otherwise we're done. */
|
||||
|
@ -505,7 +503,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* OK, we have the initial tuples. Begin by skipping
|
||||
* unmatched inner tuples.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -519,9 +517,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
ExecMarkPos(innerPlan);
|
||||
|
||||
MarkInnerTuple(mergestate->mj_InnerTupleSlot, mergestate);
|
||||
MarkInnerTuple(node->mj_InnerTupleSlot, node);
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||
node->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -538,18 +536,18 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||
MJ_DEBUG_QUAL(mergeclauses, qualResult);
|
||||
|
||||
if (qualResult)
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
else
|
||||
mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
||||
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -560,7 +558,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
case EXEC_MJ_JOINTUPLES:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
|
||||
node->mj_JoinState = EXEC_MJ_NEXTINNER;
|
||||
|
||||
/*
|
||||
* Check the extra qual conditions to see if we actually
|
||||
|
@ -582,8 +580,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
if (qualResult)
|
||||
{
|
||||
mergestate->mj_MatchedOuter = true;
|
||||
mergestate->mj_MatchedInner = true;
|
||||
node->mj_MatchedOuter = true;
|
||||
node->mj_MatchedInner = true;
|
||||
|
||||
qualResult = (otherqual == NIL ||
|
||||
ExecQual(otherqual, econtext, false));
|
||||
|
@ -601,12 +599,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -625,20 +623,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||
case EXEC_MJ_NEXTINNER:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
|
||||
|
||||
if (doFillInner && !mergestate->mj_MatchedInner)
|
||||
if (doFillInner && !node->mj_MatchedInner)
|
||||
{
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the outer
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
node->mj_MatchedInner = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
|
||||
outerTupleSlot = node->mj_NullOuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
|
@ -653,12 +651,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -668,15 +666,15 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* now we get the next inner tuple, if any
|
||||
*/
|
||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||
innerTupleSlot = ExecProcNode(innerPlan);
|
||||
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||
mergestate->mj_MatchedInner = false;
|
||||
node->mj_MatchedInner = false;
|
||||
|
||||
if (TupIsNull(innerTupleSlot))
|
||||
mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
||||
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
||||
else
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||
node->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||
break;
|
||||
|
||||
/*-------------------------------------------
|
||||
|
@ -701,20 +699,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||
case EXEC_MJ_NEXTOUTER:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
|
||||
|
||||
if (doFillOuter && !mergestate->mj_MatchedOuter)
|
||||
if (doFillOuter && !node->mj_MatchedOuter)
|
||||
{
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the inner
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
node->mj_MatchedOuter = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
|
||||
innerTupleSlot = node->mj_NullInnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
|
@ -729,12 +727,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -744,10 +742,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* now we get the next outer tuple, if any
|
||||
*/
|
||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||
outerTupleSlot = ExecProcNode(outerPlan);
|
||||
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
node->mj_MatchedOuter = false;
|
||||
|
||||
/*
|
||||
* if the outer tuple is null then we are done with the
|
||||
|
@ -756,21 +754,21 @@ ExecMergeJoin(MergeJoin *node)
|
|||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
MJ_printf("ExecMergeJoin: end of outer subplan\n");
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||
{
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||
node->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||
break;
|
||||
}
|
||||
/* Otherwise we're done. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_TESTOUTER;
|
||||
node->mj_JoinState = EXEC_MJ_TESTOUTER;
|
||||
break;
|
||||
|
||||
/*--------------------------------------------------------
|
||||
|
@ -816,9 +814,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
*/
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_MarkedTupleSlot;
|
||||
innerTupleSlot = node->mj_MarkedTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||
|
@ -843,7 +841,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* the extra joinquals.
|
||||
*/
|
||||
ExecRestrPos(innerPlan);
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -862,7 +860,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* larger than our marked inner tuples. So we're done.
|
||||
* ----------------
|
||||
*/
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
if (TupIsNull(innerTupleSlot))
|
||||
{
|
||||
if (doFillOuter)
|
||||
|
@ -871,7 +869,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
* Need to emit left-join tuples for remaining
|
||||
* outer tuples.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
node->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
break;
|
||||
}
|
||||
/* Otherwise we're done. */
|
||||
|
@ -879,7 +877,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
}
|
||||
|
||||
/* continue on to skip outer tuples */
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -913,9 +911,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
*/
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||
|
@ -925,13 +923,13 @@ ExecMergeJoin(MergeJoin *node)
|
|||
{
|
||||
ExecMarkPos(innerPlan);
|
||||
|
||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
||||
MarkInnerTuple(innerTupleSlot, node);
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
break;
|
||||
}
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||
break;
|
||||
|
||||
case EXEC_MJ_SKIPOUTER_TEST:
|
||||
|
@ -940,9 +938,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* ok, now test the skip qualification
|
||||
*/
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
compareResult = MergeCompare(mergeclauses,
|
||||
|
@ -957,7 +955,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
*/
|
||||
if (compareResult)
|
||||
{
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -973,9 +971,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
|
||||
|
||||
if (compareResult)
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||
else
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||
node->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -985,20 +983,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||
case EXEC_MJ_SKIPOUTER_ADVANCE:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
|
||||
|
||||
if (doFillOuter && !mergestate->mj_MatchedOuter)
|
||||
if (doFillOuter && !node->mj_MatchedOuter)
|
||||
{
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the inner
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
node->mj_MatchedOuter = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
|
||||
innerTupleSlot = node->mj_NullInnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
|
@ -1013,12 +1011,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -1028,10 +1026,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* now we get the next outer tuple, if any
|
||||
*/
|
||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||
outerTupleSlot = ExecProcNode(outerPlan);
|
||||
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
node->mj_MatchedOuter = false;
|
||||
|
||||
/*
|
||||
* if the outer tuple is null then we are done with the
|
||||
|
@ -1040,14 +1038,14 @@ ExecMergeJoin(MergeJoin *node)
|
|||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
MJ_printf("ExecMergeJoin: end of outer subplan\n");
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||
{
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||
node->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||
break;
|
||||
}
|
||||
/* Otherwise we're done. */
|
||||
|
@ -1057,7 +1055,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* otherwise test the new tuple against the skip qual.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||
break;
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
|
@ -1090,9 +1088,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
*/
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||
|
@ -1102,13 +1100,13 @@ ExecMergeJoin(MergeJoin *node)
|
|||
{
|
||||
ExecMarkPos(innerPlan);
|
||||
|
||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
||||
MarkInnerTuple(innerTupleSlot, node);
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
break;
|
||||
}
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||
break;
|
||||
|
||||
case EXEC_MJ_SKIPINNER_TEST:
|
||||
|
@ -1117,9 +1115,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* ok, now test the skip qualification
|
||||
*/
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
compareResult = MergeCompare(mergeclauses,
|
||||
|
@ -1134,7 +1132,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
*/
|
||||
if (compareResult)
|
||||
{
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1150,9 +1148,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||
MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
|
||||
|
||||
if (compareResult)
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
||||
else
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||
node->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -1162,20 +1160,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||
case EXEC_MJ_SKIPINNER_ADVANCE:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
|
||||
|
||||
if (doFillInner && !mergestate->mj_MatchedInner)
|
||||
if (doFillInner && !node->mj_MatchedInner)
|
||||
{
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the outer
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
node->mj_MatchedInner = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
|
||||
outerTupleSlot = node->mj_NullOuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
|
@ -1190,12 +1188,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -1205,10 +1203,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* now we get the next inner tuple, if any
|
||||
*/
|
||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||
innerTupleSlot = ExecProcNode(innerPlan);
|
||||
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||
mergestate->mj_MatchedInner = false;
|
||||
node->mj_MatchedInner = false;
|
||||
|
||||
/*
|
||||
* if the inner tuple is null then we are done with the
|
||||
|
@ -1217,14 +1215,14 @@ ExecMergeJoin(MergeJoin *node)
|
|||
if (TupIsNull(innerTupleSlot))
|
||||
{
|
||||
MJ_printf("ExecMergeJoin: end of inner subplan\n");
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
if (doFillOuter && !TupIsNull(outerTupleSlot))
|
||||
{
|
||||
/*
|
||||
* Need to emit left-join tuples for remaining
|
||||
* outer tuples.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
node->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
break;
|
||||
}
|
||||
/* Otherwise we're done. */
|
||||
|
@ -1234,7 +1232,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* otherwise test the new tuple against the skip qual.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||
node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -1247,20 +1245,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
Assert(doFillInner);
|
||||
|
||||
if (!mergestate->mj_MatchedInner)
|
||||
if (!node->mj_MatchedInner)
|
||||
{
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the outer
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
node->mj_MatchedInner = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
|
||||
outerTupleSlot = node->mj_NullOuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
|
@ -1275,12 +1273,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -1290,10 +1288,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* now we get the next inner tuple, if any
|
||||
*/
|
||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
||||
innerTupleSlot = ExecProcNode(innerPlan);
|
||||
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||
mergestate->mj_MatchedInner = false;
|
||||
node->mj_MatchedInner = false;
|
||||
|
||||
if (TupIsNull(innerTupleSlot))
|
||||
{
|
||||
|
@ -1314,20 +1312,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
Assert(doFillOuter);
|
||||
|
||||
if (!mergestate->mj_MatchedOuter)
|
||||
if (!node->mj_MatchedOuter)
|
||||
{
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the inner
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
node->mj_MatchedOuter = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
|
||||
innerTupleSlot = node->mj_NullInnerTupleSlot;
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
|
@ -1342,12 +1340,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||
&isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
mergestate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -1357,10 +1355,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||
/*
|
||||
* now we get the next outer tuple, if any
|
||||
*/
|
||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
||||
outerTupleSlot = ExecProcNode(outerPlan);
|
||||
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
node->mj_MatchedOuter = false;
|
||||
|
||||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
|
@ -1377,7 +1375,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||
*/
|
||||
default:
|
||||
elog(WARNING, "ExecMergeJoin: invalid join state %d, aborting",
|
||||
mergestate->mj_JoinState);
|
||||
node->mj_JoinState);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1385,14 +1383,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitMergeJoin
|
||||
*
|
||||
* old comments
|
||||
* Creates the run-time state information for the node and
|
||||
* sets the relation id to contain relevant decriptors.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
||||
MergeJoinState *
|
||||
ExecInitMergeJoin(MergeJoin *node, EState *estate)
|
||||
{
|
||||
MergeJoinState *mergestate;
|
||||
|
||||
|
@ -1400,40 +1394,52 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||
"initializing node");
|
||||
|
||||
/*
|
||||
* assign the node's execution state and get the range table and
|
||||
* direction from it
|
||||
*/
|
||||
node->join.plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new merge state for node
|
||||
* create state structure
|
||||
*/
|
||||
mergestate = makeNode(MergeJoinState);
|
||||
node->mergestate = mergestate;
|
||||
mergestate->js.ps.plan = (Plan *) node;
|
||||
mergestate->js.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &mergestate->jstate);
|
||||
ExecAssignExprContext(estate, &mergestate->js.ps);
|
||||
|
||||
/*
|
||||
* initialize subplans
|
||||
* initialize child expressions
|
||||
*/
|
||||
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
|
||||
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
||||
mergestate->js.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->join.plan.targetlist,
|
||||
(PlanState *) mergestate);
|
||||
mergestate->js.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->join.plan.qual,
|
||||
(PlanState *) mergestate);
|
||||
mergestate->js.jointype = node->join.jointype;
|
||||
mergestate->js.joinqual = (List *)
|
||||
ExecInitExpr((Node *) node->join.joinqual,
|
||||
(PlanState *) mergestate);
|
||||
mergestate->mergeclauses = (List *)
|
||||
ExecInitExpr((Node *) node->mergeclauses,
|
||||
(PlanState *) mergestate);
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlanState(mergestate) = ExecInitNode(outerPlan(node), estate);
|
||||
innerPlanState(mergestate) = ExecInitNode(innerPlan(node), estate);
|
||||
|
||||
#define MERGEJOIN_NSLOTS 4
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &mergestate->jstate);
|
||||
ExecInitResultTupleSlot(estate, &mergestate->js.ps);
|
||||
|
||||
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
|
||||
ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
|
||||
ExecGetTupType(innerPlan((Plan *) node)),
|
||||
ExecGetTupType(innerPlanState(mergestate)),
|
||||
false);
|
||||
|
||||
switch (node->join.jointype)
|
||||
|
@ -1443,12 +1449,12 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||
case JOIN_LEFT:
|
||||
mergestate->mj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(innerPlan((Plan *) node)));
|
||||
ExecGetTupType(innerPlanState(mergestate)));
|
||||
break;
|
||||
case JOIN_RIGHT:
|
||||
mergestate->mj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(outerPlan((Plan *) node)));
|
||||
ExecGetTupType(outerPlanState(mergestate)));
|
||||
|
||||
/*
|
||||
* Can't handle right or full join with non-nil extra
|
||||
|
@ -1460,10 +1466,10 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||
case JOIN_FULL:
|
||||
mergestate->mj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(outerPlan((Plan *) node)));
|
||||
ExecGetTupType(outerPlanState(mergestate)));
|
||||
mergestate->mj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(innerPlan((Plan *) node)));
|
||||
ExecGetTupType(innerPlanState(mergestate)));
|
||||
|
||||
/*
|
||||
* Can't handle right or full join with non-nil extra
|
||||
|
@ -1480,8 +1486,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* initialize tuple type and projection info
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
|
||||
ExecAssignResultTypeFromTL(&mergestate->js.ps);
|
||||
ExecAssignProjectionInfo(&mergestate->js.ps);
|
||||
|
||||
/*
|
||||
* form merge skip qualifications
|
||||
|
@ -1500,7 +1506,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||
* initialize join state
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
||||
mergestate->jstate.cs_TupFromTlist = false;
|
||||
mergestate->js.ps.ps_TupFromTlist = false;
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
mergestate->mj_MatchedInner = false;
|
||||
mergestate->mj_OuterTupleSlot = NULL;
|
||||
|
@ -1512,7 +1518,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||
MJ1_printf("ExecInitMergeJoin: %s\n",
|
||||
"node initialized");
|
||||
|
||||
return TRUE;
|
||||
return mergestate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1531,65 +1537,52 @@ ExecCountSlotsMergeJoin(MergeJoin *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndMergeJoin(MergeJoin *node)
|
||||
ExecEndMergeJoin(MergeJoinState *node)
|
||||
{
|
||||
MergeJoinState *mergestate;
|
||||
|
||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||
"ending node processing");
|
||||
|
||||
/*
|
||||
* get state information from the node
|
||||
*/
|
||||
mergestate = node->mergestate;
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(mergestate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&mergestate->jstate);
|
||||
ExecFreeExprContext(&mergestate->jstate);
|
||||
ExecFreeProjectionInfo(&node->js.ps);
|
||||
ExecFreeExprContext(&node->js.ps);
|
||||
|
||||
/*
|
||||
* shut down the subplans
|
||||
*/
|
||||
ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode(innerPlanState(node));
|
||||
ExecEndNode(outerPlanState(node));
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
||||
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||
ExecClearTuple(node->mj_MarkedTupleSlot);
|
||||
|
||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||
"node processing ended");
|
||||
}
|
||||
|
||||
void
|
||||
ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
MergeJoinState *mergestate = node->mergestate;
|
||||
ExecClearTuple(node->mj_MarkedTupleSlot);
|
||||
|
||||
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
||||
|
||||
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
||||
mergestate->jstate.cs_TupFromTlist = false;
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
mergestate->mj_MatchedInner = false;
|
||||
mergestate->mj_OuterTupleSlot = NULL;
|
||||
mergestate->mj_InnerTupleSlot = NULL;
|
||||
node->mj_JoinState = EXEC_MJ_INITIALIZE;
|
||||
node->js.ps.ps_TupFromTlist = false;
|
||||
node->mj_MatchedOuter = false;
|
||||
node->mj_MatchedInner = false;
|
||||
node->mj_OuterTupleSlot = NULL;
|
||||
node->mj_InnerTupleSlot = NULL;
|
||||
|
||||
/*
|
||||
* if chgParam of subnodes is not null then plans will be re-scanned
|
||||
* by first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((Plan *) node)->righttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->righttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
if (((PlanState *) node)->righttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->righttree, exprCtxt);
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.26 2002/06/20 20:29:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.27 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -57,11 +57,10 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecNestLoop(NestLoop *node)
|
||||
ExecNestLoop(NestLoopState *node)
|
||||
{
|
||||
NestLoopState *nlstate;
|
||||
Plan *innerPlan;
|
||||
Plan *outerPlan;
|
||||
PlanState *innerPlan;
|
||||
PlanState *outerPlan;
|
||||
TupleTableSlot *outerTupleSlot;
|
||||
TupleTableSlot *innerTupleSlot;
|
||||
List *joinqual;
|
||||
|
@ -73,17 +72,16 @@ ExecNestLoop(NestLoop *node)
|
|||
*/
|
||||
ENL1_printf("getting info from node");
|
||||
|
||||
nlstate = node->nlstate;
|
||||
joinqual = node->join.joinqual;
|
||||
otherqual = node->join.plan.qual;
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
innerPlan = innerPlan((Plan *) node);
|
||||
econtext = nlstate->jstate.cs_ExprContext;
|
||||
joinqual = node->js.joinqual;
|
||||
otherqual = node->js.ps.qual;
|
||||
outerPlan = outerPlanState(node);
|
||||
innerPlan = innerPlanState(node);
|
||||
econtext = node->js.ps.ps_ExprContext;
|
||||
|
||||
/*
|
||||
* get the current outer tuple
|
||||
*/
|
||||
outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
|
||||
outerTupleSlot = node->js.ps.ps_OuterTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
|
||||
/*
|
||||
|
@ -91,16 +89,16 @@ ExecNestLoop(NestLoop *node)
|
|||
* join tuple (because there is a function-returning-set in the
|
||||
* projection expressions). If so, try to project another one.
|
||||
*/
|
||||
if (nlstate->jstate.cs_TupFromTlist)
|
||||
if (node->js.ps.ps_TupFromTlist)
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
ExprDoneCond isDone;
|
||||
|
||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
return result;
|
||||
/* Done with that source tuple... */
|
||||
nlstate->jstate.cs_TupFromTlist = false;
|
||||
node->js.ps.ps_TupFromTlist = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -122,10 +120,10 @@ ExecNestLoop(NestLoop *node)
|
|||
* If we don't have an outer tuple, get the next one and reset the
|
||||
* inner scan.
|
||||
*/
|
||||
if (nlstate->nl_NeedNewOuter)
|
||||
if (node->nl_NeedNewOuter)
|
||||
{
|
||||
ENL1_printf("getting new outer tuple");
|
||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
outerTupleSlot = ExecProcNode(outerPlan);
|
||||
|
||||
/*
|
||||
* if there are no more outer tuples, then the join is
|
||||
|
@ -138,10 +136,10 @@ ExecNestLoop(NestLoop *node)
|
|||
}
|
||||
|
||||
ENL1_printf("saving new outer tuple information");
|
||||
nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
|
||||
node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
nlstate->nl_NeedNewOuter = false;
|
||||
nlstate->nl_MatchedOuter = false;
|
||||
node->nl_NeedNewOuter = false;
|
||||
node->nl_MatchedOuter = false;
|
||||
|
||||
/*
|
||||
* now rescan the inner plan
|
||||
|
@ -153,7 +151,7 @@ ExecNestLoop(NestLoop *node)
|
|||
* outer tuple (e.g. in index scans), that's why we pass our
|
||||
* expr context.
|
||||
*/
|
||||
ExecReScan(innerPlan, econtext, (Plan *) node);
|
||||
ExecReScan(innerPlan, econtext);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -161,17 +159,17 @@ ExecNestLoop(NestLoop *node)
|
|||
*/
|
||||
ENL1_printf("getting new inner tuple");
|
||||
|
||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
||||
innerTupleSlot = ExecProcNode(innerPlan);
|
||||
econtext->ecxt_innertuple = innerTupleSlot;
|
||||
|
||||
if (TupIsNull(innerTupleSlot))
|
||||
{
|
||||
ENL1_printf("no inner tuple, need new outer tuple");
|
||||
|
||||
nlstate->nl_NeedNewOuter = true;
|
||||
node->nl_NeedNewOuter = true;
|
||||
|
||||
if (!nlstate->nl_MatchedOuter &&
|
||||
node->join.jointype == JOIN_LEFT)
|
||||
if (!node->nl_MatchedOuter &&
|
||||
node->js.jointype == JOIN_LEFT)
|
||||
{
|
||||
/*
|
||||
* We are doing an outer join and there were no join
|
||||
|
@ -179,7 +177,7 @@ ExecNestLoop(NestLoop *node)
|
|||
* tuple with nulls for the inner tuple, and return it if
|
||||
* it passes the non-join quals.
|
||||
*/
|
||||
econtext->ecxt_innertuple = nlstate->nl_NullInnerTupleSlot;
|
||||
econtext->ecxt_innertuple = node->nl_NullInnerTupleSlot;
|
||||
|
||||
ENL1_printf("testing qualification for outer-join tuple");
|
||||
|
||||
|
@ -195,11 +193,11 @@ ExecNestLoop(NestLoop *node)
|
|||
|
||||
ENL1_printf("qualification succeeded, projecting tuple");
|
||||
|
||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
nlstate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -224,7 +222,7 @@ ExecNestLoop(NestLoop *node)
|
|||
|
||||
if (ExecQual(joinqual, econtext, false))
|
||||
{
|
||||
nlstate->nl_MatchedOuter = true;
|
||||
node->nl_MatchedOuter = true;
|
||||
|
||||
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
@ -238,11 +236,11 @@ ExecNestLoop(NestLoop *node)
|
|||
|
||||
ENL1_printf("qualification succeeded, projecting tuple");
|
||||
|
||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
||||
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
nlstate->jstate.cs_TupFromTlist =
|
||||
node->js.ps.ps_TupFromTlist =
|
||||
(isDone == ExprMultipleResult);
|
||||
return result;
|
||||
}
|
||||
|
@ -260,14 +258,10 @@ ExecNestLoop(NestLoop *node)
|
|||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitNestLoop
|
||||
*
|
||||
* Creates the run-time state information for the nestloop node
|
||||
* produced by the planner and initailizes inner and outer relations
|
||||
* (child nodes).
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
||||
NestLoopState *
|
||||
ExecInitNestLoop(NestLoop *node, EState *estate)
|
||||
{
|
||||
NestLoopState *nlstate;
|
||||
|
||||
|
@ -275,35 +269,45 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||
"initializing node");
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
*/
|
||||
node->join.plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new nest loop state
|
||||
* create state structure
|
||||
*/
|
||||
nlstate = makeNode(NestLoopState);
|
||||
node->nlstate = nlstate;
|
||||
nlstate->js.ps.plan = (Plan *) node;
|
||||
nlstate->js.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &nlstate->jstate);
|
||||
ExecAssignExprContext(estate, &nlstate->js.ps);
|
||||
|
||||
/*
|
||||
* now initialize children
|
||||
* initialize child expressions
|
||||
*/
|
||||
ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
|
||||
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
||||
nlstate->js.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->join.plan.targetlist,
|
||||
(PlanState *) nlstate);
|
||||
nlstate->js.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->join.plan.qual,
|
||||
(PlanState *) nlstate);
|
||||
nlstate->js.jointype = node->join.jointype;
|
||||
nlstate->js.joinqual = (List *)
|
||||
ExecInitExpr((Node *) node->join.joinqual,
|
||||
(PlanState *) nlstate);
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlanState(nlstate) = ExecInitNode(outerPlan(node), estate);
|
||||
innerPlanState(nlstate) = ExecInitNode(innerPlan(node), estate);
|
||||
|
||||
#define NESTLOOP_NSLOTS 2
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &nlstate->jstate);
|
||||
ExecInitResultTupleSlot(estate, &nlstate->js.ps);
|
||||
|
||||
switch (node->join.jointype)
|
||||
{
|
||||
|
@ -312,7 +316,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||
case JOIN_LEFT:
|
||||
nlstate->nl_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(innerPlan((Plan *) node)));
|
||||
ExecGetTupType(innerPlanState(nlstate)));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecInitNestLoop: unsupported join type %d",
|
||||
|
@ -322,20 +326,21 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* initialize tuple type and projection info
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
|
||||
ExecAssignResultTypeFromTL(&nlstate->js.ps);
|
||||
ExecAssignProjectionInfo(&nlstate->js.ps);
|
||||
|
||||
/*
|
||||
* finally, wipe the current outer tuple clean.
|
||||
*/
|
||||
nlstate->jstate.cs_OuterTupleSlot = NULL;
|
||||
nlstate->jstate.cs_TupFromTlist = false;
|
||||
nlstate->js.ps.ps_OuterTupleSlot = NULL;
|
||||
nlstate->js.ps.ps_TupFromTlist = false;
|
||||
nlstate->nl_NeedNewOuter = true;
|
||||
nlstate->nl_MatchedOuter = false;
|
||||
|
||||
NL1_printf("ExecInitNestLoop: %s\n",
|
||||
"node initialized");
|
||||
return TRUE;
|
||||
|
||||
return nlstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -353,38 +358,27 @@ ExecCountSlotsNestLoop(NestLoop *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndNestLoop(NestLoop *node)
|
||||
ExecEndNestLoop(NestLoopState *node)
|
||||
{
|
||||
NestLoopState *nlstate;
|
||||
|
||||
NL1_printf("ExecEndNestLoop: %s\n",
|
||||
"ending node processing");
|
||||
|
||||
/*
|
||||
* get info from the node
|
||||
*/
|
||||
nlstate = node->nlstate;
|
||||
|
||||
/*
|
||||
* Free the projection info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(nlstate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&nlstate->jstate);
|
||||
ExecFreeExprContext(&nlstate->jstate);
|
||||
ExecFreeProjectionInfo(&node->js.ps);
|
||||
ExecFreeExprContext(&node->js.ps);
|
||||
|
||||
/*
|
||||
* close down subplans
|
||||
*/
|
||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
||||
ExecEndNode(outerPlanState(node));
|
||||
ExecEndNode(innerPlanState(node));
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||
|
||||
NL1_printf("ExecEndNestLoop: %s\n",
|
||||
"node processing ended");
|
||||
|
@ -395,10 +389,9 @@ ExecEndNestLoop(NestLoop *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
NestLoopState *nlstate = node->nlstate;
|
||||
Plan *outerPlan = outerPlan((Plan *) node);
|
||||
PlanState *outerPlan = outerPlanState(node);
|
||||
|
||||
/*
|
||||
* If outerPlan->chgParam is not null then plan will be automatically
|
||||
|
@ -408,11 +401,11 @@ ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
|
|||
* run-time keys...
|
||||
*/
|
||||
if (outerPlan->chgParam == NULL)
|
||||
ExecReScan(outerPlan, exprCtxt, (Plan *) node);
|
||||
ExecReScan(outerPlan, exprCtxt);
|
||||
|
||||
/* let outerPlan to free its result tuple ... */
|
||||
nlstate->jstate.cs_OuterTupleSlot = NULL;
|
||||
nlstate->jstate.cs_TupFromTlist = false;
|
||||
nlstate->nl_NeedNewOuter = true;
|
||||
nlstate->nl_MatchedOuter = false;
|
||||
node->js.ps.ps_OuterTupleSlot = NULL;
|
||||
node->js.ps.ps_TupFromTlist = false;
|
||||
node->nl_NeedNewOuter = true;
|
||||
node->nl_MatchedOuter = false;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.21 2002/06/20 20:29:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.22 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -60,34 +60,29 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecResult(Result *node)
|
||||
ExecResult(ResultState *node)
|
||||
{
|
||||
ResultState *resstate;
|
||||
TupleTableSlot *outerTupleSlot;
|
||||
TupleTableSlot *resultSlot;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
ExprContext *econtext;
|
||||
ExprDoneCond isDone;
|
||||
|
||||
/*
|
||||
* initialize the result node's state
|
||||
*/
|
||||
resstate = node->resstate;
|
||||
econtext = resstate->cstate.cs_ExprContext;
|
||||
econtext = node->ps.ps_ExprContext;
|
||||
|
||||
/*
|
||||
* check constant qualifications like (2 > 1), if not already done
|
||||
*/
|
||||
if (resstate->rs_checkqual)
|
||||
if (node->rs_checkqual)
|
||||
{
|
||||
bool qualResult = ExecQual((List *) node->resconstantqual,
|
||||
econtext,
|
||||
false);
|
||||
|
||||
resstate->rs_checkqual = false;
|
||||
if (qualResult == false)
|
||||
node->rs_checkqual = false;
|
||||
if (!qualResult)
|
||||
{
|
||||
resstate->rs_done = true;
|
||||
node->rs_done = true;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -97,13 +92,13 @@ ExecResult(Result *node)
|
|||
* scan tuple (because there is a function-returning-set in the
|
||||
* projection expressions). If so, try to project another one.
|
||||
*/
|
||||
if (resstate->cstate.cs_TupFromTlist)
|
||||
if (node->ps.ps_TupFromTlist)
|
||||
{
|
||||
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
|
||||
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
return resultSlot;
|
||||
/* Done with that source tuple... */
|
||||
resstate->cstate.cs_TupFromTlist = false;
|
||||
node->ps.ps_TupFromTlist = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -119,9 +114,9 @@ ExecResult(Result *node)
|
|||
* called, OR that we failed the constant qual check. Either way, now
|
||||
* we are through.
|
||||
*/
|
||||
while (!resstate->rs_done)
|
||||
while (!node->rs_done)
|
||||
{
|
||||
outerPlan = outerPlan(node);
|
||||
outerPlan = outerPlanState(node);
|
||||
|
||||
if (outerPlan != NULL)
|
||||
{
|
||||
|
@ -129,12 +124,12 @@ ExecResult(Result *node)
|
|||
* retrieve tuples from the outer plan until there are no
|
||||
* more.
|
||||
*/
|
||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
outerTupleSlot = ExecProcNode(outerPlan);
|
||||
|
||||
if (TupIsNull(outerTupleSlot))
|
||||
return NULL;
|
||||
|
||||
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
|
||||
node->ps.ps_OuterTupleSlot = outerTupleSlot;
|
||||
|
||||
/*
|
||||
* XXX gross hack. use outer tuple as scan tuple for
|
||||
|
@ -149,7 +144,7 @@ ExecResult(Result *node)
|
|||
* if we don't have an outer plan, then we are just generating
|
||||
* the results from a constant target list. Do it only once.
|
||||
*/
|
||||
resstate->rs_done = true;
|
||||
node->rs_done = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -157,11 +152,11 @@ ExecResult(Result *node)
|
|||
* unless the projection produces an empty set, in which case we
|
||||
* must loop back to see if there are more outerPlan tuples.
|
||||
*/
|
||||
resultSlot = ExecProject(resstate->cstate.cs_ProjInfo, &isDone);
|
||||
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
|
||||
|
||||
if (isDone != ExprEndResult)
|
||||
{
|
||||
resstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
|
||||
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
|
||||
return resultSlot;
|
||||
}
|
||||
}
|
||||
|
@ -177,42 +172,51 @@ ExecResult(Result *node)
|
|||
* (child nodes).
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitResult(Result *node, EState *estate, Plan *parent)
|
||||
ResultState *
|
||||
ExecInitResult(Result *node, EState *estate)
|
||||
{
|
||||
ResultState *resstate;
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new ResultState for node
|
||||
* create state structure
|
||||
*/
|
||||
resstate = makeNode(ResultState);
|
||||
resstate->ps.plan = (Plan *) node;
|
||||
resstate->ps.state = estate;
|
||||
|
||||
resstate->rs_done = false;
|
||||
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
||||
node->resstate = resstate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &resstate->cstate);
|
||||
ExecAssignExprContext(estate, &resstate->ps);
|
||||
|
||||
#define RESULT_NSLOTS 1
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &resstate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &resstate->ps);
|
||||
|
||||
/*
|
||||
* then initialize children
|
||||
* initialize child expressions
|
||||
*/
|
||||
ExecInitNode(outerPlan(node), estate, (Plan *) node);
|
||||
resstate->ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->plan.targetlist,
|
||||
(PlanState *) resstate);
|
||||
resstate->ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->plan.qual,
|
||||
(PlanState *) resstate);
|
||||
resstate->resconstantqual = ExecInitExpr(node->resconstantqual,
|
||||
(PlanState *) resstate);
|
||||
|
||||
/*
|
||||
* initialize child nodes
|
||||
*/
|
||||
outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate);
|
||||
|
||||
/*
|
||||
* we don't use inner plan
|
||||
|
@ -222,10 +226,10 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* initialize tuple type and projection info
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
|
||||
ExecAssignResultTypeFromTL(&resstate->ps);
|
||||
ExecAssignProjectionInfo(&resstate->ps);
|
||||
|
||||
return TRUE;
|
||||
return resstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -241,49 +245,37 @@ ExecCountSlotsResult(Result *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndResult(Result *node)
|
||||
ExecEndResult(ResultState *node)
|
||||
{
|
||||
ResultState *resstate;
|
||||
|
||||
resstate = node->resstate;
|
||||
|
||||
/*
|
||||
* Free the projection info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(resstate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&resstate->cstate);
|
||||
ExecFreeExprContext(&resstate->cstate);
|
||||
|
||||
/*
|
||||
* shut down subplans
|
||||
*/
|
||||
ExecEndNode(outerPlan(node), (Plan *) node);
|
||||
ExecFreeProjectionInfo(&node->ps);
|
||||
ExecFreeExprContext(&node->ps);
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
||||
pfree(resstate);
|
||||
node->resstate = NULL; /* XXX - new for us - er1p */
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* shut down subplans
|
||||
*/
|
||||
ExecEndNode(outerPlanState(node));
|
||||
}
|
||||
|
||||
void
|
||||
ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
ResultState *resstate = node->resstate;
|
||||
|
||||
resstate->rs_done = false;
|
||||
resstate->cstate.cs_TupFromTlist = false;
|
||||
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
||||
node->rs_done = false;
|
||||
node->ps.ps_TupFromTlist = false;
|
||||
node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree &&
|
||||
((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree &&
|
||||
((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.38 2002/11/30 05:21:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.39 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -29,9 +29,8 @@
|
|||
#include "executor/nodeSeqscan.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
static Oid InitScanRelation(SeqScan *node, EState *estate,
|
||||
CommonScanState *scanstate);
|
||||
static TupleTableSlot *SeqNext(SeqScan *node);
|
||||
static void InitScanRelation(SeqScanState *node, EState *estate);
|
||||
static TupleTableSlot *SeqNext(SeqScanState *node);
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Scan Support
|
||||
|
@ -44,11 +43,11 @@ static TupleTableSlot *SeqNext(SeqScan *node);
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
SeqNext(SeqScan *node)
|
||||
SeqNext(SeqScanState *node)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
HeapScanDesc scandesc;
|
||||
CommonScanState *scanstate;
|
||||
Index scanrelid;
|
||||
EState *estate;
|
||||
ScanDirection direction;
|
||||
TupleTableSlot *slot;
|
||||
|
@ -56,11 +55,11 @@ SeqNext(SeqScan *node)
|
|||
/*
|
||||
* get information from the estate and scan state
|
||||
*/
|
||||
estate = node->plan.state;
|
||||
scanstate = node->scanstate;
|
||||
scandesc = scanstate->css_currentScanDesc;
|
||||
estate = node->ps.state;
|
||||
scandesc = node->ss_currentScanDesc;
|
||||
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
|
||||
direction = estate->es_direction;
|
||||
slot = scanstate->css_ScanTupleSlot;
|
||||
slot = node->ss_ScanTupleSlot;
|
||||
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||
|
@ -69,13 +68,13 @@ SeqNext(SeqScan *node)
|
|||
* switching in Init/ReScan plan...
|
||||
*/
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
||||
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||
{
|
||||
ExecClearTuple(slot);
|
||||
if (estate->es_evTupleNull[node->scanrelid - 1])
|
||||
if (estate->es_evTupleNull[scanrelid - 1])
|
||||
return slot; /* return empty slot */
|
||||
|
||||
ExecStoreTuple(estate->es_evTuple[node->scanrelid - 1],
|
||||
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
|
||||
slot, InvalidBuffer, false);
|
||||
|
||||
/*
|
||||
|
@ -85,7 +84,7 @@ SeqNext(SeqScan *node)
|
|||
*/
|
||||
|
||||
/* Flag for the next call that no more tuples */
|
||||
estate->es_evTupleNull[node->scanrelid - 1] = true;
|
||||
estate->es_evTupleNull[scanrelid - 1] = true;
|
||||
return (slot);
|
||||
}
|
||||
|
||||
|
@ -124,12 +123,12 @@ SeqNext(SeqScan *node)
|
|||
*/
|
||||
|
||||
TupleTableSlot *
|
||||
ExecSeqScan(SeqScan *node)
|
||||
ExecSeqScan(SeqScanState *node)
|
||||
{
|
||||
/*
|
||||
* use SeqNext as access method
|
||||
*/
|
||||
return ExecScan(node, (ExecScanAccessMtd) SeqNext);
|
||||
return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -139,9 +138,8 @@ ExecSeqScan(SeqScan *node)
|
|||
* subplans of scans.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static Oid
|
||||
InitScanRelation(SeqScan *node, EState *estate,
|
||||
CommonScanState *scanstate)
|
||||
static void
|
||||
InitScanRelation(SeqScanState *node, EState *estate)
|
||||
{
|
||||
Index relid;
|
||||
List *rangeTable;
|
||||
|
@ -156,7 +154,7 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||
*
|
||||
* We acquire AccessShareLock for the duration of the scan.
|
||||
*/
|
||||
relid = node->scanrelid;
|
||||
relid = ((SeqScan *) node->ps.plan)->scanrelid;
|
||||
rangeTable = estate->es_range_table;
|
||||
rtentry = rt_fetch(relid, rangeTable);
|
||||
reloid = rtentry->relid;
|
||||
|
@ -168,12 +166,10 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||
0,
|
||||
NULL);
|
||||
|
||||
scanstate->css_currentRelation = currentRelation;
|
||||
scanstate->css_currentScanDesc = currentScanDesc;
|
||||
node->ss_currentRelation = currentRelation;
|
||||
node->ss_currentScanDesc = currentScanDesc;
|
||||
|
||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
||||
|
||||
return reloid;
|
||||
ExecAssignScanType(node, RelationGetDescr(currentRelation), false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,59 +177,64 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||
* ExecInitSeqScan
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
|
||||
SeqScanState *
|
||||
ExecInitSeqScan(SeqScan *node, EState *estate)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
Oid reloid;
|
||||
SeqScanState *scanstate;
|
||||
|
||||
/*
|
||||
* Once upon a time it was possible to have an outerPlan of a SeqScan,
|
||||
* but not any more.
|
||||
*/
|
||||
Assert(outerPlan((Plan *) node) == NULL);
|
||||
Assert(innerPlan((Plan *) node) == NULL);
|
||||
Assert(outerPlan(node) == NULL);
|
||||
Assert(innerPlan(node) == NULL);
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
* create state structure
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new CommonScanState for node
|
||||
*/
|
||||
scanstate = makeNode(CommonScanState);
|
||||
node->scanstate = scanstate;
|
||||
scanstate = makeNode(SeqScanState);
|
||||
scanstate->ps.plan = (Plan *) node;
|
||||
scanstate->ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||
ExecAssignExprContext(estate, &scanstate->ps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*/
|
||||
scanstate->ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->plan.targetlist,
|
||||
(PlanState *) scanstate);
|
||||
scanstate->ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->plan.qual,
|
||||
(PlanState *) scanstate);
|
||||
|
||||
#define SEQSCAN_NSLOTS 2
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &scanstate->ps);
|
||||
ExecInitScanTupleSlot(estate, scanstate);
|
||||
|
||||
/*
|
||||
* initialize scan relation
|
||||
*/
|
||||
reloid = InitScanRelation(node, estate, scanstate);
|
||||
InitScanRelation(scanstate, estate);
|
||||
|
||||
scanstate->cstate.cs_TupFromTlist = false;
|
||||
scanstate->ps.ps_TupFromTlist = false;
|
||||
|
||||
/*
|
||||
* initialize tuple type
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
||||
ExecAssignResultTypeFromTL(&scanstate->ps);
|
||||
ExecAssignProjectionInfo(&scanstate->ps);
|
||||
|
||||
return TRUE;
|
||||
return scanstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -251,34 +252,34 @@ ExecCountSlotsSeqScan(SeqScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndSeqScan(SeqScan *node)
|
||||
ExecEndSeqScan(SeqScanState *node)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
Relation relation;
|
||||
HeapScanDesc scanDesc;
|
||||
|
||||
/*
|
||||
* get information from node
|
||||
*/
|
||||
scanstate = node->scanstate;
|
||||
relation = scanstate->css_currentRelation;
|
||||
scanDesc = scanstate->css_currentScanDesc;
|
||||
relation = node->ss_currentRelation;
|
||||
scanDesc = node->ss_currentScanDesc;
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(scanstate) because the rule manager
|
||||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
||||
ExecFreeExprContext(&scanstate->cstate);
|
||||
ExecFreeProjectionInfo(&node->ps);
|
||||
ExecFreeExprContext(&node->ps);
|
||||
|
||||
/*
|
||||
* close heap scan
|
||||
*/
|
||||
heap_endscan(scanDesc);
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss_ScanTupleSlot);
|
||||
|
||||
/*
|
||||
* close the heap relation.
|
||||
*
|
||||
|
@ -288,12 +289,6 @@ ExecEndSeqScan(SeqScan *node)
|
|||
* locking, however.)
|
||||
*/
|
||||
heap_close(relation, NoLock);
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -308,24 +303,24 @@ ExecEndSeqScan(SeqScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
EState *estate;
|
||||
Index scanrelid;
|
||||
HeapScanDesc scan;
|
||||
|
||||
scanstate = node->scanstate;
|
||||
estate = node->plan.state;
|
||||
estate = node->ps.state;
|
||||
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
|
||||
|
||||
/* If this is re-scanning of PlanQual ... */
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
||||
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||
{
|
||||
estate->es_evTupleNull[node->scanrelid - 1] = false;
|
||||
estate->es_evTupleNull[scanrelid - 1] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
scan = scanstate->css_currentScanDesc;
|
||||
scan = node->ss_currentScanDesc;
|
||||
|
||||
heap_rescan(scan, /* scan desc */
|
||||
NULL); /* new scan keys */
|
||||
|
@ -338,13 +333,11 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSeqMarkPos(SeqScan *node)
|
||||
ExecSeqMarkPos(SeqScanState *node)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
HeapScanDesc scan;
|
||||
|
||||
scanstate = node->scanstate;
|
||||
scan = scanstate->css_currentScanDesc;
|
||||
scan = node->ss_currentScanDesc;
|
||||
heap_markpos(scan);
|
||||
}
|
||||
|
||||
|
@ -355,12 +348,10 @@ ExecSeqMarkPos(SeqScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSeqRestrPos(SeqScan *node)
|
||||
ExecSeqRestrPos(SeqScanState *node)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
HeapScanDesc scan;
|
||||
|
||||
scanstate = node->scanstate;
|
||||
scan = scanstate->css_currentScanDesc;
|
||||
scan = node->ss_currentScanDesc;
|
||||
heap_restrpos(scan);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.6 2002/06/20 20:29:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.7 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -44,28 +44,27 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot * /* return: a tuple or NULL */
|
||||
ExecSetOp(SetOp *node)
|
||||
ExecSetOp(SetOpState *node)
|
||||
{
|
||||
SetOpState *setopstate;
|
||||
SetOp *plannode = (SetOp *) node->ps.plan;
|
||||
TupleTableSlot *resultTupleSlot;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
/*
|
||||
* get information from the node
|
||||
*/
|
||||
setopstate = node->setopstate;
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
resultTupleSlot = setopstate->cstate.cs_ResultTupleSlot;
|
||||
tupDesc = ExecGetResultType(&setopstate->cstate);
|
||||
outerPlan = outerPlanState(node);
|
||||
resultTupleSlot = node->ps.ps_ResultTupleSlot;
|
||||
tupDesc = ExecGetResultType(&node->ps);
|
||||
|
||||
/*
|
||||
* If the previously-returned tuple needs to be returned more than
|
||||
* once, keep returning it.
|
||||
*/
|
||||
if (setopstate->numOutput > 0)
|
||||
if (node->numOutput > 0)
|
||||
{
|
||||
setopstate->numOutput--;
|
||||
node->numOutput--;
|
||||
return resultTupleSlot;
|
||||
}
|
||||
|
||||
|
@ -88,15 +87,15 @@ ExecSetOp(SetOp *node)
|
|||
/*
|
||||
* fetch a tuple from the outer subplan, unless we already did.
|
||||
*/
|
||||
if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
|
||||
!setopstate->subplan_done)
|
||||
if (node->ps.ps_OuterTupleSlot == NULL &&
|
||||
!node->subplan_done)
|
||||
{
|
||||
setopstate->cstate.cs_OuterTupleSlot =
|
||||
ExecProcNode(outerPlan, (Plan *) node);
|
||||
if (TupIsNull(setopstate->cstate.cs_OuterTupleSlot))
|
||||
setopstate->subplan_done = true;
|
||||
node->ps.ps_OuterTupleSlot =
|
||||
ExecProcNode(outerPlan);
|
||||
if (TupIsNull(node->ps.ps_OuterTupleSlot))
|
||||
node->subplan_done = true;
|
||||
}
|
||||
inputTupleSlot = setopstate->cstate.cs_OuterTupleSlot;
|
||||
inputTupleSlot = node->ps.ps_OuterTupleSlot;
|
||||
|
||||
if (TupIsNull(resultTupleSlot))
|
||||
{
|
||||
|
@ -104,18 +103,18 @@ ExecSetOp(SetOp *node)
|
|||
* First of group: save a copy in result slot, and reset
|
||||
* duplicate-counters for new group.
|
||||
*/
|
||||
if (setopstate->subplan_done)
|
||||
if (node->subplan_done)
|
||||
return NULL; /* no more tuples */
|
||||
ExecStoreTuple(heap_copytuple(inputTupleSlot->val),
|
||||
resultTupleSlot,
|
||||
InvalidBuffer,
|
||||
true); /* free copied tuple at
|
||||
* ExecClearTuple */
|
||||
setopstate->numLeft = 0;
|
||||
setopstate->numRight = 0;
|
||||
node->numLeft = 0;
|
||||
node->numRight = 0;
|
||||
endOfGroup = false;
|
||||
}
|
||||
else if (setopstate->subplan_done)
|
||||
else if (node->subplan_done)
|
||||
{
|
||||
/*
|
||||
* Reached end of input, so finish processing final group
|
||||
|
@ -131,9 +130,9 @@ ExecSetOp(SetOp *node)
|
|||
if (execTuplesMatch(inputTupleSlot->val,
|
||||
resultTupleSlot->val,
|
||||
tupDesc,
|
||||
node->numCols, node->dupColIdx,
|
||||
setopstate->eqfunctions,
|
||||
setopstate->tempContext))
|
||||
plannode->numCols, plannode->dupColIdx,
|
||||
node->eqfunctions,
|
||||
node->tempContext))
|
||||
endOfGroup = false;
|
||||
else
|
||||
endOfGroup = true;
|
||||
|
@ -146,37 +145,37 @@ ExecSetOp(SetOp *node)
|
|||
* Decide how many copies (if any) to emit. This logic is
|
||||
* straight from the SQL92 specification.
|
||||
*/
|
||||
switch (node->cmd)
|
||||
switch (plannode->cmd)
|
||||
{
|
||||
case SETOPCMD_INTERSECT:
|
||||
if (setopstate->numLeft > 0 && setopstate->numRight > 0)
|
||||
setopstate->numOutput = 1;
|
||||
if (node->numLeft > 0 && node->numRight > 0)
|
||||
node->numOutput = 1;
|
||||
else
|
||||
setopstate->numOutput = 0;
|
||||
node->numOutput = 0;
|
||||
break;
|
||||
case SETOPCMD_INTERSECT_ALL:
|
||||
setopstate->numOutput =
|
||||
(setopstate->numLeft < setopstate->numRight) ?
|
||||
setopstate->numLeft : setopstate->numRight;
|
||||
node->numOutput =
|
||||
(node->numLeft < node->numRight) ?
|
||||
node->numLeft : node->numRight;
|
||||
break;
|
||||
case SETOPCMD_EXCEPT:
|
||||
if (setopstate->numLeft > 0 && setopstate->numRight == 0)
|
||||
setopstate->numOutput = 1;
|
||||
if (node->numLeft > 0 && node->numRight == 0)
|
||||
node->numOutput = 1;
|
||||
else
|
||||
setopstate->numOutput = 0;
|
||||
node->numOutput = 0;
|
||||
break;
|
||||
case SETOPCMD_EXCEPT_ALL:
|
||||
setopstate->numOutput =
|
||||
(setopstate->numLeft < setopstate->numRight) ?
|
||||
0 : (setopstate->numLeft - setopstate->numRight);
|
||||
node->numOutput =
|
||||
(node->numLeft < node->numRight) ?
|
||||
0 : (node->numLeft - node->numRight);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecSetOp: bogus command code %d",
|
||||
(int) node->cmd);
|
||||
(int) plannode->cmd);
|
||||
break;
|
||||
}
|
||||
/* Fall out of for-loop if we have tuples to emit */
|
||||
if (setopstate->numOutput > 0)
|
||||
if (node->numOutput > 0)
|
||||
break;
|
||||
/* Else flag that we have no current tuple, and loop around */
|
||||
ExecClearTuple(resultTupleSlot);
|
||||
|
@ -191,16 +190,16 @@ ExecSetOp(SetOp *node)
|
|||
bool isNull;
|
||||
|
||||
flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
|
||||
node->flagColIdx,
|
||||
plannode->flagColIdx,
|
||||
tupDesc,
|
||||
&isNull));
|
||||
Assert(!isNull);
|
||||
if (flag)
|
||||
setopstate->numRight++;
|
||||
node->numRight++;
|
||||
else
|
||||
setopstate->numLeft++;
|
||||
node->numLeft++;
|
||||
/* Set flag to fetch a new input tuple, and loop around */
|
||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
||||
node->ps.ps_OuterTupleSlot = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,8 +207,8 @@ ExecSetOp(SetOp *node)
|
|||
* If we fall out of loop, then we need to emit at least one copy of
|
||||
* resultTuple.
|
||||
*/
|
||||
Assert(setopstate->numOutput > 0);
|
||||
setopstate->numOutput--;
|
||||
Assert(node->numOutput > 0);
|
||||
node->numOutput--;
|
||||
return resultTupleSlot;
|
||||
}
|
||||
|
||||
|
@ -220,23 +219,19 @@ ExecSetOp(SetOp *node)
|
|||
* the node's subplan.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool /* return: initialization status */
|
||||
ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
||||
SetOpState *
|
||||
ExecInitSetOp(SetOp *node, EState *estate)
|
||||
{
|
||||
SetOpState *setopstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new SetOpState for node
|
||||
* create state structure
|
||||
*/
|
||||
setopstate = makeNode(SetOpState);
|
||||
node->setopstate = setopstate;
|
||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
||||
setopstate->ps.plan = (Plan *) node;
|
||||
setopstate->ps.state = estate;
|
||||
|
||||
setopstate->ps.ps_OuterTupleSlot = NULL;
|
||||
setopstate->subplan_done = false;
|
||||
setopstate->numOutput = 0;
|
||||
|
||||
|
@ -259,30 +254,29 @@ ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* Tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &setopstate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &setopstate->ps);
|
||||
|
||||
/*
|
||||
* then initialize outer plan
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate);
|
||||
|
||||
/*
|
||||
* setop nodes do no projections, so initialize projection info for
|
||||
* this node appropriately
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &setopstate->cstate);
|
||||
setopstate->cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromOuterPlan(&setopstate->ps);
|
||||
setopstate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
* Precompute fmgr lookup data for inner loop
|
||||
*/
|
||||
setopstate->eqfunctions =
|
||||
execTuplesMatchPrepare(ExecGetResultType(&setopstate->cstate),
|
||||
execTuplesMatchPrepare(ExecGetResultType(&setopstate->ps),
|
||||
node->numCols,
|
||||
node->dupColIdx);
|
||||
|
||||
return TRUE;
|
||||
return setopstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -301,34 +295,30 @@ ExecCountSlotsSetOp(SetOp *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndSetOp(SetOp *node)
|
||||
ExecEndSetOp(SetOpState *node)
|
||||
{
|
||||
SetOpState *setopstate = node->setopstate;
|
||||
|
||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||
|
||||
MemoryContextDelete(setopstate->tempContext);
|
||||
|
||||
/* clean up tuple table */
|
||||
ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
|
||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
node->ps.ps_OuterTupleSlot = NULL;
|
||||
|
||||
ExecEndNode(outerPlanState(node));
|
||||
|
||||
MemoryContextDelete(node->tempContext);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
SetOpState *setopstate = node->setopstate;
|
||||
|
||||
ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
|
||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
||||
setopstate->subplan_done = false;
|
||||
setopstate->numOutput = 0;
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
node->ps.ps_OuterTupleSlot = NULL;
|
||||
node->subplan_done = false;
|
||||
node->numOutput = 0;
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.40 2002/11/13 00:39:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.41 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -88,10 +88,9 @@ ExtractSortKeys(Sort *sortnode,
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecSort(Sort *node)
|
||||
ExecSort(SortState *node)
|
||||
{
|
||||
EState *estate;
|
||||
SortState *sortstate;
|
||||
ScanDirection dir;
|
||||
Tuplesortstate *tuplesortstate;
|
||||
HeapTuple heapTuple;
|
||||
|
@ -104,10 +103,9 @@ ExecSort(Sort *node)
|
|||
SO1_printf("ExecSort: %s\n",
|
||||
"entering routine");
|
||||
|
||||
sortstate = node->sortstate;
|
||||
estate = node->plan.state;
|
||||
estate = node->ss.ps.state;
|
||||
dir = estate->es_direction;
|
||||
tuplesortstate = (Tuplesortstate *) sortstate->tuplesortstate;
|
||||
tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
|
||||
|
||||
/*
|
||||
* If first time through, read all tuples from outer plan and pass
|
||||
|
@ -115,9 +113,10 @@ ExecSort(Sort *node)
|
|||
* tuplesort.
|
||||
*/
|
||||
|
||||
if (!sortstate->sort_Done)
|
||||
if (!node->sort_Done)
|
||||
{
|
||||
Plan *outerNode;
|
||||
Sort *plannode = (Sort *) node->ss.ps.plan;
|
||||
PlanState *outerNode;
|
||||
TupleDesc tupDesc;
|
||||
Oid *sortOperators;
|
||||
AttrNumber *attNums;
|
||||
|
@ -127,8 +126,7 @@ ExecSort(Sort *node)
|
|||
|
||||
/*
|
||||
* Want to scan subplan in the forward direction while creating
|
||||
* the sorted data. (Does setting my direction actually affect
|
||||
* the subplan? I bet this is useless code...)
|
||||
* the sorted data.
|
||||
*/
|
||||
estate->es_direction = ForwardScanDirection;
|
||||
|
||||
|
@ -138,15 +136,15 @@ ExecSort(Sort *node)
|
|||
SO1_printf("ExecSort: %s\n",
|
||||
"calling tuplesort_begin");
|
||||
|
||||
outerNode = outerPlan((Plan *) node);
|
||||
outerNode = outerPlanState(node);
|
||||
tupDesc = ExecGetTupType(outerNode);
|
||||
|
||||
ExtractSortKeys(node, &sortOperators, &attNums);
|
||||
ExtractSortKeys(plannode, &sortOperators, &attNums);
|
||||
|
||||
tuplesortstate = tuplesort_begin_heap(tupDesc, node->keycount,
|
||||
tuplesortstate = tuplesort_begin_heap(tupDesc, plannode->keycount,
|
||||
sortOperators, attNums,
|
||||
true /* randomAccess */ );
|
||||
sortstate->tuplesortstate = (void *) tuplesortstate;
|
||||
node->tuplesortstate = (void *) tuplesortstate;
|
||||
|
||||
pfree(sortOperators);
|
||||
pfree(attNums);
|
||||
|
@ -157,7 +155,7 @@ ExecSort(Sort *node)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
slot = ExecProcNode(outerNode, (Plan *) node);
|
||||
slot = ExecProcNode(outerNode);
|
||||
|
||||
if (TupIsNull(slot))
|
||||
break;
|
||||
|
@ -178,12 +176,12 @@ ExecSort(Sort *node)
|
|||
/*
|
||||
* make sure the tuple descriptor is up to date (is this needed?)
|
||||
*/
|
||||
ExecAssignResultType(&sortstate->csstate.cstate, tupDesc, false);
|
||||
ExecAssignResultType(&node->ss.ps, tupDesc, false);
|
||||
|
||||
/*
|
||||
* finally set the sorted flag to true
|
||||
*/
|
||||
sortstate->sort_Done = true;
|
||||
node->sort_Done = true;
|
||||
SO1_printf("ExecSort: %s\n", "sorting done");
|
||||
}
|
||||
|
||||
|
@ -198,7 +196,7 @@ ExecSort(Sort *node)
|
|||
ScanDirectionIsForward(dir),
|
||||
&should_free);
|
||||
|
||||
slot = sortstate->csstate.cstate.cs_ResultTupleSlot;
|
||||
slot = node->ss.ps.ps_ResultTupleSlot;
|
||||
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
|
||||
}
|
||||
|
||||
|
@ -209,29 +207,24 @@ ExecSort(Sort *node)
|
|||
* produced by the planner and initailizes its outer subtree.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitSort(Sort *node, EState *estate, Plan *parent)
|
||||
SortState *
|
||||
ExecInitSort(Sort *node, EState *estate)
|
||||
{
|
||||
SortState *sortstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
SO1_printf("ExecInitSort: %s\n",
|
||||
"initializing sort node");
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
sortstate = makeNode(SortState);
|
||||
sortstate->ss.ps.plan = (Plan *) node;
|
||||
sortstate->ss.ps.state = estate;
|
||||
|
||||
sortstate->sort_Done = false;
|
||||
sortstate->tuplesortstate = NULL;
|
||||
|
||||
node->sortstate = sortstate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
|
@ -246,27 +239,26 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
|
|||
*
|
||||
* sort nodes only return scan tuples from their sorted relation.
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
|
||||
ExecInitScanTupleSlot(estate, &sortstate->csstate);
|
||||
ExecInitResultTupleSlot(estate, &sortstate->ss.ps);
|
||||
ExecInitScanTupleSlot(estate, &sortstate->ss);
|
||||
|
||||
/*
|
||||
* initializes child nodes
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate);
|
||||
|
||||
/*
|
||||
* initialize tuple type. no need to initialize projection info
|
||||
* because this node doesn't do projections.
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &sortstate->csstate.cstate);
|
||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
|
||||
sortstate->csstate.cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromOuterPlan(&sortstate->ss.ps);
|
||||
ExecAssignScanTypeFromOuterPlan(&sortstate->ss);
|
||||
sortstate->ss.ps.ps_ProjInfo = NULL;
|
||||
|
||||
SO1_printf("ExecInitSort: %s\n",
|
||||
"sort node initialized");
|
||||
|
||||
return TRUE;
|
||||
return sortstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -282,39 +274,27 @@ ExecCountSlotsSort(Sort *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndSort(Sort *node)
|
||||
ExecEndSort(SortState *node)
|
||||
{
|
||||
SortState *sortstate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* get info from the sort state
|
||||
*/
|
||||
SO1_printf("ExecEndSort: %s\n",
|
||||
"shutting down sort node");
|
||||
|
||||
sortstate = node->sortstate;
|
||||
|
||||
/*
|
||||
* shut down the subplan
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecEndNode(outerPlan, (Plan *) node);
|
||||
|
||||
/*
|
||||
* clean out the tuple table
|
||||
*/
|
||||
ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
|
||||
/*
|
||||
* shut down the subplan
|
||||
*/
|
||||
ExecEndNode(outerPlanState(node));
|
||||
|
||||
/*
|
||||
* Release tuplesort resources
|
||||
*/
|
||||
if (sortstate->tuplesortstate != NULL)
|
||||
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
sortstate->tuplesortstate = NULL;
|
||||
|
||||
pfree(sortstate);
|
||||
node->sortstate = NULL;
|
||||
if (node->tuplesortstate != NULL)
|
||||
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
||||
node->tuplesortstate = NULL;
|
||||
|
||||
SO1_printf("ExecEndSort: %s\n",
|
||||
"sort node shutdown");
|
||||
|
@ -327,17 +307,15 @@ ExecEndSort(Sort *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSortMarkPos(Sort *node)
|
||||
ExecSortMarkPos(SortState *node)
|
||||
{
|
||||
SortState *sortstate = node->sortstate;
|
||||
|
||||
/*
|
||||
* if we haven't sorted yet, just return
|
||||
*/
|
||||
if (!sortstate->sort_Done)
|
||||
if (!node->sort_Done)
|
||||
return;
|
||||
|
||||
tuplesort_markpos((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
tuplesort_markpos((Tuplesortstate *) node->tuplesortstate);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -347,36 +325,32 @@ ExecSortMarkPos(Sort *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSortRestrPos(Sort *node)
|
||||
ExecSortRestrPos(SortState *node)
|
||||
{
|
||||
SortState *sortstate = node->sortstate;
|
||||
|
||||
/*
|
||||
* if we haven't sorted yet, just return.
|
||||
*/
|
||||
if (!sortstate->sort_Done)
|
||||
if (!node->sort_Done)
|
||||
return;
|
||||
|
||||
/*
|
||||
* restore the scan to the previously marked position
|
||||
*/
|
||||
tuplesort_restorepos((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
tuplesort_restorepos((Tuplesortstate *) node->tuplesortstate);
|
||||
}
|
||||
|
||||
void
|
||||
ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanSort(SortState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
SortState *sortstate = node->sortstate;
|
||||
|
||||
/*
|
||||
* If we haven't sorted yet, just return. If outerplan' chgParam is
|
||||
* not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||
* reason to re-scan it at all.
|
||||
*/
|
||||
if (!sortstate->sort_Done)
|
||||
if (!node->sort_Done)
|
||||
return;
|
||||
|
||||
ExecClearTuple(sortstate->csstate.cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* If subnode is to be rescanned then we forget previous sort results;
|
||||
|
@ -384,12 +358,12 @@ ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent)
|
|||
*
|
||||
* Otherwise we can just rewind and rescan the sorted output.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam != NULL)
|
||||
if (((PlanState *) node)->lefttree->chgParam != NULL)
|
||||
{
|
||||
sortstate->sort_Done = false;
|
||||
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
sortstate->tuplesortstate = NULL;
|
||||
node->sort_Done = false;
|
||||
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
||||
node->tuplesortstate = NULL;
|
||||
}
|
||||
else
|
||||
tuplesort_rescan((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.34 2002/11/26 03:01:57 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.35 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -27,14 +27,15 @@
|
|||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecSubPlan(node)
|
||||
*
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
Datum
|
||||
ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
ExecSubPlan(SubPlanState *node, List *pvar,
|
||||
ExprContext *econtext, bool *isNull)
|
||||
{
|
||||
Plan *plan = node->plan;
|
||||
SubLink *sublink = node->sublink;
|
||||
PlanState *planstate = node->planstate;
|
||||
SubPlan *subplan = (SubPlan *) node->ps.plan;
|
||||
SubLink *sublink = subplan->sublink;
|
||||
SubLinkType subLinkType = sublink->subLinkType;
|
||||
bool useor = sublink->useor;
|
||||
MemoryContext oldcontext;
|
||||
|
@ -49,15 +50,15 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||
*/
|
||||
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
|
||||
|
||||
if (node->setParam != NIL)
|
||||
if (subplan->setParam != NIL)
|
||||
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
|
||||
|
||||
/*
|
||||
* Set Params of this plan from parent plan correlation Vars
|
||||
*/
|
||||
if (node->parParam != NIL)
|
||||
if (subplan->parParam != NIL)
|
||||
{
|
||||
foreach(lst, node->parParam)
|
||||
foreach(lst, subplan->parParam)
|
||||
{
|
||||
ParamExecData *prm;
|
||||
|
||||
|
@ -69,11 +70,12 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||
NULL);
|
||||
pvar = lnext(pvar);
|
||||
}
|
||||
plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
|
||||
planstate->chgParam = nconc(planstate->chgParam,
|
||||
listCopy(subplan->parParam));
|
||||
}
|
||||
Assert(pvar == NIL);
|
||||
|
||||
ExecReScan(plan, NULL, NULL);
|
||||
ExecReScan(planstate, NULL);
|
||||
|
||||
/*
|
||||
* For all sublink types except EXPR_SUBLINK, the result is boolean as
|
||||
|
@ -96,9 +98,9 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||
result = BoolGetDatum(subLinkType == ALL_SUBLINK);
|
||||
*isNull = false;
|
||||
|
||||
for (slot = ExecProcNode(plan, NULL);
|
||||
for (slot = ExecProcNode(planstate);
|
||||
!TupIsNull(slot);
|
||||
slot = ExecProcNode(plan, NULL))
|
||||
slot = ExecProcNode(planstate))
|
||||
{
|
||||
HeapTuple tup = slot->val;
|
||||
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
||||
|
@ -283,13 +285,37 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitSubPlan
|
||||
*
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
||||
SubPlanState *
|
||||
ExecInitSubPlan(SubPlan *node, EState *estate)
|
||||
{
|
||||
EState *sp_estate = CreateExecutorState();
|
||||
SubPlanState *subplanstate;
|
||||
EState *sp_estate;
|
||||
|
||||
/*
|
||||
* Do access checking on the rangetable entries in the subquery.
|
||||
* Here, we assume the subquery is a SELECT.
|
||||
*/
|
||||
ExecCheckRTPerms(node->rtable, CMD_SELECT);
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
*/
|
||||
subplanstate = makeNode(SubPlanState);
|
||||
subplanstate->ps.plan = (Plan *) node;
|
||||
subplanstate->ps.state = estate;
|
||||
|
||||
subplanstate->needShutdown = false;
|
||||
subplanstate->curTuple = NULL;
|
||||
|
||||
/* XXX temporary hack */
|
||||
node->pstate = subplanstate;
|
||||
|
||||
/*
|
||||
* create an EState for the subplan
|
||||
*/
|
||||
sp_estate = CreateExecutorState();
|
||||
|
||||
sp_estate->es_range_table = node->rtable;
|
||||
sp_estate->es_param_list_info = estate->es_param_list_info;
|
||||
|
@ -297,14 +323,14 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
|||
sp_estate->es_tupleTable =
|
||||
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
|
||||
sp_estate->es_snapshot = estate->es_snapshot;
|
||||
sp_estate->es_instrument = estate->es_instrument;
|
||||
|
||||
node->needShutdown = false;
|
||||
node->curTuple = NULL;
|
||||
/*
|
||||
* Start up the subplan
|
||||
*/
|
||||
subplanstate->planstate = ExecInitNode(node->plan, sp_estate);
|
||||
|
||||
if (!ExecInitNode(node->plan, sp_estate, parent))
|
||||
return false;
|
||||
|
||||
node->needShutdown = true; /* now we need to shutdown the subplan */
|
||||
subplanstate->needShutdown = true; /* now we need to shutdown the subplan */
|
||||
|
||||
/*
|
||||
* If this plan is un-correlated or undirect correlated one and want
|
||||
|
@ -318,7 +344,7 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
|||
{
|
||||
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
|
||||
|
||||
prm->execPlan = node;
|
||||
prm->execPlan = subplanstate;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -328,7 +354,7 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
|||
*/
|
||||
}
|
||||
|
||||
return true;
|
||||
return subplanstate;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -345,10 +371,12 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
||||
ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
||||
{
|
||||
Plan *plan = node->plan;
|
||||
SubLink *sublink = node->sublink;
|
||||
PlanState *planstate = node->planstate;
|
||||
SubPlan *subplan = (SubPlan *) node->ps.plan;
|
||||
SubLink *sublink = subplan->sublink;
|
||||
EState *estate = node->ps.state;
|
||||
MemoryContext oldcontext;
|
||||
TupleTableSlot *slot;
|
||||
List *lst;
|
||||
|
@ -364,12 +392,12 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
sublink->subLinkType == ALL_SUBLINK)
|
||||
elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
|
||||
|
||||
if (plan->chgParam != NULL)
|
||||
ExecReScan(plan, NULL, NULL);
|
||||
if (planstate->chgParam != NULL)
|
||||
ExecReScan(planstate, NULL);
|
||||
|
||||
for (slot = ExecProcNode(plan, NULL);
|
||||
for (slot = ExecProcNode(planstate);
|
||||
!TupIsNull(slot);
|
||||
slot = ExecProcNode(plan, NULL))
|
||||
slot = ExecProcNode(planstate))
|
||||
{
|
||||
HeapTuple tup = slot->val;
|
||||
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
||||
|
@ -377,7 +405,7 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
|
||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
||||
{
|
||||
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
|
||||
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(subplan->setParam)]);
|
||||
|
||||
prm->execPlan = NULL;
|
||||
prm->value = BoolGetDatum(true);
|
||||
|
@ -404,9 +432,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
heap_freetuple(node->curTuple);
|
||||
node->curTuple = tup;
|
||||
|
||||
foreach(lst, node->setParam)
|
||||
foreach(lst, subplan->setParam)
|
||||
{
|
||||
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
|
||||
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
|
||||
|
||||
prm->execPlan = NULL;
|
||||
prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
|
||||
|
@ -418,7 +446,7 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
{
|
||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
||||
{
|
||||
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]);
|
||||
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(subplan->setParam)]);
|
||||
|
||||
prm->execPlan = NULL;
|
||||
prm->value = BoolGetDatum(false);
|
||||
|
@ -426,9 +454,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach(lst, node->setParam)
|
||||
foreach(lst, subplan->setParam)
|
||||
{
|
||||
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
|
||||
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
|
||||
|
||||
prm->execPlan = NULL;
|
||||
prm->value = (Datum) 0;
|
||||
|
@ -437,9 +465,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
}
|
||||
}
|
||||
|
||||
if (plan->extParam == NULL) /* un-correlated ... */
|
||||
if (planstate->plan->extParam == NULL) /* un-correlated ... */
|
||||
{
|
||||
ExecEndNode(plan, NULL);
|
||||
ExecEndNode(planstate);
|
||||
node->needShutdown = false;
|
||||
}
|
||||
|
||||
|
@ -451,11 +479,11 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndSubPlan(SubPlan *node)
|
||||
ExecEndSubPlan(SubPlanState *node)
|
||||
{
|
||||
if (node->needShutdown)
|
||||
{
|
||||
ExecEndNode(node->plan, NULL);
|
||||
ExecEndNode(node->planstate);
|
||||
node->needShutdown = false;
|
||||
}
|
||||
if (node->curTuple)
|
||||
|
@ -466,33 +494,34 @@ ExecEndSubPlan(SubPlan *node)
|
|||
}
|
||||
|
||||
void
|
||||
ExecReScanSetParamPlan(SubPlan *node, Plan *parent)
|
||||
ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
|
||||
{
|
||||
Plan *plan = node->plan;
|
||||
PlanState *planstate = node->planstate;
|
||||
SubPlan *subplan = (SubPlan *) node->ps.plan;
|
||||
EState *estate = node->ps.state;
|
||||
List *lst;
|
||||
|
||||
if (node->parParam != NULL)
|
||||
if (subplan->parParam != NULL)
|
||||
elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
|
||||
if (node->setParam == NULL)
|
||||
if (subplan->setParam == NULL)
|
||||
elog(ERROR, "ExecReScanSetParamPlan: setParam list is NULL");
|
||||
if (plan->extParam == NULL)
|
||||
if (planstate->plan->extParam == NULL)
|
||||
elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
|
||||
|
||||
/*
|
||||
* Don't actual re-scan: ExecSetParamPlan does re-scan if
|
||||
* node->plan->chgParam is not NULL... ExecReScan (plan, NULL, NULL);
|
||||
* subplan->plan->chgParam is not NULL... ExecReScan (planstate, NULL);
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mark this subplan's output parameters as needing recalculation
|
||||
*/
|
||||
foreach(lst, node->setParam)
|
||||
foreach(lst, subplan->setParam)
|
||||
{
|
||||
ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(lst)]);
|
||||
ParamExecData *prm = &(estate->es_param_exec_vals[lfirsti(lst)]);
|
||||
|
||||
prm->execPlan = node;
|
||||
}
|
||||
|
||||
parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));
|
||||
|
||||
parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.13 2002/06/20 20:29:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.14 2002/12/05 15:50:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -35,7 +35,7 @@
|
|||
#include "parser/parsetree.h"
|
||||
#include "tcop/pquery.h"
|
||||
|
||||
static TupleTableSlot *SubqueryNext(SubqueryScan *node);
|
||||
static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Scan Support
|
||||
|
@ -48,9 +48,8 @@ static TupleTableSlot *SubqueryNext(SubqueryScan *node);
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
SubqueryNext(SubqueryScan *node)
|
||||
SubqueryNext(SubqueryScanState *node)
|
||||
{
|
||||
SubqueryScanState *subquerystate;
|
||||
EState *estate;
|
||||
ScanDirection direction;
|
||||
TupleTableSlot *slot;
|
||||
|
@ -58,8 +57,7 @@ SubqueryNext(SubqueryScan *node)
|
|||
/*
|
||||
* get information from the estate and scan state
|
||||
*/
|
||||
estate = node->scan.plan.state;
|
||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
||||
estate = node->ss.ps.state;
|
||||
direction = estate->es_direction;
|
||||
|
||||
/*
|
||||
|
@ -70,11 +68,11 @@ SubqueryNext(SubqueryScan *node)
|
|||
/*
|
||||
* get the next tuple from the sub-query
|
||||
*/
|
||||
subquerystate->sss_SubEState->es_direction = direction;
|
||||
node->sss_SubEState->es_direction = direction;
|
||||
|
||||
slot = ExecProcNode(node->subplan, (Plan *) node);
|
||||
slot = ExecProcNode(node->subplan);
|
||||
|
||||
subquerystate->csstate.css_ScanTupleSlot = slot;
|
||||
node->ss.ss_ScanTupleSlot = slot;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
@ -90,20 +88,20 @@ SubqueryNext(SubqueryScan *node)
|
|||
*/
|
||||
|
||||
TupleTableSlot *
|
||||
ExecSubqueryScan(SubqueryScan *node)
|
||||
ExecSubqueryScan(SubqueryScanState *node)
|
||||
{
|
||||
/*
|
||||
* use SubqueryNext as access method
|
||||
*/
|
||||
return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
|
||||
return ExecScan(&node->ss, (ExecScanAccessMtd) SubqueryNext);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ExecInitSubqueryScan
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
||||
SubqueryScanState *
|
||||
ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
|
||||
{
|
||||
SubqueryScanState *subquerystate;
|
||||
RangeTblEntry *rte;
|
||||
|
@ -112,33 +110,39 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* SubqueryScan should not have any "normal" children.
|
||||
*/
|
||||
Assert(outerPlan((Plan *) node) == NULL);
|
||||
Assert(innerPlan((Plan *) node) == NULL);
|
||||
Assert(outerPlan(node) == NULL);
|
||||
Assert(innerPlan(node) == NULL);
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
node->scan.plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new SubqueryScanState for node
|
||||
* create state structure
|
||||
*/
|
||||
subquerystate = makeNode(SubqueryScanState);
|
||||
node->scan.scanstate = (CommonScanState *) subquerystate;
|
||||
subquerystate->ss.ps.plan = (Plan *) node;
|
||||
subquerystate->ss.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &subquerystate->csstate.cstate);
|
||||
ExecAssignExprContext(estate, &subquerystate->ss.ps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*/
|
||||
subquerystate->ss.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.targetlist,
|
||||
(PlanState *) subquerystate);
|
||||
subquerystate->ss.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.qual,
|
||||
(PlanState *) subquerystate);
|
||||
|
||||
#define SUBQUERYSCAN_NSLOTS 1
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
|
||||
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
|
||||
|
||||
/*
|
||||
* initialize subquery
|
||||
|
@ -157,20 +161,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
|||
sp_estate->es_tupleTable =
|
||||
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
|
||||
sp_estate->es_snapshot = estate->es_snapshot;
|
||||
sp_estate->es_instrument = estate->es_instrument;
|
||||
|
||||
if (!ExecInitNode(node->subplan, sp_estate, (Plan *) node))
|
||||
return false;
|
||||
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
|
||||
|
||||
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
||||
subquerystate->csstate.cstate.cs_TupFromTlist = false;
|
||||
subquerystate->ss.ss_ScanTupleSlot = NULL;
|
||||
subquerystate->ss.ps.ps_TupFromTlist = false;
|
||||
|
||||
/*
|
||||
* initialize tuple type
|
||||
*/
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
|
||||
ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
|
||||
ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
|
||||
ExecAssignProjectionInfo(&subquerystate->ss.ps);
|
||||
|
||||
return TRUE;
|
||||
return subquerystate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -191,42 +195,31 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndSubqueryScan(SubqueryScan *node)
|
||||
ExecEndSubqueryScan(SubqueryScanState *node)
|
||||
{
|
||||
SubqueryScanState *subquerystate;
|
||||
|
||||
/*
|
||||
* get information from node
|
||||
*/
|
||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
*
|
||||
* Note: we don't ExecFreeResultType(subquerystate) because the rule
|
||||
* manager depends on the tupType returned by ExecMain(). So for now,
|
||||
* this is freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&subquerystate->csstate.cstate);
|
||||
ExecFreeExprContext(&subquerystate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* close down subquery
|
||||
*/
|
||||
ExecEndNode(node->subplan, (Plan *) node);
|
||||
|
||||
/*
|
||||
* clean up subquery's tuple table
|
||||
*/
|
||||
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
||||
ExecDropTupleTable(subquerystate->sss_SubEState->es_tupleTable, true);
|
||||
|
||||
/* XXX we seem to be leaking the sub-EState... */
|
||||
ExecFreeProjectionInfo(&node->ss.ps);
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
|
||||
/*
|
||||
* clean out the upper tuple table
|
||||
*/
|
||||
ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* close down subquery
|
||||
*/
|
||||
ExecEndNode(node->subplan);
|
||||
|
||||
/*
|
||||
* clean up subquery's tuple table
|
||||
*/
|
||||
node->ss.ss_ScanTupleSlot = NULL;
|
||||
ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
|
||||
|
||||
/* XXX we seem to be leaking the sub-EState... */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -236,27 +229,25 @@ ExecEndSubqueryScan(SubqueryScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
SubqueryScanState *subquerystate;
|
||||
EState *estate;
|
||||
|
||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
||||
estate = node->scan.plan.state;
|
||||
estate = node->ss.ps.state;
|
||||
|
||||
/*
|
||||
* ExecReScan doesn't know about my subplan, so I have to do
|
||||
* changed-parameter signaling myself.
|
||||
*/
|
||||
if (node->scan.plan.chgParam != NULL)
|
||||
SetChangedParamList(node->subplan, node->scan.plan.chgParam);
|
||||
if (node->ss.ps.chgParam != NULL)
|
||||
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (node->subplan->chgParam == NULL)
|
||||
ExecReScan(node->subplan, NULL, (Plan *) node);
|
||||
ExecReScan(node->subplan, NULL);
|
||||
|
||||
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
||||
node->ss.ss_ScanTupleSlot = NULL;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.27 2002/11/30 05:21:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.28 2002/12/05 15:50:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -30,7 +30,7 @@
|
|||
#include "parser/parsetree.h"
|
||||
|
||||
static int TidListCreate(List *, ExprContext *, ItemPointerData[]);
|
||||
static TupleTableSlot *TidNext(TidScan *node);
|
||||
static TupleTableSlot *TidNext(TidScanState *node);
|
||||
|
||||
static int
|
||||
TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
|
||||
|
@ -65,19 +65,17 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static TupleTableSlot *
|
||||
TidNext(TidScan *node)
|
||||
TidNext(TidScanState *node)
|
||||
{
|
||||
EState *estate;
|
||||
CommonScanState *scanstate;
|
||||
TidScanState *tidstate;
|
||||
ScanDirection direction;
|
||||
Snapshot snapshot;
|
||||
Relation heapRelation;
|
||||
HeapTuple tuple;
|
||||
TupleTableSlot *slot;
|
||||
Index scanrelid;
|
||||
Buffer buffer = InvalidBuffer;
|
||||
int numTids;
|
||||
|
||||
bool bBackward;
|
||||
int tidNumber;
|
||||
ItemPointerData *tidList;
|
||||
|
@ -85,15 +83,14 @@ TidNext(TidScan *node)
|
|||
/*
|
||||
* extract necessary information from tid scan node
|
||||
*/
|
||||
estate = node->scan.plan.state;
|
||||
estate = node->ss.ps.state;
|
||||
direction = estate->es_direction;
|
||||
snapshot = estate->es_snapshot;
|
||||
scanstate = node->scan.scanstate;
|
||||
tidstate = node->tidstate;
|
||||
heapRelation = scanstate->css_currentRelation;
|
||||
numTids = tidstate->tss_NumTids;
|
||||
tidList = tidstate->tss_TidList;
|
||||
slot = scanstate->css_ScanTupleSlot;
|
||||
heapRelation = node->ss.ss_currentRelation;
|
||||
numTids = node->tss_NumTids;
|
||||
tidList = node->tss_TidList;
|
||||
slot = node->ss.ss_ScanTupleSlot;
|
||||
scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||
|
@ -102,10 +99,10 @@ TidNext(TidScan *node)
|
|||
* switching in Init/ReScan plan...
|
||||
*/
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||
{
|
||||
ExecClearTuple(slot);
|
||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
||||
if (estate->es_evTupleNull[scanrelid - 1])
|
||||
return slot; /* return empty slot */
|
||||
|
||||
/*
|
||||
|
@ -113,15 +110,15 @@ TidNext(TidScan *node)
|
|||
* list? In runtime-key case this is not certain, is it?
|
||||
*/
|
||||
|
||||
ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
|
||||
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
|
||||
slot, InvalidBuffer, false);
|
||||
|
||||
/* Flag for the next call that no more tuples */
|
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
||||
estate->es_evTupleNull[scanrelid - 1] = true;
|
||||
return (slot);
|
||||
}
|
||||
|
||||
tuple = &(tidstate->tss_htup);
|
||||
tuple = &(node->tss_htup);
|
||||
|
||||
/*
|
||||
* ok, now that we have what we need, fetch an tid tuple. if scanning
|
||||
|
@ -131,26 +128,26 @@ TidNext(TidScan *node)
|
|||
bBackward = ScanDirectionIsBackward(direction);
|
||||
if (bBackward)
|
||||
{
|
||||
tidNumber = numTids - tidstate->tss_TidPtr - 1;
|
||||
tidNumber = numTids - node->tss_TidPtr - 1;
|
||||
if (tidNumber < 0)
|
||||
{
|
||||
tidNumber = 0;
|
||||
tidstate->tss_TidPtr = numTids - 1;
|
||||
node->tss_TidPtr = numTids - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((tidNumber = tidstate->tss_TidPtr) < 0)
|
||||
if ((tidNumber = node->tss_TidPtr) < 0)
|
||||
{
|
||||
tidNumber = 0;
|
||||
tidstate->tss_TidPtr = 0;
|
||||
node->tss_TidPtr = 0;
|
||||
}
|
||||
}
|
||||
while (tidNumber < numTids)
|
||||
{
|
||||
bool slot_is_valid = false;
|
||||
|
||||
tuple->t_self = tidList[tidstate->tss_TidPtr];
|
||||
tuple->t_self = tidList[node->tss_TidPtr];
|
||||
if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
|
||||
{
|
||||
bool prev_matches = false;
|
||||
|
@ -181,7 +178,7 @@ TidNext(TidScan *node)
|
|||
* do this by passing the tuple through ExecQual and look for
|
||||
* failure with all previous qualifications.
|
||||
*/
|
||||
for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
|
||||
for (prev_tid = 0; prev_tid < node->tss_TidPtr;
|
||||
prev_tid++)
|
||||
{
|
||||
if (ItemPointerEquals(&tidList[prev_tid], &tuple->t_self))
|
||||
|
@ -197,9 +194,9 @@ TidNext(TidScan *node)
|
|||
}
|
||||
tidNumber++;
|
||||
if (bBackward)
|
||||
tidstate->tss_TidPtr--;
|
||||
node->tss_TidPtr--;
|
||||
else
|
||||
tidstate->tss_TidPtr++;
|
||||
node->tss_TidPtr++;
|
||||
if (slot_is_valid)
|
||||
return slot;
|
||||
}
|
||||
|
@ -231,12 +228,12 @@ TidNext(TidScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecTidScan(TidScan *node)
|
||||
ExecTidScan(TidScanState *node)
|
||||
{
|
||||
/*
|
||||
* use TidNext as access method
|
||||
*/
|
||||
return ExecScan(&node->scan, (ExecScanAccessMtd) TidNext);
|
||||
return ExecScan(&node->ss, (ExecScanAccessMtd) TidNext);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -244,42 +241,30 @@ ExecTidScan(TidScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecTidReScan(TidScanState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
EState *estate;
|
||||
TidScanState *tidstate;
|
||||
ItemPointerData *tidList;
|
||||
Index scanrelid;
|
||||
|
||||
estate = node->scan.plan.state;
|
||||
tidstate = node->tidstate;
|
||||
tidList = tidstate->tss_TidList;
|
||||
estate = node->ss.ps.state;
|
||||
tidList = node->tss_TidList;
|
||||
scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||
|
||||
/* If we are being passed an outer tuple, save it for runtime key calc */
|
||||
if (exprCtxt != NULL)
|
||||
node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
|
||||
node->ss.ps.ps_ExprContext->ecxt_outertuple =
|
||||
exprCtxt->ecxt_outertuple;
|
||||
|
||||
/* do runtime calc of target TIDs, if needed */
|
||||
if (node->needRescan)
|
||||
tidstate->tss_NumTids =
|
||||
TidListCreate(node->tideval,
|
||||
node->scan.scanstate->cstate.cs_ExprContext,
|
||||
tidList);
|
||||
|
||||
/* If this is re-scanning of PlanQual ... */
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||
{
|
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
|
||||
estate->es_evTupleNull[scanrelid - 1] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
tidstate->tss_TidPtr = -1;
|
||||
|
||||
/*
|
||||
* perhaps return something meaningful
|
||||
*/
|
||||
return;
|
||||
node->tss_TidPtr = -1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -290,18 +275,13 @@ ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndTidScan(TidScan *node)
|
||||
ExecEndTidScan(TidScanState *node)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
TidScanState *tidstate;
|
||||
|
||||
/*
|
||||
* extract information from the node
|
||||
*/
|
||||
scanstate = node->scan.scanstate;
|
||||
tidstate = node->tidstate;
|
||||
if (tidstate && tidstate->tss_TidList)
|
||||
pfree(tidstate->tss_TidList);
|
||||
if (node && node->tss_TidList)
|
||||
pfree(node->tss_TidList);
|
||||
|
||||
/*
|
||||
* Free the projection info and the scan attribute info
|
||||
|
@ -310,8 +290,14 @@ ExecEndTidScan(TidScan *node)
|
|||
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||
* freed at end-transaction time. -cim 6/2/91
|
||||
*/
|
||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
||||
ExecFreeExprContext(&scanstate->cstate);
|
||||
ExecFreeProjectionInfo(&node->ss.ps);
|
||||
ExecFreeExprContext(&node->ss.ps);
|
||||
|
||||
/*
|
||||
* clear out tuple table slots
|
||||
*/
|
||||
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||
|
||||
/*
|
||||
* close the heap relation.
|
||||
|
@ -320,13 +306,7 @@ ExecEndTidScan(TidScan *node)
|
|||
* ExecInitTidScan. This lock should be held till end of transaction.
|
||||
* (There is a faction that considers this too much locking, however.)
|
||||
*/
|
||||
heap_close(scanstate->css_currentRelation, NoLock);
|
||||
|
||||
/*
|
||||
* clear out tuple table slots
|
||||
*/
|
||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
||||
heap_close(node->ss.ss_currentRelation, NoLock);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -337,12 +317,9 @@ ExecEndTidScan(TidScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecTidMarkPos(TidScan *node)
|
||||
ExecTidMarkPos(TidScanState *node)
|
||||
{
|
||||
TidScanState *tidstate;
|
||||
|
||||
tidstate = node->tidstate;
|
||||
tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
|
||||
node->tss_MarkTidPtr = node->tss_TidPtr;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -355,12 +332,9 @@ ExecTidMarkPos(TidScan *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecTidRestrPos(TidScan *node)
|
||||
ExecTidRestrPos(TidScanState *node)
|
||||
{
|
||||
TidScanState *tidstate;
|
||||
|
||||
tidstate = node->tidstate;
|
||||
tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
|
||||
node->tss_TidPtr = node->tss_MarkTidPtr;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -374,11 +348,10 @@ ExecTidRestrPos(TidScan *node)
|
|||
* estate: the execution state initialized in InitPlan.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool
|
||||
ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
||||
TidScanState *
|
||||
ExecInitTidScan(TidScan *node, EState *estate)
|
||||
{
|
||||
TidScanState *tidstate;
|
||||
CommonScanState *scanstate;
|
||||
ItemPointerData *tidList;
|
||||
int numTids;
|
||||
int tidPtr;
|
||||
|
@ -390,56 +363,50 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||
List *execParam = NIL;
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
* create state structure
|
||||
*/
|
||||
node->scan.plan.state = estate;
|
||||
|
||||
/*
|
||||
* Part 1) initialize scan state
|
||||
*
|
||||
* create new CommonScanState for node
|
||||
*/
|
||||
scanstate = makeNode(CommonScanState);
|
||||
node->scan.scanstate = scanstate;
|
||||
tidstate = makeNode(TidScanState);
|
||||
tidstate->ss.ps.plan = (Plan *) node;
|
||||
tidstate->ss.ps.state = estate;
|
||||
|
||||
/*
|
||||
* Miscellaneous initialization
|
||||
*
|
||||
* create expression context for node
|
||||
*/
|
||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||
ExecAssignExprContext(estate, &tidstate->ss.ps);
|
||||
|
||||
/*
|
||||
* initialize child expressions
|
||||
*/
|
||||
tidstate->ss.ps.targetlist = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.targetlist,
|
||||
(PlanState *) tidstate);
|
||||
tidstate->ss.ps.qual = (List *)
|
||||
ExecInitExpr((Node *) node->scan.plan.qual,
|
||||
(PlanState *) tidstate);
|
||||
|
||||
#define TIDSCAN_NSLOTS 2
|
||||
|
||||
/*
|
||||
* tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
||||
ExecInitScanTupleSlot(estate, scanstate);
|
||||
ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
|
||||
ExecInitScanTupleSlot(estate, &tidstate->ss);
|
||||
|
||||
/*
|
||||
* initialize projection info. result type comes from scan desc
|
||||
* below..
|
||||
*/
|
||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
||||
|
||||
/*
|
||||
* Part 2) initialize tid scan state
|
||||
*
|
||||
* create new TidScanState for node
|
||||
*/
|
||||
tidstate = makeNode(TidScanState);
|
||||
node->tidstate = tidstate;
|
||||
ExecAssignProjectionInfo(&tidstate->ss.ps);
|
||||
|
||||
/*
|
||||
* get the tid node information
|
||||
*/
|
||||
tidList = (ItemPointerData *) palloc(length(node->tideval) * sizeof(ItemPointerData));
|
||||
numTids = 0;
|
||||
if (!node->needRescan)
|
||||
numTids = TidListCreate(node->tideval,
|
||||
scanstate->cstate.cs_ExprContext,
|
||||
tidList);
|
||||
numTids = TidListCreate(node->tideval,
|
||||
tidstate->ss.ps.ps_ExprContext,
|
||||
tidList);
|
||||
tidPtr = -1;
|
||||
|
||||
CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
|
||||
|
@ -465,25 +432,25 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||
|
||||
currentRelation = heap_open(reloid, AccessShareLock);
|
||||
|
||||
scanstate->css_currentRelation = currentRelation;
|
||||
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
|
||||
tidstate->ss.ss_currentRelation = currentRelation;
|
||||
tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
||||
|
||||
/*
|
||||
* get the scan type from the relation descriptor.
|
||||
*/
|
||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
||||
ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation), false);
|
||||
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
|
||||
|
||||
/*
|
||||
* if there are some PARAM_EXEC in skankeys then force tid rescan on
|
||||
* first scan.
|
||||
*/
|
||||
((Plan *) node)->chgParam = execParam;
|
||||
tidstate->ss.ps.chgParam = execParam;
|
||||
|
||||
/*
|
||||
* all done.
|
||||
*/
|
||||
return TRUE;
|
||||
return tidstate;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.34 2002/06/20 20:29:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.35 2002/12/05 15:50:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -21,7 +21,6 @@
|
|||
* NOTES
|
||||
* Assumes tuples returned from subplan arrive in
|
||||
* sorted order.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
@ -39,21 +38,20 @@
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot * /* return: a tuple or NULL */
|
||||
ExecUnique(Unique *node)
|
||||
ExecUnique(UniqueState *node)
|
||||
{
|
||||
UniqueState *uniquestate;
|
||||
Unique *plannode = (Unique *) node->ps.plan;
|
||||
TupleTableSlot *resultTupleSlot;
|
||||
TupleTableSlot *slot;
|
||||
Plan *outerPlan;
|
||||
PlanState *outerPlan;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
/*
|
||||
* get information from the node
|
||||
*/
|
||||
uniquestate = node->uniquestate;
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
resultTupleSlot = uniquestate->cstate.cs_ResultTupleSlot;
|
||||
tupDesc = ExecGetResultType(&uniquestate->cstate);
|
||||
outerPlan = outerPlanState(node);
|
||||
resultTupleSlot = node->ps.ps_ResultTupleSlot;
|
||||
tupDesc = ExecGetResultType(&node->ps);
|
||||
|
||||
/*
|
||||
* now loop, returning only non-duplicate tuples. We assume that the
|
||||
|
@ -64,14 +62,14 @@ ExecUnique(Unique *node)
|
|||
/*
|
||||
* fetch a tuple from the outer subplan
|
||||
*/
|
||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
slot = ExecProcNode(outerPlan);
|
||||
if (TupIsNull(slot))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Always return the first tuple from the subplan.
|
||||
*/
|
||||
if (uniquestate->priorTuple == NULL)
|
||||
if (node->priorTuple == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -79,11 +77,11 @@ ExecUnique(Unique *node)
|
|||
* match. If so then we loop back and fetch another new tuple
|
||||
* from the subplan.
|
||||
*/
|
||||
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
|
||||
if (!execTuplesMatch(slot->val, node->priorTuple,
|
||||
tupDesc,
|
||||
node->numCols, node->uniqColIdx,
|
||||
uniquestate->eqfunctions,
|
||||
uniquestate->tempContext))
|
||||
plannode->numCols, plannode->uniqColIdx,
|
||||
node->eqfunctions,
|
||||
node->tempContext))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -99,11 +97,11 @@ ExecUnique(Unique *node)
|
|||
* handling in execMain.c). We assume that the caller will no longer
|
||||
* be interested in the current tuple after he next calls us.
|
||||
*/
|
||||
if (uniquestate->priorTuple != NULL)
|
||||
heap_freetuple(uniquestate->priorTuple);
|
||||
uniquestate->priorTuple = heap_copytuple(slot->val);
|
||||
if (node->priorTuple != NULL)
|
||||
heap_freetuple(node->priorTuple);
|
||||
node->priorTuple = heap_copytuple(slot->val);
|
||||
|
||||
ExecStoreTuple(uniquestate->priorTuple,
|
||||
ExecStoreTuple(node->priorTuple,
|
||||
resultTupleSlot,
|
||||
InvalidBuffer,
|
||||
false); /* tuple does not belong to slot */
|
||||
|
@ -118,22 +116,18 @@ ExecUnique(Unique *node)
|
|||
* the node's subplan.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
bool /* return: initialization status */
|
||||
ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
||||
UniqueState *
|
||||
ExecInitUnique(Unique *node, EState *estate)
|
||||
{
|
||||
UniqueState *uniquestate;
|
||||
Plan *outerPlan;
|
||||
|
||||
/*
|
||||
* assign execution state to node
|
||||
*/
|
||||
node->plan.state = estate;
|
||||
|
||||
/*
|
||||
* create new UniqueState for node
|
||||
* create state structure
|
||||
*/
|
||||
uniquestate = makeNode(UniqueState);
|
||||
node->uniquestate = uniquestate;
|
||||
uniquestate->ps.plan = (Plan *) node;
|
||||
uniquestate->ps.state = estate;
|
||||
|
||||
uniquestate->priorTuple = NULL;
|
||||
|
||||
/*
|
||||
|
@ -155,30 +149,29 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
|||
/*
|
||||
* Tuple table initialization
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, &uniquestate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &uniquestate->ps);
|
||||
|
||||
/*
|
||||
* then initialize outer plan
|
||||
*/
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||
outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
|
||||
|
||||
/*
|
||||
* unique nodes do no projections, so initialize projection info for
|
||||
* this node appropriately
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &uniquestate->cstate);
|
||||
uniquestate->cstate.cs_ProjInfo = NULL;
|
||||
ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
|
||||
uniquestate->ps.ps_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
* Precompute fmgr lookup data for inner loop
|
||||
*/
|
||||
uniquestate->eqfunctions =
|
||||
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->cstate),
|
||||
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
|
||||
node->numCols,
|
||||
node->uniqColIdx);
|
||||
|
||||
return TRUE;
|
||||
return uniquestate;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -197,41 +190,36 @@ ExecCountSlotsUnique(Unique *node)
|
|||
* ----------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
ExecEndUnique(Unique *node)
|
||||
ExecEndUnique(UniqueState *node)
|
||||
{
|
||||
UniqueState *uniquestate = node->uniquestate;
|
||||
|
||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||
|
||||
MemoryContextDelete(uniquestate->tempContext);
|
||||
|
||||
/* clean up tuple table */
|
||||
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
|
||||
if (uniquestate->priorTuple != NULL)
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
if (node->priorTuple != NULL)
|
||||
{
|
||||
heap_freetuple(uniquestate->priorTuple);
|
||||
uniquestate->priorTuple = NULL;
|
||||
heap_freetuple(node->priorTuple);
|
||||
node->priorTuple = NULL;
|
||||
}
|
||||
|
||||
ExecEndNode(outerPlanState(node));
|
||||
|
||||
MemoryContextDelete(node->tempContext);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
|
||||
{
|
||||
UniqueState *uniquestate = node->uniquestate;
|
||||
|
||||
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
|
||||
if (uniquestate->priorTuple != NULL)
|
||||
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||
if (node->priorTuple != NULL)
|
||||
{
|
||||
heap_freetuple(uniquestate->priorTuple);
|
||||
uniquestate->priorTuple = NULL;
|
||||
heap_freetuple(node->priorTuple);
|
||||
node->priorTuple = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
*/
|
||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
|
||||
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.78 2002/11/13 00:39:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.79 2002/12/05 15:50:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -33,7 +33,7 @@ static int _SPI_connected = -1;
|
|||
static int _SPI_curid = -1;
|
||||
|
||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
||||
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
||||
static int _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount);
|
||||
|
||||
static int _SPI_execute_plan(_SPI_plan *plan,
|
||||
Datum *Values, char *Nulls, int tcount);
|
||||
|
@ -705,9 +705,8 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||
List *ptlist = spiplan->ptlist;
|
||||
Query *queryTree;
|
||||
Plan *planTree;
|
||||
ParamListInfo paramLI;
|
||||
QueryDesc *queryDesc;
|
||||
EState *eState;
|
||||
TupleDesc attinfo;
|
||||
MemoryContext oldcontext;
|
||||
Portal portal;
|
||||
char portalname[64];
|
||||
|
@ -774,28 +773,21 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||
queryTree->into->relname = pstrdup(name);
|
||||
queryTree->isBinary = false;
|
||||
|
||||
/* Create the QueryDesc object and the executor state */
|
||||
queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL);
|
||||
eState = CreateExecutorState();
|
||||
|
||||
/* If the plan has parameters, put them into the executor state */
|
||||
/* If the plan has parameters, set them up */
|
||||
if (spiplan->nargs > 0)
|
||||
{
|
||||
ParamListInfo paramLI;
|
||||
|
||||
paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
|
||||
sizeof(ParamListInfoData));
|
||||
sizeof(ParamListInfoData));
|
||||
|
||||
eState->es_param_list_info = paramLI;
|
||||
for (k = 0; k < spiplan->nargs; paramLI++, k++)
|
||||
for (k = 0; k < spiplan->nargs; k++)
|
||||
{
|
||||
paramLI->kind = PARAM_NUM;
|
||||
paramLI->id = k + 1;
|
||||
paramLI->isnull = (Nulls && Nulls[k] == 'n');
|
||||
if (paramLI->isnull)
|
||||
paramLI[k].kind = PARAM_NUM;
|
||||
paramLI[k].id = k + 1;
|
||||
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
|
||||
if (paramLI[k].isnull)
|
||||
{
|
||||
/* nulls just copy */
|
||||
paramLI->value = Values[k];
|
||||
paramLI[k].value = Values[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -805,20 +797,24 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||
|
||||
get_typlenbyval(spiplan->argtypes[k],
|
||||
¶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);
|
||||
|
@ -1042,7 +1038,6 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||
Plan *planTree;
|
||||
bool canSetResult;
|
||||
QueryDesc *qdesc;
|
||||
EState *state;
|
||||
|
||||
planTree = pg_plan_query(queryTree);
|
||||
plan_list = lappend(plan_list, planTree);
|
||||
|
@ -1089,9 +1084,9 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||
else if (plan == NULL)
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None, NULL);
|
||||
state = CreateExecutorState();
|
||||
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
|
||||
canSetResult ? SPI : None,
|
||||
NULL, NULL, false);
|
||||
res = _SPI_pquery(qdesc, true, canSetResult ? tcount : 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
CommandCounterIncrement();
|
||||
|
@ -1099,8 +1094,9 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||
else
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None, NULL);
|
||||
res = _SPI_pquery(qdesc, NULL, 0);
|
||||
canSetResult ? SPI : None,
|
||||
NULL, NULL, false);
|
||||
res = _SPI_pquery(qdesc, false, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
@ -1152,7 +1148,6 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||
Plan *planTree;
|
||||
bool canSetResult;
|
||||
QueryDesc *qdesc;
|
||||
EState *state;
|
||||
|
||||
planTree = lfirst(plan_list);
|
||||
plan_list = lnext(plan_list);
|
||||
|
@ -1183,30 +1178,31 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||
}
|
||||
else
|
||||
{
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None, NULL);
|
||||
state = CreateExecutorState();
|
||||
ParamListInfo paramLI;
|
||||
|
||||
if (nargs > 0)
|
||||
{
|
||||
ParamListInfo paramLI;
|
||||
int k;
|
||||
|
||||
paramLI = (ParamListInfo)
|
||||
palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
||||
|
||||
state->es_param_list_info = paramLI;
|
||||
for (k = 0; k < plan->nargs; paramLI++, k++)
|
||||
for (k = 0; k < plan->nargs; k++)
|
||||
{
|
||||
paramLI->kind = PARAM_NUM;
|
||||
paramLI->id = k + 1;
|
||||
paramLI->isnull = (Nulls && Nulls[k] == 'n');
|
||||
paramLI->value = Values[k];
|
||||
paramLI[k].kind = PARAM_NUM;
|
||||
paramLI[k].id = k + 1;
|
||||
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
|
||||
paramLI[k].value = Values[k];
|
||||
}
|
||||
paramLI->kind = PARAM_INVALID;
|
||||
paramLI[k].kind = PARAM_INVALID;
|
||||
}
|
||||
else
|
||||
state->es_param_list_info = NULL;
|
||||
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
|
||||
paramLI = NULL;
|
||||
|
||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||
canSetResult ? SPI : None,
|
||||
NULL, paramLI, false);
|
||||
res = _SPI_pquery(qdesc, true, canSetResult ? tcount : 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
CommandCounterIncrement();
|
||||
|
@ -1218,7 +1214,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||
}
|
||||
|
||||
static int
|
||||
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
_SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
|
||||
{
|
||||
Query *parseTree = queryDesc->parsetree;
|
||||
int operation = queryDesc->operation;
|
||||
|
@ -1262,7 +1258,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||
return SPI_ERROR_OPUNKNOWN;
|
||||
}
|
||||
|
||||
if (state == NULL) /* plan preparation, don't execute */
|
||||
if (!runit) /* plan preparation, don't execute */
|
||||
return res;
|
||||
|
||||
#ifdef SPI_EXECUTOR_STATS
|
||||
|
@ -1270,20 +1266,20 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||
ResetUsage();
|
||||
#endif
|
||||
|
||||
ExecutorStart(queryDesc, state);
|
||||
ExecutorStart(queryDesc);
|
||||
|
||||
/*
|
||||
* Don't work currently --- need to rearrange callers so that we
|
||||
* prepare the portal before doing CreateExecutorState() etc. See
|
||||
* prepare the portal before doing ExecutorStart() etc. See
|
||||
* pquery.c for the correct order of operations.
|
||||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
||||
|
||||
ExecutorRun(queryDesc, state, ForwardScanDirection, (long) tcount);
|
||||
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
|
||||
|
||||
_SPI_current->processed = state->es_processed;
|
||||
save_lastoid = state->es_lastoid;
|
||||
_SPI_current->processed = queryDesc->estate->es_processed;
|
||||
save_lastoid = queryDesc->estate->es_lastoid;
|
||||
|
||||
if (operation == CMD_SELECT && queryDesc->dest == SPI)
|
||||
{
|
||||
|
@ -1291,7 +1287,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||
elog(FATAL, "SPI_select: # of processed tuples check failed");
|
||||
}
|
||||
|
||||
ExecutorEnd(queryDesc, state);
|
||||
ExecutorEnd(queryDesc);
|
||||
|
||||
#ifdef SPI_EXECUTOR_STATS
|
||||
if (ShowExecutorStats)
|
||||
|
@ -1342,7 +1338,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
querydesc = PortalGetQueryDesc(portal);
|
||||
estate = PortalGetState(portal);
|
||||
estate = querydesc->estate;
|
||||
|
||||
/* Save the queries command destination and set it to SPI (for fetch) */
|
||||
/* or None (for move) */
|
||||
|
@ -1357,7 +1353,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||
else
|
||||
direction = ForwardScanDirection;
|
||||
|
||||
ExecutorRun(querydesc, estate, direction, (long) count);
|
||||
ExecutorRun(querydesc, direction, (long) count);
|
||||
|
||||
if (estate->es_processed > 0)
|
||||
portal->atStart = false; /* OK to back up now */
|
||||
|
@ -1371,7 +1367,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||
else
|
||||
direction = BackwardScanDirection;
|
||||
|
||||
ExecutorRun(querydesc, estate, direction, (long) count);
|
||||
ExecutorRun(querydesc, direction, (long) count);
|
||||
|
||||
if (estate->es_processed > 0)
|
||||
portal->atEnd = false; /* OK to go forward now */
|
||||
|
|
|
@ -3,27 +3,28 @@
|
|||
* copyfuncs.c
|
||||
* Copy functions for Postgres tree nodes.
|
||||
*
|
||||
* NOTE: a general convention when copying or comparing plan nodes is
|
||||
* that we ignore the executor state subnode. We do not need to look
|
||||
* at it because no current uses of copyObject() or equal() need to
|
||||
* deal with already-executing plan trees. By leaving the state subnodes
|
||||
* out, we avoid needing to write copy/compare routines for all the
|
||||
* different executor state node types.
|
||||
* NOTE: we currently support copying all node types found in parse and
|
||||
* plan trees. We do not support copying executor state trees; there
|
||||
* is no need for that, and no point in maintaining all the code that
|
||||
* would be needed. We also do not support copying Path trees, mainly
|
||||
* because the circular linkages between RelOptInfo and Path nodes can't
|
||||
* be handled easily in a simple depth-first traversal.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.225 2002/11/30 05:21:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.226 2002/12/05 15:50:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planmain.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "utils/datum.h"
|
||||
|
||||
|
||||
|
@ -58,15 +59,6 @@
|
|||
memcpy(newnode->fldname, from->fldname, _size); \
|
||||
} while (0)
|
||||
|
||||
/* Special hack for fixing subplan lists of Plan nodes (ick) */
|
||||
#define FIX_SUBPLAN_LINKS(subplanfldname, fldname) \
|
||||
do { \
|
||||
if (from->subplanfldname != NIL) \
|
||||
newnode->subplanfldname = \
|
||||
nconc(newnode->subplanfldname, \
|
||||
pull_subplans((Node *) (newnode->fldname))); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* listCopy
|
||||
|
@ -119,19 +111,13 @@ CopyPlanFields(Plan *from, Plan *newnode)
|
|||
COPY_SCALAR_FIELD(total_cost);
|
||||
COPY_SCALAR_FIELD(plan_rows);
|
||||
COPY_SCALAR_FIELD(plan_width);
|
||||
/* execution state is NOT copied */
|
||||
COPY_NODE_FIELD(targetlist);
|
||||
COPY_NODE_FIELD(qual);
|
||||
COPY_NODE_FIELD(lefttree);
|
||||
COPY_NODE_FIELD(righttree);
|
||||
COPY_NODE_FIELD(initPlan);
|
||||
COPY_INTLIST_FIELD(extParam);
|
||||
COPY_INTLIST_FIELD(locParam);
|
||||
COPY_INTLIST_FIELD(chgParam);
|
||||
COPY_NODE_FIELD(initPlan);
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
newnode->subPlan = NIL;
|
||||
FIX_SUBPLAN_LINKS(subPlan, targetlist);
|
||||
FIX_SUBPLAN_LINKS(subPlan, qual);
|
||||
COPY_SCALAR_FIELD(nParamExec);
|
||||
}
|
||||
|
||||
|
@ -170,9 +156,6 @@ _copyResult(Result *from)
|
|||
*/
|
||||
COPY_NODE_FIELD(resconstantqual);
|
||||
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
FIX_SUBPLAN_LINKS(plan.subPlan, resconstantqual);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
@ -266,10 +249,6 @@ _copyIndexScan(IndexScan *from)
|
|||
COPY_NODE_FIELD(indxqualorig);
|
||||
COPY_SCALAR_FIELD(indxorderdir);
|
||||
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
FIX_SUBPLAN_LINKS(scan.plan.subPlan, indxqual);
|
||||
FIX_SUBPLAN_LINKS(scan.plan.subPlan, indxqualorig);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
@ -289,12 +268,8 @@ _copyTidScan(TidScan *from)
|
|||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_SCALAR_FIELD(needRescan);
|
||||
COPY_NODE_FIELD(tideval);
|
||||
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
FIX_SUBPLAN_LINKS(scan.plan.subPlan, tideval);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
@ -348,9 +323,6 @@ CopyJoinFields(Join *from, Join *newnode)
|
|||
|
||||
COPY_SCALAR_FIELD(jointype);
|
||||
COPY_NODE_FIELD(joinqual);
|
||||
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
FIX_SUBPLAN_LINKS(plan.subPlan, joinqual);
|
||||
}
|
||||
|
||||
|
||||
|
@ -406,9 +378,6 @@ _copyMergeJoin(MergeJoin *from)
|
|||
*/
|
||||
COPY_NODE_FIELD(mergeclauses);
|
||||
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
FIX_SUBPLAN_LINKS(join.plan.subPlan, mergeclauses);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
@ -430,9 +399,6 @@ _copyHashJoin(HashJoin *from)
|
|||
*/
|
||||
COPY_NODE_FIELD(hashclauses);
|
||||
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
FIX_SUBPLAN_LINKS(join.plan.subPlan, hashclauses);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
@ -530,6 +496,27 @@ _copyUnique(Unique *from)
|
|||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyHash
|
||||
*/
|
||||
static Hash *
|
||||
_copyHash(Hash *from)
|
||||
{
|
||||
Hash *newnode = makeNode(Hash);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(hashkeys);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copySetOp
|
||||
*/
|
||||
|
@ -576,29 +563,6 @@ _copyLimit(Limit *from)
|
|||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyHash
|
||||
*/
|
||||
static Hash *
|
||||
_copyHash(Hash *from)
|
||||
{
|
||||
Hash *newnode = makeNode(Hash);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(hashkeys);
|
||||
|
||||
/* XXX could the hashkeys contain subplans? Not at present... */
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static SubPlan *
|
||||
_copySubPlan(SubPlan *from)
|
||||
{
|
||||
|
@ -611,10 +575,6 @@ _copySubPlan(SubPlan *from)
|
|||
COPY_INTLIST_FIELD(parParam);
|
||||
COPY_NODE_FIELD(sublink);
|
||||
|
||||
/* do not copy execution state */
|
||||
newnode->needShutdown = false;
|
||||
newnode->curTuple = NULL;
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
@ -933,313 +893,11 @@ _copyArrayRef(ArrayRef *from)
|
|||
/* ****************************************************************
|
||||
* relation.h copy functions
|
||||
*
|
||||
* XXX the code to copy RelOptInfo and Path nodes is really completely bogus,
|
||||
* because it makes no attempt to deal with multiple links from RelOptInfo
|
||||
* to Paths, nor with back-links from Paths to their parent RelOptInfo.
|
||||
* Currently, since we never actually try to copy a RelOptInfo, this is okay.
|
||||
* We don't support copying RelOptInfo, IndexOptInfo, or Path nodes.
|
||||
* There are some subsidiary structs that are useful to copy, though.
|
||||
* ****************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* _copyRelOptInfo
|
||||
*/
|
||||
static RelOptInfo *
|
||||
_copyRelOptInfo(RelOptInfo *from)
|
||||
{
|
||||
RelOptInfo *newnode = makeNode(RelOptInfo);
|
||||
|
||||
COPY_SCALAR_FIELD(reloptkind);
|
||||
COPY_INTLIST_FIELD(relids);
|
||||
COPY_SCALAR_FIELD(rows);
|
||||
COPY_SCALAR_FIELD(width);
|
||||
COPY_NODE_FIELD(targetlist);
|
||||
COPY_NODE_FIELD(pathlist);
|
||||
/* XXX cheapest-path fields should point to members of pathlist? */
|
||||
COPY_NODE_FIELD(cheapest_startup_path);
|
||||
COPY_NODE_FIELD(cheapest_total_path);
|
||||
COPY_SCALAR_FIELD(pruneable);
|
||||
COPY_SCALAR_FIELD(rtekind);
|
||||
COPY_NODE_FIELD(indexlist);
|
||||
COPY_SCALAR_FIELD(pages);
|
||||
COPY_SCALAR_FIELD(tuples);
|
||||
COPY_NODE_FIELD(subplan);
|
||||
COPY_SCALAR_FIELD(joinrti);
|
||||
COPY_INTLIST_FIELD(joinrteids);
|
||||
COPY_NODE_FIELD(baserestrictinfo);
|
||||
COPY_SCALAR_FIELD(baserestrictcost);
|
||||
COPY_INTLIST_FIELD(outerjoinset);
|
||||
COPY_NODE_FIELD(joininfo);
|
||||
COPY_INTLIST_FIELD(index_outer_relids);
|
||||
COPY_NODE_FIELD(index_inner_paths);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyIndexOptInfo
|
||||
*/
|
||||
static IndexOptInfo *
|
||||
_copyIndexOptInfo(IndexOptInfo *from)
|
||||
{
|
||||
IndexOptInfo *newnode = makeNode(IndexOptInfo);
|
||||
|
||||
COPY_SCALAR_FIELD(indexoid);
|
||||
COPY_SCALAR_FIELD(pages);
|
||||
COPY_SCALAR_FIELD(tuples);
|
||||
COPY_SCALAR_FIELD(ncolumns);
|
||||
COPY_SCALAR_FIELD(nkeys);
|
||||
|
||||
if (from->classlist)
|
||||
{
|
||||
/* copy the trailing zero too */
|
||||
COPY_POINTER_FIELD(classlist, (from->ncolumns + 1) * sizeof(Oid));
|
||||
}
|
||||
|
||||
if (from->indexkeys)
|
||||
{
|
||||
/* copy the trailing zero too */
|
||||
COPY_POINTER_FIELD(indexkeys, (from->nkeys + 1) * sizeof(int));
|
||||
}
|
||||
|
||||
if (from->ordering)
|
||||
{
|
||||
/* copy the trailing zero too */
|
||||
COPY_POINTER_FIELD(ordering, (from->ncolumns + 1) * sizeof(Oid));
|
||||
}
|
||||
|
||||
COPY_SCALAR_FIELD(relam);
|
||||
COPY_SCALAR_FIELD(amcostestimate);
|
||||
COPY_SCALAR_FIELD(indproc);
|
||||
COPY_NODE_FIELD(indpred);
|
||||
COPY_SCALAR_FIELD(unique);
|
||||
COPY_INTLIST_FIELD(outer_relids);
|
||||
COPY_NODE_FIELD(inner_paths);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* CopyPathFields
|
||||
*
|
||||
* This function copies the fields of the Path node. It is used by
|
||||
* all the copy functions for classes which inherit from Path.
|
||||
*/
|
||||
static void
|
||||
CopyPathFields(Path *from, Path *newnode)
|
||||
{
|
||||
/*
|
||||
* Modify the next line, since it causes the copying to cycle (i.e.
|
||||
* the parent points right back here! -- JMH, 7/7/92. Old version:
|
||||
* COPY_NODE_FIELD(parent);
|
||||
*/
|
||||
COPY_SCALAR_FIELD(parent);
|
||||
|
||||
COPY_SCALAR_FIELD(startup_cost);
|
||||
COPY_SCALAR_FIELD(total_cost);
|
||||
COPY_SCALAR_FIELD(pathtype);
|
||||
COPY_NODE_FIELD(pathkeys);
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyPath
|
||||
*/
|
||||
static Path *
|
||||
_copyPath(Path *from)
|
||||
{
|
||||
Path *newnode = makeNode(Path);
|
||||
|
||||
CopyPathFields(from, newnode);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyIndexPath
|
||||
*/
|
||||
static IndexPath *
|
||||
_copyIndexPath(IndexPath *from)
|
||||
{
|
||||
IndexPath *newnode = makeNode(IndexPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPathFields((Path *) from, (Path *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(indexinfo);
|
||||
COPY_NODE_FIELD(indexqual);
|
||||
COPY_SCALAR_FIELD(indexscandir);
|
||||
COPY_SCALAR_FIELD(rows);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyTidPath
|
||||
*/
|
||||
static TidPath *
|
||||
_copyTidPath(TidPath *from)
|
||||
{
|
||||
TidPath *newnode = makeNode(TidPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPathFields((Path *) from, (Path *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(tideval);
|
||||
COPY_INTLIST_FIELD(unjoined_relids);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyAppendPath
|
||||
*/
|
||||
static AppendPath *
|
||||
_copyAppendPath(AppendPath *from)
|
||||
{
|
||||
AppendPath *newnode = makeNode(AppendPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPathFields((Path *) from, (Path *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(subpaths);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyResultPath
|
||||
*/
|
||||
static ResultPath *
|
||||
_copyResultPath(ResultPath *from)
|
||||
{
|
||||
ResultPath *newnode = makeNode(ResultPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPathFields((Path *) from, (Path *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(subpath);
|
||||
COPY_NODE_FIELD(constantqual);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyMaterialPath
|
||||
*/
|
||||
static MaterialPath *
|
||||
_copyMaterialPath(MaterialPath *from)
|
||||
{
|
||||
MaterialPath *newnode = makeNode(MaterialPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyPathFields((Path *) from, (Path *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(subpath);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* CopyJoinPathFields
|
||||
*
|
||||
* This function copies the fields of the JoinPath node. It is used by
|
||||
* all the copy functions for classes which inherit from JoinPath.
|
||||
*/
|
||||
static void
|
||||
CopyJoinPathFields(JoinPath *from, JoinPath *newnode)
|
||||
{
|
||||
CopyPathFields((Path *) from, (Path *) newnode);
|
||||
|
||||
COPY_SCALAR_FIELD(jointype);
|
||||
COPY_NODE_FIELD(outerjoinpath);
|
||||
COPY_NODE_FIELD(innerjoinpath);
|
||||
COPY_NODE_FIELD(joinrestrictinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyNestPath
|
||||
*/
|
||||
static NestPath *
|
||||
_copyNestPath(NestPath *from)
|
||||
{
|
||||
NestPath *newnode = makeNode(NestPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyMergePath
|
||||
*/
|
||||
static MergePath *
|
||||
_copyMergePath(MergePath *from)
|
||||
{
|
||||
MergePath *newnode = makeNode(MergePath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(path_mergeclauses);
|
||||
COPY_NODE_FIELD(outersortkeys);
|
||||
COPY_NODE_FIELD(innersortkeys);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyHashPath
|
||||
*/
|
||||
static HashPath *
|
||||
_copyHashPath(HashPath *from)
|
||||
{
|
||||
HashPath *newnode = makeNode(HashPath);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(path_hashclauses);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyPathKeyItem
|
||||
*/
|
||||
|
@ -1301,21 +959,6 @@ _copyJoinInfo(JoinInfo *from)
|
|||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyInnerIndexscanInfo
|
||||
*/
|
||||
static InnerIndexscanInfo *
|
||||
_copyInnerIndexscanInfo(InnerIndexscanInfo *from)
|
||||
{
|
||||
InnerIndexscanInfo *newnode = makeNode(InnerIndexscanInfo);
|
||||
|
||||
COPY_INTLIST_FIELD(other_relids);
|
||||
COPY_SCALAR_FIELD(isouterjoin);
|
||||
COPY_NODE_FIELD(best_innerpath);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/* ****************************************************************
|
||||
* parsenodes.h copy functions
|
||||
* ****************************************************************
|
||||
|
@ -1737,7 +1380,8 @@ _copyQuery(Query *from)
|
|||
/*
|
||||
* We do not copy the planner internal fields: base_rel_list,
|
||||
* other_rel_list, join_rel_list, equi_key_list, query_pathkeys,
|
||||
* hasJoinRTEs. Not entirely clear if this is right?
|
||||
* hasJoinRTEs. That would get us into copying RelOptInfo/Path
|
||||
* trees, which we don't want to do.
|
||||
*/
|
||||
|
||||
return newnode;
|
||||
|
@ -2683,15 +2327,15 @@ copyObject(void *from)
|
|||
case T_Unique:
|
||||
retval = _copyUnique(from);
|
||||
break;
|
||||
case T_Hash:
|
||||
retval = _copyHash(from);
|
||||
break;
|
||||
case T_SetOp:
|
||||
retval = _copySetOp(from);
|
||||
break;
|
||||
case T_Limit:
|
||||
retval = _copyLimit(from);
|
||||
break;
|
||||
case T_Hash:
|
||||
retval = _copyHash(from);
|
||||
break;
|
||||
case T_SubPlan:
|
||||
retval = _copySubPlan(from);
|
||||
break;
|
||||
|
@ -2757,39 +2401,6 @@ copyObject(void *from)
|
|||
/*
|
||||
* RELATION NODES
|
||||
*/
|
||||
case T_RelOptInfo:
|
||||
retval = _copyRelOptInfo(from);
|
||||
break;
|
||||
case T_IndexOptInfo:
|
||||
retval = _copyIndexOptInfo(from);
|
||||
break;
|
||||
case T_Path:
|
||||
retval = _copyPath(from);
|
||||
break;
|
||||
case T_IndexPath:
|
||||
retval = _copyIndexPath(from);
|
||||
break;
|
||||
case T_TidPath:
|
||||
retval = _copyTidPath(from);
|
||||
break;
|
||||
case T_AppendPath:
|
||||
retval = _copyAppendPath(from);
|
||||
break;
|
||||
case T_ResultPath:
|
||||
retval = _copyResultPath(from);
|
||||
break;
|
||||
case T_MaterialPath:
|
||||
retval = _copyMaterialPath(from);
|
||||
break;
|
||||
case T_NestPath:
|
||||
retval = _copyNestPath(from);
|
||||
break;
|
||||
case T_MergePath:
|
||||
retval = _copyMergePath(from);
|
||||
break;
|
||||
case T_HashPath:
|
||||
retval = _copyHashPath(from);
|
||||
break;
|
||||
case T_PathKeyItem:
|
||||
retval = _copyPathKeyItem(from);
|
||||
break;
|
||||
|
@ -2799,9 +2410,6 @@ copyObject(void *from)
|
|||
case T_JoinInfo:
|
||||
retval = _copyJoinInfo(from);
|
||||
break;
|
||||
case T_InnerIndexscanInfo:
|
||||
retval = _copyInnerIndexscanInfo(from);
|
||||
break;
|
||||
|
||||
/*
|
||||
* VALUE NODES
|
||||
|
|
|
@ -3,30 +3,30 @@
|
|||
* equalfuncs.c
|
||||
* Equality functions to compare node trees.
|
||||
*
|
||||
* NOTE: a general convention when copying or comparing plan nodes is
|
||||
* that we ignore the executor state subnode. We do not need to look
|
||||
* at it because no current uses of copyObject() or equal() need to
|
||||
* deal with already-executing plan trees. By leaving the state subnodes
|
||||
* out, we avoid needing to write copy/compare routines for all the
|
||||
* different executor state node types.
|
||||
* NOTE: we currently support comparing all node types found in parse
|
||||
* trees. We do not support comparing executor state trees; there
|
||||
* is no need for that, and no point in maintaining all the code that
|
||||
* would be needed. We also do not support comparing Path trees, mainly
|
||||
* because the circular linkages between RelOptInfo and Path nodes can't
|
||||
* be handled easily in a simple depth-first traversal.
|
||||
*
|
||||
* Currently, in fact, equal() doesn't know how to compare Plan nodes
|
||||
* at all, let alone their executor-state subnodes. This will probably
|
||||
* need to be fixed someday, but presently there is no need to compare
|
||||
* plan trees.
|
||||
* Currently, in fact, equal() doesn't know how to compare Plan trees
|
||||
* either. This might need to be fixed someday.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.170 2002/11/30 05:21:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.171 2002/12/05 15:50:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/params.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "utils/datum.h"
|
||||
|
@ -369,147 +369,6 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
|
|||
* Stuff from relation.h
|
||||
*/
|
||||
|
||||
static bool
|
||||
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
|
||||
{
|
||||
/*
|
||||
* We treat RelOptInfos as equal if they refer to the same base rels
|
||||
* joined in the same order. Is this appropriate/sufficient?
|
||||
*/
|
||||
COMPARE_INTLIST_FIELD(relids);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalIndexOptInfo(IndexOptInfo *a, IndexOptInfo *b)
|
||||
{
|
||||
/*
|
||||
* We treat IndexOptInfos as equal if they refer to the same index. Is
|
||||
* this sufficient?
|
||||
*/
|
||||
COMPARE_SCALAR_FIELD(indexoid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalPath(Path *a, Path *b)
|
||||
{
|
||||
/* This is safe only because _equalRelOptInfo is incomplete... */
|
||||
COMPARE_NODE_FIELD(parent);
|
||||
/*
|
||||
* do not check path costs, since they may not be set yet, and being
|
||||
* float values there are roundoff error issues anyway...
|
||||
*/
|
||||
COMPARE_SCALAR_FIELD(pathtype);
|
||||
COMPARE_NODE_FIELD(pathkeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalIndexPath(IndexPath *a, IndexPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(indexinfo);
|
||||
COMPARE_NODE_FIELD(indexqual);
|
||||
COMPARE_SCALAR_FIELD(indexscandir);
|
||||
|
||||
/*
|
||||
* Skip 'rows' because of possibility of floating-point roundoff
|
||||
* error. It should be derivable from the other fields anyway.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalTidPath(TidPath *a, TidPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(tideval);
|
||||
COMPARE_INTLIST_FIELD(unjoined_relids);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalAppendPath(AppendPath *a, AppendPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(subpaths);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalResultPath(ResultPath *a, ResultPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(subpath);
|
||||
COMPARE_NODE_FIELD(constantqual);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalMaterialPath(MaterialPath *a, MaterialPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(subpath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJoinPath(JoinPath *a, JoinPath *b)
|
||||
{
|
||||
if (!_equalPath((Path *) a, (Path *) b))
|
||||
return false;
|
||||
COMPARE_SCALAR_FIELD(jointype);
|
||||
COMPARE_NODE_FIELD(outerjoinpath);
|
||||
COMPARE_NODE_FIELD(innerjoinpath);
|
||||
COMPARE_NODE_FIELD(joinrestrictinfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalNestPath(NestPath *a, NestPath *b)
|
||||
{
|
||||
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalMergePath(MergePath *a, MergePath *b)
|
||||
{
|
||||
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(path_mergeclauses);
|
||||
COMPARE_NODE_FIELD(outersortkeys);
|
||||
COMPARE_NODE_FIELD(innersortkeys);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalHashPath(HashPath *a, HashPath *b)
|
||||
{
|
||||
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
|
||||
return false;
|
||||
COMPARE_NODE_FIELD(path_hashclauses);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
|
||||
{
|
||||
|
@ -547,16 +406,6 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalInnerIndexscanInfo(InnerIndexscanInfo *a, InnerIndexscanInfo *b)
|
||||
{
|
||||
COMPARE_INTLIST_FIELD(other_relids);
|
||||
COMPARE_SCALAR_FIELD(isouterjoin);
|
||||
COMPARE_NODE_FIELD(best_innerpath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Stuff from parsenodes.h
|
||||
|
@ -1711,39 +1560,6 @@ equal(void *a, void *b)
|
|||
retval = _equalJoinExpr(a, b);
|
||||
break;
|
||||
|
||||
case T_RelOptInfo:
|
||||
retval = _equalRelOptInfo(a, b);
|
||||
break;
|
||||
case T_IndexOptInfo:
|
||||
retval = _equalIndexOptInfo(a, b);
|
||||
break;
|
||||
case T_Path:
|
||||
retval = _equalPath(a, b);
|
||||
break;
|
||||
case T_IndexPath:
|
||||
retval = _equalIndexPath(a, b);
|
||||
break;
|
||||
case T_TidPath:
|
||||
retval = _equalTidPath(a, b);
|
||||
break;
|
||||
case T_AppendPath:
|
||||
retval = _equalAppendPath(a, b);
|
||||
break;
|
||||
case T_ResultPath:
|
||||
retval = _equalResultPath(a, b);
|
||||
break;
|
||||
case T_MaterialPath:
|
||||
retval = _equalMaterialPath(a, b);
|
||||
break;
|
||||
case T_NestPath:
|
||||
retval = _equalNestPath(a, b);
|
||||
break;
|
||||
case T_MergePath:
|
||||
retval = _equalMergePath(a, b);
|
||||
break;
|
||||
case T_HashPath:
|
||||
retval = _equalHashPath(a, b);
|
||||
break;
|
||||
case T_PathKeyItem:
|
||||
retval = _equalPathKeyItem(a, b);
|
||||
break;
|
||||
|
@ -1753,9 +1569,6 @@ equal(void *a, void *b)
|
|||
case T_JoinInfo:
|
||||
retval = _equalJoinInfo(a, b);
|
||||
break;
|
||||
case T_InnerIndexscanInfo:
|
||||
retval = _equalInnerIndexscanInfo(a, b);
|
||||
break;
|
||||
|
||||
case T_List:
|
||||
{
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.185 2002/11/30 05:21:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.186 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
* have an output function defined here (as well as an input function
|
||||
* in readfuncs.c). For use in debugging, we also provide output
|
||||
* functions for nodes that appear in raw parsetrees and plan trees.
|
||||
* functions for nodes that appear in raw parsetrees, path, and plan trees.
|
||||
* These nodes however need not have input functions.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
|
@ -24,10 +24,8 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#include "lib/stringinfo.h"
|
||||
#include "nodes/nodes.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/primnodes.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "parser/parse.h"
|
||||
#include "utils/datum.h"
|
||||
|
@ -385,11 +383,9 @@ _outPlanInfo(StringInfo str, Plan *node)
|
|||
WRITE_NODE_FIELD(qual);
|
||||
WRITE_NODE_FIELD(lefttree);
|
||||
WRITE_NODE_FIELD(righttree);
|
||||
WRITE_NODE_FIELD(initPlan);
|
||||
WRITE_INTLIST_FIELD(extParam);
|
||||
WRITE_INTLIST_FIELD(locParam);
|
||||
/* chgParam is execution state too */
|
||||
WRITE_NODE_FIELD(initPlan);
|
||||
/* we don't write subPlan; reader must reconstruct list */
|
||||
WRITE_INT_FIELD(nParamExec);
|
||||
}
|
||||
|
||||
|
@ -482,7 +478,6 @@ _outTidScan(StringInfo str, TidScan *node)
|
|||
|
||||
_outScanInfo(str, (Scan *) node);
|
||||
|
||||
WRITE_BOOL_FIELD(needRescan);
|
||||
WRITE_NODE_FIELD(tideval);
|
||||
}
|
||||
|
||||
|
@ -930,6 +925,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
|
|||
|
||||
/*
|
||||
* print the basic stuff of all nodes that inherit from Path
|
||||
*
|
||||
* Note we do NOT print the parent, else we'd be in infinite recursion
|
||||
*/
|
||||
static void
|
||||
_outPathInfo(StringInfo str, Path *node)
|
||||
|
@ -986,7 +983,6 @@ _outTidPath(StringInfo str, TidPath *node)
|
|||
_outPathInfo(str, (Path *) node);
|
||||
|
||||
WRITE_NODE_FIELD(tideval);
|
||||
WRITE_INTLIST_FIELD(unjoined_relids);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.126 2002/11/30 05:21:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.127 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -602,9 +602,6 @@ create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
|
|||
scan_relid,
|
||||
best_path->tideval);
|
||||
|
||||
if (best_path->unjoined_relids)
|
||||
scan_plan->needRescan = true;
|
||||
|
||||
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
|
||||
|
||||
return scan_plan;
|
||||
|
@ -1302,13 +1299,11 @@ make_seqscan(List *qptlist,
|
|||
Plan *plan = &node->plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = qptlist;
|
||||
plan->qual = qpqual;
|
||||
plan->lefttree = NULL;
|
||||
plan->righttree = NULL;
|
||||
node->scanrelid = scanrelid;
|
||||
node->scanstate = (CommonScanState *) NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -1326,7 +1321,6 @@ make_indexscan(List *qptlist,
|
|||
Plan *plan = &node->scan.plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = qptlist;
|
||||
plan->qual = qpqual;
|
||||
plan->lefttree = NULL;
|
||||
|
@ -1336,7 +1330,6 @@ make_indexscan(List *qptlist,
|
|||
node->indxqual = indxqual;
|
||||
node->indxqualorig = indxqualorig;
|
||||
node->indxorderdir = indexscandir;
|
||||
node->scan.scanstate = (CommonScanState *) NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -1351,16 +1344,12 @@ make_tidscan(List *qptlist,
|
|||
Plan *plan = &node->scan.plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = qptlist;
|
||||
plan->qual = qpqual;
|
||||
plan->lefttree = NULL;
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->tideval = copyObject(tideval); /* XXX do we really need a
|
||||
* copy? */
|
||||
node->needRescan = false;
|
||||
node->scan.scanstate = (CommonScanState *) NULL;
|
||||
node->tideval = tideval;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -1375,14 +1364,12 @@ make_subqueryscan(List *qptlist,
|
|||
Plan *plan = &node->scan.plan;
|
||||
|
||||
copy_plan_costsize(plan, subplan);
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = qptlist;
|
||||
plan->qual = qpqual;
|
||||
plan->lefttree = NULL;
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->subplan = subplan;
|
||||
node->scan.scanstate = (CommonScanState *) NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -1396,13 +1383,11 @@ make_functionscan(List *qptlist,
|
|||
Plan *plan = &node->scan.plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = qptlist;
|
||||
plan->qual = qpqual;
|
||||
plan->lefttree = NULL;
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->scan.scanstate = (CommonScanState *) NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -1430,7 +1415,6 @@ make_append(List *appendplans, bool isTarget, List *tlist)
|
|||
if (plan->plan_width < subplan->plan_width)
|
||||
plan->plan_width = subplan->plan_width;
|
||||
}
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = NULL;
|
||||
|
@ -1453,7 +1437,6 @@ make_nestloop(List *tlist,
|
|||
Plan *plan = &node->join.plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = otherclauses;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1477,7 +1460,6 @@ make_hashjoin(List *tlist,
|
|||
Plan *plan = &node->join.plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = otherclauses;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1502,7 +1484,6 @@ make_hash(List *tlist, List *hashkeys, Plan *lefttree)
|
|||
* input plan; this only affects EXPLAIN display not decisions.
|
||||
*/
|
||||
plan->startup_cost = plan->total_cost;
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NULL;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1525,7 +1506,6 @@ make_mergejoin(List *tlist,
|
|||
Plan *plan = &node->join.plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = otherclauses;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1557,7 +1537,6 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
|
|||
lefttree->plan_width);
|
||||
plan->startup_cost = sort_path.startup_cost;
|
||||
plan->total_cost = sort_path.total_cost;
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1646,7 +1625,6 @@ make_material(List *tlist, Plan *lefttree)
|
|||
Plan *plan = &node->plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1690,7 +1668,6 @@ make_agg(Query *root, List *tlist, List *qual,
|
|||
else
|
||||
plan->plan_rows = numGroups;
|
||||
|
||||
plan->state = (EState *) NULL;
|
||||
plan->qual = qual;
|
||||
plan->targetlist = tlist;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1726,7 +1703,6 @@ make_group(Query *root,
|
|||
/* One output tuple per estimated result group */
|
||||
plan->plan_rows = numGroups;
|
||||
|
||||
plan->state = (EState *) NULL;
|
||||
plan->qual = NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1765,7 +1741,6 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
|
|||
* if he has a better idea.
|
||||
*/
|
||||
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1824,7 +1799,6 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
|
|||
if (plan->plan_rows < 1)
|
||||
plan->plan_rows = 1;
|
||||
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1905,7 +1879,6 @@ make_limit(List *tlist, Plan *lefttree,
|
|||
}
|
||||
}
|
||||
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
|
@ -1935,13 +1908,11 @@ make_result(List *tlist,
|
|||
plan->plan_width = 0; /* XXX try to be smarter? */
|
||||
}
|
||||
|
||||
plan->state = (EState *) NULL;
|
||||
plan->targetlist = tlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = subplan;
|
||||
plan->righttree = NULL;
|
||||
node->resconstantqual = resconstantqual;
|
||||
node->resstate = NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.83 2002/11/30 21:25:04 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.84 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -41,6 +41,7 @@ typedef struct
|
|||
} replace_vars_with_subplan_refs_context;
|
||||
|
||||
static void fix_expr_references(Plan *plan, Node *node);
|
||||
static bool fix_expr_references_walker(Node *node, void *context);
|
||||
static void set_join_references(Join *join, List *rtable);
|
||||
static void set_uppernode_references(Plan *plan, Index subvarno);
|
||||
static Node *join_references_mutator(Node *node,
|
||||
|
@ -66,8 +67,6 @@ static bool fix_opids_walker(Node *node, void *context);
|
|||
* for the convenience of the executor. We update Vars in upper plan nodes
|
||||
* to refer to the outputs of their subplans, and we compute regproc OIDs
|
||||
* for operators (ie, we look up the function that implements each op).
|
||||
* We must also build lists of all the subplan nodes present in each
|
||||
* plan node's expression trees.
|
||||
*
|
||||
* set_plan_references recursively traverses the whole plan tree.
|
||||
*
|
||||
|
@ -81,12 +80,6 @@ set_plan_references(Plan *plan, List *rtable)
|
|||
if (plan == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We must rebuild the plan's list of subplan nodes, since we are
|
||||
* copying/mutating its expression trees.
|
||||
*/
|
||||
plan->subPlan = NIL;
|
||||
|
||||
/*
|
||||
* Plan-type-specific fixes
|
||||
*/
|
||||
|
@ -107,6 +100,8 @@ set_plan_references(Plan *plan, List *rtable)
|
|||
case T_TidScan:
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
fix_expr_references(plan,
|
||||
(Node *) ((TidScan *) plan)->tideval);
|
||||
break;
|
||||
case T_SubqueryScan:
|
||||
{
|
||||
|
@ -175,9 +170,9 @@ set_plan_references(Plan *plan, List *rtable)
|
|||
* unmodified input tuples). The optimizer is lazy about
|
||||
* creating really valid targetlists for them. Best to just
|
||||
* leave the targetlist alone. In particular, we do not want
|
||||
* to pull a subplan list for them, since we will likely end
|
||||
* up with duplicate list entries for subplans that also
|
||||
* appear in lower levels of the plan tree!
|
||||
* to process subplans for them, since we will likely end
|
||||
* up reprocessing subplans that also appear in lower levels
|
||||
* of the plan tree!
|
||||
*/
|
||||
break;
|
||||
case T_Agg:
|
||||
|
@ -206,7 +201,7 @@ set_plan_references(Plan *plan, List *rtable)
|
|||
* Append, like Sort et al, doesn't actually evaluate its
|
||||
* targetlist or quals, and we haven't bothered to give it its
|
||||
* own tlist copy. So, don't fix targetlist/qual. But do
|
||||
* recurse into subplans.
|
||||
* recurse into child plans.
|
||||
*/
|
||||
foreach(pl, ((Append *) plan)->appendplans)
|
||||
set_plan_references((Plan *) lfirst(pl), rtable);
|
||||
|
@ -218,24 +213,19 @@ set_plan_references(Plan *plan, List *rtable)
|
|||
}
|
||||
|
||||
/*
|
||||
* Now recurse into subplans, if any
|
||||
* Now recurse into child plans and initplans, if any
|
||||
*
|
||||
* NOTE: it is essential that we recurse into subplans AFTER we set
|
||||
* NOTE: it is essential that we recurse into child plans AFTER we set
|
||||
* subplan references in this plan's tlist and quals. If we did the
|
||||
* reference-adjustments bottom-up, then we would fail to match this
|
||||
* plan's var nodes against the already-modified nodes of the
|
||||
* subplans.
|
||||
* children. Fortunately, that consideration doesn't apply to SubPlan
|
||||
* nodes; else we'd need two passes over the expression trees.
|
||||
*/
|
||||
set_plan_references(plan->lefttree, rtable);
|
||||
set_plan_references(plan->righttree, rtable);
|
||||
foreach(pl, plan->initPlan)
|
||||
{
|
||||
SubPlan *sp = (SubPlan *) lfirst(pl);
|
||||
|
||||
Assert(IsA(sp, SubPlan));
|
||||
set_plan_references(sp->plan, sp->rtable);
|
||||
}
|
||||
foreach(pl, plan->subPlan)
|
||||
foreach(pl, plan->initPlan)
|
||||
{
|
||||
SubPlan *sp = (SubPlan *) lfirst(pl);
|
||||
|
||||
|
@ -249,13 +239,38 @@ set_plan_references(Plan *plan, List *rtable)
|
|||
* Do final cleanup on expressions (targetlists or quals).
|
||||
*
|
||||
* This consists of looking up operator opcode info for Oper nodes
|
||||
* and adding subplans to the Plan node's list of contained subplans.
|
||||
* and recursively performing set_plan_references on SubPlans.
|
||||
*
|
||||
* The Plan argument is currently unused, but might be needed again someday.
|
||||
*/
|
||||
static void
|
||||
fix_expr_references(Plan *plan, Node *node)
|
||||
{
|
||||
fix_opids(node);
|
||||
plan->subPlan = nconc(plan->subPlan, pull_subplans(node));
|
||||
/* This tree walk requires no special setup, so away we go... */
|
||||
fix_expr_references_walker(node, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
fix_expr_references_walker(Node *node, void *context)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
if (IsA(node, Expr))
|
||||
{
|
||||
Expr *expr = (Expr *) node;
|
||||
|
||||
if (expr->opType == OP_EXPR ||
|
||||
expr->opType == DISTINCT_EXPR)
|
||||
replace_opid((Oper *) expr->oper);
|
||||
else if (expr->opType == SUBPLAN_EXPR)
|
||||
{
|
||||
SubPlan *sp = (SubPlan *) expr->oper;
|
||||
|
||||
Assert(IsA(sp, SubPlan));
|
||||
set_plan_references(sp->plan, sp->rtable);
|
||||
}
|
||||
}
|
||||
return expression_tree_walker(node, fix_expr_references_walker, context);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.58 2002/11/30 05:21:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.59 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,6 +16,7 @@
|
|||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/params.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/planmain.h"
|
||||
|
@ -297,7 +298,7 @@ make_subplan(SubLink *slink)
|
|||
switch (nodeTag(plan))
|
||||
{
|
||||
case T_SeqScan:
|
||||
if (plan->initPlan || plan->subPlan)
|
||||
if (plan->initPlan)
|
||||
use_material = true;
|
||||
else
|
||||
{
|
||||
|
@ -453,20 +454,13 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
|
|||
}
|
||||
|
||||
/*
|
||||
* finalize_primnode: build lists of subplans and params appearing
|
||||
* in the given expression tree. NOTE: items are added to lists passed in,
|
||||
* so caller must initialize lists to NIL before first call!
|
||||
*
|
||||
* Note: the subplan list that is constructed here and assigned to the
|
||||
* plan's subPlan field will be replaced with an up-to-date list in
|
||||
* set_plan_references(). We could almost dispense with building this
|
||||
* subplan list at all; I believe the only place that uses it is the
|
||||
* check in make_subplan to see whether a subselect has any subselects.
|
||||
* finalize_primnode: build lists of params appearing
|
||||
* in the given expression tree. NOTE: items are added to list passed in,
|
||||
* so caller must initialize list to NIL before first call!
|
||||
*/
|
||||
|
||||
typedef struct finalize_primnode_results
|
||||
{
|
||||
List *subplans; /* List of subplans found in expr */
|
||||
List *paramids; /* List of PARAM_EXEC paramids found */
|
||||
} finalize_primnode_results;
|
||||
|
||||
|
@ -491,8 +485,6 @@ finalize_primnode(Node *node, finalize_primnode_results *results)
|
|||
SubPlan *subplan = (SubPlan *) ((Expr *) node)->oper;
|
||||
List *lst;
|
||||
|
||||
/* Add subplan to subplans list */
|
||||
results->subplans = lappend(results->subplans, subplan);
|
||||
/* Check extParam list for params to add to paramids */
|
||||
foreach(lst, subplan->plan->extParam)
|
||||
{
|
||||
|
@ -595,18 +587,16 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||
if (plan == NULL)
|
||||
return NIL;
|
||||
|
||||
results.subplans = NIL; /* initialize lists to NIL */
|
||||
results.paramids = NIL;
|
||||
results.paramids = NIL; /* initialize list to NIL */
|
||||
|
||||
/*
|
||||
* When we call finalize_primnode, results.paramids lists are
|
||||
* automatically merged together. But when recursing to self, we have
|
||||
* to do it the hard way. We want the paramids list to include params
|
||||
* in subplans as well as at this level. (We don't care about finding
|
||||
* subplans of subplans, though.)
|
||||
* in subplans as well as at this level.
|
||||
*/
|
||||
|
||||
/* Find params and subplans in targetlist and qual */
|
||||
/* Find params in targetlist and qual */
|
||||
finalize_primnode((Node *) plan->targetlist, &results);
|
||||
finalize_primnode((Node *) plan->qual, &results);
|
||||
|
||||
|
@ -624,8 +614,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||
|
||||
/*
|
||||
* we need not look at indxqualorig, since it will have the
|
||||
* same param references as indxqual, and we aren't really
|
||||
* concerned yet about having a complete subplan list.
|
||||
* same param references as indxqual.
|
||||
*/
|
||||
break;
|
||||
|
||||
|
@ -704,7 +693,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||
nodeTag(plan));
|
||||
}
|
||||
|
||||
/* Process left and right subplans, if any */
|
||||
/* Process left and right child plans, if any */
|
||||
results.paramids = set_unioni(results.paramids,
|
||||
SS_finalize_plan(plan->lefttree,
|
||||
rtable));
|
||||
|
@ -712,7 +701,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||
SS_finalize_plan(plan->righttree,
|
||||
rtable));
|
||||
|
||||
/* Now we have all the paramids and subplans */
|
||||
/* Now we have all the paramids */
|
||||
|
||||
foreach(lst, results.paramids)
|
||||
{
|
||||
|
@ -733,7 +722,6 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||
|
||||
plan->extParam = extParam;
|
||||
plan->locParam = locParam;
|
||||
plan->subPlan = results.subplans;
|
||||
|
||||
return results.paramids;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.82 2002/11/30 05:21:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.83 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -385,9 +385,7 @@ create_tidscan_path(Query *root, RelOptInfo *rel, List *tideval)
|
|||
pathnode->path.pathtype = T_TidScan;
|
||||
pathnode->path.parent = rel;
|
||||
pathnode->path.pathkeys = NIL;
|
||||
pathnode->tideval = copyObject(tideval); /* is copy really
|
||||
* necessary? */
|
||||
pathnode->unjoined_relids = NIL;
|
||||
pathnode->tideval = tideval;
|
||||
|
||||
cost_tidscan(&pathnode->path, root, rel, tideval);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.56 2002/11/18 01:17:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.57 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -23,15 +23,16 @@
|
|||
#include "utils/ps_status.h"
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* CreateQueryDesc
|
||||
* ----------------------------------------------------------------
|
||||
/*
|
||||
* CreateQueryDesc
|
||||
*/
|
||||
QueryDesc *
|
||||
CreateQueryDesc(Query *parsetree,
|
||||
Plan *plantree,
|
||||
CommandDest dest,
|
||||
const char *portalName)
|
||||
const char *portalName,
|
||||
ParamListInfo params,
|
||||
bool doInstrument)
|
||||
{
|
||||
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
||||
|
||||
|
@ -40,56 +41,17 @@ CreateQueryDesc(Query *parsetree,
|
|||
qd->plantree = plantree; /* plan */
|
||||
qd->dest = dest; /* output dest */
|
||||
qd->portalName = portalName; /* name, if dest is a portal */
|
||||
qd->tupDesc = NULL; /* until set by ExecutorStart */
|
||||
qd->params = params; /* parameter values passed into query */
|
||||
qd->doInstrument = doInstrument; /* instrumentation wanted? */
|
||||
|
||||
/* null these fields until set by ExecutorStart */
|
||||
qd->tupDesc = NULL;
|
||||
qd->estate = NULL;
|
||||
qd->planstate = NULL;
|
||||
|
||||
return qd;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* CreateExecutorState
|
||||
*
|
||||
* Note: this may someday take parameters -cim 9/18/89
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
EState *
|
||||
CreateExecutorState(void)
|
||||
{
|
||||
EState *state;
|
||||
|
||||
/*
|
||||
* create a new executor state
|
||||
*/
|
||||
state = makeNode(EState);
|
||||
|
||||
/*
|
||||
* initialize the Executor State structure
|
||||
*/
|
||||
state->es_direction = ForwardScanDirection;
|
||||
state->es_range_table = NIL;
|
||||
|
||||
state->es_result_relations = NULL;
|
||||
state->es_num_result_relations = 0;
|
||||
state->es_result_relation_info = NULL;
|
||||
|
||||
state->es_junkFilter = NULL;
|
||||
|
||||
state->es_into_relation_descriptor = NULL;
|
||||
|
||||
state->es_param_list_info = NULL;
|
||||
state->es_param_exec_vals = NULL;
|
||||
|
||||
state->es_tupleTable = NULL;
|
||||
|
||||
state->es_query_cxt = CurrentMemoryContext;
|
||||
|
||||
state->es_per_tuple_exprcontext = NULL;
|
||||
|
||||
/*
|
||||
* return the executor state structure
|
||||
*/
|
||||
return state;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PreparePortal
|
||||
* ----------------
|
||||
|
@ -147,8 +109,6 @@ ProcessQuery(Query *parsetree,
|
|||
Portal portal = NULL;
|
||||
MemoryContext oldContext = NULL;
|
||||
QueryDesc *queryDesc;
|
||||
EState *state;
|
||||
TupleDesc attinfo;
|
||||
|
||||
/*
|
||||
* Check for special-case destinations
|
||||
|
@ -193,7 +153,7 @@ ProcessQuery(Query *parsetree,
|
|||
|
||||
/*
|
||||
* We stay in portal's memory context for now, so that query desc,
|
||||
* EState, and plan startup info are also allocated in the portal
|
||||
* exec state, and plan startup info are also allocated in the portal
|
||||
* context.
|
||||
*/
|
||||
}
|
||||
|
@ -201,17 +161,12 @@ ProcessQuery(Query *parsetree,
|
|||
/*
|
||||
* Now we can create the QueryDesc object.
|
||||
*/
|
||||
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
|
||||
|
||||
/*
|
||||
* create a default executor state.
|
||||
*/
|
||||
state = CreateExecutorState();
|
||||
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName, NULL, false);
|
||||
|
||||
/*
|
||||
* call ExecStart to prepare the plan for execution
|
||||
*/
|
||||
attinfo = ExecutorStart(queryDesc, state);
|
||||
ExecutorStart(queryDesc);
|
||||
|
||||
/*
|
||||
* If retrieve into portal, stop now; we do not run the plan until a
|
||||
|
@ -219,11 +174,8 @@ ProcessQuery(Query *parsetree,
|
|||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
{
|
||||
PortalSetQuery(portal,
|
||||
queryDesc,
|
||||
attinfo,
|
||||
state,
|
||||
PortalCleanup);
|
||||
/* Arrange to shut down the executor if portal is dropped */
|
||||
PortalSetQuery(portal, queryDesc, PortalCleanup);
|
||||
|
||||
/* Now we can return to caller's memory context. */
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
|
@ -239,7 +191,7 @@ ProcessQuery(Query *parsetree,
|
|||
* Now we get to the important call to ExecutorRun() where we actually
|
||||
* run the plan..
|
||||
*/
|
||||
ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
|
||||
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
|
||||
|
||||
/*
|
||||
* Build command completion status string, if caller wants one.
|
||||
|
@ -254,20 +206,20 @@ ProcessQuery(Query *parsetree,
|
|||
strcpy(completionTag, "SELECT");
|
||||
break;
|
||||
case CMD_INSERT:
|
||||
if (state->es_processed == 1)
|
||||
lastOid = state->es_lastoid;
|
||||
if (queryDesc->estate->es_processed == 1)
|
||||
lastOid = queryDesc->estate->es_lastoid;
|
||||
else
|
||||
lastOid = InvalidOid;
|
||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||
"INSERT %u %u", lastOid, state->es_processed);
|
||||
"INSERT %u %u", lastOid, queryDesc->estate->es_processed);
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||
"UPDATE %u", state->es_processed);
|
||||
"UPDATE %u", queryDesc->estate->es_processed);
|
||||
break;
|
||||
case CMD_DELETE:
|
||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||
"DELETE %u", state->es_processed);
|
||||
"DELETE %u", queryDesc->estate->es_processed);
|
||||
break;
|
||||
default:
|
||||
strcpy(completionTag, "???");
|
||||
|
@ -278,5 +230,5 @@ ProcessQuery(Query *parsetree,
|
|||
/*
|
||||
* Now, we close down all the scans and free allocated resources.
|
||||
*/
|
||||
ExecutorEnd(queryDesc, state);
|
||||
ExecutorEnd(queryDesc);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.49 2002/06/20 20:29:40 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.50 2002/12/05 15:50:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -149,26 +149,15 @@ GetPortalByName(char *name)
|
|||
/*
|
||||
* PortalSetQuery
|
||||
* Attaches a "query" to portal.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if portal is invalid.
|
||||
* BadArg if queryDesc is "invalid."
|
||||
* BadArg if state is "invalid."
|
||||
*/
|
||||
void
|
||||
PortalSetQuery(Portal portal,
|
||||
QueryDesc *queryDesc,
|
||||
TupleDesc attinfo,
|
||||
EState *state,
|
||||
void (*cleanup) (Portal portal))
|
||||
{
|
||||
AssertArg(PortalIsValid(portal));
|
||||
AssertArg(IsA((Node *) state, EState));
|
||||
|
||||
portal->queryDesc = queryDesc;
|
||||
portal->attinfo = attinfo;
|
||||
portal->state = state;
|
||||
portal->atStart = true; /* Allow fetch forward only */
|
||||
portal->atEnd = false;
|
||||
portal->cleanup = cleanup;
|
||||
|
@ -212,8 +201,6 @@ CreatePortal(char *name)
|
|||
|
||||
/* initialize portal query */
|
||||
portal->queryDesc = NULL;
|
||||
portal->attinfo = NULL;
|
||||
portal->state = NULL;
|
||||
portal->atStart = true; /* disallow fetches until query is set */
|
||||
portal->atEnd = true;
|
||||
portal->cleanup = NULL;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execdesc.h,v 1.20 2002/09/04 20:31:42 momjian Exp $
|
||||
* $Id: execdesc.h,v 1.21 2002/12/05 15:50:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,30 +16,38 @@
|
|||
#define EXECDESC_H
|
||||
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
#include "tcop/dest.h"
|
||||
|
||||
|
||||
/* ----------------
|
||||
* query descriptor:
|
||||
*
|
||||
* a QueryDesc encapsulates everything that the executor
|
||||
* needs to execute the query
|
||||
* ---------------------
|
||||
*/
|
||||
typedef struct QueryDesc
|
||||
{
|
||||
/* These fields are provided by CreateQueryDesc */
|
||||
CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */
|
||||
Query *parsetree;
|
||||
Plan *plantree;
|
||||
Query *parsetree; /* rewritten parsetree */
|
||||
Plan *plantree; /* planner's output */
|
||||
CommandDest dest; /* the destination output of the execution */
|
||||
const char *portalName; /* name of portal, or NULL */
|
||||
ParamListInfo params; /* param values being passed in */
|
||||
bool doInstrument; /* TRUE requests runtime instrumentation */
|
||||
|
||||
TupleDesc tupDesc; /* set by ExecutorStart */
|
||||
/* These fields are set by ExecutorStart */
|
||||
TupleDesc tupDesc; /* descriptor for result tuples */
|
||||
EState *estate; /* executor's query-wide state */
|
||||
PlanState *planstate; /* tree of per-plan-node state */
|
||||
} QueryDesc;
|
||||
|
||||
/* in pquery.c */
|
||||
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
||||
CommandDest dest, const char *portalName);
|
||||
|
||||
CommandDest dest, const char *portalName,
|
||||
ParamListInfo params,
|
||||
bool doInstrument);
|
||||
|
||||
#endif /* EXECDESC_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: executor.h,v 1.80 2002/12/01 20:27:32 tgl Exp $
|
||||
* $Id: executor.h,v 1.81 2002/12/05 15:50:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "executor/execdesc.h"
|
||||
|
||||
|
||||
/* ----------------
|
||||
* TupIsNull
|
||||
*
|
||||
|
@ -30,9 +31,9 @@
|
|||
/*
|
||||
* prototypes from functions in execAmi.c
|
||||
*/
|
||||
extern void ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern void ExecMarkPos(Plan *node);
|
||||
extern void ExecRestrPos(Plan *node);
|
||||
extern void ExecReScan(PlanState *node, ExprContext *exprCtxt);
|
||||
extern void ExecMarkPos(PlanState *node);
|
||||
extern void ExecRestrPos(PlanState *node);
|
||||
extern bool ExecSupportsMarkRestore(NodeTag plantype);
|
||||
|
||||
/*
|
||||
|
@ -49,10 +50,12 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
|
|||
/*
|
||||
* prototypes from functions in execMain.c
|
||||
*/
|
||||
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
|
||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
||||
extern void ExecutorStart(QueryDesc *queryDesc);
|
||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
||||
ScanDirection direction, long count);
|
||||
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
||||
extern void ExecutorEnd(QueryDesc *queryDesc);
|
||||
extern EState *CreateExecutorState(void);
|
||||
extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
||||
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
|
||||
TupleTableSlot *slot, EState *estate);
|
||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
||||
|
@ -61,11 +64,11 @@ extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
|||
/*
|
||||
* prototypes from functions in execProcnode.c
|
||||
*/
|
||||
extern bool ExecInitNode(Plan *node, EState *estate, Plan *parent);
|
||||
extern TupleTableSlot *ExecProcNode(Plan *node, Plan *parent);
|
||||
extern PlanState *ExecInitNode(Plan *node, EState *estate);
|
||||
extern TupleTableSlot *ExecProcNode(PlanState *node);
|
||||
extern int ExecCountSlotsNode(Plan *node);
|
||||
extern void ExecEndNode(Plan *node, Plan *parent);
|
||||
extern TupleDesc ExecGetTupType(Plan *node);
|
||||
extern void ExecEndNode(PlanState *node);
|
||||
extern TupleDesc ExecGetTupType(PlanState *node);
|
||||
|
||||
/*
|
||||
* prototypes from functions in execQual.c
|
||||
|
@ -89,6 +92,7 @@ extern Datum ExecEvalExpr(Node *expression, ExprContext *econtext,
|
|||
bool *isNull, ExprDoneCond *isDone);
|
||||
extern Datum ExecEvalExprSwitchContext(Node *expression, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
extern Node *ExecInitExpr(Node *node, PlanState *parent);
|
||||
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
|
||||
extern int ExecTargetListLength(List *targetlist);
|
||||
extern int ExecCleanTargetListLength(List *targetlist);
|
||||
|
@ -98,9 +102,9 @@ extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
|
|||
/*
|
||||
* prototypes from functions in execScan.c
|
||||
*/
|
||||
typedef TupleTableSlot *(*ExecScanAccessMtd) (Scan *node);
|
||||
typedef TupleTableSlot *(*ExecScanAccessMtd) (ScanState *node);
|
||||
|
||||
extern TupleTableSlot *ExecScan(Scan *node, ExecScanAccessMtd accessMtd);
|
||||
extern TupleTableSlot *ExecScan(ScanState *node, ExecScanAccessMtd accessMtd);
|
||||
|
||||
/*
|
||||
* prototypes from functions in execTuples.c
|
||||
|
@ -117,14 +121,13 @@ extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
|
|||
extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
|
||||
TupleDesc tupdesc, bool shouldFree);
|
||||
extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
|
||||
extern void ExecInitResultTupleSlot(EState *estate, CommonState *commonstate);
|
||||
extern void ExecInitScanTupleSlot(EState *estate,
|
||||
CommonScanState *commonscanstate);
|
||||
extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate);
|
||||
extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate);
|
||||
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
|
||||
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
|
||||
TupleDesc tupType);
|
||||
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
|
||||
extern void SetChangedParamList(Plan *node, List *newchg);
|
||||
extern void SetChangedParamList(PlanState *node, List *newchg);
|
||||
|
||||
typedef struct TupOutputState
|
||||
{
|
||||
|
@ -155,21 +158,19 @@ extern void end_tup_output(TupOutputState *tstate);
|
|||
* prototypes from functions in execUtils.c
|
||||
*/
|
||||
extern void ResetTupleCount(void);
|
||||
extern void ExecAssignExprContext(EState *estate, CommonState *commonstate);
|
||||
extern void ExecAssignResultType(CommonState *commonstate,
|
||||
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
|
||||
extern void ExecAssignResultType(PlanState *planstate,
|
||||
TupleDesc tupDesc, bool shouldFree);
|
||||
extern void ExecAssignResultTypeFromOuterPlan(Plan *node,
|
||||
CommonState *commonstate);
|
||||
extern void ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate);
|
||||
extern TupleDesc ExecGetResultType(CommonState *commonstate);
|
||||
extern void ExecAssignProjectionInfo(Plan *node, CommonState *commonstate);
|
||||
extern void ExecFreeProjectionInfo(CommonState *commonstate);
|
||||
extern void ExecFreeExprContext(CommonState *commonstate);
|
||||
extern TupleDesc ExecGetScanType(CommonScanState *csstate);
|
||||
extern void ExecAssignScanType(CommonScanState *csstate,
|
||||
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
|
||||
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
|
||||
extern TupleDesc ExecGetResultType(PlanState *planstate);
|
||||
extern void ExecAssignProjectionInfo(PlanState *planstate);
|
||||
extern void ExecFreeProjectionInfo(PlanState *planstate);
|
||||
extern void ExecFreeExprContext(PlanState *planstate);
|
||||
extern TupleDesc ExecGetScanType(ScanState *scanstate);
|
||||
extern void ExecAssignScanType(ScanState *scanstate,
|
||||
TupleDesc tupDesc, bool shouldFree);
|
||||
extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
|
||||
CommonScanState *csstate);
|
||||
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
|
||||
|
||||
extern ExprContext *MakeExprContext(TupleTableSlot *slot,
|
||||
MemoryContext queryContext);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeAgg.h,v 1.17 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeAgg.h,v 1.18 2002/12/05 15:50:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -15,13 +15,13 @@
|
|||
#define NODEAGG_H
|
||||
|
||||
#include "fmgr.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecAgg(Agg *node);
|
||||
extern bool ExecInitAgg(Agg *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsAgg(Agg *node);
|
||||
extern void ExecEndAgg(Agg *node);
|
||||
extern void ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern AggState *ExecInitAgg(Agg *node, EState *estate);
|
||||
extern TupleTableSlot *ExecAgg(AggState *node);
|
||||
extern void ExecEndAgg(AggState *node);
|
||||
extern void ExecReScanAgg(AggState *node, ExprContext *exprCtxt);
|
||||
|
||||
extern Datum aggregate_dummy(PG_FUNCTION_ARGS);
|
||||
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeAppend.h,v 1.17 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeAppend.h,v 1.18 2002/12/05 15:50:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEAPPEND_H
|
||||
#define NODEAPPEND_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern bool ExecInitAppend(Append *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsAppend(Append *node);
|
||||
extern TupleTableSlot *ExecProcAppend(Append *node);
|
||||
extern void ExecEndAppend(Append *node);
|
||||
extern void ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern AppendState *ExecInitAppend(Append *node, EState *estate);
|
||||
extern TupleTableSlot *ExecProcAppend(AppendState *node);
|
||||
extern void ExecEndAppend(AppendState *node);
|
||||
extern void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODEAPPEND_H */
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeFunctionscan.h,v 1.2 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeFunctionscan.h,v 1.3 2002/12/05 15:50:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEFUNCTIONSCAN_H
|
||||
#define NODEFUNCTIONSCAN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecFunctionScan(FunctionScan *node);
|
||||
extern void ExecEndFunctionScan(FunctionScan *node);
|
||||
extern bool ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsFunctionScan(FunctionScan *node);
|
||||
extern void ExecFunctionMarkPos(FunctionScan *node);
|
||||
extern void ExecFunctionRestrPos(FunctionScan *node);
|
||||
extern void ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate);
|
||||
extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
|
||||
extern void ExecEndFunctionScan(FunctionScanState *node);
|
||||
extern void ExecFunctionMarkPos(FunctionScanState *node);
|
||||
extern void ExecFunctionRestrPos(FunctionScanState *node);
|
||||
extern void ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODEFUNCTIONSCAN_H */
|
||||
|
|
|
@ -7,20 +7,20 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeGroup.h,v 1.22 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeGroup.h,v 1.23 2002/12/05 15:50:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEGROUP_H
|
||||
#define NODEGROUP_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecGroup(Group *node);
|
||||
extern bool ExecInitGroup(Group *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsGroup(Group *node);
|
||||
extern void ExecEndGroup(Group *node);
|
||||
extern void ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern GroupState *ExecInitGroup(Group *node, EState *estate);
|
||||
extern TupleTableSlot *ExecGroup(GroupState *node);
|
||||
extern void ExecEndGroup(GroupState *node);
|
||||
extern void ExecReScanGroup(GroupState *node, ExprContext *exprCtxt);
|
||||
|
||||
extern bool execTuplesMatch(HeapTuple tuple1,
|
||||
HeapTuple tuple2,
|
||||
|
|
|
@ -7,19 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeHash.h,v 1.26 2002/11/30 00:08:20 tgl Exp $
|
||||
* $Id: nodeHash.h,v 1.27 2002/12/05 15:50:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEHASH_H
|
||||
#define NODEHASH_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecHash(Hash *node);
|
||||
extern bool ExecInitHash(Hash *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsHash(Hash *node);
|
||||
extern void ExecEndHash(Hash *node);
|
||||
extern HashState *ExecInitHash(Hash *node, EState *estate);
|
||||
extern TupleTableSlot *ExecHash(HashState *node);
|
||||
extern void ExecEndHash(HashState *node);
|
||||
extern void ExecReScanHash(HashState *node, ExprContext *exprCtxt);
|
||||
|
||||
extern HashJoinTable ExecHashTableCreate(Hash *node);
|
||||
extern void ExecHashTableDestroy(HashJoinTable hashtable);
|
||||
extern void ExecHashTableInsert(HashJoinTable hashtable,
|
||||
|
@ -31,7 +33,6 @@ extern int ExecHashGetBucket(HashJoinTable hashtable,
|
|||
extern HeapTuple ExecScanHashBucket(HashJoinState *hjstate, List *hjclauses,
|
||||
ExprContext *econtext);
|
||||
extern void ExecHashTableReset(HashJoinTable hashtable, long ntuples);
|
||||
extern void ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern void ExecChooseHashTableSize(double ntuples, int tupwidth,
|
||||
int *virtualbuckets,
|
||||
int *physicalbuckets,
|
||||
|
|
|
@ -7,20 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeHashjoin.h,v 1.23 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeHashjoin.h,v 1.24 2002/12/05 15:50:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEHASHJOIN_H
|
||||
#define NODEHASHJOIN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecHashJoin(HashJoin *node);
|
||||
extern bool ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsHashJoin(HashJoin *node);
|
||||
extern void ExecEndHashJoin(HashJoin *node);
|
||||
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate);
|
||||
extern TupleTableSlot *ExecHashJoin(HashJoinState *node);
|
||||
extern void ExecEndHashJoin(HashJoinState *node);
|
||||
extern void ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt);
|
||||
|
||||
extern void ExecHashJoinSaveTuple(HeapTuple heapTuple, BufFile *file);
|
||||
extern void ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent);
|
||||
|
||||
#endif /* NODEHASHJOIN_H */
|
||||
|
|
|
@ -7,22 +7,23 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeIndexscan.h,v 1.16 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeIndexscan.h,v 1.17 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEINDEXSCAN_H
|
||||
#define NODEINDEXSCAN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecIndexScan(IndexScan *node);
|
||||
extern void ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern void ExecEndIndexScan(IndexScan *node);
|
||||
extern void ExecIndexMarkPos(IndexScan *node);
|
||||
extern void ExecIndexRestrPos(IndexScan *node);
|
||||
extern void ExecUpdateIndexScanKeys(IndexScan *node, ExprContext *econtext);
|
||||
extern bool ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsIndexScan(IndexScan *node);
|
||||
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate);
|
||||
extern TupleTableSlot *ExecIndexScan(IndexScanState *node);
|
||||
extern void ExecEndIndexScan(IndexScanState *node);
|
||||
extern void ExecIndexMarkPos(IndexScanState *node);
|
||||
extern void ExecIndexRestrPos(IndexScanState *node);
|
||||
extern void ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt);
|
||||
|
||||
extern void ExecUpdateIndexScanKeys(IndexScanState *node, ExprContext *econtext);
|
||||
|
||||
#endif /* NODEINDEXSCAN_H */
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeLimit.h,v 1.6 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeLimit.h,v 1.7 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODELIMIT_H
|
||||
#define NODELIMIT_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecLimit(Limit *node);
|
||||
extern bool ExecInitLimit(Limit *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsLimit(Limit *node);
|
||||
extern void ExecEndLimit(Limit *node);
|
||||
extern void ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern LimitState *ExecInitLimit(Limit *node, EState *estate);
|
||||
extern TupleTableSlot *ExecLimit(LimitState *node);
|
||||
extern void ExecEndLimit(LimitState *node);
|
||||
extern void ExecReScanLimit(LimitState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODELIMIT_H */
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeMaterial.h,v 1.18 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeMaterial.h,v 1.19 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEMATERIAL_H
|
||||
#define NODEMATERIAL_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecMaterial(Material *node);
|
||||
extern bool ExecInitMaterial(Material *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsMaterial(Material *node);
|
||||
extern void ExecEndMaterial(Material *node);
|
||||
extern void ExecMaterialMarkPos(Material *node);
|
||||
extern void ExecMaterialRestrPos(Material *node);
|
||||
extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern MaterialState *ExecInitMaterial(Material *node, EState *estate);
|
||||
extern TupleTableSlot *ExecMaterial(MaterialState *node);
|
||||
extern void ExecEndMaterial(MaterialState *node);
|
||||
extern void ExecMaterialMarkPos(MaterialState *node);
|
||||
extern void ExecMaterialRestrPos(MaterialState *node);
|
||||
extern void ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODEMATERIAL_H */
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeMergejoin.h,v 1.17 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeMergejoin.h,v 1.18 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEMERGEJOIN_H
|
||||
#define NODEMERGEJOIN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecMergeJoin(MergeJoin *node);
|
||||
extern bool ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsMergeJoin(MergeJoin *node);
|
||||
extern void ExecEndMergeJoin(MergeJoin *node);
|
||||
extern void ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate);
|
||||
extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node);
|
||||
extern void ExecEndMergeJoin(MergeJoinState *node);
|
||||
extern void ExecReScanMergeJoin(MergeJoinState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODEMERGEJOIN_H; */
|
||||
#endif /* NODEMERGEJOIN_H */
|
||||
|
|
|
@ -7,20 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeNestloop.h,v 1.18 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeNestloop.h,v 1.19 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODENESTLOOP_H
|
||||
#define NODENESTLOOP_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecNestLoop(NestLoop *node);
|
||||
extern bool ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsNestLoop(NestLoop *node);
|
||||
extern void ExecEndNestLoop(NestLoop *node);
|
||||
extern void ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt,
|
||||
Plan *parent);
|
||||
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate);
|
||||
extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
|
||||
extern void ExecEndNestLoop(NestLoopState *node);
|
||||
extern void ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODENESTLOOP_H */
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeResult.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeResult.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODERESULT_H
|
||||
#define NODERESULT_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecResult(Result *node);
|
||||
extern bool ExecInitResult(Result *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsResult(Result *node);
|
||||
extern void ExecEndResult(Result *node);
|
||||
extern void ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern ResultState *ExecInitResult(Result *node, EState *estate);
|
||||
extern TupleTableSlot *ExecResult(ResultState *node);
|
||||
extern void ExecEndResult(ResultState *node);
|
||||
extern void ExecReScanResult(ResultState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODERESULT_H */
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeSeqscan.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeSeqscan.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODESEQSCAN_H
|
||||
#define NODESEQSCAN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecSeqScan(SeqScan *node);
|
||||
extern bool ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsSeqScan(SeqScan *node);
|
||||
extern void ExecEndSeqScan(SeqScan *node);
|
||||
extern void ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern void ExecSeqMarkPos(SeqScan *node);
|
||||
extern void ExecSeqRestrPos(SeqScan *node);
|
||||
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate);
|
||||
extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
|
||||
extern void ExecEndSeqScan(SeqScanState *node);
|
||||
extern void ExecSeqMarkPos(SeqScanState *node);
|
||||
extern void ExecSeqRestrPos(SeqScanState *node);
|
||||
extern void ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODESEQSCAN_H */
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeSetOp.h,v 1.6 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeSetOp.h,v 1.7 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODESETOP_H
|
||||
#define NODESETOP_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecSetOp(SetOp *node);
|
||||
extern bool ExecInitSetOp(SetOp *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsSetOp(SetOp *node);
|
||||
extern void ExecEndSetOp(SetOp *node);
|
||||
extern void ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate);
|
||||
extern TupleTableSlot *ExecSetOp(SetOpState *node);
|
||||
extern void ExecEndSetOp(SetOpState *node);
|
||||
extern void ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODESETOP_H */
|
||||
|
|
|
@ -7,21 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeSort.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeSort.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODESORT_H
|
||||
#define NODESORT_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecSort(Sort *node);
|
||||
extern bool ExecInitSort(Sort *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsSort(Sort *node);
|
||||
extern void ExecEndSort(Sort *node);
|
||||
extern void ExecSortMarkPos(Sort *node);
|
||||
extern void ExecSortRestrPos(Sort *node);
|
||||
extern void ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern SortState *ExecInitSort(Sort *node, EState *estate);
|
||||
extern TupleTableSlot *ExecSort(SortState *node);
|
||||
extern void ExecEndSort(SortState *node);
|
||||
extern void ExecSortMarkPos(SortState *node);
|
||||
extern void ExecSortRestrPos(SortState *node);
|
||||
extern void ExecReScanSort(SortState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODESORT_H */
|
||||
|
|
|
@ -2,18 +2,26 @@
|
|||
*
|
||||
* nodeSubplan.h
|
||||
*
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeSubplan.h,v 1.12 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODESUBPLAN_H
|
||||
#define NODESUBPLAN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern Datum ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext,
|
||||
extern SubPlanState *ExecInitSubPlan(SubPlan *node, EState *estate);
|
||||
extern Datum ExecSubPlan(SubPlanState *node, List *pvar, ExprContext *econtext,
|
||||
bool *isNull);
|
||||
extern bool ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent);
|
||||
extern void ExecReScanSetParamPlan(SubPlan *node, Plan *parent);
|
||||
extern void ExecSetParamPlan(SubPlan *node, ExprContext *econtext);
|
||||
extern void ExecEndSubPlan(SubPlan *node);
|
||||
extern void ExecEndSubPlan(SubPlanState *node);
|
||||
extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
|
||||
|
||||
extern void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext);
|
||||
|
||||
#endif /* NODESUBPLAN_H */
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeSubqueryscan.h,v 1.6 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeSubqueryscan.h,v 1.7 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODESUBQUERYSCAN_H
|
||||
#define NODESUBQUERYSCAN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecSubqueryScan(SubqueryScan *node);
|
||||
extern void ExecEndSubqueryScan(SubqueryScan *node);
|
||||
extern bool ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsSubqueryScan(SubqueryScan *node);
|
||||
extern void ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate);
|
||||
extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
|
||||
extern void ExecEndSubqueryScan(SubqueryScanState *node);
|
||||
extern void ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODESUBQUERYSCAN_H */
|
||||
|
|
|
@ -7,22 +7,21 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeTidscan.h,v 1.10 2002/11/30 05:21:03 tgl Exp $
|
||||
* $Id: nodeTidscan.h,v 1.11 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODETIDSCAN_H
|
||||
#define NODETIDSCAN_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecTidScan(TidScan *node);
|
||||
extern void ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern void ExecEndTidScan(TidScan *node);
|
||||
extern void ExecTidMarkPos(TidScan *node);
|
||||
extern void ExecTidRestrPos(TidScan *node);
|
||||
extern bool ExecInitTidScan(TidScan *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsTidScan(TidScan *node);
|
||||
extern void ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate);
|
||||
extern TupleTableSlot *ExecTidScan(TidScanState *node);
|
||||
extern void ExecEndTidScan(TidScanState *node);
|
||||
extern void ExecTidMarkPos(TidScanState *node);
|
||||
extern void ExecTidRestrPos(TidScanState *node);
|
||||
extern void ExecTidReScan(TidScanState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODETIDSCAN_H */
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeUnique.h,v 1.15 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: nodeUnique.h,v 1.16 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEUNIQUE_H
|
||||
#define NODEUNIQUE_H
|
||||
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecUnique(Unique *node);
|
||||
extern bool ExecInitUnique(Unique *node, EState *estate, Plan *parent);
|
||||
extern int ExecCountSlotsUnique(Unique *node);
|
||||
extern void ExecEndUnique(Unique *node);
|
||||
extern void ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent);
|
||||
extern UniqueState *ExecInitUnique(Unique *node, EState *estate);
|
||||
extern TupleTableSlot *ExecUnique(UniqueState *node);
|
||||
extern void ExecEndUnique(UniqueState *node);
|
||||
extern void ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt);
|
||||
|
||||
#endif /* NODEUNIQUE_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execnodes.h,v 1.81 2002/11/30 00:08:20 tgl Exp $
|
||||
* $Id: execnodes.h,v 1.82 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -15,12 +15,11 @@
|
|||
#define EXECNODES_H
|
||||
|
||||
#include "access/relscan.h"
|
||||
#include "access/sdir.h"
|
||||
#include "executor/hashjoin.h"
|
||||
#include "executor/tuptable.h"
|
||||
#include "fmgr.h"
|
||||
#include "nodes/params.h"
|
||||
#include "nodes/primnodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "utils/tuplestore.h"
|
||||
|
||||
|
||||
|
@ -316,6 +315,8 @@ typedef struct EState
|
|||
List *es_rowMark; /* not good place, but there is no other */
|
||||
MemoryContext es_query_cxt; /* per-query context in which EState lives */
|
||||
|
||||
bool es_instrument; /* true requests runtime instrumentation */
|
||||
|
||||
/*
|
||||
* this ExprContext is for per-output-tuple operations, such as
|
||||
* constraint checks and index-value computations. It will be reset
|
||||
|
@ -332,98 +333,101 @@ typedef struct EState
|
|||
bool es_useEvalPlan;
|
||||
} EState;
|
||||
|
||||
/* ----------------
|
||||
* Executor Type information needed by plannodes.h
|
||||
*
|
||||
*| Note: the bogus classes CommonState and CommonScanState exist only
|
||||
*| because our inheritance system only allows single inheritance
|
||||
*| and we have to have unique slot names. Hence two or more
|
||||
*| classes which want to have a common slot must ALL inherit
|
||||
*| the slot from some other class. (This is a big hack to
|
||||
*| allow our classes to share slot names..)
|
||||
*|
|
||||
*| Example:
|
||||
*| the class Result and the class NestLoop nodes both want
|
||||
*| a slot called "OuterTuple" so they both have to inherit
|
||||
*| it from some other class. In this case they inherit
|
||||
*| it from CommonState. "CommonState" and "CommonScanState" are
|
||||
*| the best names I could come up with for this sort of
|
||||
*| stuff.
|
||||
*|
|
||||
*| As a result, many classes have extra slots which they
|
||||
*| don't use. These slots are denoted (unused) in the
|
||||
*| comment preceding the class definition. If you
|
||||
*| comes up with a better idea of a way of doing things
|
||||
*| along these lines, then feel free to make your idea
|
||||
*| known to me.. -cim 10/15/89
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Common Executor State Information
|
||||
* Executor State Information
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* CommonState information
|
||||
* PlanState node
|
||||
*
|
||||
* Superclass for all executor node-state object types.
|
||||
*
|
||||
* OuterTupleSlot pointer to slot containing current "outer" tuple
|
||||
* ResultTupleSlot pointer to slot in tuple table for projected tuple
|
||||
* ExprContext node's expression-evaluation context
|
||||
* ProjInfo info this node uses to form tuple projections
|
||||
* TupFromTlist state flag used by some node types (why kept here?)
|
||||
* We never actually instantiate any PlanState nodes; this is just the common
|
||||
* abstract superclass for all PlanState-type nodes.
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct CommonState
|
||||
typedef struct PlanState
|
||||
{
|
||||
NodeTag type; /* its first field is NodeTag */
|
||||
TupleTableSlot *cs_OuterTupleSlot;
|
||||
TupleTableSlot *cs_ResultTupleSlot;
|
||||
ExprContext *cs_ExprContext;
|
||||
ProjectionInfo *cs_ProjInfo;
|
||||
bool cs_TupFromTlist;
|
||||
} CommonState;
|
||||
NodeTag type;
|
||||
|
||||
Plan *plan; /* associated Plan node */
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Control Node State Information
|
||||
* ----------------------------------------------------------------
|
||||
EState *state; /* at execution time, state's of
|
||||
* individual nodes point to one EState
|
||||
* for the whole top-level plan */
|
||||
|
||||
struct Instrumentation *instrument; /* Optional runtime stats for this
|
||||
* plan node */
|
||||
|
||||
/*
|
||||
* Common structural data for all Plan types. These links to subsidiary
|
||||
* state trees parallel links in the associated plan tree (except for
|
||||
* the subPlan list, which does not exist in the plan tree).
|
||||
*/
|
||||
List *targetlist; /* target list to be computed at this node */
|
||||
List *qual; /* implicitly-ANDed qual conditions */
|
||||
struct PlanState *lefttree; /* input plan tree(s) */
|
||||
struct PlanState *righttree;
|
||||
List *initPlan; /* Init SubPlanState nodes (un-correlated
|
||||
* expr subselects) */
|
||||
List *subPlan; /* SubPlanState nodes in my expressions */
|
||||
|
||||
/*
|
||||
* State for management of parameter-change-driven rescanning
|
||||
*/
|
||||
List *chgParam; /* integer list of IDs of changed Params */
|
||||
|
||||
/*
|
||||
* Other run-time state needed by most if not all node types.
|
||||
*/
|
||||
TupleTableSlot *ps_OuterTupleSlot; /* slot for current "outer" tuple */
|
||||
TupleTableSlot *ps_ResultTupleSlot; /* slot for my result tuples */
|
||||
ExprContext *ps_ExprContext; /* node's expression-evaluation context */
|
||||
ProjectionInfo *ps_ProjInfo; /* info for doing tuple projection */
|
||||
bool ps_TupFromTlist; /* state flag for processing set-valued
|
||||
* functions in targetlist */
|
||||
} PlanState;
|
||||
|
||||
/* ----------------
|
||||
* these are are defined to avoid confusion problems with "left"
|
||||
* and "right" and "inner" and "outer". The convention is that
|
||||
* the "left" plan is the "outer" plan and the "right" plan is
|
||||
* the inner plan, but these make the code more readable.
|
||||
* ----------------
|
||||
*/
|
||||
#define innerPlanState(node) (((PlanState *)(node))->righttree)
|
||||
#define outerPlanState(node) (((PlanState *)(node))->lefttree)
|
||||
|
||||
|
||||
/* ----------------
|
||||
* ResultState information
|
||||
*
|
||||
* done flag which tells us to quit when we
|
||||
* have already returned a constant tuple.
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct ResultState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
bool rs_done;
|
||||
bool rs_checkqual;
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
Node *resconstantqual;
|
||||
bool rs_done; /* are we done? */
|
||||
bool rs_checkqual; /* do we need to check the qual? */
|
||||
} ResultState;
|
||||
|
||||
/* ----------------
|
||||
* AppendState information
|
||||
*
|
||||
* nplans how many plans are in the list
|
||||
* whichplan which plan is being executed (0 .. n-1)
|
||||
* firstplan first plan to execute (usually 0)
|
||||
* lastplan last plan to execute (usually n-1)
|
||||
* nplans how many plans are in the list
|
||||
* initialized array of ExecInitNode() results
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct AppendState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
PlanState **appendplans; /* array of PlanStates for my inputs */
|
||||
int as_nplans;
|
||||
int as_whichplan;
|
||||
int as_firstplan;
|
||||
int as_lastplan;
|
||||
int as_nplans;
|
||||
bool *as_initialized;
|
||||
} AppendState;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -432,9 +436,9 @@ typedef struct AppendState
|
|||
*/
|
||||
|
||||
/* ----------------
|
||||
* CommonScanState information
|
||||
* ScanState information
|
||||
*
|
||||
* CommonScanState extends CommonState for node types that represent
|
||||
* ScanState extends PlanState for node types that represent
|
||||
* scans of an underlying relation. It can also be used for nodes
|
||||
* that scan the output of an underlying plan node --- in that case,
|
||||
* only ScanTupleSlot is actually useful, and it refers to the tuple
|
||||
|
@ -445,27 +449,23 @@ typedef struct AppendState
|
|||
* ScanTupleSlot pointer to slot in tuple table holding scan tuple
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct CommonScanState
|
||||
typedef struct ScanState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
Relation css_currentRelation;
|
||||
HeapScanDesc css_currentScanDesc;
|
||||
TupleTableSlot *css_ScanTupleSlot;
|
||||
} CommonScanState;
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
Relation ss_currentRelation;
|
||||
HeapScanDesc ss_currentScanDesc;
|
||||
TupleTableSlot *ss_ScanTupleSlot;
|
||||
} ScanState;
|
||||
|
||||
/*
|
||||
* SeqScan uses a bare CommonScanState as its state item, since it needs
|
||||
* SeqScan uses a bare ScanState as its state node, since it needs
|
||||
* no additional fields.
|
||||
*/
|
||||
typedef ScanState SeqScanState;
|
||||
|
||||
/* ----------------
|
||||
* IndexScanState information
|
||||
*
|
||||
* Note that an IndexScan node *also* has a CommonScanState state item.
|
||||
* IndexScanState stores the info needed specifically for indexing.
|
||||
* There's probably no good reason why this is a separate node type
|
||||
* rather than an extension of CommonScanState.
|
||||
*
|
||||
* NumIndices number of indices in this scan
|
||||
* IndexPtr current index in use
|
||||
* ScanKeys Skey structures to scan index rels
|
||||
|
@ -479,7 +479,9 @@ typedef struct CommonScanState
|
|||
*/
|
||||
typedef struct IndexScanState
|
||||
{
|
||||
NodeTag type;
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
List *indxqual;
|
||||
List *indxqualorig;
|
||||
int iss_NumIndices;
|
||||
int iss_IndexPtr;
|
||||
int iss_MarkIndexPtr;
|
||||
|
@ -495,10 +497,6 @@ typedef struct IndexScanState
|
|||
/* ----------------
|
||||
* TidScanState information
|
||||
*
|
||||
* Note that a TidScan node *also* has a CommonScanState state item.
|
||||
* There's probably no good reason why this is a separate node type
|
||||
* rather than an extension of CommonScanState.
|
||||
*
|
||||
* NumTids number of tids in this scan
|
||||
* TidPtr current tid in use
|
||||
* TidList evaluated item pointers
|
||||
|
@ -506,7 +504,7 @@ typedef struct IndexScanState
|
|||
*/
|
||||
typedef struct TidScanState
|
||||
{
|
||||
NodeTag type;
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
int tss_NumTids;
|
||||
int tss_TidPtr;
|
||||
int tss_MarkTidPtr;
|
||||
|
@ -526,7 +524,8 @@ typedef struct TidScanState
|
|||
*/
|
||||
typedef struct SubqueryScanState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
PlanState *subplan;
|
||||
EState *sss_SubEState;
|
||||
} SubqueryScanState;
|
||||
|
||||
|
@ -538,12 +537,12 @@ typedef struct SubqueryScanState
|
|||
*
|
||||
* tupdesc expected return tuple description
|
||||
* tuplestorestate private state of tuplestore.c
|
||||
* funcexpr function expression being evaluated
|
||||
* funcexpr state for function expression being evaluated
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct FunctionScanState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
TupleDesc tupdesc;
|
||||
Tuplestorestate *tuplestorestate;
|
||||
Node *funcexpr;
|
||||
|
@ -557,11 +556,15 @@ typedef struct FunctionScanState
|
|||
/* ----------------
|
||||
* JoinState information
|
||||
*
|
||||
* Superclass for state items of join nodes.
|
||||
* Currently this is the same as CommonState.
|
||||
* Superclass for state nodes of join plans.
|
||||
* ----------------
|
||||
*/
|
||||
typedef CommonState JoinState;
|
||||
typedef struct JoinState
|
||||
{
|
||||
PlanState ps;
|
||||
JoinType jointype;
|
||||
List *joinqual; /* JOIN quals (in addition to ps.qual) */
|
||||
} JoinState;
|
||||
|
||||
/* ----------------
|
||||
* NestLoopState information
|
||||
|
@ -573,7 +576,7 @@ typedef CommonState JoinState;
|
|||
*/
|
||||
typedef struct NestLoopState
|
||||
{
|
||||
JoinState jstate; /* its first field is NodeTag */
|
||||
JoinState js; /* its first field is NodeTag */
|
||||
bool nl_NeedNewOuter;
|
||||
bool nl_MatchedOuter;
|
||||
TupleTableSlot *nl_NullInnerTupleSlot;
|
||||
|
@ -596,7 +599,8 @@ typedef struct NestLoopState
|
|||
*/
|
||||
typedef struct MergeJoinState
|
||||
{
|
||||
JoinState jstate; /* its first field is NodeTag */
|
||||
JoinState js; /* its first field is NodeTag */
|
||||
List *mergeclauses;
|
||||
List *mj_OuterSkipQual;
|
||||
List *mj_InnerSkipQual;
|
||||
int mj_JoinState;
|
||||
|
@ -630,7 +634,8 @@ typedef struct MergeJoinState
|
|||
*/
|
||||
typedef struct HashJoinState
|
||||
{
|
||||
JoinState jstate; /* its first field is NodeTag */
|
||||
JoinState js; /* its first field is NodeTag */
|
||||
List *hashclauses;
|
||||
HashJoinTable hj_HashTable;
|
||||
int hj_CurBucketNo;
|
||||
HashJoinTuple hj_CurTuple;
|
||||
|
@ -656,23 +661,46 @@ typedef struct HashJoinState
|
|||
* materialize nodes are used to materialize the results
|
||||
* of a subplan into a temporary file.
|
||||
*
|
||||
* csstate.css_ScanTupleSlot refers to output of underlying plan.
|
||||
* ss.ss_ScanTupleSlot refers to output of underlying plan.
|
||||
*
|
||||
* tuplestorestate private state of tuplestore.c
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct MaterialState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
void *tuplestorestate;
|
||||
} MaterialState;
|
||||
|
||||
/* ----------------
|
||||
* SortState information
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct SortState
|
||||
{
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
bool sort_Done; /* sort completed yet? */
|
||||
void *tuplesortstate; /* private state of tuplesort.c */
|
||||
} SortState;
|
||||
|
||||
/* ---------------------
|
||||
* AggregateState information
|
||||
* GroupState information
|
||||
* -------------------------
|
||||
*/
|
||||
typedef struct GroupState
|
||||
{
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
|
||||
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
|
||||
bool grp_done; /* indicates completion of Group scan */
|
||||
} GroupState;
|
||||
|
||||
/* ---------------------
|
||||
* AggState information
|
||||
*
|
||||
* csstate.css_ScanTupleSlot refers to output of underlying plan.
|
||||
* ss.ss_ScanTupleSlot refers to output of underlying plan.
|
||||
*
|
||||
* Note: csstate.cstate.cs_ExprContext contains ecxt_aggvalues and
|
||||
* Note: ss.ps.ps_ExprContext contains ecxt_aggvalues and
|
||||
* ecxt_aggnulls arrays, which hold the computed agg values for the current
|
||||
* input group during evaluation of an Agg node's output tuple(s). We
|
||||
* create a second ExprContext, tmpcontext, in which to evaluate input
|
||||
|
@ -687,7 +715,7 @@ typedef struct AggHashTableData *AggHashTable;
|
|||
|
||||
typedef struct AggState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
ScanState ss; /* its first field is NodeTag */
|
||||
List *aggs; /* all Aggref nodes in targetlist & quals */
|
||||
int numaggs; /* length of list (could be zero!) */
|
||||
FmgrInfo *eqfunctions; /* per-grouping-field equality fns */
|
||||
|
@ -705,32 +733,6 @@ typedef struct AggState
|
|||
int next_hash_bucket; /* next chain */
|
||||
} AggState;
|
||||
|
||||
/* ---------------------
|
||||
* GroupState information
|
||||
* -------------------------
|
||||
*/
|
||||
typedef struct GroupState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
|
||||
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
|
||||
bool grp_done; /* indicates completion of Group scan */
|
||||
} GroupState;
|
||||
|
||||
/* ----------------
|
||||
* SortState information
|
||||
*
|
||||
* sort_Done indicates whether sort has been performed yet
|
||||
* tuplesortstate private state of tuplesort.c
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct SortState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
bool sort_Done;
|
||||
void *tuplesortstate;
|
||||
} SortState;
|
||||
|
||||
/* ----------------
|
||||
* UniqueState information
|
||||
*
|
||||
|
@ -744,12 +746,22 @@ typedef struct SortState
|
|||
*/
|
||||
typedef struct UniqueState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
|
||||
HeapTuple priorTuple; /* most recently returned tuple, or NULL */
|
||||
MemoryContext tempContext; /* short-term context for comparisons */
|
||||
} UniqueState;
|
||||
|
||||
/* ----------------
|
||||
* HashState information
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct HashState
|
||||
{
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
HashJoinTable hashtable; /* hash table for the hashjoin */
|
||||
} HashState;
|
||||
|
||||
/* ----------------
|
||||
* SetOpState information
|
||||
*
|
||||
|
@ -761,7 +773,7 @@ typedef struct UniqueState
|
|||
*/
|
||||
typedef struct SetOpState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
|
||||
bool subplan_done; /* has subplan returned EOF? */
|
||||
long numLeft; /* number of left-input dups of cur group */
|
||||
|
@ -794,7 +806,9 @@ typedef enum
|
|||
|
||||
typedef struct LimitState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
Node *limitOffset; /* OFFSET parameter, or NULL if none */
|
||||
Node *limitCount; /* COUNT parameter, or NULL if none */
|
||||
long offset; /* current OFFSET value */
|
||||
long count; /* current COUNT, if any */
|
||||
bool noCount; /* if true, ignore count */
|
||||
|
@ -803,46 +817,16 @@ typedef struct LimitState
|
|||
TupleTableSlot *subSlot; /* tuple last obtained from subplan */
|
||||
} LimitState;
|
||||
|
||||
|
||||
/* ----------------
|
||||
* HashState information
|
||||
*
|
||||
* hashtable hash table for the hashjoin
|
||||
* ----------------
|
||||
/* ---------------------
|
||||
* SubPlanState information
|
||||
* ---------------------
|
||||
*/
|
||||
typedef struct HashState
|
||||
typedef struct SubPlanState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
HashJoinTable hashtable;
|
||||
} HashState;
|
||||
|
||||
#ifdef NOT_USED
|
||||
/* -----------------------
|
||||
* TeeState information
|
||||
* leftPlace : next item in the queue unseen by the left parent
|
||||
* rightPlace : next item in the queue unseen by the right parent
|
||||
* lastPlace : last item in the queue
|
||||
* bufferRelname : name of the relation used as the buffer queue
|
||||
* bufferRel : the relation used as the buffer queue
|
||||
* mcxt : for now, tee's have their own memory context
|
||||
* may be cleaned up later if portals are cleaned up
|
||||
*
|
||||
* initially, a Tee starts with [left/right]Place variables set to -1.
|
||||
* on cleanup, queue is free'd when both leftPlace and rightPlace = -1
|
||||
* -------------------------
|
||||
*/
|
||||
typedef struct TeeState
|
||||
{
|
||||
CommonState cstate; /* its first field is NodeTag */
|
||||
int tee_leftPlace,
|
||||
tee_rightPlace,
|
||||
tee_lastPlace;
|
||||
char *tee_bufferRelname;
|
||||
Relation tee_bufferRel;
|
||||
MemoryContext tee_mcxt;
|
||||
HeapScanDesc tee_leftScanDesc,
|
||||
tee_rightScanDesc;
|
||||
} TeeState;
|
||||
#endif
|
||||
PlanState ps; /* its first field is NodeTag */
|
||||
PlanState *planstate; /* subselect plan's state tree */
|
||||
bool needShutdown; /* TRUE = need to shutdown subplan */
|
||||
HeapTuple curTuple; /* copy of most recent tuple from subplan */
|
||||
} SubPlanState;
|
||||
|
||||
#endif /* EXECNODES_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodes.h,v 1.125 2002/11/30 05:21:03 tgl Exp $
|
||||
* $Id: nodes.h,v 1.126 2002/12/05 15:50:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -18,43 +18,84 @@
|
|||
* The first field of every node is NodeTag. Each node created (with makeNode)
|
||||
* will have one of the following tags as the value of its first field.
|
||||
*
|
||||
* Note that the number of the node tags are not contiguous. We left holes
|
||||
* Note that the numbers of the node tags are not contiguous. We left holes
|
||||
* here so that we can add more tags without changing the existing enum's.
|
||||
* (Since node tag numbers never exist outside backend memory, there's no
|
||||
* real harm in renumbering, it just costs a full rebuild ...)
|
||||
*/
|
||||
typedef enum NodeTag
|
||||
{
|
||||
T_Invalid = 0,
|
||||
|
||||
/*
|
||||
* TAGS FOR EXECUTOR NODES (execnodes.h)
|
||||
*/
|
||||
T_IndexInfo = 10,
|
||||
T_ResultRelInfo,
|
||||
T_TupleTableSlot,
|
||||
T_ExprContext,
|
||||
T_ProjectionInfo,
|
||||
T_JunkFilter,
|
||||
T_EState,
|
||||
|
||||
/*
|
||||
* TAGS FOR PLAN NODES (plannodes.h)
|
||||
*/
|
||||
T_Plan = 10,
|
||||
T_Plan = 100,
|
||||
T_Result,
|
||||
T_Append,
|
||||
T_Scan,
|
||||
T_SeqScan,
|
||||
T_IndexScan,
|
||||
T_TidScan,
|
||||
T_SubqueryScan,
|
||||
T_FunctionScan,
|
||||
T_Join,
|
||||
T_NestLoop,
|
||||
T_MergeJoin,
|
||||
T_HashJoin,
|
||||
T_Limit,
|
||||
T_Material,
|
||||
T_Sort,
|
||||
T_Group,
|
||||
T_Agg,
|
||||
T_Unique,
|
||||
T_Hash,
|
||||
T_SetOp,
|
||||
T_Group,
|
||||
T_Limit,
|
||||
T_SubPlan,
|
||||
T_TidScan,
|
||||
T_SubqueryScan,
|
||||
T_FunctionScan,
|
||||
|
||||
/*
|
||||
* TAGS FOR PLAN STATE NODES (execnodes.h)
|
||||
*
|
||||
* These should correspond one-to-one with Plan node types.
|
||||
*/
|
||||
T_PlanState = 200,
|
||||
T_ResultState,
|
||||
T_AppendState,
|
||||
T_ScanState,
|
||||
T_SeqScanState,
|
||||
T_IndexScanState,
|
||||
T_TidScanState,
|
||||
T_SubqueryScanState,
|
||||
T_FunctionScanState,
|
||||
T_JoinState,
|
||||
T_NestLoopState,
|
||||
T_MergeJoinState,
|
||||
T_HashJoinState,
|
||||
T_MaterialState,
|
||||
T_SortState,
|
||||
T_GroupState,
|
||||
T_AggState,
|
||||
T_UniqueState,
|
||||
T_HashState,
|
||||
T_SetOpState,
|
||||
T_LimitState,
|
||||
T_SubPlanState,
|
||||
|
||||
/*
|
||||
* TAGS FOR PRIMITIVE NODES (primnodes.h)
|
||||
*/
|
||||
T_Resdom = 100,
|
||||
T_Resdom = 300,
|
||||
T_Fjoin,
|
||||
T_Expr,
|
||||
T_Var,
|
||||
|
@ -74,7 +115,7 @@ typedef enum NodeTag
|
|||
/*
|
||||
* TAGS FOR PLANNER NODES (relation.h)
|
||||
*/
|
||||
T_RelOptInfo = 200,
|
||||
T_RelOptInfo = 400,
|
||||
T_IndexOptInfo,
|
||||
T_Path,
|
||||
T_IndexPath,
|
||||
|
@ -90,48 +131,16 @@ typedef enum NodeTag
|
|||
T_JoinInfo,
|
||||
T_InnerIndexscanInfo,
|
||||
|
||||
/*
|
||||
* TAGS FOR EXECUTOR NODES (execnodes.h)
|
||||
*/
|
||||
T_IndexInfo = 300,
|
||||
T_ResultRelInfo,
|
||||
T_TupleTableSlot,
|
||||
T_ExprContext,
|
||||
T_ProjectionInfo,
|
||||
T_JunkFilter,
|
||||
T_EState,
|
||||
T_CommonState,
|
||||
T_ResultState,
|
||||
T_AppendState,
|
||||
T_CommonScanState,
|
||||
T_ScanState,
|
||||
T_IndexScanState,
|
||||
T_JoinState,
|
||||
T_NestLoopState,
|
||||
T_MergeJoinState,
|
||||
T_HashJoinState,
|
||||
T_MaterialState,
|
||||
T_AggState,
|
||||
T_GroupState,
|
||||
T_SortState,
|
||||
T_UniqueState,
|
||||
T_HashState,
|
||||
T_TidScanState,
|
||||
T_SubqueryScanState,
|
||||
T_SetOpState,
|
||||
T_LimitState,
|
||||
T_FunctionScanState,
|
||||
|
||||
/*
|
||||
* TAGS FOR MEMORY NODES (memnodes.h)
|
||||
*/
|
||||
T_MemoryContext = 400,
|
||||
T_MemoryContext = 500,
|
||||
T_AllocSetContext,
|
||||
|
||||
/*
|
||||
* TAGS FOR VALUE NODES (pg_list.h)
|
||||
*/
|
||||
T_Value = 500,
|
||||
T_Value = 600,
|
||||
T_List,
|
||||
T_Integer,
|
||||
T_Float,
|
||||
|
@ -142,7 +151,7 @@ typedef enum NodeTag
|
|||
/*
|
||||
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
||||
*/
|
||||
T_Query = 600,
|
||||
T_Query = 700,
|
||||
T_InsertStmt,
|
||||
T_DeleteStmt,
|
||||
T_UpdateStmt,
|
||||
|
@ -208,7 +217,7 @@ typedef enum NodeTag
|
|||
T_ExecuteStmt,
|
||||
T_DeallocateStmt,
|
||||
|
||||
T_A_Expr = 700,
|
||||
T_A_Expr = 800,
|
||||
T_ColumnRef,
|
||||
T_ParamRef,
|
||||
T_A_Const,
|
||||
|
@ -248,7 +257,7 @@ typedef enum NodeTag
|
|||
/*
|
||||
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
|
||||
*/
|
||||
T_TriggerData = 800, /* in commands/trigger.h */
|
||||
T_TriggerData = 900, /* in commands/trigger.h */
|
||||
T_ReturnSetInfo /* in nodes/execnodes.h */
|
||||
|
||||
} NodeTag;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: params.h,v 1.18 2002/11/25 21:29:42 tgl Exp $
|
||||
* $Id: params.h,v 1.19 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -88,7 +88,7 @@ typedef ParamListInfoData *ParamListInfo;
|
|||
* array of ParamExecData records, which is referenced through
|
||||
* es_param_exec_vals or ecxt_param_exec_vals.
|
||||
*
|
||||
* If execPlan is not NULL, it points to a SubPlan node that needs to
|
||||
* If execPlan is not NULL, it points to a SubPlanState node that needs to
|
||||
* be executed to produce the value. (This is done so that we can have
|
||||
* lazy evaluation of InitPlans: they aren't executed until/unless a
|
||||
* result value is needed.) Otherwise the value is assumed to be valid
|
||||
|
@ -98,7 +98,7 @@ typedef ParamListInfoData *ParamListInfo;
|
|||
|
||||
typedef struct ParamExecData
|
||||
{
|
||||
void *execPlan; /* should be "SubPlan *" */
|
||||
void *execPlan; /* should be "SubPlanState *" */
|
||||
Datum value;
|
||||
bool isnull;
|
||||
} ParamExecData;
|
||||
|
|
|
@ -7,52 +7,15 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: plannodes.h,v 1.61 2002/11/30 00:08:22 tgl Exp $
|
||||
* $Id: plannodes.h,v 1.62 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PLANNODES_H
|
||||
#define PLANNODES_H
|
||||
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Executor State types are used in the plannode structures
|
||||
* so we have to include their definitions too.
|
||||
*
|
||||
* Node Type node information used by executor
|
||||
*
|
||||
* control nodes
|
||||
*
|
||||
* Result ResultState resstate;
|
||||
* Append AppendState appendstate;
|
||||
*
|
||||
* scan nodes
|
||||
*
|
||||
* Scan *** CommonScanState scanstate;
|
||||
* IndexScan IndexScanState indxstate;
|
||||
* SubqueryScan SubqueryScanState subquerystate;
|
||||
* FunctionScan FunctionScanState functionstate;
|
||||
*
|
||||
* (*** nodes which inherit Scan also inherit scanstate)
|
||||
*
|
||||
* join nodes
|
||||
*
|
||||
* NestLoop NestLoopState nlstate;
|
||||
* MergeJoin MergeJoinState mergestate;
|
||||
* HashJoin HashJoinState hashjoinstate;
|
||||
*
|
||||
* materialize nodes
|
||||
*
|
||||
* Material MaterialState matstate;
|
||||
* Sort SortState sortstate;
|
||||
* Unique UniqueState uniquestate;
|
||||
* SetOp SetOpState setopstate;
|
||||
* Limit LimitState limitstate;
|
||||
* Hash HashState hashstate;
|
||||
*
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
#include "access/sdir.h"
|
||||
#include "nodes/primnodes.h"
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -62,45 +25,47 @@
|
|||
|
||||
/* ----------------
|
||||
* Plan node
|
||||
*
|
||||
* All plan nodes "derive" from the Plan structure by having the
|
||||
* Plan structure as the first field. This ensures that everything works
|
||||
* when nodes are cast to Plan's. (node pointers are frequently cast to Plan*
|
||||
* when passed around generically in the executor)
|
||||
*
|
||||
* We never actually instantiate any Plan nodes; this is just the common
|
||||
* abstract superclass for all Plan-type nodes.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
typedef struct Plan
|
||||
{
|
||||
NodeTag type;
|
||||
|
||||
/* estimated execution costs for plan (see costsize.c for more info) */
|
||||
/*
|
||||
* estimated execution costs for plan (see costsize.c for more info)
|
||||
*/
|
||||
Cost startup_cost; /* cost expended before fetching any
|
||||
* tuples */
|
||||
Cost total_cost; /* total cost (assuming all tuples
|
||||
* fetched) */
|
||||
|
||||
/*
|
||||
* planner's estimate of result size (note: LIMIT, if any, is not
|
||||
* considered in setting plan_rows)
|
||||
* planner's estimate of result size of this plan step
|
||||
*/
|
||||
double plan_rows; /* number of rows plan is expected to emit */
|
||||
int plan_width; /* average row width in bytes */
|
||||
|
||||
/*
|
||||
* execution state data. Having Plan point to this, rather than the
|
||||
* other way round, is 100% bogus.
|
||||
* Common structural data for all Plan types.
|
||||
*/
|
||||
EState *state; /* at execution time, state's of
|
||||
* individual nodes point to one EState
|
||||
* for the whole top-level plan */
|
||||
|
||||
struct Instrumentation *instrument; /* Optional runtime stats for this
|
||||
* plan node */
|
||||
List *targetlist; /* target list to be computed at this node */
|
||||
List *qual; /* implicitly-ANDed qual conditions */
|
||||
struct Plan *lefttree; /* input plan tree(s) */
|
||||
struct Plan *righttree;
|
||||
List *initPlan; /* Init Plan nodes (un-correlated expr
|
||||
* subselects) */
|
||||
|
||||
/*
|
||||
* Common structural data for all Plan types. XXX chgParam is runtime
|
||||
* data and should be in the EState, not here.
|
||||
* Information for management of parameter-change-driven rescanning
|
||||
*/
|
||||
List *targetlist;
|
||||
List *qual; /* implicitly-ANDed qual conditions */
|
||||
struct Plan *lefttree;
|
||||
struct Plan *righttree;
|
||||
List *extParam; /* indices of _all_ _external_ PARAM_EXEC
|
||||
* for this plan in global
|
||||
* es_param_exec_vals. Params from
|
||||
|
@ -108,10 +73,6 @@ typedef struct Plan
|
|||
* included, but their execParam-s are
|
||||
* here!!! */
|
||||
List *locParam; /* someones from setParam-s */
|
||||
List *chgParam; /* list of changed ones from the above */
|
||||
List *initPlan; /* Init Plan nodes (un-correlated expr
|
||||
* subselects) */
|
||||
List *subPlan; /* Other SubPlan nodes */
|
||||
|
||||
/*
|
||||
* We really need in some TopPlan node to store range table and
|
||||
|
@ -134,20 +95,6 @@ typedef struct Plan
|
|||
#define outerPlan(node) (((Plan *)(node))->lefttree)
|
||||
|
||||
|
||||
/*
|
||||
* ===============
|
||||
* Top-level nodes
|
||||
* ===============
|
||||
*/
|
||||
|
||||
/*
|
||||
* all plan nodes "derive" from the Plan structure by having the
|
||||
* Plan structure as the first field. This ensures that everything works
|
||||
* when nodes are cast to Plan's. (node pointers are frequently cast to Plan*
|
||||
* when passed around generically in the executor)
|
||||
*/
|
||||
|
||||
|
||||
/* ----------------
|
||||
* Result node -
|
||||
* If no outer plan, evaluate a variable-free targetlist.
|
||||
|
@ -163,7 +110,6 @@ typedef struct Result
|
|||
{
|
||||
Plan plan;
|
||||
Node *resconstantqual;
|
||||
ResultState *resstate;
|
||||
} Result;
|
||||
|
||||
/* ----------------
|
||||
|
@ -182,7 +128,6 @@ typedef struct Append
|
|||
Plan plan;
|
||||
List *appendplans;
|
||||
bool isTarget;
|
||||
AppendState *appendstate;
|
||||
} Append;
|
||||
|
||||
/*
|
||||
|
@ -194,7 +139,6 @@ typedef struct Scan
|
|||
{
|
||||
Plan plan;
|
||||
Index scanrelid; /* relid is index into the range table */
|
||||
CommonScanState *scanstate;
|
||||
} Scan;
|
||||
|
||||
/* ----------------
|
||||
|
@ -214,7 +158,6 @@ typedef struct IndexScan
|
|||
List *indxqual;
|
||||
List *indxqualorig;
|
||||
ScanDirection indxorderdir;
|
||||
IndexScanState *indxstate;
|
||||
} IndexScan;
|
||||
|
||||
/* ----------------
|
||||
|
@ -224,9 +167,7 @@ typedef struct IndexScan
|
|||
typedef struct TidScan
|
||||
{
|
||||
Scan scan;
|
||||
bool needRescan;
|
||||
List *tideval;
|
||||
TidScanState *tidstate;
|
||||
} TidScan;
|
||||
|
||||
/* ----------------
|
||||
|
@ -257,7 +198,6 @@ typedef struct FunctionScan
|
|||
{
|
||||
Scan scan;
|
||||
/* no other fields needed at present */
|
||||
/* scan.scanstate actually points at a FunctionScanState node */
|
||||
} FunctionScan;
|
||||
|
||||
/*
|
||||
|
@ -296,7 +236,6 @@ typedef struct Join
|
|||
typedef struct NestLoop
|
||||
{
|
||||
Join join;
|
||||
NestLoopState *nlstate;
|
||||
} NestLoop;
|
||||
|
||||
/* ----------------
|
||||
|
@ -307,7 +246,6 @@ typedef struct MergeJoin
|
|||
{
|
||||
Join join;
|
||||
List *mergeclauses;
|
||||
MergeJoinState *mergestate;
|
||||
} MergeJoin;
|
||||
|
||||
/* ----------------
|
||||
|
@ -318,9 +256,40 @@ typedef struct HashJoin
|
|||
{
|
||||
Join join;
|
||||
List *hashclauses;
|
||||
HashJoinState *hashjoinstate;
|
||||
} HashJoin;
|
||||
|
||||
/* ----------------
|
||||
* materialization node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct Material
|
||||
{
|
||||
Plan plan;
|
||||
} Material;
|
||||
|
||||
/* ----------------
|
||||
* sort node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct Sort
|
||||
{
|
||||
Plan plan;
|
||||
int keycount;
|
||||
} Sort;
|
||||
|
||||
/* ---------------
|
||||
* group node -
|
||||
* Used for queries with GROUP BY (but no aggregates) specified.
|
||||
* The input must be presorted according to the grouping columns.
|
||||
* ---------------
|
||||
*/
|
||||
typedef struct Group
|
||||
{
|
||||
Plan plan;
|
||||
int numCols; /* number of grouping columns */
|
||||
AttrNumber *grpColIdx; /* their indexes in the target list */
|
||||
} Group;
|
||||
|
||||
/* ---------------
|
||||
* aggregate node
|
||||
*
|
||||
|
@ -349,44 +318,8 @@ typedef struct Agg
|
|||
int numCols; /* number of grouping columns */
|
||||
AttrNumber *grpColIdx; /* their indexes in the target list */
|
||||
long numGroups; /* estimated number of groups in input */
|
||||
AggState *aggstate;
|
||||
} Agg;
|
||||
|
||||
/* ---------------
|
||||
* group node -
|
||||
* Used for queries with GROUP BY (but no aggregates) specified.
|
||||
* The input must be presorted according to the grouping columns.
|
||||
* ---------------
|
||||
*/
|
||||
typedef struct Group
|
||||
{
|
||||
Plan plan;
|
||||
int numCols; /* number of grouping columns */
|
||||
AttrNumber *grpColIdx; /* their indexes in the target list */
|
||||
GroupState *grpstate;
|
||||
} Group;
|
||||
|
||||
/* ----------------
|
||||
* materialization node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct Material
|
||||
{
|
||||
Plan plan;
|
||||
MaterialState *matstate;
|
||||
} Material;
|
||||
|
||||
/* ----------------
|
||||
* sort node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct Sort
|
||||
{
|
||||
Plan plan;
|
||||
int keycount;
|
||||
SortState *sortstate;
|
||||
} Sort;
|
||||
|
||||
/* ----------------
|
||||
* unique node
|
||||
* ----------------
|
||||
|
@ -397,9 +330,18 @@ typedef struct Unique
|
|||
int numCols; /* number of columns to check for
|
||||
* uniqueness */
|
||||
AttrNumber *uniqColIdx; /* indexes into the target list */
|
||||
UniqueState *uniquestate;
|
||||
} Unique;
|
||||
|
||||
/* ----------------
|
||||
* hash build node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct Hash
|
||||
{
|
||||
Plan plan;
|
||||
List *hashkeys;
|
||||
} Hash;
|
||||
|
||||
/* ----------------
|
||||
* setop node
|
||||
* ----------------
|
||||
|
@ -420,7 +362,6 @@ typedef struct SetOp
|
|||
* duplicate-ness */
|
||||
AttrNumber *dupColIdx; /* indexes into the target list */
|
||||
AttrNumber flagColIdx;
|
||||
SetOpState *setopstate;
|
||||
} SetOp;
|
||||
|
||||
/* ----------------
|
||||
|
@ -432,44 +373,13 @@ typedef struct Limit
|
|||
Plan plan;
|
||||
Node *limitOffset; /* OFFSET parameter, or NULL if none */
|
||||
Node *limitCount; /* COUNT parameter, or NULL if none */
|
||||
LimitState *limitstate;
|
||||
} Limit;
|
||||
|
||||
/* ----------------
|
||||
* hash build node
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct Hash
|
||||
{
|
||||
Plan plan;
|
||||
List *hashkeys;
|
||||
HashState *hashstate;
|
||||
} Hash;
|
||||
|
||||
#ifdef NOT_USED
|
||||
/* -------------------
|
||||
* Tee node information
|
||||
*
|
||||
* leftParent : the left parent of this node
|
||||
* rightParent: the right parent of this node
|
||||
* -------------------
|
||||
*/
|
||||
typedef struct Tee
|
||||
{
|
||||
Plan plan;
|
||||
Plan *leftParent;
|
||||
Plan *rightParent;
|
||||
TeeState *teestate;
|
||||
char *teeTableName; /* the name of the table to materialize
|
||||
* the tee into */
|
||||
List *rtentries; /* the range table for the plan below the
|
||||
* Tee may be different than the parent
|
||||
* plans */
|
||||
} Tee;
|
||||
#endif
|
||||
|
||||
/* ---------------------
|
||||
* SubPlan node
|
||||
*
|
||||
* XXX Perhaps does not belong in this file? It's not really a Plan node.
|
||||
* Should we make it inherit from Plan anyway?
|
||||
* ---------------------
|
||||
*/
|
||||
typedef struct SubPlan
|
||||
|
@ -489,12 +399,7 @@ typedef struct SubPlan
|
|||
* about what to do with subselect's
|
||||
* results */
|
||||
|
||||
/*
|
||||
* Remaining fields are working state for executor; not used in
|
||||
* planning
|
||||
*/
|
||||
bool needShutdown; /* TRUE = need to shutdown subplan */
|
||||
HeapTuple curTuple; /* copy of most recent tuple from subplan */
|
||||
struct SubPlanState *pstate; /* XXX TEMPORARY HACK */
|
||||
} SubPlan;
|
||||
|
||||
#endif /* PLANNODES_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: print.h,v 1.19 2002/09/04 20:31:44 momjian Exp $
|
||||
* $Id: print.h,v 1.20 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -15,10 +15,10 @@
|
|||
#define PRINT_H
|
||||
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/execnodes.h"
|
||||
|
||||
|
||||
#define nodeDisplay pprint
|
||||
#define nodeDisplay(x) pprint(x)
|
||||
|
||||
extern void print(void *obj);
|
||||
extern void pprint(void *obj);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: relation.h,v 1.72 2002/11/30 05:21:03 tgl Exp $
|
||||
* $Id: relation.h,v 1.73 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -377,8 +377,7 @@ typedef struct IndexPath
|
|||
typedef struct TidPath
|
||||
{
|
||||
Path path;
|
||||
List *tideval; /* qual(s) involving CTID = something */
|
||||
Relids unjoined_relids; /* some rels not yet part of my Path */
|
||||
List *tideval; /* qual(s) involving CTID = something */
|
||||
} TidPath;
|
||||
|
||||
/*
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pquery.h,v 1.22 2002/09/04 20:31:45 momjian Exp $
|
||||
* $Id: pquery.h,v 1.23 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -21,8 +21,6 @@
|
|||
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest,
|
||||
char *completionTag);
|
||||
|
||||
extern EState *CreateExecutorState(void);
|
||||
|
||||
extern Portal PreparePortal(char *portalName);
|
||||
|
||||
#endif /* PQUERY_H */
|
||||
|
|
|
@ -3,19 +3,16 @@
|
|||
* portal.h
|
||||
* POSTGRES portal definitions.
|
||||
*
|
||||
* A portal is an abstraction which represents the execution state of
|
||||
* a running query (specifically, a CURSOR).
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: portal.h,v 1.35 2002/09/04 20:31:45 momjian Exp $
|
||||
* $Id: portal.h,v 1.36 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* Note:
|
||||
* A portal is an abstraction which represents the execution state of
|
||||
* a running query (specifically, a CURSOR).
|
||||
*/
|
||||
#ifndef PORTAL_H
|
||||
#define PORTAL_H
|
||||
|
||||
|
@ -30,8 +27,6 @@ typedef struct PortalData
|
|||
char *name; /* Portal's name */
|
||||
MemoryContext heap; /* subsidiary memory */
|
||||
QueryDesc *queryDesc; /* Info about query associated with portal */
|
||||
TupleDesc attinfo;
|
||||
EState *state; /* Execution state of query */
|
||||
bool atStart; /* T => fetch backwards is not allowed */
|
||||
bool atEnd; /* T => fetch forwards is not allowed */
|
||||
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
||||
|
@ -47,8 +42,6 @@ typedef struct PortalData
|
|||
* Access macros for Portal ... use these in preference to field access.
|
||||
*/
|
||||
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
|
||||
#define PortalGetTupleDesc(portal) ((portal)->attinfo)
|
||||
#define PortalGetState(portal) ((portal)->state)
|
||||
#define PortalGetHeapMemory(portal) ((portal)->heap)
|
||||
|
||||
/*
|
||||
|
@ -64,7 +57,6 @@ extern Portal CreatePortal(char *name);
|
|||
extern void PortalDrop(Portal portal);
|
||||
extern Portal GetPortalByName(char *name);
|
||||
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
|
||||
TupleDesc attinfo, EState *state,
|
||||
void (*cleanup) (Portal portal));
|
||||
void (*cleanup) (Portal portal));
|
||||
|
||||
#endif /* PORTAL_H */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.71 2002/11/30 21:25:08 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.72 2002/12/05 15:50:39 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
|
@ -3583,7 +3583,6 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
|
|||
if (plan->lefttree != NULL ||
|
||||
plan->righttree != NULL ||
|
||||
plan->initPlan != NULL ||
|
||||
plan->subPlan != NULL ||
|
||||
plan->qual != NULL ||
|
||||
((Result *) plan)->resconstantqual != NULL)
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue