mirror of
https://github.com/postgres/postgres.git
synced 2025-12-06 00:02:13 +03:00
Phase 1 of read-only-plans project: cause executor state nodes to point
to plan nodes, not vice-versa. All executor state nodes now inherit from struct PlanState. Copying of plan trees has been simplified by not storing a list of SubPlans in Plan nodes (eliminating duplicate links). The executor still needs such a list, but it can build it during ExecutorStart since it has to scan the plan tree anyway. No initdb forced since no stored-on-disk structures changed, but you will need a full recompile because of node-numbering changes.
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
* 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 */
|
/* options */
|
||||||
bool printCost; /* print cost */
|
bool printCost; /* print cost */
|
||||||
bool printNodes; /* do nodeToString() instead */
|
bool printNodes; /* do nodeToString() too */
|
||||||
bool printAnalyze; /* print actual times */
|
bool printAnalyze; /* print actual times */
|
||||||
/* other states */
|
/* other states */
|
||||||
List *rtable; /* range table */
|
List *rtable; /* range table */
|
||||||
} ExplainState;
|
} ExplainState;
|
||||||
|
|
||||||
static StringInfo Explain_PlanToString(Plan *plan, ExplainState *es);
|
|
||||||
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
|
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
|
||||||
TupOutputState *tstate);
|
TupOutputState *tstate);
|
||||||
static void explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
static double elapsed_time(struct timeval *starttime);
|
||||||
int indent, ExplainState *es);
|
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,
|
static void show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
|
||||||
int scanrelid, Plan *outer_plan,
|
int scanrelid, Plan *outer_plan,
|
||||||
StringInfo str, int indent, ExplainState *es);
|
StringInfo str, int indent, ExplainState *es);
|
||||||
@@ -116,8 +118,11 @@ static void
|
|||||||
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
||||||
{
|
{
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
|
QueryDesc *queryDesc;
|
||||||
ExplainState *es;
|
ExplainState *es;
|
||||||
|
StringInfo str;
|
||||||
double totaltime = 0;
|
double totaltime = 0;
|
||||||
|
struct timeval starttime;
|
||||||
|
|
||||||
/* planner will not cope with utility statements */
|
/* planner will not cope with utility statements */
|
||||||
if (query->commandType == CMD_UTILITY)
|
if (query->commandType == CMD_UTILITY)
|
||||||
@@ -136,41 +141,34 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
|||||||
if (plan == NULL)
|
if (plan == NULL)
|
||||||
return;
|
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 */
|
/* Execute the plan for statistics if asked for */
|
||||||
if (stmt->analyze)
|
if (stmt->analyze)
|
||||||
{
|
{
|
||||||
struct timeval starttime;
|
/* run the plan */
|
||||||
struct timeval endtime;
|
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
|
||||||
|
|
||||||
/*
|
/* We can't clean up 'till we're done printing the stats... */
|
||||||
* Set up the instrumentation for the top node. This will cascade
|
|
||||||
* during plan initialisation
|
|
||||||
*/
|
|
||||||
plan->instrument = InstrAlloc();
|
|
||||||
|
|
||||||
gettimeofday(&starttime, NULL);
|
totaltime += elapsed_time(&starttime);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
es = (ExplainState *) palloc0(sizeof(ExplainState));
|
es = (ExplainState *) palloc0(sizeof(ExplainState));
|
||||||
|
|
||||||
es->printCost = true; /* default */
|
es->printCost = true; /* default */
|
||||||
|
es->printNodes = stmt->verbose;
|
||||||
if (stmt->verbose)
|
es->printAnalyze = stmt->analyze;
|
||||||
es->printNodes = true;
|
|
||||||
|
|
||||||
es->rtable = query->rtable;
|
es->rtable = query->rtable;
|
||||||
|
|
||||||
if (es->printNodes)
|
if (es->printNodes)
|
||||||
@@ -193,33 +191,73 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str = makeStringInfo();
|
||||||
|
|
||||||
if (es->printCost)
|
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)
|
if (stmt->analyze)
|
||||||
appendStringInfo(str, "Total runtime: %.2f msec\n",
|
appendStringInfo(str, "Total runtime: %.2f msec\n",
|
||||||
1000.0 * totaltime);
|
1000.0 * totaltime);
|
||||||
do_text_output_multiline(tstate, str->data);
|
do_text_output_multiline(tstate, str->data);
|
||||||
pfree(str->data);
|
|
||||||
pfree(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pfree(str->data);
|
||||||
|
pfree(str);
|
||||||
pfree(es);
|
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 -
|
* explain_outNode -
|
||||||
* converts a Plan node into ascii string and appends it to 'str'
|
* 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
|
* 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
|
* side of a join with the current node. This is only interesting for
|
||||||
* deciphering runtime keys of an inner indexscan.
|
* deciphering runtime keys of an inner indexscan.
|
||||||
*/
|
*/
|
||||||
static void
|
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)
|
int indent, ExplainState *es)
|
||||||
{
|
{
|
||||||
List *l;
|
List *l;
|
||||||
@@ -410,18 +448,23 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
plan->startup_cost, plan->total_cost,
|
plan->startup_cost, plan->total_cost,
|
||||||
plan->plan_rows, plan->plan_width);
|
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)",
|
appendStringInfo(str, " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)",
|
||||||
1000.0 * plan->instrument->startup / nloops,
|
1000.0 * planstate->instrument->startup / nloops,
|
||||||
1000.0 * plan->instrument->total / nloops,
|
1000.0 * planstate->instrument->total / nloops,
|
||||||
plan->instrument->ntuples / nloops,
|
planstate->instrument->ntuples / nloops,
|
||||||
plan->instrument->nloops);
|
planstate->instrument->nloops);
|
||||||
es->printAnalyze = true;
|
|
||||||
}
|
}
|
||||||
else if( es->printAnalyze )
|
else if (es->printAnalyze)
|
||||||
{
|
{
|
||||||
appendStringInfo(str, " (never executed)");
|
appendStringInfo(str, " (never executed)");
|
||||||
}
|
}
|
||||||
@@ -538,6 +581,7 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
if (plan->initPlan)
|
if (plan->initPlan)
|
||||||
{
|
{
|
||||||
List *saved_rtable = es->rtable;
|
List *saved_rtable = es->rtable;
|
||||||
|
List *pslist = planstate->initPlan;
|
||||||
List *lst;
|
List *lst;
|
||||||
|
|
||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
@@ -545,12 +589,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
appendStringInfo(str, " InitPlan\n");
|
appendStringInfo(str, " InitPlan\n");
|
||||||
foreach(lst, plan->initPlan)
|
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++)
|
for (i = 0; i < indent; i++)
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
|
explain_outNode(str, subplan->plan,
|
||||||
|
subplanstate->planstate,
|
||||||
|
NULL,
|
||||||
indent + 4, es);
|
indent + 4, es);
|
||||||
|
pslist = lnext(pslist);
|
||||||
}
|
}
|
||||||
es->rtable = saved_rtable;
|
es->rtable = saved_rtable;
|
||||||
}
|
}
|
||||||
@@ -561,7 +611,10 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
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 */
|
/* righttree */
|
||||||
@@ -570,15 +623,20 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, innerPlan(plan), outerPlan(plan),
|
explain_outNode(str, innerPlan(plan),
|
||||||
|
innerPlanState(planstate),
|
||||||
|
outerPlan(plan),
|
||||||
indent + 3, es);
|
indent + 3, es);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsA(plan, Append))
|
if (IsA(plan, Append))
|
||||||
{
|
{
|
||||||
Append *appendplan = (Append *) plan;
|
Append *appendplan = (Append *) plan;
|
||||||
|
AppendState *appendstate = (AppendState *) planstate;
|
||||||
List *lst;
|
List *lst;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
foreach(lst, appendplan->appendplans)
|
foreach(lst, appendplan->appendplans)
|
||||||
{
|
{
|
||||||
Plan *subnode = (Plan *) lfirst(lst);
|
Plan *subnode = (Plan *) lfirst(lst);
|
||||||
@@ -587,13 +645,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
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))
|
if (IsA(plan, SubqueryScan))
|
||||||
{
|
{
|
||||||
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
|
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
|
||||||
|
SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
|
||||||
Plan *subnode = subqueryscan->subplan;
|
Plan *subnode = subqueryscan->subplan;
|
||||||
RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
|
RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
|
||||||
es->rtable);
|
es->rtable);
|
||||||
@@ -606,13 +669,16 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
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;
|
es->rtable = saved_rtable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* subPlan-s */
|
/* subPlan-s */
|
||||||
if (plan->subPlan)
|
if (planstate->subPlan)
|
||||||
{
|
{
|
||||||
List *saved_rtable = es->rtable;
|
List *saved_rtable = es->rtable;
|
||||||
List *lst;
|
List *lst;
|
||||||
@@ -620,29 +686,24 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
|
|||||||
for (i = 0; i < indent; i++)
|
for (i = 0; i < indent; i++)
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
appendStringInfo(str, " SubPlan\n");
|
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++)
|
for (i = 0; i < indent; i++)
|
||||||
appendStringInfo(str, " ");
|
appendStringInfo(str, " ");
|
||||||
appendStringInfo(str, " -> ");
|
appendStringInfo(str, " -> ");
|
||||||
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, NULL,
|
explain_outNode(str, sp->plan,
|
||||||
|
sps->planstate,
|
||||||
|
NULL,
|
||||||
indent + 4, es);
|
indent + 4, es);
|
||||||
}
|
}
|
||||||
es->rtable = saved_rtable;
|
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
|
* Show a qualifier expression for a scan plan node
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* 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
|
void
|
||||||
PortalCleanup(Portal portal)
|
PortalCleanup(Portal portal)
|
||||||
@@ -43,7 +47,7 @@ PortalCleanup(Portal portal)
|
|||||||
/*
|
/*
|
||||||
* tell the executor to shutdown the query
|
* tell the executor to shutdown the query
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
|
ExecutorEnd(PortalGetQueryDesc(portal));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch back to previous context
|
* switch back to previous context
|
||||||
@@ -116,7 +120,7 @@ PerformPortalFetch(char *name,
|
|||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
queryDesc = PortalGetQueryDesc(portal);
|
queryDesc = PortalGetQueryDesc(portal);
|
||||||
estate = PortalGetState(portal);
|
estate = queryDesc->estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the requested destination is not the same as the query's
|
* If the requested destination is not the same as the query's
|
||||||
@@ -158,7 +162,7 @@ PerformPortalFetch(char *name,
|
|||||||
else
|
else
|
||||||
direction = ForwardScanDirection;
|
direction = ForwardScanDirection;
|
||||||
|
|
||||||
ExecutorRun(queryDesc, estate, direction, (long) count);
|
ExecutorRun(queryDesc, direction, (long) count);
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
if (estate->es_processed > 0)
|
||||||
portal->atStart = false; /* OK to back up now */
|
portal->atStart = false; /* OK to back up now */
|
||||||
@@ -172,7 +176,7 @@ PerformPortalFetch(char *name,
|
|||||||
else
|
else
|
||||||
direction = BackwardScanDirection;
|
direction = BackwardScanDirection;
|
||||||
|
|
||||||
ExecutorRun(queryDesc, estate, direction, (long) count);
|
ExecutorRun(queryDesc, direction, (long) count);
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
if (estate->es_processed > 0)
|
||||||
portal->atEnd = false; /* OK to go forward now */
|
portal->atEnd = false; /* OK to go forward now */
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Copyright (c) 2002, PostgreSQL Global Development Group
|
* Copyright (c) 2002, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,
|
static void StoreQuery(const char *stmt_name, List *query_list,
|
||||||
List *plan_list, List *argtype_list);
|
List *plan_list, List *argtype_list);
|
||||||
static QueryHashEntry *FetchQuery(const char *plan_name);
|
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
|
else
|
||||||
{
|
{
|
||||||
QueryDesc *qdesc;
|
QueryDesc *qdesc;
|
||||||
EState *state;
|
|
||||||
|
|
||||||
if (log_executor_stats)
|
if (log_executor_stats)
|
||||||
ResetUsage();
|
ResetUsage();
|
||||||
|
|
||||||
qdesc = CreateQueryDesc(query, plan, outputDest, NULL);
|
qdesc = CreateQueryDesc(query, plan, outputDest, NULL,
|
||||||
state = CreateExecutorState();
|
paramLI, false);
|
||||||
|
|
||||||
state->es_param_list_info = paramLI;
|
|
||||||
|
|
||||||
if (stmt->into)
|
if (stmt->into)
|
||||||
{
|
{
|
||||||
@@ -170,7 +167,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
|||||||
qdesc->dest = None;
|
qdesc->dest = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
RunQuery(qdesc, state);
|
RunQuery(qdesc);
|
||||||
|
|
||||||
if (log_executor_stats)
|
if (log_executor_stats)
|
||||||
ShowUsage("EXECUTOR STATISTICS");
|
ShowUsage("EXECUTOR STATISTICS");
|
||||||
@@ -334,15 +331,11 @@ FetchQueryParams(const char *plan_name)
|
|||||||
* Actually execute a prepared query.
|
* Actually execute a prepared query.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
RunQuery(QueryDesc *qdesc, EState *state)
|
RunQuery(QueryDesc *qdesc)
|
||||||
{
|
{
|
||||||
TupleDesc tupdesc;
|
ExecutorStart(qdesc);
|
||||||
|
ExecutorRun(qdesc, ForwardScanDirection, 0L);
|
||||||
tupdesc = ExecutorStart(qdesc, state);
|
ExecutorEnd(qdesc);
|
||||||
|
|
||||||
ExecutorRun(qdesc, state, state->es_direction, 0L);
|
|
||||||
|
|
||||||
ExecutorEnd(qdesc, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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
|
The Postgres Executor
|
||||||
---------------------
|
---------------------
|
||||||
@@ -39,6 +39,27 @@ delivered by the plan tree.
|
|||||||
XXX a great deal more documentation needs to be written here...
|
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)
|
EvalPlanQual (READ COMMITTED update checking)
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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/instrument.h"
|
||||||
#include "executor/nodeAgg.h"
|
#include "executor/nodeAgg.h"
|
||||||
#include "executor/nodeAppend.h"
|
#include "executor/nodeAppend.h"
|
||||||
|
#include "executor/nodeFunctionscan.h"
|
||||||
#include "executor/nodeGroup.h"
|
#include "executor/nodeGroup.h"
|
||||||
#include "executor/nodeGroup.h"
|
#include "executor/nodeGroup.h"
|
||||||
#include "executor/nodeHash.h"
|
#include "executor/nodeHash.h"
|
||||||
#include "executor/nodeHashjoin.h"
|
#include "executor/nodeHashjoin.h"
|
||||||
#include "executor/nodeIndexscan.h"
|
#include "executor/nodeIndexscan.h"
|
||||||
#include "executor/nodeTidscan.h"
|
|
||||||
#include "executor/nodeLimit.h"
|
#include "executor/nodeLimit.h"
|
||||||
#include "executor/nodeMaterial.h"
|
#include "executor/nodeMaterial.h"
|
||||||
#include "executor/nodeMergejoin.h"
|
#include "executor/nodeMergejoin.h"
|
||||||
@@ -35,45 +35,45 @@
|
|||||||
#include "executor/nodeSort.h"
|
#include "executor/nodeSort.h"
|
||||||
#include "executor/nodeSubplan.h"
|
#include "executor/nodeSubplan.h"
|
||||||
#include "executor/nodeSubqueryscan.h"
|
#include "executor/nodeSubqueryscan.h"
|
||||||
#include "executor/nodeFunctionscan.h"
|
#include "executor/nodeTidscan.h"
|
||||||
#include "executor/nodeUnique.h"
|
#include "executor/nodeUnique.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecReScan
|
* ExecReScan
|
||||||
*
|
*
|
||||||
* XXX this should be extended to cope with all the node types..
|
|
||||||
*
|
|
||||||
* takes the new expression context as an argument, so that
|
* takes the new expression context as an argument, so that
|
||||||
* index scans needn't have their scan keys updated separately
|
* index scans needn't have their scan keys updated separately
|
||||||
* - marcel 09/20/94
|
* - marcel 09/20/94
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScan(PlanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
|
/* If collecting timing stats, update them */
|
||||||
if (node->instrument)
|
if (node->instrument)
|
||||||
InstrEndLoop(node->instrument);
|
InstrEndLoop(node->instrument);
|
||||||
|
|
||||||
if (node->chgParam != NULL) /* Wow! */
|
/* If we have changed parameters, propagate that info */
|
||||||
|
if (node->chgParam != NIL)
|
||||||
{
|
{
|
||||||
List *lst;
|
List *lst;
|
||||||
|
|
||||||
foreach(lst, node->initPlan)
|
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 */
|
* locParam */
|
||||||
SetChangedParamList(splan, node->chgParam);
|
SetChangedParamList(splan, node->chgParam);
|
||||||
if (splan->chgParam != NULL)
|
if (splan->chgParam != NIL)
|
||||||
ExecReScanSetParamPlan((SubPlan *) lfirst(lst), node);
|
ExecReScanSetParamPlan((SubPlanState *) lfirst(lst), node);
|
||||||
}
|
}
|
||||||
foreach(lst, node->subPlan)
|
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);
|
SetChangedParamList(splan, node->chgParam);
|
||||||
}
|
}
|
||||||
/* Well. Now set chgParam for left/right trees. */
|
/* Well. Now set chgParam for left/right trees. */
|
||||||
@@ -85,76 +85,76 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
case T_SeqScan:
|
case T_ResultState:
|
||||||
ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
|
ExecReScanResult((ResultState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_IndexScan:
|
case T_AppendState:
|
||||||
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
|
ExecReScanAppend((AppendState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TidScan:
|
case T_SeqScanState:
|
||||||
ExecTidReScan((TidScan *) node, exprCtxt, parent);
|
ExecSeqReScan((SeqScanState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SubqueryScan:
|
case T_IndexScanState:
|
||||||
ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
|
ExecIndexReScan((IndexScanState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FunctionScan:
|
case T_TidScanState:
|
||||||
ExecFunctionReScan((FunctionScan *) node, exprCtxt, parent);
|
ExecTidReScan((TidScanState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Material:
|
case T_SubqueryScanState:
|
||||||
ExecMaterialReScan((Material *) node, exprCtxt, parent);
|
ExecSubqueryReScan((SubqueryScanState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_NestLoop:
|
case T_FunctionScanState:
|
||||||
ExecReScanNestLoop((NestLoop *) node, exprCtxt, parent);
|
ExecFunctionReScan((FunctionScanState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_HashJoin:
|
case T_NestLoopState:
|
||||||
ExecReScanHashJoin((HashJoin *) node, exprCtxt, parent);
|
ExecReScanNestLoop((NestLoopState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Hash:
|
case T_MergeJoinState:
|
||||||
ExecReScanHash((Hash *) node, exprCtxt, parent);
|
ExecReScanMergeJoin((MergeJoinState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Agg:
|
case T_HashJoinState:
|
||||||
ExecReScanAgg((Agg *) node, exprCtxt, parent);
|
ExecReScanHashJoin((HashJoinState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_MaterialState:
|
||||||
ExecReScanGroup((Group *) node, exprCtxt, parent);
|
ExecMaterialReScan((MaterialState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Result:
|
case T_SortState:
|
||||||
ExecReScanResult((Result *) node, exprCtxt, parent);
|
ExecReScanSort((SortState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Unique:
|
case T_GroupState:
|
||||||
ExecReScanUnique((Unique *) node, exprCtxt, parent);
|
ExecReScanGroup((GroupState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SetOp:
|
case T_AggState:
|
||||||
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
|
ExecReScanAgg((AggState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Limit:
|
case T_UniqueState:
|
||||||
ExecReScanLimit((Limit *) node, exprCtxt, parent);
|
ExecReScanUnique((UniqueState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_HashState:
|
||||||
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
ExecReScanHash((HashState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_MergeJoin:
|
case T_SetOpState:
|
||||||
ExecReScanMergeJoin((MergeJoin *) node, exprCtxt, parent);
|
ExecReScanSetOp((SetOpState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Append:
|
case T_LimitState:
|
||||||
ExecReScanAppend((Append *) node, exprCtxt, parent);
|
ExecReScanLimit((LimitState *) node, exprCtxt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -163,10 +163,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->chgParam != NULL)
|
if (node->chgParam != NIL)
|
||||||
{
|
{
|
||||||
freeList(node->chgParam);
|
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.
|
* Marks the current scan position.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecMarkPos(Plan *node)
|
ExecMarkPos(PlanState *node)
|
||||||
{
|
{
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
case T_SeqScan:
|
case T_SeqScanState:
|
||||||
ExecSeqMarkPos((SeqScan *) node);
|
ExecSeqMarkPos((SeqScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_IndexScan:
|
case T_IndexScanState:
|
||||||
ExecIndexMarkPos((IndexScan *) node);
|
ExecIndexMarkPos((IndexScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TidScan:
|
case T_TidScanState:
|
||||||
ExecTidMarkPos((TidScan *) node);
|
ExecTidMarkPos((TidScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FunctionScan:
|
case T_FunctionScanState:
|
||||||
ExecFunctionMarkPos((FunctionScan *) node);
|
ExecFunctionMarkPos((FunctionScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Material:
|
case T_MaterialState:
|
||||||
ExecMaterialMarkPos((Material *) node);
|
ExecMaterialMarkPos((MaterialState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_SortState:
|
||||||
ExecSortMarkPos((Sort *) node);
|
ExecSortMarkPos((SortState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* don't make hard error unless caller asks to restore... */
|
/* 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));
|
nodeTag(node));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -218,32 +218,32 @@ ExecMarkPos(Plan *node)
|
|||||||
* restores the scan position previously saved with ExecMarkPos()
|
* restores the scan position previously saved with ExecMarkPos()
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecRestrPos(Plan *node)
|
ExecRestrPos(PlanState *node)
|
||||||
{
|
{
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
case T_SeqScan:
|
case T_SeqScanState:
|
||||||
ExecSeqRestrPos((SeqScan *) node);
|
ExecSeqRestrPos((SeqScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_IndexScan:
|
case T_IndexScanState:
|
||||||
ExecIndexRestrPos((IndexScan *) node);
|
ExecIndexRestrPos((IndexScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TidScan:
|
case T_TidScanState:
|
||||||
ExecTidRestrPos((TidScan *) node);
|
ExecTidRestrPos((TidScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FunctionScan:
|
case T_FunctionScanState:
|
||||||
ExecFunctionRestrPos((FunctionScan *) node);
|
ExecFunctionRestrPos((FunctionScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Material:
|
case T_MaterialState:
|
||||||
ExecMaterialRestrPos((Material *) node);
|
ExecMaterialRestrPos((MaterialState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_SortState:
|
||||||
ExecSortRestrPos((Sort *) node);
|
ExecSortRestrPos((SortState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -258,6 +258,7 @@ ExecRestrPos(Plan *node)
|
|||||||
*
|
*
|
||||||
* XXX Ideally, all plan node types would support mark/restore, and this
|
* 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.
|
* 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
|
bool
|
||||||
ExecSupportsMarkRestore(NodeTag plantype)
|
ExecSupportsMarkRestore(NodeTag plantype)
|
||||||
|
|||||||
@@ -12,10 +12,9 @@
|
|||||||
* ExecutorRun() and ExecutorEnd()
|
* ExecutorRun() and ExecutorEnd()
|
||||||
*
|
*
|
||||||
* These three procedures are the external interfaces to the executor.
|
* These three procedures are the external interfaces to the executor.
|
||||||
* In each case, the query descriptor and the execution state is required
|
* In each case, the query descriptor is required as an argument.
|
||||||
* as arguments
|
|
||||||
*
|
*
|
||||||
* 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
|
* query plan and ExecutorEnd() should always be called at the end of
|
||||||
* execution of a plan.
|
* execution of a plan.
|
||||||
*
|
*
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 */
|
/* decls for local routines only used within this module */
|
||||||
static TupleDesc InitPlan(CmdType operation,
|
static void InitPlan(QueryDesc *queryDesc);
|
||||||
Query *parseTree,
|
|
||||||
Plan *plan,
|
|
||||||
EState *estate);
|
|
||||||
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
|
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||||
Index resultRelationIndex,
|
Index resultRelationIndex,
|
||||||
List *rangeTable,
|
List *rangeTable,
|
||||||
CmdType operation);
|
CmdType operation);
|
||||||
static void EndPlan(Plan *plan, EState *estate);
|
static void EndPlan(PlanState *planstate, EState *estate);
|
||||||
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
|
static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
long numberTuples,
|
long numberTuples,
|
||||||
ScanDirection direction,
|
ScanDirection direction,
|
||||||
@@ -73,11 +69,6 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
|
|||||||
EState *estate);
|
EState *estate);
|
||||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||||
static void EndEvalPlanQual(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);
|
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
||||||
|
|
||||||
/* end of local decls */
|
/* 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
|
* This routine must be called at the beginning of any execution of any
|
||||||
* query plan
|
* query plan
|
||||||
*
|
*
|
||||||
* returns a TupleDesc which describes the attributes of the tuples to
|
* Takes a QueryDesc previously created by CreateQueryDesc (it's not real
|
||||||
* be returned by the query. (Same value is saved in queryDesc)
|
* 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
|
* NB: the CurrentMemoryContext when this is called must be the context
|
||||||
* to be used as the per-query context for the query plan. ExecutorRun()
|
* to be used as the per-query context for the query plan. ExecutorRun()
|
||||||
* and ExecutorEnd() must be called in this same memory context.
|
* and ExecutorEnd() must be called in this same memory context.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleDesc
|
void
|
||||||
ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
ExecutorStart(QueryDesc *queryDesc)
|
||||||
{
|
{
|
||||||
TupleDesc result;
|
EState *estate;
|
||||||
|
|
||||||
/* sanity checks */
|
/* sanity checks: queryDesc must not be started already */
|
||||||
Assert(queryDesc != NULL);
|
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)
|
if (queryDesc->plantree->nParamExec > 0)
|
||||||
estate->es_param_exec_vals = (ParamExecData *)
|
estate->es_param_exec_vals = (ParamExecData *)
|
||||||
palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
|
palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
|
||||||
|
|
||||||
|
estate->es_instrument = queryDesc->doInstrument;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make our own private copy of the current query snapshot data.
|
* Make our own private copy of the current query snapshot data.
|
||||||
*
|
*
|
||||||
@@ -119,16 +124,9 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||||||
estate->es_snapshot = CopyQuerySnapshot();
|
estate->es_snapshot = CopyQuerySnapshot();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the plan
|
* Initialize the plan state tree
|
||||||
*/
|
*/
|
||||||
result = InitPlan(queryDesc->operation,
|
InitPlan(queryDesc);
|
||||||
queryDesc->parsetree,
|
|
||||||
queryDesc->plantree,
|
|
||||||
estate);
|
|
||||||
|
|
||||||
queryDesc->tupDesc = result;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -150,11 +148,11 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
ExecutorRun(QueryDesc *queryDesc,
|
||||||
ScanDirection direction, long count)
|
ScanDirection direction, long count)
|
||||||
{
|
{
|
||||||
CmdType operation;
|
CmdType operation;
|
||||||
Plan *plan;
|
EState *estate;
|
||||||
CommandDest dest;
|
CommandDest dest;
|
||||||
DestReceiver *destfunc;
|
DestReceiver *destfunc;
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
@@ -169,7 +167,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
|||||||
* feature.
|
* feature.
|
||||||
*/
|
*/
|
||||||
operation = queryDesc->operation;
|
operation = queryDesc->operation;
|
||||||
plan = queryDesc->plantree;
|
estate = queryDesc->estate;
|
||||||
dest = queryDesc->dest;
|
dest = queryDesc->dest;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -189,7 +187,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
|||||||
result = NULL;
|
result = NULL;
|
||||||
else
|
else
|
||||||
result = ExecutePlan(estate,
|
result = ExecutePlan(estate,
|
||||||
plan,
|
queryDesc->planstate,
|
||||||
operation,
|
operation,
|
||||||
count,
|
count,
|
||||||
direction,
|
direction,
|
||||||
@@ -211,12 +209,16 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecutorEnd(QueryDesc *queryDesc, EState *estate)
|
ExecutorEnd(QueryDesc *queryDesc)
|
||||||
{
|
{
|
||||||
|
EState *estate;
|
||||||
|
|
||||||
/* sanity checks */
|
/* sanity checks */
|
||||||
Assert(queryDesc != NULL);
|
Assert(queryDesc != NULL);
|
||||||
|
|
||||||
EndPlan(queryDesc->plantree, estate);
|
estate = queryDesc->estate;
|
||||||
|
|
||||||
|
EndPlan(queryDesc->planstate, estate);
|
||||||
|
|
||||||
if (estate->es_snapshot != NULL)
|
if (estate->es_snapshot != NULL)
|
||||||
{
|
{
|
||||||
@@ -235,97 +237,55 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecCheckQueryPerms
|
* CreateExecutorState
|
||||||
* Check access permissions for all relations referenced in a query.
|
|
||||||
*/
|
*/
|
||||||
static void
|
EState *
|
||||||
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
|
CreateExecutorState(void)
|
||||||
{
|
{
|
||||||
/*
|
EState *state;
|
||||||
* Check RTEs in the query's primary rangetable.
|
|
||||||
*/
|
|
||||||
ExecCheckRTPerms(parseTree->rtable, operation);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* ExecCheckRTPerms
|
||||||
* Check access permissions for all relations listed in a range table.
|
* Check access permissions for all relations listed in a range table.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
ExecCheckRTPerms(List *rangeTable, CmdType operation)
|
ExecCheckRTPerms(List *rangeTable, CmdType operation)
|
||||||
{
|
{
|
||||||
List *lp;
|
List *lp;
|
||||||
@@ -350,11 +310,18 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
|||||||
AclResult aclcheck_result;
|
AclResult aclcheck_result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only plain-relation RTEs need to be checked here. Subquery RTEs
|
* If it's a subquery, recursively examine its rangetable.
|
||||||
* will be checked when ExecCheckPlanPerms finds the SubqueryScan
|
*/
|
||||||
* node, and function RTEs are checked by init_fcache when the
|
if (rte->rtekind == RTE_SUBQUERY)
|
||||||
* function is prepared for execution. Join and special RTEs need no
|
{
|
||||||
* checks.
|
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)
|
if (rte->rtekind != RTE_RELATION)
|
||||||
return;
|
return;
|
||||||
@@ -367,7 +334,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
|||||||
*
|
*
|
||||||
* Note: GetUserId() is presently fast enough that there's no harm in
|
* Note: GetUserId() is presently fast enough that there's no harm in
|
||||||
* calling it separately for each RTE. If that stops being true, we
|
* 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.
|
* from there. But for now, no need for the extra clutter.
|
||||||
*/
|
*/
|
||||||
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
|
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
|
||||||
@@ -428,7 +395,8 @@ typedef struct execRowMark
|
|||||||
|
|
||||||
typedef struct evalPlanQual
|
typedef struct evalPlanQual
|
||||||
{
|
{
|
||||||
Plan *plan;
|
Plan *plan; /* XXX temporary */
|
||||||
|
PlanState *planstate;
|
||||||
Index rti;
|
Index rti;
|
||||||
EState estate;
|
EState estate;
|
||||||
struct evalPlanQual *free;
|
struct evalPlanQual *free;
|
||||||
@@ -441,17 +409,24 @@ typedef struct evalPlanQual
|
|||||||
* and start up the rule manager
|
* and start up the rule manager
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static TupleDesc
|
static void
|
||||||
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
InitPlan(QueryDesc *queryDesc)
|
||||||
{
|
{
|
||||||
|
CmdType operation = queryDesc->operation;
|
||||||
|
Query *parseTree = queryDesc->parsetree;
|
||||||
|
Plan *plan = queryDesc->plantree;
|
||||||
|
EState *estate = queryDesc->estate;
|
||||||
|
PlanState *planstate;
|
||||||
List *rangeTable;
|
List *rangeTable;
|
||||||
Relation intoRelationDesc;
|
Relation intoRelationDesc;
|
||||||
TupleDesc tupType;
|
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
|
* 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
|
* query tree. This opens files, allocates storage and leaves us
|
||||||
* ready to start processing tuples.
|
* ready to start processing tuples.
|
||||||
*/
|
*/
|
||||||
ExecInitNode(plan, estate, NULL);
|
planstate = ExecInitNode(plan, estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the tuple descriptor describing the type of tuples to return.
|
* Get the tuple descriptor describing the type of tuples to return.
|
||||||
* (this is especially important if we are creating a relation with
|
* (this is especially important if we are creating a relation with
|
||||||
* "SELECT INTO")
|
* "SELECT INTO")
|
||||||
*/
|
*/
|
||||||
tupType = ExecGetTupType(plan); /* tuple descriptor */
|
tupType = ExecGetTupType(planstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the junk filter if needed. SELECT and INSERT queries
|
* 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)
|
if (parseTree->resultRelations != NIL)
|
||||||
{
|
{
|
||||||
List *subplans;
|
PlanState **appendplans;
|
||||||
|
int as_nplans;
|
||||||
ResultRelInfo *resultRelInfo;
|
ResultRelInfo *resultRelInfo;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Top plan had better be an Append here. */
|
/* Top plan had better be an Append here. */
|
||||||
Assert(IsA(plan, Append));
|
Assert(IsA(plan, Append));
|
||||||
Assert(((Append *) plan)->isTarget);
|
Assert(((Append *) plan)->isTarget);
|
||||||
subplans = ((Append *) plan)->appendplans;
|
Assert(IsA(planstate, AppendState));
|
||||||
Assert(length(subplans) == estate->es_num_result_relations);
|
appendplans = ((AppendState *) planstate)->appendplans;
|
||||||
|
as_nplans = ((AppendState *) planstate)->as_nplans;
|
||||||
|
Assert(as_nplans == estate->es_num_result_relations);
|
||||||
resultRelInfo = estate->es_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;
|
JunkFilter *j;
|
||||||
|
|
||||||
j = ExecInitJunkFilter(subplan->targetlist,
|
j = ExecInitJunkFilter(subplan->plan->targetlist,
|
||||||
ExecGetTupType(subplan),
|
ExecGetTupType(subplan),
|
||||||
ExecAllocTableSlot(estate->es_tupleTable));
|
ExecAllocTableSlot(estate->es_tupleTable));
|
||||||
resultRelInfo->ri_junkFilter = j;
|
resultRelInfo->ri_junkFilter = j;
|
||||||
resultRelInfo++;
|
resultRelInfo++;
|
||||||
subplans = lnext(subplans);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -661,7 +639,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||||||
/* Normal case with just one JunkFilter */
|
/* Normal case with just one JunkFilter */
|
||||||
JunkFilter *j;
|
JunkFilter *j;
|
||||||
|
|
||||||
j = ExecInitJunkFilter(plan->targetlist,
|
j = ExecInitJunkFilter(planstate->plan->targetlist,
|
||||||
tupType,
|
tupType,
|
||||||
ExecAllocTableSlot(estate->es_tupleTable));
|
ExecAllocTableSlot(estate->es_tupleTable));
|
||||||
estate->es_junkFilter = j;
|
estate->es_junkFilter = j;
|
||||||
@@ -755,7 +733,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
|||||||
|
|
||||||
estate->es_into_relation_descriptor = intoRelationDesc;
|
estate->es_into_relation_descriptor = intoRelationDesc;
|
||||||
|
|
||||||
return tupType;
|
queryDesc->tupDesc = tupType;
|
||||||
|
queryDesc->planstate = planstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -816,11 +795,11 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
|
|||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* EndPlan
|
* 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
|
static void
|
||||||
EndPlan(Plan *plan, EState *estate)
|
EndPlan(PlanState *planstate, EState *estate)
|
||||||
{
|
{
|
||||||
ResultRelInfo *resultRelInfo;
|
ResultRelInfo *resultRelInfo;
|
||||||
int i;
|
int i;
|
||||||
@@ -835,7 +814,7 @@ EndPlan(Plan *plan, EState *estate)
|
|||||||
/*
|
/*
|
||||||
* shut down the node-type-specific query processing
|
* shut down the node-type-specific query processing
|
||||||
*/
|
*/
|
||||||
ExecEndNode(plan, NULL);
|
ExecEndNode(planstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* destroy the executor "tuple" table.
|
* destroy the executor "tuple" table.
|
||||||
@@ -902,7 +881,7 @@ EndPlan(Plan *plan, EState *estate)
|
|||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
ExecutePlan(EState *estate,
|
ExecutePlan(EState *estate,
|
||||||
Plan *plan,
|
PlanState *planstate,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
long numberTuples,
|
long numberTuples,
|
||||||
ScanDirection direction,
|
ScanDirection direction,
|
||||||
@@ -964,10 +943,10 @@ lnext: ;
|
|||||||
{
|
{
|
||||||
slot = EvalPlanQualNext(estate);
|
slot = EvalPlanQualNext(estate);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
slot = ExecProcNode(plan, NULL);
|
slot = ExecProcNode(planstate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
slot = ExecProcNode(plan, NULL);
|
slot = ExecProcNode(planstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the tuple is null, then we assume there is nothing more to
|
* 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;
|
oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
|
||||||
Assert(oldepq->rti != 0);
|
Assert(oldepq->rti != 0);
|
||||||
/* stop execution */
|
/* stop execution */
|
||||||
ExecEndNode(epq->plan, NULL);
|
ExecEndNode(epq->planstate);
|
||||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||||
epqstate->es_tupleTable = NULL;
|
epqstate->es_tupleTable = NULL;
|
||||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
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
|
* Each stack level has its own copy of the plan tree. This
|
||||||
* is wasteful, but necessary as long as plan nodes point to
|
* is wasteful, but necessary until plan trees are fully
|
||||||
* exec state nodes rather than vice versa. Note that
|
* read-only.
|
||||||
* copyfuncs.c doesn't attempt to copy the exec state nodes,
|
|
||||||
* which is a good thing in this situation.
|
|
||||||
*/
|
*/
|
||||||
newepq->plan = copyObject(estate->es_origPlan);
|
newepq->plan = copyObject(estate->es_origPlan);
|
||||||
|
|
||||||
@@ -1858,7 +1835,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
|||||||
if (endNode)
|
if (endNode)
|
||||||
{
|
{
|
||||||
/* stop execution */
|
/* stop execution */
|
||||||
ExecEndNode(epq->plan, NULL);
|
ExecEndNode(epq->planstate);
|
||||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||||
epqstate->es_tupleTable = NULL;
|
epqstate->es_tupleTable = NULL;
|
||||||
}
|
}
|
||||||
@@ -1886,7 +1863,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
|||||||
epqstate->es_tupleTable =
|
epqstate->es_tupleTable =
|
||||||
ExecCreateTupleTable(estate->es_tupleTable->size);
|
ExecCreateTupleTable(estate->es_tupleTable->size);
|
||||||
|
|
||||||
ExecInitNode(epq->plan, epqstate, NULL);
|
epq->planstate = ExecInitNode(epq->plan, epqstate);
|
||||||
|
|
||||||
return EvalPlanQualNext(estate);
|
return EvalPlanQualNext(estate);
|
||||||
}
|
}
|
||||||
@@ -1902,7 +1879,7 @@ EvalPlanQualNext(EState *estate)
|
|||||||
Assert(epq->rti != 0);
|
Assert(epq->rti != 0);
|
||||||
|
|
||||||
lpqnext:;
|
lpqnext:;
|
||||||
slot = ExecProcNode(epq->plan, NULL);
|
slot = ExecProcNode(epq->planstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No more tuples for this PQ. Continue previous one.
|
* No more tuples for this PQ. Continue previous one.
|
||||||
@@ -1910,7 +1887,7 @@ lpqnext:;
|
|||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
{
|
{
|
||||||
/* stop execution */
|
/* stop execution */
|
||||||
ExecEndNode(epq->plan, NULL);
|
ExecEndNode(epq->planstate);
|
||||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||||
epqstate->es_tupleTable = NULL;
|
epqstate->es_tupleTable = NULL;
|
||||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
||||||
@@ -1951,7 +1928,7 @@ EndEvalPlanQual(EState *estate)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* stop execution */
|
/* stop execution */
|
||||||
ExecEndNode(epq->plan, NULL);
|
ExecEndNode(epq->planstate);
|
||||||
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
ExecDropTupleTable(epqstate->es_tupleTable, true);
|
||||||
epqstate->es_tupleTable = NULL;
|
epqstate->es_tupleTable = NULL;
|
||||||
if (epqstate->es_evTuple[epq->rti - 1] != NULL)
|
if (epqstate->es_evTuple[epq->rti - 1] != NULL)
|
||||||
|
|||||||
@@ -5,23 +5,23 @@
|
|||||||
* "get a tuple", and "cleanup" routines for the given node type.
|
* "get a tuple", and "cleanup" routines for the given node type.
|
||||||
* If the node has children, then it will presumably call ExecInitNode,
|
* If the node has children, then it will presumably call ExecInitNode,
|
||||||
* ExecProcNode, or ExecEndNode on its subnodes and do the appropriate
|
* ExecProcNode, or ExecEndNode on its subnodes and do the appropriate
|
||||||
* processing..
|
* processing.
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* INTERFACE ROUTINES
|
||||||
|
* ExecCountSlotsNode - count tuple slots needed by plan tree
|
||||||
* ExecInitNode - initialize a plan node and its subplans
|
* ExecInitNode - initialize a plan node and its subplans
|
||||||
* ExecProcNode - get a tuple by executing the plan node
|
* ExecProcNode - get a tuple by executing the plan node
|
||||||
* ExecEndNode - shut down a plan node and its subplans
|
* 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
|
* ExecGetTupType - get result tuple type of a plan node
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
@@ -53,10 +53,12 @@
|
|||||||
* * ExecInitNode() notices that it is looking at a nest loop and
|
* * ExecInitNode() notices that it is looking at a nest loop and
|
||||||
* as the code below demonstrates, it calls ExecInitNestLoop().
|
* as the code below demonstrates, it calls ExecInitNestLoop().
|
||||||
* Eventually this calls ExecInitNode() on the right and left subplans
|
* 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
|
* * Then when ExecRun() is called, it calls ExecutePlan() which calls
|
||||||
* calls ExecProcNode() repeatedly on the top node of the plan.
|
* ExecProcNode() repeatedly on the top node of the plan state tree.
|
||||||
* Each time this happens, ExecProcNode() will end up calling
|
* Each time this happens, ExecProcNode() will end up calling
|
||||||
* ExecNestLoop(), which calls ExecProcNode() on its subplans.
|
* ExecNestLoop(), which calls ExecProcNode() on its subplans.
|
||||||
* Each of these subplans is a sequential scan so ExecSeqScan() is
|
* Each of these subplans is a sequential scan so ExecSeqScan() is
|
||||||
@@ -73,7 +75,6 @@
|
|||||||
* ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
|
* ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
|
||||||
* their work to the appopriate node support routines which may
|
* their work to the appopriate node support routines which may
|
||||||
* in turn call these routines themselves on their subplans.
|
* in turn call these routines themselves on their subplans.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@@ -81,11 +82,11 @@
|
|||||||
#include "executor/instrument.h"
|
#include "executor/instrument.h"
|
||||||
#include "executor/nodeAgg.h"
|
#include "executor/nodeAgg.h"
|
||||||
#include "executor/nodeAppend.h"
|
#include "executor/nodeAppend.h"
|
||||||
|
#include "executor/nodeFunctionscan.h"
|
||||||
#include "executor/nodeGroup.h"
|
#include "executor/nodeGroup.h"
|
||||||
#include "executor/nodeHash.h"
|
#include "executor/nodeHash.h"
|
||||||
#include "executor/nodeHashjoin.h"
|
#include "executor/nodeHashjoin.h"
|
||||||
#include "executor/nodeIndexscan.h"
|
#include "executor/nodeIndexscan.h"
|
||||||
#include "executor/nodeTidscan.h"
|
|
||||||
#include "executor/nodeLimit.h"
|
#include "executor/nodeLimit.h"
|
||||||
#include "executor/nodeMaterial.h"
|
#include "executor/nodeMaterial.h"
|
||||||
#include "executor/nodeMergejoin.h"
|
#include "executor/nodeMergejoin.h"
|
||||||
@@ -96,7 +97,7 @@
|
|||||||
#include "executor/nodeSort.h"
|
#include "executor/nodeSort.h"
|
||||||
#include "executor/nodeSubplan.h"
|
#include "executor/nodeSubplan.h"
|
||||||
#include "executor/nodeSubqueryscan.h"
|
#include "executor/nodeSubqueryscan.h"
|
||||||
#include "executor/nodeFunctionscan.h"
|
#include "executor/nodeTidscan.h"
|
||||||
#include "executor/nodeUnique.h"
|
#include "executor/nodeUnique.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
@@ -109,32 +110,23 @@
|
|||||||
*
|
*
|
||||||
* Initial States:
|
* Initial States:
|
||||||
* 'node' is the plan produced by the query planner
|
* '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
|
PlanState *
|
||||||
ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
ExecInitNode(Plan *node, EState *estate)
|
||||||
{
|
{
|
||||||
bool result;
|
PlanState *result;
|
||||||
|
List *subps;
|
||||||
List *subp;
|
List *subp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do nothing when we get to the end of a leaf on tree.
|
* do nothing when we get to the end of a leaf on tree.
|
||||||
*/
|
*/
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return FALSE;
|
return NULL;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
@@ -142,104 +134,124 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
* control nodes
|
* control nodes
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_Result:
|
||||||
result = ExecInitResult((Result *) node, estate, parent);
|
result = (PlanState *) ExecInitResult((Result *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Append:
|
case T_Append:
|
||||||
result = ExecInitAppend((Append *) node, estate, parent);
|
result = (PlanState *) ExecInitAppend((Append *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
result = ExecInitSeqScan((SeqScan *) node, estate, parent);
|
result = (PlanState *) ExecInitSeqScan((SeqScan *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_IndexScan:
|
case T_IndexScan:
|
||||||
result = ExecInitIndexScan((IndexScan *) node, estate, parent);
|
result = (PlanState *) ExecInitIndexScan((IndexScan *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TidScan:
|
case T_TidScan:
|
||||||
result = ExecInitTidScan((TidScan *) node, estate, parent);
|
result = (PlanState *) ExecInitTidScan((TidScan *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SubqueryScan:
|
case T_SubqueryScan:
|
||||||
result = ExecInitSubqueryScan((SubqueryScan *) node, estate,
|
result = (PlanState *) ExecInitSubqueryScan((SubqueryScan *) node, estate);
|
||||||
parent);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FunctionScan:
|
case T_FunctionScan:
|
||||||
result = ExecInitFunctionScan((FunctionScan *) node, estate,
|
result = (PlanState *) ExecInitFunctionScan((FunctionScan *) node, estate);
|
||||||
parent);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoop:
|
||||||
result = ExecInitNestLoop((NestLoop *) node, estate, parent);
|
result = (PlanState *) ExecInitNestLoop((NestLoop *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_MergeJoin:
|
case T_MergeJoin:
|
||||||
result = ExecInitMergeJoin((MergeJoin *) node, estate, parent);
|
result = (PlanState *) ExecInitMergeJoin((MergeJoin *) node, estate);
|
||||||
break;
|
|
||||||
|
|
||||||
case T_Hash:
|
|
||||||
result = ExecInitHash((Hash *) node, estate, parent);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_HashJoin:
|
case T_HashJoin:
|
||||||
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
|
result = (PlanState *) ExecInitHashJoin((HashJoin *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_Material:
|
||||||
result = ExecInitMaterial((Material *) node, estate, parent);
|
result = (PlanState *) ExecInitMaterial((Material *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_Sort:
|
||||||
result = ExecInitSort((Sort *) node, estate, parent);
|
result = (PlanState *) ExecInitSort((Sort *) node, estate);
|
||||||
break;
|
|
||||||
|
|
||||||
case T_Unique:
|
|
||||||
result = ExecInitUnique((Unique *) node, estate, parent);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_SetOp:
|
|
||||||
result = ExecInitSetOp((SetOp *) node, estate, parent);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_Limit:
|
|
||||||
result = ExecInitLimit((Limit *) node, estate, parent);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_Group:
|
||||||
result = ExecInitGroup((Group *) node, estate, parent);
|
result = (PlanState *) ExecInitGroup((Group *) node, estate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Agg:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecInitNode: node type %d unsupported",
|
elog(ERROR, "ExecInitNode: node type %d unsupported",
|
||||||
(int) nodeTag(node));
|
(int) nodeTag(node));
|
||||||
result = FALSE;
|
result = NULL; /* keep compiler quiet */
|
||||||
break;
|
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)
|
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||||
{
|
|
||||||
result = ExecInitSubPlan((SubPlan *) lfirst(subp), estate, node);
|
Assert(IsA(subplan, SubPlan));
|
||||||
if (result == FALSE)
|
subps = lappend(subps, ExecInitSubPlan(subplan, estate));
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -248,12 +260,11 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecProcNode
|
* ExecProcNode
|
||||||
*
|
*
|
||||||
* Initial States:
|
* Execute the given node to return a(nother) tuple.
|
||||||
* the query tree must be initialized once by calling ExecInit.
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecProcNode(Plan *node, Plan *parent)
|
ExecProcNode(PlanState *node)
|
||||||
{
|
{
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
|
||||||
@@ -265,8 +276,8 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (node->chgParam != NULL) /* something changed */
|
if (node->chgParam != NIL) /* something changed */
|
||||||
ExecReScan(node, NULL, parent); /* let ReScan handle this */
|
ExecReScan(node, NULL); /* let ReScan handle this */
|
||||||
|
|
||||||
if (node->instrument)
|
if (node->instrument)
|
||||||
InstrStartNode(node->instrument);
|
InstrStartNode(node->instrument);
|
||||||
@@ -276,85 +287,85 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* control nodes
|
* control nodes
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_ResultState:
|
||||||
result = ExecResult((Result *) node);
|
result = ExecResult((ResultState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Append:
|
case T_AppendState:
|
||||||
result = ExecProcAppend((Append *) node);
|
result = ExecProcAppend((AppendState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScanState:
|
||||||
result = ExecSeqScan((SeqScan *) node);
|
result = ExecSeqScan((SeqScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_IndexScan:
|
case T_IndexScanState:
|
||||||
result = ExecIndexScan((IndexScan *) node);
|
result = ExecIndexScan((IndexScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TidScan:
|
case T_TidScanState:
|
||||||
result = ExecTidScan((TidScan *) node);
|
result = ExecTidScan((TidScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SubqueryScan:
|
case T_SubqueryScanState:
|
||||||
result = ExecSubqueryScan((SubqueryScan *) node);
|
result = ExecSubqueryScan((SubqueryScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FunctionScan:
|
case T_FunctionScanState:
|
||||||
result = ExecFunctionScan((FunctionScan *) node);
|
result = ExecFunctionScan((FunctionScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoopState:
|
||||||
result = ExecNestLoop((NestLoop *) node);
|
result = ExecNestLoop((NestLoopState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_MergeJoin:
|
case T_MergeJoinState:
|
||||||
result = ExecMergeJoin((MergeJoin *) node);
|
result = ExecMergeJoin((MergeJoinState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Hash:
|
case T_HashJoinState:
|
||||||
result = ExecHash((Hash *) node);
|
result = ExecHashJoin((HashJoinState *) node);
|
||||||
break;
|
|
||||||
|
|
||||||
case T_HashJoin:
|
|
||||||
result = ExecHashJoin((HashJoin *) node);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_MaterialState:
|
||||||
result = ExecMaterial((Material *) node);
|
result = ExecMaterial((MaterialState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_SortState:
|
||||||
result = ExecSort((Sort *) node);
|
result = ExecSort((SortState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Unique:
|
case T_GroupState:
|
||||||
result = ExecUnique((Unique *) node);
|
result = ExecGroup((GroupState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SetOp:
|
case T_AggState:
|
||||||
result = ExecSetOp((SetOp *) node);
|
result = ExecAgg((AggState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Limit:
|
case T_UniqueState:
|
||||||
result = ExecLimit((Limit *) node);
|
result = ExecUnique((UniqueState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_HashState:
|
||||||
result = ExecGroup((Group *) node);
|
result = ExecHash((HashState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Agg:
|
case T_SetOpState:
|
||||||
result = ExecAgg((Agg *) node);
|
result = ExecSetOp((SetOpState *) node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_LimitState:
|
||||||
|
result = ExecLimit((LimitState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -370,10 +381,16 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
return result;
|
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
|
int
|
||||||
ExecCountSlotsNode(Plan *node)
|
ExecCountSlotsNode(Plan *node)
|
||||||
{
|
{
|
||||||
if (node == (Plan *) NULL)
|
if (node == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
@@ -414,9 +431,6 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
case T_MergeJoin:
|
case T_MergeJoin:
|
||||||
return ExecCountSlotsMergeJoin((MergeJoin *) node);
|
return ExecCountSlotsMergeJoin((MergeJoin *) node);
|
||||||
|
|
||||||
case T_Hash:
|
|
||||||
return ExecCountSlotsHash((Hash *) node);
|
|
||||||
|
|
||||||
case T_HashJoin:
|
case T_HashJoin:
|
||||||
return ExecCountSlotsHashJoin((HashJoin *) node);
|
return ExecCountSlotsHashJoin((HashJoin *) node);
|
||||||
|
|
||||||
@@ -429,26 +443,30 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
case T_Sort:
|
case T_Sort:
|
||||||
return ExecCountSlotsSort((Sort *) node);
|
return ExecCountSlotsSort((Sort *) node);
|
||||||
|
|
||||||
|
case T_Group:
|
||||||
|
return ExecCountSlotsGroup((Group *) node);
|
||||||
|
|
||||||
|
case T_Agg:
|
||||||
|
return ExecCountSlotsAgg((Agg *) node);
|
||||||
|
|
||||||
case T_Unique:
|
case T_Unique:
|
||||||
return ExecCountSlotsUnique((Unique *) node);
|
return ExecCountSlotsUnique((Unique *) node);
|
||||||
|
|
||||||
|
case T_Hash:
|
||||||
|
return ExecCountSlotsHash((Hash *) node);
|
||||||
|
|
||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
return ExecCountSlotsSetOp((SetOp *) node);
|
return ExecCountSlotsSetOp((SetOp *) node);
|
||||||
|
|
||||||
case T_Limit:
|
case T_Limit:
|
||||||
return ExecCountSlotsLimit((Limit *) node);
|
return ExecCountSlotsLimit((Limit *) node);
|
||||||
|
|
||||||
case T_Group:
|
|
||||||
return ExecCountSlotsGroup((Group *) node);
|
|
||||||
|
|
||||||
case T_Agg:
|
|
||||||
return ExecCountSlotsAgg((Agg *) node);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecCountSlotsNode: node type %d unsupported",
|
elog(ERROR, "ExecCountSlotsNode: node type %d unsupported",
|
||||||
(int) nodeTag(node));
|
(int) nodeTag(node));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +482,7 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndNode(Plan *node, Plan *parent)
|
ExecEndNode(PlanState *node)
|
||||||
{
|
{
|
||||||
List *subp;
|
List *subp;
|
||||||
|
|
||||||
@@ -474,14 +492,19 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (node->instrument)
|
||||||
|
InstrEndLoop(node->instrument);
|
||||||
|
|
||||||
|
/* Clean up initPlans and subPlans */
|
||||||
foreach(subp, node->initPlan)
|
foreach(subp, node->initPlan)
|
||||||
ExecEndSubPlan((SubPlan *) lfirst(subp));
|
ExecEndSubPlan((SubPlanState *) lfirst(subp));
|
||||||
foreach(subp, node->subPlan)
|
foreach(subp, node->subPlan)
|
||||||
ExecEndSubPlan((SubPlan *) lfirst(subp));
|
ExecEndSubPlan((SubPlanState *) lfirst(subp));
|
||||||
if (node->chgParam != NULL)
|
|
||||||
|
if (node->chgParam != NIL)
|
||||||
{
|
{
|
||||||
freeList(node->chgParam);
|
freeList(node->chgParam);
|
||||||
node->chgParam = NULL;
|
node->chgParam = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
@@ -489,85 +512,85 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* control nodes
|
* control nodes
|
||||||
*/
|
*/
|
||||||
case T_Result:
|
case T_ResultState:
|
||||||
ExecEndResult((Result *) node);
|
ExecEndResult((ResultState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Append:
|
case T_AppendState:
|
||||||
ExecEndAppend((Append *) node);
|
ExecEndAppend((AppendState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scan nodes
|
* scan nodes
|
||||||
*/
|
*/
|
||||||
case T_SeqScan:
|
case T_SeqScanState:
|
||||||
ExecEndSeqScan((SeqScan *) node);
|
ExecEndSeqScan((SeqScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_IndexScan:
|
case T_IndexScanState:
|
||||||
ExecEndIndexScan((IndexScan *) node);
|
ExecEndIndexScan((IndexScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_TidScan:
|
case T_TidScanState:
|
||||||
ExecEndTidScan((TidScan *) node);
|
ExecEndTidScan((TidScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SubqueryScan:
|
case T_SubqueryScanState:
|
||||||
ExecEndSubqueryScan((SubqueryScan *) node);
|
ExecEndSubqueryScan((SubqueryScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_FunctionScan:
|
case T_FunctionScanState:
|
||||||
ExecEndFunctionScan((FunctionScan *) node);
|
ExecEndFunctionScan((FunctionScanState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* join nodes
|
* join nodes
|
||||||
*/
|
*/
|
||||||
case T_NestLoop:
|
case T_NestLoopState:
|
||||||
ExecEndNestLoop((NestLoop *) node);
|
ExecEndNestLoop((NestLoopState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_MergeJoin:
|
case T_MergeJoinState:
|
||||||
ExecEndMergeJoin((MergeJoin *) node);
|
ExecEndMergeJoin((MergeJoinState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Hash:
|
case T_HashJoinState:
|
||||||
ExecEndHash((Hash *) node);
|
ExecEndHashJoin((HashJoinState *) node);
|
||||||
break;
|
|
||||||
|
|
||||||
case T_HashJoin:
|
|
||||||
ExecEndHashJoin((HashJoin *) node);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* materialization nodes
|
* materialization nodes
|
||||||
*/
|
*/
|
||||||
case T_Material:
|
case T_MaterialState:
|
||||||
ExecEndMaterial((Material *) node);
|
ExecEndMaterial((MaterialState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_SortState:
|
||||||
ExecEndSort((Sort *) node);
|
ExecEndSort((SortState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Unique:
|
case T_GroupState:
|
||||||
ExecEndUnique((Unique *) node);
|
ExecEndGroup((GroupState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_SetOp:
|
case T_AggState:
|
||||||
ExecEndSetOp((SetOp *) node);
|
ExecEndAgg((AggState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Limit:
|
case T_UniqueState:
|
||||||
ExecEndLimit((Limit *) node);
|
ExecEndUnique((UniqueState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_HashState:
|
||||||
ExecEndGroup((Group *) node);
|
ExecEndHash((HashState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_Agg:
|
case T_SetOpState:
|
||||||
ExecEndAgg((Agg *) node);
|
ExecEndSetOp((SetOpState *) node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_LimitState:
|
||||||
|
ExecEndLimit((LimitState *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -575,9 +598,6 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
(int) nodeTag(node));
|
(int) nodeTag(node));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->instrument)
|
|
||||||
InstrEndLoop(node->instrument);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -592,7 +612,7 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleDesc
|
TupleDesc
|
||||||
ExecGetTupType(Plan *node)
|
ExecGetTupType(PlanState *node)
|
||||||
{
|
{
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
@@ -601,147 +621,147 @@ ExecGetTupType(Plan *node)
|
|||||||
|
|
||||||
switch (nodeTag(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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
isNull, isDone);
|
||||||
break;
|
break;
|
||||||
case SUBPLAN_EXPR:
|
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,
|
expr->args, econtext,
|
||||||
isNull);
|
isNull);
|
||||||
break;
|
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
|
* ExecQual / ExecTargetList / ExecProject
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *
|
TupleTableSlot *
|
||||||
ExecScan(Scan *node,
|
ExecScan(ScanState *node,
|
||||||
ExecScanAccessMtd accessMtd) /* function returning a tuple */
|
ExecScanAccessMtd accessMtd) /* function returning a tuple */
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
List *qual;
|
List *qual;
|
||||||
@@ -57,23 +56,22 @@ ExecScan(Scan *node,
|
|||||||
/*
|
/*
|
||||||
* Fetch data from node
|
* Fetch data from node
|
||||||
*/
|
*/
|
||||||
estate = node->plan.state;
|
estate = node->ps.state;
|
||||||
scanstate = node->scanstate;
|
econtext = node->ps.ps_ExprContext;
|
||||||
econtext = scanstate->cstate.cs_ExprContext;
|
qual = node->ps.qual;
|
||||||
qual = node->plan.qual;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* scan tuple (because there is a function-returning-set in the
|
* scan tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* 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)
|
if (isDone == ExprMultipleResult)
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
/* Done with that source tuple... */
|
/* 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))
|
if (TupIsNull(slot))
|
||||||
{
|
{
|
||||||
return ExecStoreTuple(NULL,
|
return ExecStoreTuple(NULL,
|
||||||
scanstate->cstate.cs_ProjInfo->pi_slot,
|
node->ps.ps_ProjInfo->pi_slot,
|
||||||
InvalidBuffer,
|
InvalidBuffer,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@@ -130,10 +128,10 @@ ExecScan(Scan *node,
|
|||||||
* return it --- unless we find we can project no tuples from
|
* return it --- unless we find we can project no tuples from
|
||||||
* this scan tuple, in which case continue scan.
|
* 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)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
scanstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
|
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
void
|
||||||
ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
|
ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
|
||||||
{
|
{
|
||||||
INIT_SLOT_DEFS;
|
INIT_SLOT_DEFS;
|
||||||
INIT_SLOT_ALLOC;
|
INIT_SLOT_ALLOC;
|
||||||
commonstate->cs_ResultTupleSlot = slot;
|
planstate->ps_ResultTupleSlot = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -495,11 +495,11 @@ ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecInitScanTupleSlot(EState *estate, CommonScanState *commonscanstate)
|
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
|
||||||
{
|
{
|
||||||
INIT_SLOT_DEFS;
|
INIT_SLOT_DEFS;
|
||||||
INIT_SLOT_ALLOC;
|
INIT_SLOT_ALLOC;
|
||||||
commonscanstate->css_ScanTupleSlot = slot;
|
scanstate->ss_ScanTupleSlot = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
void
|
||||||
ExecAssignExprContext(EState *estate, CommonState *commonstate)
|
ExecAssignExprContext(EState *estate, PlanState *planstate)
|
||||||
{
|
{
|
||||||
ExprContext *econtext = makeNode(ExprContext);
|
ExprContext *econtext = makeNode(ExprContext);
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
|
|||||||
econtext->ecxt_aggnulls = NULL;
|
econtext->ecxt_aggnulls = NULL;
|
||||||
econtext->ecxt_callbacks = NULL;
|
econtext->ecxt_callbacks = NULL;
|
||||||
|
|
||||||
commonstate->cs_ExprContext = econtext;
|
planstate->ps_ExprContext = econtext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -259,10 +259,10 @@ MakePerTupleExprContext(EState *estate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignResultType(CommonState *commonstate,
|
ExecAssignResultType(PlanState *planstate,
|
||||||
TupleDesc tupDesc, bool shouldFree)
|
TupleDesc tupDesc, bool shouldFree)
|
||||||
{
|
{
|
||||||
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
|
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
|
||||||
|
|
||||||
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
|
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
|
||||||
}
|
}
|
||||||
@@ -272,15 +272,15 @@ ExecAssignResultType(CommonState *commonstate,
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
|
ExecAssignResultTypeFromOuterPlan(PlanState *planstate)
|
||||||
{
|
{
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlanState(planstate);
|
||||||
tupDesc = ExecGetTupType(outerPlan);
|
tupDesc = ExecGetTupType(outerPlan);
|
||||||
|
|
||||||
ExecAssignResultType(commonstate, tupDesc, false);
|
ExecAssignResultType(planstate, tupDesc, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -288,7 +288,7 @@ ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
|
ExecAssignResultTypeFromTL(PlanState *planstate)
|
||||||
{
|
{
|
||||||
ResultRelInfo *ri;
|
ResultRelInfo *ri;
|
||||||
bool hasoid = false;
|
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
|
* each of the child plans of the topmost Append plan. So, this is
|
||||||
* ugly but it works, for now ...
|
* ugly but it works, for now ...
|
||||||
*/
|
*/
|
||||||
ri = node->state->es_result_relation_info;
|
ri = planstate->state->es_result_relation_info;
|
||||||
if (ri != NULL)
|
if (ri != NULL)
|
||||||
{
|
{
|
||||||
Relation rel = ri->ri_RelationDesc;
|
Relation rel = ri->ri_RelationDesc;
|
||||||
@@ -320,8 +320,13 @@ ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
|
|||||||
hasoid = rel->rd_rel->relhasoids;
|
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
|
TupleDesc
|
||||||
ExecGetResultType(CommonState *commonstate)
|
ExecGetResultType(PlanState *planstate)
|
||||||
{
|
{
|
||||||
TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
|
TupleTableSlot *slot = planstate->ps_ResultTupleSlot;
|
||||||
|
|
||||||
return slot->ttc_tupleDescriptor;
|
return slot->ttc_tupleDescriptor;
|
||||||
}
|
}
|
||||||
@@ -342,23 +347,23 @@ ExecGetResultType(CommonState *commonstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
|
ExecAssignProjectionInfo(PlanState *planstate)
|
||||||
{
|
{
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
List *targetList;
|
List *targetList;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
targetList = node->targetlist;
|
targetList = planstate->targetlist;
|
||||||
len = ExecTargetListLength(targetList);
|
len = ExecTargetListLength(targetList);
|
||||||
|
|
||||||
projInfo = makeNode(ProjectionInfo);
|
projInfo = makeNode(ProjectionInfo);
|
||||||
projInfo->pi_targetlist = targetList;
|
projInfo->pi_targetlist = targetList;
|
||||||
projInfo->pi_len = len;
|
projInfo->pi_len = len;
|
||||||
projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
|
projInfo->pi_tupValue = (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
|
||||||
projInfo->pi_exprContext = commonstate->cs_ExprContext;
|
projInfo->pi_exprContext = planstate->ps_ExprContext;
|
||||||
projInfo->pi_slot = commonstate->cs_ResultTupleSlot;
|
projInfo->pi_slot = planstate->ps_ResultTupleSlot;
|
||||||
|
|
||||||
commonstate->cs_ProjInfo = projInfo;
|
planstate->ps_ProjInfo = projInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -367,7 +372,7 @@ ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecFreeProjectionInfo(CommonState *commonstate)
|
ExecFreeProjectionInfo(PlanState *planstate)
|
||||||
{
|
{
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
|
|
||||||
@@ -375,7 +380,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||||||
* get projection info. if NULL then this node has none so we just
|
* get projection info. if NULL then this node has none so we just
|
||||||
* return.
|
* return.
|
||||||
*/
|
*/
|
||||||
projInfo = commonstate->cs_ProjInfo;
|
projInfo = planstate->ps_ProjInfo;
|
||||||
if (projInfo == NULL)
|
if (projInfo == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -386,7 +391,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||||||
pfree(projInfo->pi_tupValue);
|
pfree(projInfo->pi_tupValue);
|
||||||
|
|
||||||
pfree(projInfo);
|
pfree(projInfo);
|
||||||
commonstate->cs_ProjInfo = NULL;
|
planstate->ps_ProjInfo = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -394,7 +399,7 @@ ExecFreeProjectionInfo(CommonState *commonstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecFreeExprContext(CommonState *commonstate)
|
ExecFreeExprContext(PlanState *planstate)
|
||||||
{
|
{
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
@@ -402,7 +407,7 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||||||
* get expression context. if NULL then this node has none so we just
|
* get expression context. if NULL then this node has none so we just
|
||||||
* return.
|
* return.
|
||||||
*/
|
*/
|
||||||
econtext = commonstate->cs_ExprContext;
|
econtext = planstate->ps_ExprContext;
|
||||||
if (econtext == NULL)
|
if (econtext == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -416,7 +421,7 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||||||
*/
|
*/
|
||||||
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
MemoryContextDelete(econtext->ecxt_per_tuple_memory);
|
||||||
pfree(econtext);
|
pfree(econtext);
|
||||||
commonstate->cs_ExprContext = NULL;
|
planstate->ps_ExprContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -434,9 +439,9 @@ ExecFreeExprContext(CommonState *commonstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
TupleDesc
|
TupleDesc
|
||||||
ExecGetScanType(CommonScanState *csstate)
|
ExecGetScanType(ScanState *scanstate)
|
||||||
{
|
{
|
||||||
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
|
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
|
||||||
|
|
||||||
return slot->ttc_tupleDescriptor;
|
return slot->ttc_tupleDescriptor;
|
||||||
}
|
}
|
||||||
@@ -446,10 +451,10 @@ ExecGetScanType(CommonScanState *csstate)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignScanType(CommonScanState *csstate,
|
ExecAssignScanType(ScanState *scanstate,
|
||||||
TupleDesc tupDesc, bool shouldFree)
|
TupleDesc tupDesc, bool shouldFree)
|
||||||
{
|
{
|
||||||
TupleTableSlot *slot = csstate->css_ScanTupleSlot;
|
TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;
|
||||||
|
|
||||||
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
|
ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
|
||||||
}
|
}
|
||||||
@@ -459,15 +464,15 @@ ExecAssignScanType(CommonScanState *csstate,
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
|
ExecAssignScanTypeFromOuterPlan(ScanState *scanstate)
|
||||||
{
|
{
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlanState(scanstate);
|
||||||
tupDesc = ExecGetTupType(outerPlan);
|
tupDesc = ExecGetTupType(outerPlan);
|
||||||
|
|
||||||
ExecAssignScanType(csstate, tupDesc, false);
|
ExecAssignScanType(scanstate, tupDesc, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -718,7 +723,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SetChangedParamList(Plan *node, List *newchg)
|
SetChangedParamList(PlanState *node, List *newchg)
|
||||||
{
|
{
|
||||||
List *nl;
|
List *nl;
|
||||||
|
|
||||||
@@ -727,8 +732,8 @@ SetChangedParamList(Plan *node, List *newchg)
|
|||||||
int paramId = lfirsti(nl);
|
int paramId = lfirsti(nl);
|
||||||
|
|
||||||
/* if this node doesn't depend on a param ... */
|
/* if this node doesn't depend on a param ... */
|
||||||
if (!intMember(paramId, node->extParam) &&
|
if (!intMember(paramId, node->plan->extParam) &&
|
||||||
!intMember(paramId, node->locParam))
|
!intMember(paramId, node->plan->locParam))
|
||||||
continue;
|
continue;
|
||||||
/* if this param is already in list of changed ones ... */
|
/* if this param is already in list of changed ones ... */
|
||||||
if (intMember(paramId, node->chgParam))
|
if (intMember(paramId, node->chgParam))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -37,10 +39,11 @@ typedef enum
|
|||||||
|
|
||||||
typedef struct local_es
|
typedef struct local_es
|
||||||
{
|
{
|
||||||
QueryDesc *qd;
|
|
||||||
EState *estate;
|
|
||||||
struct local_es *next;
|
struct local_es *next;
|
||||||
ExecStatus status;
|
ExecStatus status;
|
||||||
|
Query *query;
|
||||||
|
Plan *plan;
|
||||||
|
QueryDesc *qd; /* null unless status == RUN */
|
||||||
} execution_state;
|
} execution_state;
|
||||||
|
|
||||||
#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *) NULL)
|
#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *) NULL)
|
||||||
@@ -62,6 +65,8 @@ typedef struct
|
|||||||
* we end execution of the function and
|
* we end execution of the function and
|
||||||
* free stuff */
|
* free stuff */
|
||||||
|
|
||||||
|
ParamListInfo paramLI; /* Param list representing current args */
|
||||||
|
|
||||||
/* head of linked list of execution_state records */
|
/* head of linked list of execution_state records */
|
||||||
execution_state *func_state;
|
execution_state *func_state;
|
||||||
} SQLFunctionCache;
|
} SQLFunctionCache;
|
||||||
@@ -73,10 +78,11 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
|
|||||||
static execution_state *init_execution_state(char *src,
|
static execution_state *init_execution_state(char *src,
|
||||||
Oid *argOidVect, int nargs);
|
Oid *argOidVect, int nargs);
|
||||||
static void init_sql_fcache(FmgrInfo *finfo);
|
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 TupleTableSlot *postquel_getnext(execution_state *es);
|
||||||
static void postquel_end(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,
|
static Datum postquel_execute(execution_state *es,
|
||||||
FunctionCallInfo fcinfo,
|
FunctionCallInfo fcinfo,
|
||||||
SQLFunctionCachePtr fcache);
|
SQLFunctionCachePtr fcache);
|
||||||
@@ -101,7 +107,6 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
|
|||||||
Query *queryTree = lfirst(qtl_item);
|
Query *queryTree = lfirst(qtl_item);
|
||||||
Plan *planTree;
|
Plan *planTree;
|
||||||
execution_state *newes;
|
execution_state *newes;
|
||||||
EState *estate;
|
|
||||||
|
|
||||||
planTree = pg_plan_query(queryTree);
|
planTree = pg_plan_query(queryTree);
|
||||||
|
|
||||||
@@ -113,29 +118,9 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
|
|||||||
|
|
||||||
newes->next = NULL;
|
newes->next = NULL;
|
||||||
newes->status = F_EXEC_START;
|
newes->status = F_EXEC_START;
|
||||||
newes->qd = CreateQueryDesc(queryTree, planTree, None, NULL);
|
newes->query = queryTree;
|
||||||
newes->estate = estate = CreateExecutorState();
|
newes->plan = planTree;
|
||||||
|
newes->qd = NULL;
|
||||||
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;
|
|
||||||
|
|
||||||
preves = newes;
|
preves = newes;
|
||||||
}
|
}
|
||||||
@@ -219,6 +204,10 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||||||
else
|
else
|
||||||
fcache->funcSlot = NULL;
|
fcache->funcSlot = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse and plan the queries. We need the argument info to pass
|
||||||
|
* to the parser.
|
||||||
|
*/
|
||||||
nargs = procedureStruct->pronargs;
|
nargs = procedureStruct->pronargs;
|
||||||
|
|
||||||
if (nargs > 0)
|
if (nargs > 0)
|
||||||
@@ -252,15 +241,18 @@ init_sql_fcache(FmgrInfo *finfo)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
postquel_start(execution_state *es)
|
postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
|
||||||
{
|
{
|
||||||
/*
|
Assert(es->qd == NULL);
|
||||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
es->qd = CreateQueryDesc(es->query, es->plan,
|
||||||
* 30-8-1996
|
None, NULL,
|
||||||
*/
|
fcache->paramLI, false);
|
||||||
if (es->qd->operation == CMD_UTILITY)
|
|
||||||
return;
|
/* Utility commands don't need Executor. */
|
||||||
ExecutorStart(es->qd, es->estate);
|
if (es->qd->operation != CMD_UTILITY)
|
||||||
|
ExecutorStart(es->qd);
|
||||||
|
|
||||||
|
es->status = F_EXEC_RUN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
@@ -282,40 +274,52 @@ postquel_getnext(execution_state *es)
|
|||||||
/* If it's not the last command, just run it to completion */
|
/* If it's not the last command, just run it to completion */
|
||||||
count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L;
|
count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L;
|
||||||
|
|
||||||
return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count);
|
return ExecutorRun(es->qd, ForwardScanDirection, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
postquel_end(execution_state *es)
|
postquel_end(execution_state *es)
|
||||||
{
|
{
|
||||||
/*
|
/* Utility commands don't need Executor. */
|
||||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
if (es->qd->operation != CMD_UTILITY)
|
||||||
* 30-8-1996
|
ExecutorEnd(es->qd);
|
||||||
*/
|
|
||||||
if (es->qd->operation == CMD_UTILITY)
|
pfree(es->qd);
|
||||||
return;
|
es->qd = NULL;
|
||||||
ExecutorEnd(es->qd, es->estate);
|
|
||||||
|
es->status = F_EXEC_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build ParamListInfo array representing current arguments */
|
||||||
static void
|
static void
|
||||||
postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo)
|
postquel_sub_params(SQLFunctionCachePtr fcache,
|
||||||
|
FunctionCallInfo fcinfo)
|
||||||
{
|
{
|
||||||
EState *estate;
|
|
||||||
ParamListInfo paramLI;
|
ParamListInfo paramLI;
|
||||||
|
int nargs = fcinfo->nargs;
|
||||||
|
|
||||||
estate = es->estate;
|
if (nargs > 0)
|
||||||
paramLI = estate->es_param_list_info;
|
|
||||||
|
|
||||||
while (paramLI->kind != PARAM_INVALID)
|
|
||||||
{
|
{
|
||||||
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[i].kind = PARAM_NUM;
|
||||||
paramLI->value = fcinfo->arg[paramLI->id - 1];
|
paramLI[i].id = i + 1;
|
||||||
paramLI->isnull = fcinfo->argnull[paramLI->id - 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 *
|
static TupleTableSlot *
|
||||||
@@ -359,27 +363,14 @@ postquel_execute(execution_state *es,
|
|||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
Datum value;
|
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)
|
if (es->status == F_EXEC_START)
|
||||||
{
|
postquel_start(es, fcache);
|
||||||
postquel_start(es);
|
|
||||||
es->status = F_EXEC_RUN;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot = postquel_getnext(es);
|
slot = postquel_getnext(es);
|
||||||
|
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
{
|
{
|
||||||
postquel_end(es);
|
postquel_end(es);
|
||||||
es->status = F_EXEC_DONE;
|
|
||||||
fcinfo->isnull = true;
|
fcinfo->isnull = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -438,10 +429,7 @@ postquel_execute(execution_state *es,
|
|||||||
* execution now.
|
* execution now.
|
||||||
*/
|
*/
|
||||||
if (!fcinfo->flinfo->fn_retset)
|
if (!fcinfo->flinfo->fn_retset)
|
||||||
{
|
|
||||||
postquel_end(es);
|
postquel_end(es);
|
||||||
es->status = F_EXEC_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -471,7 +459,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
|||||||
oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
|
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;
|
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
|
||||||
if (fcache == NULL)
|
if (fcache == NULL)
|
||||||
@@ -481,6 +469,13 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
es = fcache->func_state;
|
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.
|
* Find first unfinished query in function.
|
||||||
*/
|
*/
|
||||||
@@ -506,7 +501,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
|||||||
if (es == (execution_state *) NULL)
|
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;
|
es = fcache->func_state;
|
||||||
while (es)
|
while (es)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,
|
AggStatePerAgg peraggstate,
|
||||||
AggStatePerGroup pergroupstate,
|
AggStatePerGroup pergroupstate,
|
||||||
Datum *resultVal, bool *resultIsNull);
|
Datum *resultVal, bool *resultIsNull);
|
||||||
static void build_hash_table(Agg *node);
|
static void build_hash_table(AggState *aggstate);
|
||||||
static AggHashEntry lookup_hash_entry(Agg *node, TupleTableSlot *slot);
|
static AggHashEntry lookup_hash_entry(AggState *aggstate,
|
||||||
static TupleTableSlot *agg_retrieve_direct(Agg *node);
|
TupleTableSlot *slot);
|
||||||
static void agg_fill_hash_table(Agg *node);
|
static TupleTableSlot *agg_retrieve_direct(AggState *aggstate);
|
||||||
static TupleTableSlot *agg_retrieve_hash_table(Agg *node);
|
static void agg_fill_hash_table(AggState *aggstate);
|
||||||
|
static TupleTableSlot *agg_retrieve_hash_table(AggState *aggstate);
|
||||||
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
|
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
|
||||||
|
|
||||||
|
|
||||||
@@ -521,7 +522,7 @@ finalize_aggregate(AggState *aggstate,
|
|||||||
{
|
{
|
||||||
MemoryContext oldContext;
|
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.
|
* 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.
|
* The hash table always lives in the aggcontext memory context.
|
||||||
*/
|
*/
|
||||||
static void
|
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;
|
AggHashTable hashtable;
|
||||||
Size tabsize;
|
Size tabsize;
|
||||||
|
|
||||||
@@ -596,9 +597,9 @@ build_hash_table(Agg *node)
|
|||||||
* When called, CurrentMemoryContext should be the per-query context.
|
* When called, CurrentMemoryContext should be the per-query context.
|
||||||
*/
|
*/
|
||||||
static AggHashEntry
|
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;
|
AggHashTable hashtable = aggstate->hashtable;
|
||||||
MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
MemoryContext tmpmem = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
||||||
HeapTuple tuple = slot->val;
|
HeapTuple tuple = slot->val;
|
||||||
@@ -684,16 +685,14 @@ lookup_hash_entry(Agg *node, TupleTableSlot *slot)
|
|||||||
* the result tuple.
|
* the result tuple.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecAgg(Agg *node)
|
ExecAgg(AggState *node)
|
||||||
{
|
{
|
||||||
AggState *aggstate = node->aggstate;
|
if (node->agg_done)
|
||||||
|
|
||||||
if (aggstate->agg_done)
|
|
||||||
return NULL;
|
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);
|
agg_fill_hash_table(node);
|
||||||
return agg_retrieve_hash_table(node);
|
return agg_retrieve_hash_table(node);
|
||||||
}
|
}
|
||||||
@@ -707,10 +706,10 @@ ExecAgg(Agg *node)
|
|||||||
* ExecAgg for non-hashed case
|
* ExecAgg for non-hashed case
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
agg_retrieve_direct(Agg *node)
|
agg_retrieve_direct(AggState *aggstate)
|
||||||
{
|
{
|
||||||
AggState *aggstate;
|
Agg *node = (Agg *) aggstate->ss.ps.plan;
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
ExprContext *tmpcontext;
|
ExprContext *tmpcontext;
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
@@ -726,22 +725,21 @@ agg_retrieve_direct(Agg *node)
|
|||||||
/*
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
*/
|
*/
|
||||||
aggstate = node->aggstate;
|
outerPlan = outerPlanState(aggstate);
|
||||||
outerPlan = outerPlan(node);
|
|
||||||
/* econtext is the per-output-tuple expression context */
|
/* econtext is the per-output-tuple expression context */
|
||||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
econtext = aggstate->ss.ps.ps_ExprContext;
|
||||||
aggvalues = econtext->ecxt_aggvalues;
|
aggvalues = econtext->ecxt_aggvalues;
|
||||||
aggnulls = econtext->ecxt_aggnulls;
|
aggnulls = econtext->ecxt_aggnulls;
|
||||||
/* tmpcontext is the per-input-tuple expression context */
|
/* tmpcontext is the per-input-tuple expression context */
|
||||||
tmpcontext = aggstate->tmpcontext;
|
tmpcontext = aggstate->tmpcontext;
|
||||||
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
|
projInfo = aggstate->ss.ps.ps_ProjInfo;
|
||||||
peragg = aggstate->peragg;
|
peragg = aggstate->peragg;
|
||||||
pergroup = aggstate->pergroup;
|
pergroup = aggstate->pergroup;
|
||||||
firstSlot = aggstate->csstate.css_ScanTupleSlot;
|
firstSlot = aggstate->ss.ss_ScanTupleSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We loop retrieving groups until we find one matching
|
* We loop retrieving groups until we find one matching
|
||||||
* node->plan.qual
|
* aggstate->ss.ps.qual
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -754,7 +752,7 @@ agg_retrieve_direct(Agg *node)
|
|||||||
*/
|
*/
|
||||||
if (aggstate->grp_firstTuple == NULL)
|
if (aggstate->grp_firstTuple == NULL)
|
||||||
{
|
{
|
||||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
outerslot = ExecProcNode(outerPlan);
|
||||||
if (!TupIsNull(outerslot))
|
if (!TupIsNull(outerslot))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -810,7 +808,7 @@ agg_retrieve_direct(Agg *node)
|
|||||||
/* Reset per-input-tuple context after each tuple */
|
/* Reset per-input-tuple context after each tuple */
|
||||||
ResetExprContext(tmpcontext);
|
ResetExprContext(tmpcontext);
|
||||||
|
|
||||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
outerslot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(outerslot))
|
if (TupIsNull(outerslot))
|
||||||
{
|
{
|
||||||
/* no more outer-plan tuples available */
|
/* no more outer-plan tuples available */
|
||||||
@@ -917,7 +915,7 @@ agg_retrieve_direct(Agg *node)
|
|||||||
* Otherwise, return the tuple.
|
* Otherwise, return the tuple.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
while (!ExecQual(node->plan.qual, econtext, false));
|
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
|
||||||
|
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
}
|
}
|
||||||
@@ -926,10 +924,9 @@ agg_retrieve_direct(Agg *node)
|
|||||||
* ExecAgg for hashed case: phase 1, read input and build hash table
|
* ExecAgg for hashed case: phase 1, read input and build hash table
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
agg_fill_hash_table(Agg *node)
|
agg_fill_hash_table(AggState *aggstate)
|
||||||
{
|
{
|
||||||
AggState *aggstate;
|
PlanState *outerPlan;
|
||||||
Plan *outerPlan;
|
|
||||||
ExprContext *tmpcontext;
|
ExprContext *tmpcontext;
|
||||||
AggHashEntry entry;
|
AggHashEntry entry;
|
||||||
TupleTableSlot *outerslot;
|
TupleTableSlot *outerslot;
|
||||||
@@ -937,8 +934,7 @@ agg_fill_hash_table(Agg *node)
|
|||||||
/*
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
*/
|
*/
|
||||||
aggstate = node->aggstate;
|
outerPlan = outerPlanState(aggstate);
|
||||||
outerPlan = outerPlan(node);
|
|
||||||
/* tmpcontext is the per-input-tuple expression context */
|
/* tmpcontext is the per-input-tuple expression context */
|
||||||
tmpcontext = aggstate->tmpcontext;
|
tmpcontext = aggstate->tmpcontext;
|
||||||
|
|
||||||
@@ -948,14 +944,14 @@ agg_fill_hash_table(Agg *node)
|
|||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
outerslot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(outerslot))
|
if (TupIsNull(outerslot))
|
||||||
break;
|
break;
|
||||||
/* set up for advance_aggregates call */
|
/* set up for advance_aggregates call */
|
||||||
tmpcontext->ecxt_scantuple = outerslot;
|
tmpcontext->ecxt_scantuple = outerslot;
|
||||||
|
|
||||||
/* Find or build hashtable entry for this tuple's group */
|
/* 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 the aggregates */
|
||||||
advance_aggregates(aggstate, entry->pergroup);
|
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
|
* ExecAgg for hashed case: phase 2, retrieving groups from hash table
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
agg_retrieve_hash_table(Agg *node)
|
agg_retrieve_hash_table(AggState *aggstate)
|
||||||
{
|
{
|
||||||
AggState *aggstate;
|
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
Datum *aggvalues;
|
Datum *aggvalues;
|
||||||
@@ -992,19 +987,18 @@ agg_retrieve_hash_table(Agg *node)
|
|||||||
/*
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
*/
|
*/
|
||||||
aggstate = node->aggstate;
|
|
||||||
/* econtext is the per-output-tuple expression context */
|
/* econtext is the per-output-tuple expression context */
|
||||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
econtext = aggstate->ss.ps.ps_ExprContext;
|
||||||
aggvalues = econtext->ecxt_aggvalues;
|
aggvalues = econtext->ecxt_aggvalues;
|
||||||
aggnulls = econtext->ecxt_aggnulls;
|
aggnulls = econtext->ecxt_aggnulls;
|
||||||
projInfo = aggstate->csstate.cstate.cs_ProjInfo;
|
projInfo = aggstate->ss.ps.ps_ProjInfo;
|
||||||
peragg = aggstate->peragg;
|
peragg = aggstate->peragg;
|
||||||
hashtable = aggstate->hashtable;
|
hashtable = aggstate->hashtable;
|
||||||
firstSlot = aggstate->csstate.css_ScanTupleSlot;
|
firstSlot = aggstate->ss.ss_ScanTupleSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We loop retrieving groups until we find one matching
|
* We loop retrieving groups until we find one satisfying
|
||||||
* node->plan.qual
|
* aggstate->ss.ps.qual
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -1071,7 +1065,7 @@ agg_retrieve_hash_table(Agg *node)
|
|||||||
* Otherwise, return the tuple.
|
* Otherwise, return the tuple.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
while (!ExecQual(node->plan.qual, econtext, false));
|
while (!ExecQual(aggstate->ss.ps.qual, econtext, false));
|
||||||
|
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
}
|
}
|
||||||
@@ -1083,8 +1077,8 @@ agg_retrieve_hash_table(Agg *node)
|
|||||||
* planner and initializes its outer subtree
|
* planner and initializes its outer subtree
|
||||||
* -----------------
|
* -----------------
|
||||||
*/
|
*/
|
||||||
bool
|
AggState *
|
||||||
ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
ExecInitAgg(Agg *node, EState *estate)
|
||||||
{
|
{
|
||||||
AggState *aggstate;
|
AggState *aggstate;
|
||||||
AggStatePerAgg peragg;
|
AggStatePerAgg peragg;
|
||||||
@@ -1094,16 +1088,15 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||||||
aggno;
|
aggno;
|
||||||
List *alist;
|
List *alist;
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
*/
|
*/
|
||||||
aggstate = makeNode(AggState);
|
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->eqfunctions = NULL;
|
||||||
aggstate->peragg = NULL;
|
aggstate->peragg = NULL;
|
||||||
aggstate->agg_done = false;
|
aggstate->agg_done = false;
|
||||||
@@ -1111,38 +1104,14 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||||||
aggstate->grp_firstTuple = NULL;
|
aggstate->grp_firstTuple = NULL;
|
||||||
aggstate->hashtable = 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
|
* Create expression contexts. We need two, one for per-input-tuple
|
||||||
* processing and one for per-output-tuple processing. We cheat a little
|
* processing and one for per-output-tuple processing. We cheat a little
|
||||||
* by using ExecAssignExprContext() to build both.
|
* by using ExecAssignExprContext() to build both.
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
|
ExecAssignExprContext(estate, &aggstate->ss.ps);
|
||||||
aggstate->tmpcontext = aggstate->csstate.cstate.cs_ExprContext;
|
aggstate->tmpcontext = aggstate->ss.ps.ps_ExprContext;
|
||||||
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
|
ExecAssignExprContext(estate, &aggstate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We also need a long-lived memory context for holding hashtable
|
* 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
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitScanTupleSlot(estate, &aggstate->csstate);
|
ExecInitScanTupleSlot(estate, &aggstate->ss);
|
||||||
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
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
|
* Set up aggregate-result storage in the output expr context, and also
|
||||||
* allocate my private per-agg working storage
|
* 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_aggvalues = (Datum *) palloc0(sizeof(Datum) * numaggs);
|
||||||
econtext->ecxt_aggnulls = (bool *) palloc0(sizeof(bool) * 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)
|
if (node->aggstrategy == AGG_HASHED)
|
||||||
{
|
{
|
||||||
build_hash_table(node);
|
build_hash_table(aggstate);
|
||||||
aggstate->table_filled = false;
|
aggstate->table_filled = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1190,30 +1209,13 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||||||
aggstate->pergroup = pergroup;
|
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 we are grouping, precompute fmgr lookup data for inner loop
|
||||||
*/
|
*/
|
||||||
if (node->numCols > 0)
|
if (node->numCols > 0)
|
||||||
{
|
{
|
||||||
aggstate->eqfunctions =
|
aggstate->eqfunctions =
|
||||||
execTuplesMatchPrepare(ExecGetScanType(&aggstate->csstate),
|
execTuplesMatchPrepare(ExecGetScanType(&aggstate->ss),
|
||||||
node->numCols,
|
node->numCols,
|
||||||
node->grpColIdx);
|
node->grpColIdx);
|
||||||
}
|
}
|
||||||
@@ -1330,7 +1332,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||||||
ReleaseSysCache(aggTuple);
|
ReleaseSysCache(aggTuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return aggstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Datum
|
static Datum
|
||||||
@@ -1372,84 +1374,82 @@ ExecCountSlotsAgg(Agg *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecEndAgg(Agg *node)
|
ExecEndAgg(AggState *node)
|
||||||
{
|
{
|
||||||
AggState *aggstate = node->aggstate;
|
PlanState *outerPlan;
|
||||||
Plan *outerPlan;
|
|
||||||
int aggno;
|
int aggno;
|
||||||
|
|
||||||
/* Make sure we have closed any open tuplesorts */
|
/* 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)
|
if (peraggstate->sortstate)
|
||||||
tuplesort_end(peraggstate->sortstate);
|
tuplesort_end(peraggstate->sortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecFreeProjectionInfo(&aggstate->csstate.cstate);
|
ExecFreeProjectionInfo(&node->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free both the expr contexts.
|
* Free both the expr contexts.
|
||||||
*/
|
*/
|
||||||
ExecFreeExprContext(&aggstate->csstate.cstate);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
aggstate->csstate.cstate.cs_ExprContext = aggstate->tmpcontext;
|
node->ss.ps.ps_ExprContext = node->tmpcontext;
|
||||||
ExecFreeExprContext(&aggstate->csstate.cstate);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
MemoryContextDelete(aggstate->aggcontext);
|
MemoryContextDelete(node->aggcontext);
|
||||||
|
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlanState(node);
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
ExecEndNode(outerPlan);
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
if (aggstate->grp_firstTuple != NULL)
|
if (node->grp_firstTuple != NULL)
|
||||||
{
|
{
|
||||||
heap_freetuple(aggstate->grp_firstTuple);
|
heap_freetuple(node->grp_firstTuple);
|
||||||
aggstate->grp_firstTuple = NULL;
|
node->grp_firstTuple = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanAgg(AggState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
AggState *aggstate = node->aggstate;
|
ExprContext *econtext = node->ss.ps.ps_ExprContext;
|
||||||
ExprContext *econtext = aggstate->csstate.cstate.cs_ExprContext;
|
|
||||||
int aggno;
|
int aggno;
|
||||||
|
|
||||||
/* Make sure we have closed any open tuplesorts */
|
/* 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)
|
if (peraggstate->sortstate)
|
||||||
tuplesort_end(peraggstate->sortstate);
|
tuplesort_end(peraggstate->sortstate);
|
||||||
peraggstate->sortstate = NULL;
|
peraggstate->sortstate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
aggstate->agg_done = false;
|
node->agg_done = false;
|
||||||
if (aggstate->grp_firstTuple != NULL)
|
if (node->grp_firstTuple != NULL)
|
||||||
{
|
{
|
||||||
heap_freetuple(aggstate->grp_firstTuple);
|
heap_freetuple(node->grp_firstTuple);
|
||||||
aggstate->grp_firstTuple = NULL;
|
node->grp_firstTuple = NULL;
|
||||||
}
|
}
|
||||||
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * aggstate->numaggs);
|
MemSet(econtext->ecxt_aggvalues, 0, sizeof(Datum) * node->numaggs);
|
||||||
MemSet(econtext->ecxt_aggnulls, 0, sizeof(bool) * aggstate->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);
|
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
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NIL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "executor/nodeAppend.h"
|
||||||
#include "parser/parsetree.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
|
* exec_append_initialize_next
|
||||||
*
|
*
|
||||||
* Sets up the append node state (i.e. the append state node)
|
* Sets up the append state node for the "next" scan.
|
||||||
* for the "next" scan.
|
|
||||||
*
|
*
|
||||||
* Returns t iff there is a "next" scan to process.
|
* Returns t iff there is a "next" scan to process.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
exec_append_initialize_next(Append *node)
|
exec_append_initialize_next(AppendState *appendstate)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
AppendState *appendstate;
|
|
||||||
int whichplan;
|
int whichplan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the append node
|
* get information from the append node
|
||||||
*/
|
*/
|
||||||
estate = node->plan.state;
|
estate = appendstate->ps.state;
|
||||||
appendstate = node->appendstate;
|
|
||||||
whichplan = appendstate->as_whichplan;
|
whichplan = appendstate->as_whichplan;
|
||||||
|
|
||||||
if (whichplan < appendstate->as_firstplan)
|
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
|
* If we are controlling the target relation, select the proper
|
||||||
* active ResultRelInfo and junk filter for this target.
|
* active ResultRelInfo and junk filter for this target.
|
||||||
*/
|
*/
|
||||||
if (node->isTarget)
|
if (((Append *) appendstate->ps.plan)->isTarget)
|
||||||
{
|
{
|
||||||
Assert(whichplan < estate->es_num_result_relations);
|
Assert(whichplan < estate->es_num_result_relations);
|
||||||
estate->es_result_relation_info =
|
estate->es_result_relation_info =
|
||||||
@@ -132,9 +129,7 @@ exec_append_initialize_next(Append *node)
|
|||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecInitAppend
|
* ExecInitAppend
|
||||||
*
|
*
|
||||||
* Begins all of the subscans of the append node, storing the
|
* Begin all of the subscans of the append node.
|
||||||
* scan structures in the 'initialized' vector of the append-state
|
|
||||||
* structure.
|
|
||||||
*
|
*
|
||||||
* (This is potentially wasteful, since the entire result of the
|
* (This is potentially wasteful, since the entire result of the
|
||||||
* append node may not be scanned, but this way all 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.
|
* subplan that corresponds to the target relation being checked.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
AppendState *
|
||||||
ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
ExecInitAppend(Append *node, EState *estate)
|
||||||
{
|
{
|
||||||
AppendState *appendstate;
|
AppendState *appendstate = makeNode(AppendState);
|
||||||
|
PlanState **appendplanstates;
|
||||||
int nplans;
|
int nplans;
|
||||||
List *appendplans;
|
|
||||||
bool *initialized;
|
|
||||||
int i;
|
int i;
|
||||||
Plan *initNode;
|
Plan *initNode;
|
||||||
|
|
||||||
CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
|
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;
|
appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
|
||||||
nplans = length(appendplans);
|
|
||||||
|
|
||||||
initialized = (bool *) palloc0(nplans * sizeof(bool));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create new AppendState for our append node
|
* 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_nplans = nplans;
|
||||||
appendstate->as_initialized = initialized;
|
|
||||||
|
|
||||||
node->appendstate = appendstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do we want to scan just one subplan? (Special case for
|
* 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
|
* append nodes still have Result slots, which hold pointers to
|
||||||
* tuples, so we have to initialize them.
|
* 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
|
* 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
|
* estate->es_result_relation_info correctly while we initialize each
|
||||||
* sub-plan; ExecAssignResultTypeFromTL depends on that!
|
* sub-plan; ExecAssignResultTypeFromTL depends on that!
|
||||||
*/
|
*/
|
||||||
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
|
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
|
||||||
{
|
{
|
||||||
appendstate->as_whichplan = i;
|
appendstate->as_whichplan = i;
|
||||||
exec_append_initialize_next(node);
|
exec_append_initialize_next(appendstate);
|
||||||
|
|
||||||
initNode = (Plan *) nth(i, appendplans);
|
initNode = (Plan *) nth(i, node->appendplans);
|
||||||
initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
|
appendplanstates[i] = ExecInitNode(initNode, estate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &appendstate->cstate);
|
ExecAssignResultTypeFromTL(&appendstate->ps);
|
||||||
appendstate->cstate.cs_ProjInfo = NULL;
|
appendstate->ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return the result from the first subplan's initialization
|
* return the result from the first subplan's initialization
|
||||||
*/
|
*/
|
||||||
appendstate->as_whichplan = appendstate->as_firstplan;
|
appendstate->as_whichplan = appendstate->as_firstplan;
|
||||||
exec_append_initialize_next(node);
|
exec_append_initialize_next(appendstate);
|
||||||
|
|
||||||
return TRUE;
|
return appendstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -264,13 +254,11 @@ ExecCountSlotsAppend(Append *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecProcAppend(Append *node)
|
ExecProcAppend(AppendState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
AppendState *appendstate;
|
|
||||||
int whichplan;
|
int whichplan;
|
||||||
List *appendplans;
|
PlanState *subnode;
|
||||||
Plan *subnode;
|
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
TupleTableSlot *result_slot;
|
TupleTableSlot *result_slot;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
@@ -278,25 +266,20 @@ ExecProcAppend(Append *node)
|
|||||||
/*
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
*/
|
*/
|
||||||
appendstate = node->appendstate;
|
estate = node->ps.state;
|
||||||
estate = node->plan.state;
|
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
appendplans = node->appendplans;
|
whichplan = node->as_whichplan;
|
||||||
whichplan = appendstate->as_whichplan;
|
result_slot = node->ps.ps_ResultTupleSlot;
|
||||||
result_slot = appendstate->cstate.cs_ResultTupleSlot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* figure out which subplan we are currently processing
|
* figure out which subplan we are currently processing
|
||||||
*/
|
*/
|
||||||
subnode = (Plan *) nth(whichplan, appendplans);
|
subnode = node->appendplans[whichplan];
|
||||||
|
|
||||||
if (subnode == NULL)
|
|
||||||
elog(DEBUG1, "ExecProcAppend: subnode is NULL");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get a tuple from the subplan
|
* get a tuple from the subplan
|
||||||
*/
|
*/
|
||||||
result = ExecProcNode(subnode, (Plan *) node);
|
result = ExecProcNode(subnode);
|
||||||
|
|
||||||
if (!TupIsNull(result))
|
if (!TupIsNull(result))
|
||||||
{
|
{
|
||||||
@@ -316,9 +299,9 @@ ExecProcAppend(Append *node)
|
|||||||
* try processing again (recursively)
|
* try processing again (recursively)
|
||||||
*/
|
*/
|
||||||
if (ScanDirectionIsForward(direction))
|
if (ScanDirectionIsForward(direction))
|
||||||
appendstate->as_whichplan++;
|
node->as_whichplan++;
|
||||||
else
|
else
|
||||||
appendstate->as_whichplan--;
|
node->as_whichplan--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return something from next node or an empty slot if all of our
|
* return something from next node or an empty slot if all of our
|
||||||
@@ -343,65 +326,56 @@ ExecProcAppend(Append *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndAppend(Append *node)
|
ExecEndAppend(AppendState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
PlanState **appendplans;
|
||||||
AppendState *appendstate;
|
|
||||||
int nplans;
|
int nplans;
|
||||||
List *appendplans;
|
|
||||||
bool *initialized;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
*/
|
*/
|
||||||
appendstate = node->appendstate;
|
|
||||||
estate = node->plan.state;
|
|
||||||
appendplans = node->appendplans;
|
appendplans = node->appendplans;
|
||||||
nplans = appendstate->as_nplans;
|
nplans = node->as_nplans;
|
||||||
initialized = appendstate->as_initialized;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* shut down each of the subscans
|
* shut down each of the subscans (that we've initialized)
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nplans; i++)
|
for (i = 0; i < nplans; i++)
|
||||||
{
|
{
|
||||||
if (initialized[i])
|
if (appendplans[i])
|
||||||
ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
|
ExecEndNode(appendplans[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanAppend(AppendState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
AppendState *appendstate = node->appendstate;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++)
|
for (i = node->as_firstplan; i <= node->as_lastplan; i++)
|
||||||
{
|
{
|
||||||
Plan *subnode;
|
PlanState *subnode = node->appendplans[i];
|
||||||
|
|
||||||
subnode = (Plan *) nth(i, node->appendplans);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecReScan doesn't know about my subplans, so I have to do
|
* ExecReScan doesn't know about my subplans, so I have to do
|
||||||
* changed-parameter signaling myself.
|
* changed-parameter signaling myself.
|
||||||
*/
|
*/
|
||||||
if (node->plan.chgParam != NULL)
|
if (node->ps.chgParam != NIL)
|
||||||
SetChangedParamList(subnode, node->plan.chgParam);
|
SetChangedParamList(subnode, node->ps.chgParam);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnode is not null then plan will be re-scanned
|
* if chgParam of subnode is not null then plan will be re-scanned
|
||||||
* by first ExecProcNode.
|
* by first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (subnode->chgParam == NULL)
|
if (subnode->chgParam == NIL)
|
||||||
{
|
{
|
||||||
/* make sure estate is correct for this subnode (needed??) */
|
/* make sure estate is correct for this subnode (needed??) */
|
||||||
appendstate->as_whichplan = i;
|
node->as_whichplan = i;
|
||||||
exec_append_initialize_next(node);
|
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);
|
exec_append_initialize_next(node);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"
|
#include "utils/lsyscache.h"
|
||||||
|
|
||||||
|
|
||||||
static TupleTableSlot *FunctionNext(FunctionScan *node);
|
static TupleTableSlot *FunctionNext(FunctionScanState *node);
|
||||||
static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
|
static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -48,24 +48,22 @@ static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
FunctionNext(FunctionScan *node)
|
FunctionNext(FunctionScanState *node)
|
||||||
{
|
{
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
Tuplestorestate *tuplestorestate;
|
Tuplestorestate *tuplestorestate;
|
||||||
FunctionScanState *scanstate;
|
|
||||||
bool should_free;
|
bool should_free;
|
||||||
HeapTuple heapTuple;
|
HeapTuple heapTuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the estate and scan state
|
* get information from the estate and scan state
|
||||||
*/
|
*/
|
||||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
estate = node->ss.ps.state;
|
||||||
estate = node->scan.plan.state;
|
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
|
|
||||||
tuplestorestate = scanstate->tuplestorestate;
|
tuplestorestate = node->tuplestorestate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If first time through, read all tuples from function and put them
|
* If first time through, read all tuples from function and put them
|
||||||
@@ -74,13 +72,13 @@ FunctionNext(FunctionScan *node)
|
|||||||
*/
|
*/
|
||||||
if (tuplestorestate == NULL)
|
if (tuplestorestate == NULL)
|
||||||
{
|
{
|
||||||
ExprContext *econtext = scanstate->csstate.cstate.cs_ExprContext;
|
ExprContext *econtext = node->ss.ps.ps_ExprContext;
|
||||||
TupleDesc funcTupdesc;
|
TupleDesc funcTupdesc;
|
||||||
|
|
||||||
scanstate->tuplestorestate = tuplestorestate =
|
node->tuplestorestate = tuplestorestate =
|
||||||
ExecMakeTableFunctionResult(scanstate->funcexpr,
|
ExecMakeTableFunctionResult(node->funcexpr,
|
||||||
econtext,
|
econtext,
|
||||||
scanstate->tupdesc,
|
node->tupdesc,
|
||||||
&funcTupdesc);
|
&funcTupdesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -89,14 +87,14 @@ FunctionNext(FunctionScan *node)
|
|||||||
* well do it always.
|
* well do it always.
|
||||||
*/
|
*/
|
||||||
if (funcTupdesc &&
|
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");
|
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.
|
* Get the next tuple from tuplestore. Return NULL if no more tuples.
|
||||||
*/
|
*/
|
||||||
slot = scanstate->csstate.css_ScanTupleSlot;
|
slot = node->ss.ss_ScanTupleSlot;
|
||||||
if (tuplestorestate)
|
if (tuplestorestate)
|
||||||
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
||||||
ScanDirectionIsForward(direction),
|
ScanDirectionIsForward(direction),
|
||||||
@@ -121,20 +119,20 @@ FunctionNext(FunctionScan *node)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecFunctionScan(FunctionScan *node)
|
ExecFunctionScan(FunctionScanState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* use FunctionNext as access method
|
* use FunctionNext as access method
|
||||||
*/
|
*/
|
||||||
return ExecScan(&node->scan, (ExecScanAccessMtd) FunctionNext);
|
return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecInitFunctionScan
|
* ExecInitFunctionScan
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
FunctionScanState *
|
||||||
ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
ExecInitFunctionScan(FunctionScan *node, EState *estate)
|
||||||
{
|
{
|
||||||
FunctionScanState *scanstate;
|
FunctionScanState *scanstate;
|
||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
@@ -145,34 +143,40 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* FunctionScan should not have any children.
|
* FunctionScan should not have any children.
|
||||||
*/
|
*/
|
||||||
Assert(outerPlan((Plan *) node) == NULL);
|
Assert(outerPlan(node) == NULL);
|
||||||
Assert(innerPlan((Plan *) node) == NULL);
|
Assert(innerPlan(node) == NULL);
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->scan.plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create new ScanState for node
|
* create new ScanState for node
|
||||||
*/
|
*/
|
||||||
scanstate = makeNode(FunctionScanState);
|
scanstate = makeNode(FunctionScanState);
|
||||||
node->scan.scanstate = &scanstate->csstate;
|
scanstate->ss.ps.plan = (Plan *) node;
|
||||||
|
scanstate->ss.ps.state = estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* create expression context for node
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &scanstate->csstate.cstate);
|
ExecAssignExprContext(estate, &scanstate->ss.ps);
|
||||||
|
|
||||||
#define FUNCTIONSCAN_NSLOTS 2
|
#define FUNCTIONSCAN_NSLOTS 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
|
||||||
ExecInitScanTupleSlot(estate, &scanstate->csstate);
|
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
|
* 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");
|
elog(ERROR, "Unknown kind of return type specified for function");
|
||||||
|
|
||||||
scanstate->tupdesc = tupdesc;
|
scanstate->tupdesc = tupdesc;
|
||||||
ExecSetSlotDescriptor(scanstate->csstate.css_ScanTupleSlot,
|
ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
|
||||||
tupdesc, false);
|
tupdesc, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -239,15 +243,15 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
|
|||||||
scanstate->tuplestorestate = NULL;
|
scanstate->tuplestorestate = NULL;
|
||||||
scanstate->funcexpr = rte->funcexpr;
|
scanstate->funcexpr = rte->funcexpr;
|
||||||
|
|
||||||
scanstate->csstate.cstate.cs_TupFromTlist = false;
|
scanstate->ss.ps.ps_TupFromTlist = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->csstate.cstate);
|
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->csstate.cstate);
|
ExecAssignProjectionInfo(&scanstate->ss.ps);
|
||||||
|
|
||||||
return TRUE;
|
return scanstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -265,39 +269,26 @@ ExecCountSlotsFunctionScan(FunctionScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
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
|
* 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);
|
ExecFreeProjectionInfo(&node->ss.ps);
|
||||||
ExecFreeExprContext(&scanstate->csstate.cstate);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||||
ExecClearTuple(scanstate->csstate.css_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release tuplestore resources
|
* Release tuplestore resources
|
||||||
*/
|
*/
|
||||||
if (scanstate->tuplestorestate != NULL)
|
if (node->tuplestorestate != NULL)
|
||||||
tuplestore_end(scanstate->tuplestorestate);
|
tuplestore_end(node->tuplestorestate);
|
||||||
scanstate->tuplestorestate = NULL;
|
node->tuplestorestate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -307,19 +298,15 @@ ExecEndFunctionScan(FunctionScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecFunctionMarkPos(FunctionScan *node)
|
ExecFunctionMarkPos(FunctionScanState *node)
|
||||||
{
|
{
|
||||||
FunctionScanState *scanstate;
|
|
||||||
|
|
||||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we haven't materialized yet, just return.
|
* if we haven't materialized yet, just return.
|
||||||
*/
|
*/
|
||||||
if (!scanstate->tuplestorestate)
|
if (!node->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tuplestore_markpos(scanstate->tuplestorestate);
|
tuplestore_markpos(node->tuplestorestate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -329,19 +316,15 @@ ExecFunctionMarkPos(FunctionScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecFunctionRestrPos(FunctionScan *node)
|
ExecFunctionRestrPos(FunctionScanState *node)
|
||||||
{
|
{
|
||||||
FunctionScanState *scanstate;
|
|
||||||
|
|
||||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we haven't materialized yet, just return.
|
* if we haven't materialized yet, just return.
|
||||||
*/
|
*/
|
||||||
if (!scanstate->tuplestorestate)
|
if (!node->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tuplestore_restorepos(scanstate->tuplestorestate);
|
tuplestore_restorepos(node->tuplestorestate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -351,21 +334,14 @@ ExecFunctionRestrPos(FunctionScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
|
ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
FunctionScanState *scanstate;
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||||
|
|
||||||
/*
|
|
||||||
* get information from node
|
|
||||||
*/
|
|
||||||
scanstate = (FunctionScanState *) node->scan.scanstate;
|
|
||||||
|
|
||||||
ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we haven't materialized yet, just return.
|
* If we haven't materialized yet, just return.
|
||||||
*/
|
*/
|
||||||
if (!scanstate->tuplestorestate)
|
if (!node->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -374,13 +350,13 @@ ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
* whether the function expression contains parameters and/or is
|
* whether the function expression contains parameters and/or is
|
||||||
* marked volatile. FIXME soon.
|
* marked volatile. FIXME soon.
|
||||||
*/
|
*/
|
||||||
if (node->scan.plan.chgParam != NULL)
|
if (node->ss.ps.chgParam != NULL)
|
||||||
{
|
{
|
||||||
tuplestore_end(scanstate->tuplestorestate);
|
tuplestore_end(node->tuplestorestate);
|
||||||
scanstate->tuplestorestate = NULL;
|
node->tuplestorestate = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tuplestore_rescan(scanstate->tuplestorestate);
|
tuplestore_rescan(node->tuplestorestate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* locate group boundaries.
|
* locate group boundaries.
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* Return one tuple for each group of matching input tuples.
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecGroup(Group *node)
|
ExecGroup(GroupState *node)
|
||||||
{
|
{
|
||||||
GroupState *grpstate;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
|
int numCols;
|
||||||
|
AttrNumber *grpColIdx;
|
||||||
HeapTuple outerTuple = NULL;
|
HeapTuple outerTuple = NULL;
|
||||||
HeapTuple firsttuple;
|
HeapTuple firsttuple;
|
||||||
TupleTableSlot *outerslot;
|
TupleTableSlot *outerslot;
|
||||||
@@ -53,12 +54,13 @@ ExecGroup(Group *node)
|
|||||||
/*
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
*/
|
*/
|
||||||
grpstate = node->grpstate;
|
if (node->grp_done)
|
||||||
if (grpstate->grp_done)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
estate = node->plan.state;
|
estate = node->ss.ps.state;
|
||||||
econtext = node->grpstate->csstate.cstate.cs_ExprContext;
|
econtext = node->ss.ps.ps_ExprContext;
|
||||||
tupdesc = ExecGetScanType(&grpstate->csstate);
|
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
|
* 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 */
|
/* If we don't already have first tuple of group, fetch it */
|
||||||
/* this should occur on the first call only */
|
/* this should occur on the first call only */
|
||||||
firsttuple = grpstate->grp_firstTuple;
|
firsttuple = node->grp_firstTuple;
|
||||||
if (firsttuple == NULL)
|
if (firsttuple == NULL)
|
||||||
{
|
{
|
||||||
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
|
outerslot = ExecProcNode(outerPlanState(node));
|
||||||
if (TupIsNull(outerslot))
|
if (TupIsNull(outerslot))
|
||||||
{
|
{
|
||||||
grpstate->grp_done = TRUE;
|
node->grp_done = TRUE;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
grpstate->grp_firstTuple = firsttuple =
|
node->grp_firstTuple = firsttuple =
|
||||||
heap_copytuple(outerslot->val);
|
heap_copytuple(outerslot->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,10 +87,10 @@ ExecGroup(Group *node)
|
|||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
|
outerslot = ExecProcNode(outerPlanState(node));
|
||||||
if (TupIsNull(outerslot))
|
if (TupIsNull(outerslot))
|
||||||
{
|
{
|
||||||
grpstate->grp_done = TRUE;
|
node->grp_done = TRUE;
|
||||||
outerTuple = NULL;
|
outerTuple = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -100,8 +102,8 @@ ExecGroup(Group *node)
|
|||||||
*/
|
*/
|
||||||
if (!execTuplesMatch(firsttuple, outerTuple,
|
if (!execTuplesMatch(firsttuple, outerTuple,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
node->numCols, node->grpColIdx,
|
numCols, grpColIdx,
|
||||||
grpstate->eqfunctions,
|
node->eqfunctions,
|
||||||
econtext->ecxt_per_tuple_memory))
|
econtext->ecxt_per_tuple_memory))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -111,18 +113,18 @@ ExecGroup(Group *node)
|
|||||||
* group, and store it in the result tuple slot.
|
* group, and store it in the result tuple slot.
|
||||||
*/
|
*/
|
||||||
ExecStoreTuple(firsttuple,
|
ExecStoreTuple(firsttuple,
|
||||||
grpstate->csstate.css_ScanTupleSlot,
|
node->ss.ss_ScanTupleSlot,
|
||||||
InvalidBuffer,
|
InvalidBuffer,
|
||||||
false);
|
false);
|
||||||
econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
|
econtext->ecxt_scantuple = node->ss.ss_ScanTupleSlot;
|
||||||
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
projInfo = node->ss.ps.ps_ProjInfo;
|
||||||
resultSlot = ExecProject(projInfo, NULL);
|
resultSlot = ExecProject(projInfo, NULL);
|
||||||
|
|
||||||
/* save first tuple of next group, if we are not done yet */
|
/* save first tuple of next group, if we are not done yet */
|
||||||
if (!grpstate->grp_done)
|
if (!node->grp_done)
|
||||||
{
|
{
|
||||||
heap_freetuple(firsttuple);
|
heap_freetuple(firsttuple);
|
||||||
grpstate->grp_firstTuple = heap_copytuple(outerTuple);
|
node->grp_firstTuple = heap_copytuple(outerTuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
@@ -135,65 +137,69 @@ ExecGroup(Group *node)
|
|||||||
* planner and initializes its outer subtree
|
* planner and initializes its outer subtree
|
||||||
* -----------------
|
* -----------------
|
||||||
*/
|
*/
|
||||||
bool
|
GroupState *
|
||||||
ExecInitGroup(Group *node, EState *estate, Plan *parent)
|
ExecInitGroup(Group *node, EState *estate)
|
||||||
{
|
{
|
||||||
GroupState *grpstate;
|
GroupState *grpstate;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
*/
|
*/
|
||||||
grpstate = makeNode(GroupState);
|
grpstate = makeNode(GroupState);
|
||||||
node->grpstate = grpstate;
|
grpstate->ss.ps.plan = (Plan *) node;
|
||||||
|
grpstate->ss.ps.state = estate;
|
||||||
grpstate->grp_firstTuple = NULL;
|
grpstate->grp_firstTuple = NULL;
|
||||||
grpstate->grp_done = FALSE;
|
grpstate->grp_done = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create expression context
|
* create expression context
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &grpstate->csstate.cstate);
|
ExecAssignExprContext(estate, &grpstate->ss.ps);
|
||||||
|
|
||||||
#define GROUP_NSLOTS 2
|
#define GROUP_NSLOTS 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitScanTupleSlot(estate, &grpstate->csstate);
|
ExecInitScanTupleSlot(estate, &grpstate->ss);
|
||||||
ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &grpstate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initializes child nodes
|
* initialize child expressions
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan(node);
|
grpstate->ss.ps.targetlist = (List *)
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
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.
|
* initialize tuple type.
|
||||||
*/
|
*/
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
|
ExecAssignScanTypeFromOuterPlan(&grpstate->ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize tuple type for both result and scan. This node does no
|
* Initialize tuple type for both result and scan. This node does no
|
||||||
* projection
|
* projection
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);
|
ExecAssignResultTypeFromTL(&grpstate->ss.ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);
|
ExecAssignProjectionInfo(&grpstate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precompute fmgr lookup data for inner loop
|
* Precompute fmgr lookup data for inner loop
|
||||||
*/
|
*/
|
||||||
grpstate->eqfunctions =
|
grpstate->eqfunctions =
|
||||||
execTuplesMatchPrepare(ExecGetScanType(&grpstate->csstate),
|
execTuplesMatchPrepare(ExecGetScanType(&grpstate->ss),
|
||||||
node->numCols,
|
node->numCols,
|
||||||
node->grpColIdx);
|
node->grpColIdx);
|
||||||
|
|
||||||
return TRUE;
|
return grpstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -208,43 +214,38 @@ ExecCountSlotsGroup(Group *node)
|
|||||||
* -----------------------
|
* -----------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndGroup(Group *node)
|
ExecEndGroup(GroupState *node)
|
||||||
{
|
{
|
||||||
GroupState *grpstate;
|
PlanState *outerPlan;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
grpstate = node->grpstate;
|
ExecFreeProjectionInfo(&node->ss.ps);
|
||||||
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
ExecFreeProjectionInfo(&grpstate->csstate.cstate);
|
outerPlan = outerPlanState(node);
|
||||||
ExecFreeExprContext(&grpstate->csstate.cstate);
|
ExecEndNode(outerPlan);
|
||||||
|
|
||||||
outerPlan = outerPlan(node);
|
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
if (grpstate->grp_firstTuple != NULL)
|
if (node->grp_firstTuple != NULL)
|
||||||
{
|
{
|
||||||
heap_freetuple(grpstate->grp_firstTuple);
|
heap_freetuple(node->grp_firstTuple);
|
||||||
grpstate->grp_firstTuple = NULL;
|
node->grp_firstTuple = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanGroup(GroupState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
GroupState *grpstate = node->grpstate;
|
node->grp_done = FALSE;
|
||||||
|
if (node->grp_firstTuple != NULL)
|
||||||
grpstate->grp_done = FALSE;
|
|
||||||
if (grpstate->grp_firstTuple != NULL)
|
|
||||||
{
|
{
|
||||||
heap_freetuple(grpstate->grp_firstTuple);
|
heap_freetuple(node->grp_firstTuple);
|
||||||
grpstate->grp_firstTuple = NULL;
|
node->grp_firstTuple = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((Plan *) node)->lefttree &&
|
if (((PlanState *) node)->lefttree &&
|
||||||
((Plan *) node)->lefttree->chgParam == NULL)
|
((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *
|
TupleTableSlot *
|
||||||
ExecHash(Hash *node)
|
ExecHash(HashState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
HashState *hashstate;
|
PlanState *outerNode;
|
||||||
Plan *outerNode;
|
|
||||||
List *hashkeys;
|
List *hashkeys;
|
||||||
HashJoinTable hashtable;
|
HashJoinTable hashtable;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
@@ -55,12 +54,10 @@ ExecHash(Hash *node)
|
|||||||
/*
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
*/
|
*/
|
||||||
|
estate = node->ps.state;
|
||||||
|
outerNode = outerPlanState(node);
|
||||||
|
|
||||||
hashstate = node->hashstate;
|
hashtable = node->hashtable;
|
||||||
estate = node->plan.state;
|
|
||||||
outerNode = outerPlan(node);
|
|
||||||
|
|
||||||
hashtable = hashstate->hashtable;
|
|
||||||
if (hashtable == NULL)
|
if (hashtable == NULL)
|
||||||
elog(ERROR, "ExecHash: hash table is NULL.");
|
elog(ERROR, "ExecHash: hash table is NULL.");
|
||||||
|
|
||||||
@@ -79,15 +76,15 @@ ExecHash(Hash *node)
|
|||||||
/*
|
/*
|
||||||
* set expression context
|
* set expression context
|
||||||
*/
|
*/
|
||||||
hashkeys = node->hashkeys;
|
hashkeys = ((Hash *) node->ps.plan)->hashkeys;
|
||||||
econtext = hashstate->cstate.cs_ExprContext;
|
econtext = node->ps.ps_ExprContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get all inner tuples and insert into the hash table (or temp files)
|
* get all inner tuples and insert into the hash table (or temp files)
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
slot = ExecProcNode(outerNode, (Plan *) node);
|
slot = ExecProcNode(outerNode);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
break;
|
break;
|
||||||
econtext->ecxt_innertuple = slot;
|
econtext->ecxt_innertuple = slot;
|
||||||
@@ -108,24 +105,19 @@ ExecHash(Hash *node)
|
|||||||
* Init routine for Hash node
|
* Init routine for Hash node
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
HashState *
|
||||||
ExecInitHash(Hash *node, EState *estate, Plan *parent)
|
ExecInitHash(Hash *node, EState *estate)
|
||||||
{
|
{
|
||||||
HashState *hashstate;
|
HashState *hashstate;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
SO_printf("ExecInitHash: initializing hash node\n");
|
SO_printf("ExecInitHash: initializing hash node\n");
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
*/
|
*/
|
||||||
hashstate = makeNode(HashState);
|
hashstate = makeNode(HashState);
|
||||||
node->hashstate = hashstate;
|
hashstate->ps.plan = (Plan *) node;
|
||||||
|
hashstate->ps.state = estate;
|
||||||
hashstate->hashtable = NULL;
|
hashstate->hashtable = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -133,29 +125,38 @@ ExecInitHash(Hash *node, EState *estate, Plan *parent)
|
|||||||
*
|
*
|
||||||
* create expression context for node
|
* create expression context for node
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &hashstate->cstate);
|
ExecAssignExprContext(estate, &hashstate->ps);
|
||||||
|
|
||||||
#define HASH_NSLOTS 1
|
#define HASH_NSLOTS 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize our result slot
|
* initialize our result slot
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &hashstate->cstate);
|
ExecInitResultTupleSlot(estate, &hashstate->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initializes child nodes
|
* initialize child expressions
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan(node);
|
hashstate->ps.targetlist = (List *)
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
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
|
* initialize tuple type. no need to initialize projection info
|
||||||
* because this node doesn't do projections
|
* because this node doesn't do projections
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
|
ExecAssignResultTypeFromOuterPlan(&hashstate->ps);
|
||||||
hashstate->cstate.cs_ProjInfo = NULL;
|
hashstate->ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return hashstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -173,28 +174,22 @@ ExecCountSlotsHash(Hash *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndHash(Hash *node)
|
ExecEndHash(HashState *node)
|
||||||
{
|
{
|
||||||
HashState *hashstate;
|
PlanState *outerPlan;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get info from the hash state
|
|
||||||
*/
|
|
||||||
hashstate = node->hashstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free projection info. no need to free result type info because
|
* free projection info. no need to free result type info because
|
||||||
* that came from the outer plan...
|
* that came from the outer plan...
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&hashstate->cstate);
|
ExecFreeProjectionInfo(&node->ps);
|
||||||
ExecFreeExprContext(&hashstate->cstate);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* shut down the subplan
|
* shut down the subplan
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlanState(node);
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
ExecEndNode(outerPlan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -758,12 +753,12 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
static TupleTableSlot *ExecHashJoinOuterGetTuple(PlanState *node,
|
||||||
HashJoinState *hjstate);
|
HashJoinState *hjstate);
|
||||||
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||||
BufFile *file,
|
BufFile *file,
|
||||||
TupleTableSlot *tupleSlot);
|
TupleTableSlot *tupleSlot);
|
||||||
@@ -41,12 +41,11 @@ static int ExecHashJoinNewBatch(HashJoinState *hjstate);
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot * /* return: a tuple or NULL */
|
TupleTableSlot * /* return: a tuple or NULL */
|
||||||
ExecHashJoin(HashJoin *node)
|
ExecHashJoin(HashJoinState *node)
|
||||||
{
|
{
|
||||||
HashJoinState *hjstate;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
Plan *outerNode;
|
PlanState *outerNode;
|
||||||
Hash *hashNode;
|
HashState *hashNode;
|
||||||
List *hjclauses;
|
List *hjclauses;
|
||||||
List *outerkeys;
|
List *outerkeys;
|
||||||
List *joinqual;
|
List *joinqual;
|
||||||
@@ -65,37 +64,36 @@ ExecHashJoin(HashJoin *node)
|
|||||||
/*
|
/*
|
||||||
* get information from HashJoin node
|
* get information from HashJoin node
|
||||||
*/
|
*/
|
||||||
hjstate = node->hashjoinstate;
|
|
||||||
hjclauses = node->hashclauses;
|
hjclauses = node->hashclauses;
|
||||||
estate = node->join.plan.state;
|
estate = node->js.ps.state;
|
||||||
joinqual = node->join.joinqual;
|
joinqual = node->js.joinqual;
|
||||||
otherqual = node->join.plan.qual;
|
otherqual = node->js.ps.qual;
|
||||||
hashNode = (Hash *) innerPlan(node);
|
hashNode = (HashState *) innerPlanState(node);
|
||||||
outerNode = outerPlan(node);
|
outerNode = outerPlanState(node);
|
||||||
hashPhaseDone = hjstate->hj_hashdone;
|
hashPhaseDone = node->hj_hashdone;
|
||||||
dir = estate->es_direction;
|
dir = estate->es_direction;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from HashJoin state
|
* get information from HashJoin state
|
||||||
*/
|
*/
|
||||||
hashtable = hjstate->hj_HashTable;
|
hashtable = node->hj_HashTable;
|
||||||
outerkeys = hjstate->hj_OuterHashKeys;
|
outerkeys = node->hj_OuterHashKeys;
|
||||||
econtext = hjstate->jstate.cs_ExprContext;
|
econtext = node->js.ps.ps_ExprContext;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if we're still projecting out tuples from a previous
|
* Check to see if we're still projecting out tuples from a previous
|
||||||
* join tuple (because there is a function-returning-set in the
|
* join tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
*/
|
*/
|
||||||
if (hjstate->jstate.cs_TupFromTlist)
|
if (node->js.ps.ps_TupFromTlist)
|
||||||
{
|
{
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
|
||||||
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
if (isDone == ExprMultipleResult)
|
if (isDone == ExprMultipleResult)
|
||||||
return result;
|
return result;
|
||||||
/* Done with that source tuple... */
|
/* 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
|
* create the hash table
|
||||||
*/
|
*/
|
||||||
hashtable = ExecHashTableCreate(hashNode);
|
hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan);
|
||||||
hjstate->hj_HashTable = hashtable;
|
node->hj_HashTable = hashtable;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* execute the Hash node, to build the hash table
|
* execute the Hash node, to build the hash table
|
||||||
*/
|
*/
|
||||||
hashNode->hashstate->hashtable = hashtable;
|
hashNode->hashtable = hashtable;
|
||||||
innerTupleSlot = ExecProcNode((Plan *) hashNode, (Plan *) node);
|
innerTupleSlot = ExecProcNode((PlanState *) hashNode);
|
||||||
}
|
}
|
||||||
hjstate->hj_hashdone = true;
|
node->hj_hashdone = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open temp files for outer batches, if needed. Note that file
|
* 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
|
* 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 (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we don't have an outer tuple, get the next one
|
* If we don't have an outer tuple, get the next one
|
||||||
*/
|
*/
|
||||||
if (hjstate->hj_NeedNewOuter)
|
if (node->hj_NeedNewOuter)
|
||||||
{
|
{
|
||||||
outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,
|
outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,
|
||||||
(Plan *) node,
|
node);
|
||||||
hjstate);
|
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* when the last batch runs out, clean up and exit
|
* when the last batch runs out, clean up and exit
|
||||||
*/
|
*/
|
||||||
ExecHashTableDestroy(hashtable);
|
ExecHashTableDestroy(hashtable);
|
||||||
hjstate->hj_HashTable = NULL;
|
node->hj_HashTable = NULL;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hjstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
|
node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
hjstate->hj_NeedNewOuter = false;
|
node->hj_NeedNewOuter = false;
|
||||||
hjstate->hj_MatchedOuter = false;
|
node->hj_MatchedOuter = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now we have an outer tuple, find the corresponding bucket
|
* now we have an outer tuple, find the corresponding bucket
|
||||||
* for this tuple from the hash table
|
* for this tuple from the hash table
|
||||||
*/
|
*/
|
||||||
hjstate->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
node->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
||||||
outerkeys);
|
outerkeys);
|
||||||
hjstate->hj_CurTuple = NULL;
|
node->hj_CurTuple = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we've got an outer tuple and the corresponding hash
|
* Now we've got an outer tuple and the corresponding hash
|
||||||
@@ -182,7 +179,7 @@ ExecHashJoin(HashJoin *node)
|
|||||||
*/
|
*/
|
||||||
if (hashtable->curbatch == 0)
|
if (hashtable->curbatch == 0)
|
||||||
{
|
{
|
||||||
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
|
int batch = ExecHashJoinGetBatch(node->hj_CurBucketNo,
|
||||||
hashtable);
|
hashtable);
|
||||||
|
|
||||||
if (batch > 0)
|
if (batch > 0)
|
||||||
@@ -196,7 +193,7 @@ ExecHashJoin(HashJoin *node)
|
|||||||
hashtable->outerBatchSize[batchno]++;
|
hashtable->outerBatchSize[batchno]++;
|
||||||
ExecHashJoinSaveTuple(outerTupleSlot->val,
|
ExecHashJoinSaveTuple(outerTupleSlot->val,
|
||||||
hashtable->outerBatchFile[batchno]);
|
hashtable->outerBatchFile[batchno]);
|
||||||
hjstate->hj_NeedNewOuter = true;
|
node->hj_NeedNewOuter = true;
|
||||||
continue; /* loop around for a new outer tuple */
|
continue; /* loop around for a new outer tuple */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +204,7 @@ ExecHashJoin(HashJoin *node)
|
|||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
curtuple = ExecScanHashBucket(hjstate,
|
curtuple = ExecScanHashBucket(node,
|
||||||
hjclauses,
|
hjclauses,
|
||||||
econtext);
|
econtext);
|
||||||
if (curtuple == NULL)
|
if (curtuple == NULL)
|
||||||
@@ -217,7 +214,7 @@ ExecHashJoin(HashJoin *node)
|
|||||||
* we've got a match, but still need to test non-hashed quals
|
* we've got a match, but still need to test non-hashed quals
|
||||||
*/
|
*/
|
||||||
inntuple = ExecStoreTuple(curtuple,
|
inntuple = ExecStoreTuple(curtuple,
|
||||||
hjstate->hj_HashTupleSlot,
|
node->hj_HashTupleSlot,
|
||||||
InvalidBuffer,
|
InvalidBuffer,
|
||||||
false); /* don't pfree this tuple */
|
false); /* don't pfree this tuple */
|
||||||
econtext->ecxt_innertuple = inntuple;
|
econtext->ecxt_innertuple = inntuple;
|
||||||
@@ -235,17 +232,17 @@ ExecHashJoin(HashJoin *node)
|
|||||||
*/
|
*/
|
||||||
if (ExecQual(joinqual, econtext, false))
|
if (ExecQual(joinqual, econtext, false))
|
||||||
{
|
{
|
||||||
hjstate->hj_MatchedOuter = true;
|
node->hj_MatchedOuter = true;
|
||||||
|
|
||||||
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
|
||||||
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
hjstate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -258,10 +255,10 @@ ExecHashJoin(HashJoin *node)
|
|||||||
* whether to emit a dummy outer-join tuple. If not, loop around
|
* whether to emit a dummy outer-join tuple. If not, loop around
|
||||||
* to get a new outer tuple.
|
* to get a new outer tuple.
|
||||||
*/
|
*/
|
||||||
hjstate->hj_NeedNewOuter = true;
|
node->hj_NeedNewOuter = true;
|
||||||
|
|
||||||
if (!hjstate->hj_MatchedOuter &&
|
if (!node->hj_MatchedOuter &&
|
||||||
node->join.jointype == JOIN_LEFT)
|
node->js.jointype == JOIN_LEFT)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We are doing an outer join and there were no join matches
|
* 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
|
* nulls for the inner tuple, and return it if it passes the
|
||||||
* non-join quals.
|
* non-join quals.
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_innertuple = hjstate->hj_NullInnerTupleSlot;
|
econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
@@ -280,11 +277,11 @@ ExecHashJoin(HashJoin *node)
|
|||||||
*/
|
*/
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
|
||||||
result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
hjstate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -299,47 +296,60 @@ ExecHashJoin(HashJoin *node)
|
|||||||
* Init routine for HashJoin node.
|
* Init routine for HashJoin node.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool /* return: initialization status */
|
HashJoinState *
|
||||||
ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
ExecInitHashJoin(HashJoin *node, EState *estate)
|
||||||
{
|
{
|
||||||
HashJoinState *hjstate;
|
HashJoinState *hjstate;
|
||||||
Plan *outerNode;
|
Plan *outerNode;
|
||||||
Hash *hashNode;
|
Hash *hashNode;
|
||||||
List *hcl;
|
List *hcl;
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->join.plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
*/
|
*/
|
||||||
hjstate = makeNode(HashJoinState);
|
hjstate = makeNode(HashJoinState);
|
||||||
node->hashjoinstate = hjstate;
|
hjstate->js.ps.plan = (Plan *) node;
|
||||||
|
hjstate->js.ps.state = estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* create expression context for node
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &hjstate->jstate);
|
ExecAssignExprContext(estate, &hjstate->js.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initializes child nodes
|
* initialize child expressions
|
||||||
*/
|
*/
|
||||||
outerNode = outerPlan((Plan *) node);
|
hjstate->js.ps.targetlist = (List *)
|
||||||
hashNode = (Hash *) innerPlan((Plan *) node);
|
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
|
#define HASHJOIN_NSLOTS 3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &hjstate->jstate);
|
ExecInitResultTupleSlot(estate, &hjstate->js.ps);
|
||||||
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
|
hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);
|
||||||
|
|
||||||
switch (node->join.jointype)
|
switch (node->join.jointype)
|
||||||
@@ -349,7 +359,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
case JOIN_LEFT:
|
case JOIN_LEFT:
|
||||||
hjstate->hj_NullInnerTupleSlot =
|
hjstate->hj_NullInnerTupleSlot =
|
||||||
ExecInitNullTupleSlot(estate,
|
ExecInitNullTupleSlot(estate,
|
||||||
ExecGetTupType((Plan *) hashNode));
|
ExecGetTupType(innerPlanState(hjstate)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecInitHashJoin: unsupported join type %d",
|
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
|
* the contents of the hash table. -cim 6/9/91
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
HashState *hashstate = hashNode->hashstate;
|
HashState *hashstate = (HashState *) innerPlanState(hjstate);
|
||||||
TupleTableSlot *slot = hashstate->cstate.cs_ResultTupleSlot;
|
TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;
|
||||||
|
|
||||||
hjstate->hj_HashTupleSlot = slot;
|
hjstate->hj_HashTupleSlot = slot;
|
||||||
}
|
}
|
||||||
@@ -373,11 +383,11 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &hjstate->jstate);
|
ExecAssignResultTypeFromTL(&hjstate->js.ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
|
ExecAssignProjectionInfo(&hjstate->js.ps);
|
||||||
|
|
||||||
ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
|
ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
|
||||||
ExecGetTupType(outerNode),
|
ExecGetTupType(outerPlanState(hjstate)),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -402,12 +412,12 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
|
|||||||
get_leftop(lfirst(hcl)));
|
get_leftop(lfirst(hcl)));
|
||||||
}
|
}
|
||||||
|
|
||||||
hjstate->jstate.cs_OuterTupleSlot = NULL;
|
hjstate->js.ps.ps_OuterTupleSlot = NULL;
|
||||||
hjstate->jstate.cs_TupFromTlist = false;
|
hjstate->js.ps.ps_TupFromTlist = false;
|
||||||
hjstate->hj_NeedNewOuter = true;
|
hjstate->hj_NeedNewOuter = true;
|
||||||
hjstate->hj_MatchedOuter = false;
|
hjstate->hj_MatchedOuter = false;
|
||||||
|
|
||||||
return TRUE;
|
return hjstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -425,46 +435,35 @@ ExecCountSlotsHashJoin(HashJoin *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
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
|
* 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);
|
ExecHashTableDestroy(node->hj_HashTable);
|
||||||
hjstate->hj_HashTable = NULL;
|
node->hj_HashTable = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* 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);
|
ExecFreeProjectionInfo(&node->js.ps);
|
||||||
ExecFreeExprContext(&hjstate->jstate);
|
ExecFreeExprContext(&node->js.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean up subtrees
|
* clean up subtrees
|
||||||
*/
|
*/
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(outerPlanState(node));
|
||||||
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(innerPlanState(node));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||||
ExecClearTuple(hjstate->hj_OuterTupleSlot);
|
ExecClearTuple(node->hj_OuterTupleSlot);
|
||||||
ExecClearTuple(hjstate->hj_HashTupleSlot);
|
ExecClearTuple(node->hj_HashTupleSlot);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +477,7 @@ ExecEndHashJoin(HashJoin *node)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
ExecHashJoinOuterGetTuple(PlanState *node, HashJoinState *hjstate)
|
||||||
{
|
{
|
||||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||||
int curbatch = hashtable->curbatch;
|
int curbatch = hashtable->curbatch;
|
||||||
@@ -486,7 +485,7 @@ ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
|||||||
|
|
||||||
if (curbatch == 0)
|
if (curbatch == 0)
|
||||||
{ /* if it is the first pass */
|
{ /* if it is the first pass */
|
||||||
slot = ExecProcNode(node, parent);
|
slot = ExecProcNode(node);
|
||||||
if (!TupIsNull(slot))
|
if (!TupIsNull(slot))
|
||||||
return slot;
|
return slot;
|
||||||
|
|
||||||
@@ -611,7 +610,7 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
|||||||
*/
|
*/
|
||||||
ExecHashTableReset(hashtable, innerBatchSize[newbatch - 1]);
|
ExecHashTableReset(hashtable, innerBatchSize[newbatch - 1]);
|
||||||
|
|
||||||
econtext = hjstate->jstate.cs_ExprContext;
|
econtext = hjstate->js.ps.ps_ExprContext;
|
||||||
innerhashkeys = hjstate->hj_InnerHashKeys;
|
innerhashkeys = hjstate->hj_InnerHashKeys;
|
||||||
|
|
||||||
while ((slot = ExecHashJoinGetSavedTuple(hjstate,
|
while ((slot = ExecHashJoinGetSavedTuple(hjstate,
|
||||||
@@ -682,39 +681,37 @@ ExecHashJoinSaveTuple(HeapTuple heapTuple,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
HashJoinState *hjstate = node->hashjoinstate;
|
if (!node->hj_hashdone)
|
||||||
|
|
||||||
if (!hjstate->hj_hashdone)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hjstate->hj_hashdone = false;
|
node->hj_hashdone = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unfortunately, currently we have to destroy hashtable in all
|
* Unfortunately, currently we have to destroy hashtable in all
|
||||||
* cases...
|
* cases...
|
||||||
*/
|
*/
|
||||||
if (hjstate->hj_HashTable)
|
if (node->hj_HashTable)
|
||||||
{
|
{
|
||||||
ExecHashTableDestroy(hjstate->hj_HashTable);
|
ExecHashTableDestroy(node->hj_HashTable);
|
||||||
hjstate->hj_HashTable = NULL;
|
node->hj_HashTable = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hjstate->hj_CurBucketNo = 0;
|
node->hj_CurBucketNo = 0;
|
||||||
hjstate->hj_CurTuple = (HashJoinTuple) NULL;
|
node->hj_CurTuple = (HashJoinTuple) NULL;
|
||||||
|
|
||||||
hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
|
node->js.ps.ps_OuterTupleSlot = (TupleTableSlot *) NULL;
|
||||||
hjstate->jstate.cs_TupFromTlist = false;
|
node->js.ps.ps_TupFromTlist = false;
|
||||||
hjstate->hj_NeedNewOuter = true;
|
node->hj_NeedNewOuter = true;
|
||||||
hjstate->hj_MatchedOuter = false;
|
node->hj_MatchedOuter = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnodes is not null then plans will be re-scanned
|
* if chgParam of subnodes is not null then plans will be re-scanned
|
||||||
* by first ExecProcNode.
|
* by first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
if (((Plan *) node)->righttree->chgParam == NULL)
|
if (((PlanState *) node)->righttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->righttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->righttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 LEFT_OP 1
|
||||||
#define RIGHT_OP 2
|
#define RIGHT_OP 2
|
||||||
|
|
||||||
static TupleTableSlot *IndexNext(IndexScan *node);
|
static TupleTableSlot *IndexNext(IndexScanState *node);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* IndexNext
|
* IndexNext
|
||||||
@@ -65,15 +65,14 @@ static TupleTableSlot *IndexNext(IndexScan *node);
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
IndexNext(IndexScan *node)
|
IndexNext(IndexScanState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
CommonScanState *scanstate;
|
|
||||||
IndexScanState *indexstate;
|
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
IndexScanDescPtr scanDescs;
|
IndexScanDescPtr scanDescs;
|
||||||
IndexScanDesc scandesc;
|
IndexScanDesc scandesc;
|
||||||
|
Index scanrelid;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
int numIndices;
|
int numIndices;
|
||||||
@@ -83,21 +82,20 @@ IndexNext(IndexScan *node)
|
|||||||
/*
|
/*
|
||||||
* extract necessary information from index scan node
|
* extract necessary information from index scan node
|
||||||
*/
|
*/
|
||||||
estate = node->scan.plan.state;
|
estate = node->ss.ps.state;
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
if (ScanDirectionIsBackward(node->indxorderdir))
|
if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
|
||||||
{
|
{
|
||||||
if (ScanDirectionIsForward(direction))
|
if (ScanDirectionIsForward(direction))
|
||||||
direction = BackwardScanDirection;
|
direction = BackwardScanDirection;
|
||||||
else if (ScanDirectionIsBackward(direction))
|
else if (ScanDirectionIsBackward(direction))
|
||||||
direction = ForwardScanDirection;
|
direction = ForwardScanDirection;
|
||||||
}
|
}
|
||||||
scanstate = node->scan.scanstate;
|
scanDescs = node->iss_ScanDescs;
|
||||||
indexstate = node->indxstate;
|
numIndices = node->iss_NumIndices;
|
||||||
scanDescs = indexstate->iss_ScanDescs;
|
econtext = node->ss.ps.ps_ExprContext;
|
||||||
numIndices = indexstate->iss_NumIndices;
|
slot = node->ss.ss_ScanTupleSlot;
|
||||||
econtext = scanstate->cstate.cs_ExprContext;
|
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||||
slot = scanstate->css_ScanTupleSlot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||||
@@ -106,15 +104,15 @@ IndexNext(IndexScan *node)
|
|||||||
* switching in Init/ReScan plan...
|
* switching in Init/ReScan plan...
|
||||||
*/
|
*/
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
List *qual;
|
List *qual;
|
||||||
|
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
if (estate->es_evTupleNull[scanrelid - 1])
|
||||||
return slot; /* return empty slot */
|
return slot; /* return empty slot */
|
||||||
|
|
||||||
ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
|
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
|
||||||
slot, InvalidBuffer, false);
|
slot, InvalidBuffer, false);
|
||||||
|
|
||||||
/* Does the tuple meet any of the OR'd indxqual conditions? */
|
/* Does the tuple meet any of the OR'd indxqual conditions? */
|
||||||
@@ -131,7 +129,7 @@ IndexNext(IndexScan *node)
|
|||||||
slot->val = NULL;
|
slot->val = NULL;
|
||||||
|
|
||||||
/* Flag for the next call that no more tuples */
|
/* 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;
|
return slot;
|
||||||
}
|
}
|
||||||
@@ -144,24 +142,24 @@ IndexNext(IndexScan *node)
|
|||||||
bBackward = ScanDirectionIsBackward(direction);
|
bBackward = ScanDirectionIsBackward(direction);
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
{
|
{
|
||||||
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
|
indexNumber = numIndices - node->iss_IndexPtr - 1;
|
||||||
if (indexNumber < 0)
|
if (indexNumber < 0)
|
||||||
{
|
{
|
||||||
indexNumber = 0;
|
indexNumber = 0;
|
||||||
indexstate->iss_IndexPtr = numIndices - 1;
|
node->iss_IndexPtr = numIndices - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
|
if ((indexNumber = node->iss_IndexPtr) < 0)
|
||||||
{
|
{
|
||||||
indexNumber = 0;
|
indexNumber = 0;
|
||||||
indexstate->iss_IndexPtr = 0;
|
node->iss_IndexPtr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (indexNumber < numIndices)
|
while (indexNumber < numIndices)
|
||||||
{
|
{
|
||||||
scandesc = scanDescs[indexstate->iss_IndexPtr];
|
scandesc = scanDescs[node->iss_IndexPtr];
|
||||||
while ((tuple = index_getnext(scandesc, direction)) != NULL)
|
while ((tuple = index_getnext(scandesc, direction)) != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -181,7 +179,7 @@ IndexNext(IndexScan *node)
|
|||||||
* We do this by passing the tuple through ExecQual and
|
* We do this by passing the tuple through ExecQual and
|
||||||
* checking for failure with all previous qualifications.
|
* checking for failure with all previous qualifications.
|
||||||
*/
|
*/
|
||||||
if (indexstate->iss_IndexPtr > 0)
|
if (node->iss_IndexPtr > 0)
|
||||||
{
|
{
|
||||||
bool prev_matches = false;
|
bool prev_matches = false;
|
||||||
int prev_index;
|
int prev_index;
|
||||||
@@ -191,7 +189,7 @@ IndexNext(IndexScan *node)
|
|||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
qual = node->indxqualorig;
|
qual = node->indxqualorig;
|
||||||
for (prev_index = 0;
|
for (prev_index = 0;
|
||||||
prev_index < indexstate->iss_IndexPtr;
|
prev_index < node->iss_IndexPtr;
|
||||||
prev_index++)
|
prev_index++)
|
||||||
{
|
{
|
||||||
if (ExecQual((List *) lfirst(qual), econtext, false))
|
if (ExecQual((List *) lfirst(qual), econtext, false))
|
||||||
@@ -216,9 +214,9 @@ IndexNext(IndexScan *node)
|
|||||||
{
|
{
|
||||||
indexNumber++;
|
indexNumber++;
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
indexstate->iss_IndexPtr--;
|
node->iss_IndexPtr--;
|
||||||
else
|
else
|
||||||
indexstate->iss_IndexPtr++;
|
node->iss_IndexPtr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,21 +249,19 @@ IndexNext(IndexScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
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
|
* If we have runtime keys and they've not already been set up, do it
|
||||||
* now.
|
* now.
|
||||||
*/
|
*/
|
||||||
if (indexstate->iss_RuntimeKeyInfo && !indexstate->iss_RuntimeKeysReady)
|
if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady)
|
||||||
ExecReScan((Plan *) node, NULL, NULL);
|
ExecReScan((PlanState *) node, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* use IndexNext as access method
|
* 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
|
void
|
||||||
ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
IndexScanState *indexstate;
|
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
int numIndices;
|
int numIndices;
|
||||||
IndexScanDescPtr scanDescs;
|
IndexScanDescPtr scanDescs;
|
||||||
ScanKey *scanKeys;
|
ScanKey *scanKeys;
|
||||||
int **runtimeKeyInfo;
|
int **runtimeKeyInfo;
|
||||||
int *numScanKeys;
|
int *numScanKeys;
|
||||||
|
Index scanrelid;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
estate = node->scan.plan.state;
|
estate = node->ss.ps.state;
|
||||||
indexstate = node->indxstate;
|
econtext = node->iss_RuntimeContext; /* context for runtime keys */
|
||||||
econtext = indexstate->iss_RuntimeContext; /* context for runtime
|
numIndices = node->iss_NumIndices;
|
||||||
* keys */
|
scanDescs = node->iss_ScanDescs;
|
||||||
numIndices = indexstate->iss_NumIndices;
|
scanKeys = node->iss_ScanKeys;
|
||||||
scanDescs = indexstate->iss_ScanDescs;
|
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
|
||||||
scanKeys = indexstate->iss_ScanKeys;
|
numScanKeys = node->iss_NumScanKeys;
|
||||||
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
|
scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||||
numScanKeys = indexstate->iss_NumScanKeys;
|
|
||||||
|
|
||||||
if (econtext)
|
if (econtext)
|
||||||
{
|
{
|
||||||
@@ -315,7 +310,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
ExprContext *stdecontext;
|
ExprContext *stdecontext;
|
||||||
|
|
||||||
econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
|
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;
|
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 this is re-scanning of PlanQual ... */
|
||||||
if (estate->es_evTuple != NULL &&
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset index scans */
|
/* reset index scans */
|
||||||
if (ScanDirectionIsBackward(node->indxorderdir))
|
if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indxorderdir))
|
||||||
indexstate->iss_IndexPtr = numIndices;
|
node->iss_IndexPtr = numIndices;
|
||||||
else
|
else
|
||||||
indexstate->iss_IndexPtr = -1;
|
node->iss_IndexPtr = -1;
|
||||||
|
|
||||||
for (i = 0; i < numIndices; i++)
|
for (i = 0; i < numIndices; i++)
|
||||||
{
|
{
|
||||||
@@ -427,13 +422,10 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndIndexScan(IndexScan *node)
|
ExecEndIndexScan(IndexScanState *node)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
IndexScanState *indexstate;
|
|
||||||
int **runtimeKeyInfo;
|
int **runtimeKeyInfo;
|
||||||
ScanKey *scanKeys;
|
ScanKey *scanKeys;
|
||||||
List *indxqual;
|
|
||||||
int *numScanKeys;
|
int *numScanKeys;
|
||||||
int numIndices;
|
int numIndices;
|
||||||
Relation relation;
|
Relation relation;
|
||||||
@@ -441,32 +433,25 @@ ExecEndIndexScan(IndexScan *node)
|
|||||||
IndexScanDescPtr indexScanDescs;
|
IndexScanDescPtr indexScanDescs;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
scanstate = node->scan.scanstate;
|
runtimeKeyInfo = node->iss_RuntimeKeyInfo;
|
||||||
indexstate = node->indxstate;
|
|
||||||
indxqual = node->indxqual;
|
|
||||||
runtimeKeyInfo = indexstate->iss_RuntimeKeyInfo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extract information from the node
|
* extract information from the node
|
||||||
*/
|
*/
|
||||||
numIndices = indexstate->iss_NumIndices;
|
numIndices = node->iss_NumIndices;
|
||||||
scanKeys = indexstate->iss_ScanKeys;
|
scanKeys = node->iss_ScanKeys;
|
||||||
numScanKeys = indexstate->iss_NumScanKeys;
|
numScanKeys = node->iss_NumScanKeys;
|
||||||
indexRelationDescs = indexstate->iss_RelationDescs;
|
indexRelationDescs = node->iss_RelationDescs;
|
||||||
indexScanDescs = indexstate->iss_ScanDescs;
|
indexScanDescs = node->iss_ScanDescs;
|
||||||
relation = scanstate->css_currentRelation;
|
relation = node->ss.ss_currentRelation;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* 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);
|
ExecFreeProjectionInfo(&node->ss.ps);
|
||||||
ExecFreeExprContext(&scanstate->cstate);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
if (indexstate->iss_RuntimeContext)
|
if (node->iss_RuntimeContext)
|
||||||
FreeExprContext(indexstate->iss_RuntimeContext);
|
FreeExprContext(node->iss_RuntimeContext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close the index relations
|
* close the index relations
|
||||||
@@ -514,12 +499,11 @@ ExecEndIndexScan(IndexScan *node)
|
|||||||
/*
|
/*
|
||||||
* clear out tuple table slots
|
* clear out tuple table slots
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
pfree(scanstate);
|
pfree(node->iss_RelationDescs);
|
||||||
pfree(indexstate->iss_RelationDescs);
|
pfree(node->iss_ScanDescs);
|
||||||
pfree(indexstate->iss_ScanDescs);
|
pfree(node);
|
||||||
pfree(indexstate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -531,21 +515,16 @@ ExecEndIndexScan(IndexScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecIndexMarkPos(IndexScan *node)
|
ExecIndexMarkPos(IndexScanState *node)
|
||||||
{
|
{
|
||||||
IndexScanState *indexstate;
|
|
||||||
IndexScanDescPtr indexScanDescs;
|
IndexScanDescPtr indexScanDescs;
|
||||||
IndexScanDesc scanDesc;
|
IndexScanDesc scanDesc;
|
||||||
int indexPtr;
|
int indexPtr;
|
||||||
|
|
||||||
indexstate = node->indxstate;
|
indexPtr = node->iss_MarkIndexPtr = node->iss_IndexPtr;
|
||||||
indexPtr = indexstate->iss_MarkIndexPtr = indexstate->iss_IndexPtr;
|
indexScanDescs = node->iss_ScanDescs;
|
||||||
indexScanDescs = indexstate->iss_ScanDescs;
|
|
||||||
scanDesc = indexScanDescs[indexPtr];
|
scanDesc = indexScanDescs[indexPtr];
|
||||||
|
|
||||||
#ifdef NOT_USED
|
|
||||||
IndexScanMarkPosition(scanDesc);
|
|
||||||
#endif
|
|
||||||
index_markpos(scanDesc);
|
index_markpos(scanDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,21 +539,16 @@ ExecIndexMarkPos(IndexScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecIndexRestrPos(IndexScan *node)
|
ExecIndexRestrPos(IndexScanState *node)
|
||||||
{
|
{
|
||||||
IndexScanState *indexstate;
|
|
||||||
IndexScanDescPtr indexScanDescs;
|
IndexScanDescPtr indexScanDescs;
|
||||||
IndexScanDesc scanDesc;
|
IndexScanDesc scanDesc;
|
||||||
int indexPtr;
|
int indexPtr;
|
||||||
|
|
||||||
indexstate = node->indxstate;
|
indexPtr = node->iss_IndexPtr = node->iss_MarkIndexPtr;
|
||||||
indexPtr = indexstate->iss_IndexPtr = indexstate->iss_MarkIndexPtr;
|
indexScanDescs = node->iss_ScanDescs;
|
||||||
indexScanDescs = indexstate->iss_ScanDescs;
|
|
||||||
scanDesc = indexScanDescs[indexPtr];
|
scanDesc = indexScanDescs[indexPtr];
|
||||||
|
|
||||||
#ifdef NOT_USED
|
|
||||||
IndexScanRestorePosition(scanDesc);
|
|
||||||
#endif
|
|
||||||
index_restrpos(scanDesc);
|
index_restrpos(scanDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,11 +571,10 @@ ExecIndexRestrPos(IndexScan *node)
|
|||||||
* estate: the execution state initialized in InitPlan.
|
* estate: the execution state initialized in InitPlan.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
IndexScanState *
|
||||||
ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
ExecInitIndexScan(IndexScan *node, EState *estate)
|
||||||
{
|
{
|
||||||
IndexScanState *indexstate;
|
IndexScanState *indexstate;
|
||||||
CommonScanState *scanstate;
|
|
||||||
List *indxqual;
|
List *indxqual;
|
||||||
List *indxid;
|
List *indxid;
|
||||||
List *listscan;
|
List *listscan;
|
||||||
@@ -620,45 +593,52 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
Relation currentRelation;
|
Relation currentRelation;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
*/
|
||||||
node->scan.plan.state = estate;
|
indexstate = makeNode(IndexScanState);
|
||||||
|
indexstate->ss.ps.plan = (Plan *) node;
|
||||||
/*
|
indexstate->ss.ps.state = estate;
|
||||||
* Part 1) initialize scan state
|
|
||||||
*
|
|
||||||
* create new CommonScanState for node
|
|
||||||
*/
|
|
||||||
scanstate = makeNode(CommonScanState);
|
|
||||||
node->scan.scanstate = scanstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* 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
|
#define INDEXSCAN_NSLOTS 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
|
||||||
ExecInitScanTupleSlot(estate, scanstate);
|
ExecInitScanTupleSlot(estate, &indexstate->ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize projection info. result type comes from scan desc
|
* initialize projection info. result type comes from scan desc
|
||||||
* below..
|
* below..
|
||||||
*/
|
*/
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
ExecAssignProjectionInfo(&indexstate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Part 2) initialize index scan state
|
* Initialize index-specific scan state
|
||||||
*
|
|
||||||
* create new IndexScanState for node
|
|
||||||
*/
|
*/
|
||||||
indexstate = makeNode(IndexScanState);
|
|
||||||
indexstate->iss_NumIndices = 0;
|
indexstate->iss_NumIndices = 0;
|
||||||
indexstate->iss_IndexPtr = -1;
|
indexstate->iss_IndexPtr = -1;
|
||||||
indexstate->iss_ScanKeys = NULL;
|
indexstate->iss_ScanKeys = NULL;
|
||||||
@@ -669,8 +649,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
indexstate->iss_RelationDescs = NULL;
|
indexstate->iss_RelationDescs = NULL;
|
||||||
indexstate->iss_ScanDescs = NULL;
|
indexstate->iss_ScanDescs = NULL;
|
||||||
|
|
||||||
node->indxstate = indexstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the index node information
|
* get the index node information
|
||||||
*/
|
*/
|
||||||
@@ -836,7 +814,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
{
|
{
|
||||||
/* treat Param like a constant */
|
/* treat Param like a constant */
|
||||||
scanvalue = ExecEvalParam((Param *) leftop,
|
scanvalue = ExecEvalParam((Param *) leftop,
|
||||||
scanstate->cstate.cs_ExprContext,
|
indexstate->ss.ps.ps_ExprContext,
|
||||||
&isnull);
|
&isnull);
|
||||||
if (isnull)
|
if (isnull)
|
||||||
flags |= SK_ISNULL;
|
flags |= SK_ISNULL;
|
||||||
@@ -911,7 +889,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
{
|
{
|
||||||
/* treat Param like a constant */
|
/* treat Param like a constant */
|
||||||
scanvalue = ExecEvalParam((Param *) rightop,
|
scanvalue = ExecEvalParam((Param *) rightop,
|
||||||
scanstate->cstate.cs_ExprContext,
|
indexstate->ss.ps.ps_ExprContext,
|
||||||
&isnull);
|
&isnull);
|
||||||
if (isnull)
|
if (isnull)
|
||||||
flags |= SK_ISNULL;
|
flags |= SK_ISNULL;
|
||||||
@@ -976,12 +954,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
*/
|
*/
|
||||||
if (have_runtime_keys)
|
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_RuntimeKeyInfo = runtimeKeyInfo;
|
||||||
indexstate->iss_RuntimeContext = scanstate->cstate.cs_ExprContext;
|
indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
|
||||||
scanstate->cstate.cs_ExprContext = stdecontext;
|
indexstate->ss.ps.ps_ExprContext = stdecontext;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1008,14 +986,14 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
if (!RelationGetForm(currentRelation)->relhasindex)
|
if (!RelationGetForm(currentRelation)->relhasindex)
|
||||||
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
|
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
|
||||||
|
|
||||||
scanstate->css_currentRelation = currentRelation;
|
indexstate->ss.ss_currentRelation = currentRelation;
|
||||||
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
|
indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the scan type from the relation descriptor.
|
* get the scan type from the relation descriptor.
|
||||||
*/
|
*/
|
||||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation), false);
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* open the index relations and initialize relation and scan
|
* open the index relations and initialize relation and scan
|
||||||
@@ -1043,7 +1021,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* all done.
|
* all done.
|
||||||
*/
|
*/
|
||||||
return TRUE;
|
return indexstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/executor.h"
|
||||||
#include "executor/nodeLimit.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 */
|
TupleTableSlot * /* return: a tuple or NULL */
|
||||||
ExecLimit(Limit *node)
|
ExecLimit(LimitState *node)
|
||||||
{
|
{
|
||||||
LimitState *limitstate;
|
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
TupleTableSlot *resultTupleSlot;
|
TupleTableSlot *resultTupleSlot;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
*/
|
*/
|
||||||
limitstate = node->limitstate;
|
direction = node->ps.state->es_direction;
|
||||||
direction = node->plan.state->es_direction;
|
outerPlan = outerPlanState(node);
|
||||||
outerPlan = outerPlan((Plan *) node);
|
resultTupleSlot = node->ps.ps_ResultTupleSlot;
|
||||||
resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The main logic is a simple state machine.
|
* The main logic is a simple state machine.
|
||||||
*/
|
*/
|
||||||
switch (limitstate->lstate)
|
switch (node->lstate)
|
||||||
{
|
{
|
||||||
case LIMIT_INITIAL:
|
case LIMIT_INITIAL:
|
||||||
/*
|
/*
|
||||||
@@ -71,9 +69,9 @@ ExecLimit(Limit *node)
|
|||||||
/*
|
/*
|
||||||
* Check for empty window; if so, treat like empty subplan.
|
* 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -81,24 +79,24 @@ ExecLimit(Limit *node)
|
|||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The subplan returns too few tuples for us to produce
|
* The subplan returns too few tuples for us to produce
|
||||||
* any output at all.
|
* any output at all.
|
||||||
*/
|
*/
|
||||||
limitstate->lstate = LIMIT_EMPTY;
|
node->lstate = LIMIT_EMPTY;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
limitstate->subSlot = slot;
|
node->subSlot = slot;
|
||||||
if (++limitstate->position > limitstate->offset)
|
if (++node->position > node->offset)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Okay, we have the first tuple of the window.
|
* Okay, we have the first tuple of the window.
|
||||||
*/
|
*/
|
||||||
limitstate->lstate = LIMIT_INWINDOW;
|
node->lstate = LIMIT_INWINDOW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LIMIT_EMPTY:
|
case LIMIT_EMPTY:
|
||||||
@@ -117,23 +115,23 @@ ExecLimit(Limit *node)
|
|||||||
* advancing the subplan or the position variable; but
|
* advancing the subplan or the position variable; but
|
||||||
* change the state machine state to record having done so.
|
* change the state machine state to record having done so.
|
||||||
*/
|
*/
|
||||||
if (!limitstate->noCount &&
|
if (!node->noCount &&
|
||||||
limitstate->position >= limitstate->offset + limitstate->count)
|
node->position >= node->offset + node->count)
|
||||||
{
|
{
|
||||||
limitstate->lstate = LIMIT_WINDOWEND;
|
node->lstate = LIMIT_WINDOWEND;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Get next tuple from subplan, if any.
|
* Get next tuple from subplan, if any.
|
||||||
*/
|
*/
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
{
|
{
|
||||||
limitstate->lstate = LIMIT_SUBPLANEOF;
|
node->lstate = LIMIT_SUBPLANEOF;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
limitstate->subSlot = slot;
|
node->subSlot = slot;
|
||||||
limitstate->position++;
|
node->position++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -141,19 +139,19 @@ ExecLimit(Limit *node)
|
|||||||
* Backwards scan, so check for stepping off start of window.
|
* Backwards scan, so check for stepping off start of window.
|
||||||
* As above, change only state-machine status if so.
|
* 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Get previous tuple from subplan; there should be one!
|
* Get previous tuple from subplan; there should be one!
|
||||||
*/
|
*/
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
elog(ERROR, "ExecLimit: subplan failed to run backwards");
|
elog(ERROR, "ExecLimit: subplan failed to run backwards");
|
||||||
limitstate->subSlot = slot;
|
node->subSlot = slot;
|
||||||
limitstate->position--;
|
node->position--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -164,11 +162,11 @@ ExecLimit(Limit *node)
|
|||||||
* Backing up from subplan EOF, so re-fetch previous tuple;
|
* Backing up from subplan EOF, so re-fetch previous tuple;
|
||||||
* there should be one! Note previous tuple must be in window.
|
* there should be one! Note previous tuple must be in window.
|
||||||
*/
|
*/
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
elog(ERROR, "ExecLimit: subplan failed to run backwards");
|
elog(ERROR, "ExecLimit: subplan failed to run backwards");
|
||||||
limitstate->subSlot = slot;
|
node->subSlot = slot;
|
||||||
limitstate->lstate = LIMIT_INWINDOW;
|
node->lstate = LIMIT_INWINDOW;
|
||||||
/* position does not change 'cause we didn't advance it before */
|
/* position does not change 'cause we didn't advance it before */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -179,8 +177,8 @@ ExecLimit(Limit *node)
|
|||||||
* Backing up from window end: simply re-return the last
|
* Backing up from window end: simply re-return the last
|
||||||
* tuple fetched from the subplan.
|
* tuple fetched from the subplan.
|
||||||
*/
|
*/
|
||||||
slot = limitstate->subSlot;
|
slot = node->subSlot;
|
||||||
limitstate->lstate = LIMIT_INWINDOW;
|
node->lstate = LIMIT_INWINDOW;
|
||||||
/* position does not change 'cause we didn't advance it before */
|
/* position does not change 'cause we didn't advance it before */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -191,14 +189,14 @@ ExecLimit(Limit *node)
|
|||||||
* Advancing after having backed off window start: simply
|
* Advancing after having backed off window start: simply
|
||||||
* re-return the last tuple fetched from the subplan.
|
* re-return the last tuple fetched from the subplan.
|
||||||
*/
|
*/
|
||||||
slot = limitstate->subSlot;
|
slot = node->subSlot;
|
||||||
limitstate->lstate = LIMIT_INWINDOW;
|
node->lstate = LIMIT_INWINDOW;
|
||||||
/* position does not change 'cause we didn't change it before */
|
/* position does not change 'cause we didn't change it before */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecLimit: impossible state %d",
|
elog(ERROR, "ExecLimit: impossible state %d",
|
||||||
(int) limitstate->lstate);
|
(int) node->lstate);
|
||||||
slot = NULL; /* keep compiler quiet */
|
slot = NULL; /* keep compiler quiet */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -220,55 +218,54 @@ ExecLimit(Limit *node)
|
|||||||
* This is also a handy place to reset the current-position state info.
|
* This is also a handy place to reset the current-position state info.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
recompute_limits(Limit *node)
|
recompute_limits(LimitState *node)
|
||||||
{
|
{
|
||||||
LimitState *limitstate = node->limitstate;
|
ExprContext *econtext = node->ps.ps_ExprContext;
|
||||||
ExprContext *econtext = limitstate->cstate.cs_ExprContext;
|
|
||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
if (node->limitOffset)
|
if (node->limitOffset)
|
||||||
{
|
{
|
||||||
limitstate->offset =
|
node->offset =
|
||||||
DatumGetInt32(ExecEvalExprSwitchContext(node->limitOffset,
|
DatumGetInt32(ExecEvalExprSwitchContext(node->limitOffset,
|
||||||
econtext,
|
econtext,
|
||||||
&isNull,
|
&isNull,
|
||||||
NULL));
|
NULL));
|
||||||
/* Interpret NULL offset as no offset */
|
/* Interpret NULL offset as no offset */
|
||||||
if (isNull)
|
if (isNull)
|
||||||
limitstate->offset = 0;
|
node->offset = 0;
|
||||||
else if (limitstate->offset < 0)
|
else if (node->offset < 0)
|
||||||
limitstate->offset = 0;
|
node->offset = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* No OFFSET supplied */
|
/* No OFFSET supplied */
|
||||||
limitstate->offset = 0;
|
node->offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->limitCount)
|
if (node->limitCount)
|
||||||
{
|
{
|
||||||
limitstate->noCount = false;
|
node->noCount = false;
|
||||||
limitstate->count =
|
node->count =
|
||||||
DatumGetInt32(ExecEvalExprSwitchContext(node->limitCount,
|
DatumGetInt32(ExecEvalExprSwitchContext(node->limitCount,
|
||||||
econtext,
|
econtext,
|
||||||
&isNull,
|
&isNull,
|
||||||
NULL));
|
NULL));
|
||||||
/* Interpret NULL count as no count (LIMIT ALL) */
|
/* Interpret NULL count as no count (LIMIT ALL) */
|
||||||
if (isNull)
|
if (isNull)
|
||||||
limitstate->noCount = true;
|
node->noCount = true;
|
||||||
else if (limitstate->count < 0)
|
else if (node->count < 0)
|
||||||
limitstate->count = 0;
|
node->count = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* No COUNT supplied */
|
/* No COUNT supplied */
|
||||||
limitstate->count = 0;
|
node->count = 0;
|
||||||
limitstate->noCount = true;
|
node->noCount = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset position to start-of-scan */
|
/* Reset position to start-of-scan */
|
||||||
limitstate->position = 0;
|
node->position = 0;
|
||||||
limitstate->subSlot = NULL;
|
node->subSlot = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -278,22 +275,19 @@ recompute_limits(Limit *node)
|
|||||||
* the node's subplan.
|
* the node's subplan.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool /* return: initialization status */
|
LimitState *
|
||||||
ExecInitLimit(Limit *node, EState *estate, Plan *parent)
|
ExecInitLimit(Limit *node, EState *estate)
|
||||||
{
|
{
|
||||||
LimitState *limitstate;
|
LimitState *limitstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new LimitState for node
|
|
||||||
*/
|
*/
|
||||||
limitstate = makeNode(LimitState);
|
limitstate = makeNode(LimitState);
|
||||||
node->limitstate = limitstate;
|
limitstate->ps.plan = (Plan *) node;
|
||||||
|
limitstate->ps.state = estate;
|
||||||
|
|
||||||
limitstate->lstate = LIMIT_INITIAL;
|
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
|
* Limit nodes never call ExecQual or ExecProject, but they need an
|
||||||
* exprcontext anyway to evaluate the limit/offset parameters in.
|
* 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
|
#define LIMIT_NSLOTS 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tuple table initialization
|
* Tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &limitstate->cstate);
|
ExecInitResultTupleSlot(estate, &limitstate->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* then initialize outer plan
|
* then initialize outer plan
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan(node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
outerPlanState(limitstate) = ExecInitNode(outerPlan, estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* limit nodes do no projections, so initialize projection info for
|
* limit nodes do no projections, so initialize projection info for
|
||||||
* this node appropriately
|
* this node appropriately
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate);
|
ExecAssignResultTypeFromOuterPlan(&limitstate->ps);
|
||||||
limitstate->cstate.cs_ProjInfo = NULL;
|
limitstate->ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return limitstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -343,33 +345,29 @@ ExecCountSlotsLimit(Limit *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndLimit(Limit *node)
|
ExecEndLimit(LimitState *node)
|
||||||
{
|
{
|
||||||
LimitState *limitstate = node->limitstate;
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
ExecFreeExprContext(&limitstate->cstate);
|
ExecEndNode(outerPlanState(node));
|
||||||
|
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanLimit(LimitState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
LimitState *limitstate = node->limitstate;
|
|
||||||
|
|
||||||
/* resetting lstate will force offset/limit recalculation */
|
/* 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
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 */
|
TupleTableSlot * /* result tuple from subplan */
|
||||||
ExecMaterial(Material *node)
|
ExecMaterial(MaterialState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
MaterialState *matstate;
|
|
||||||
ScanDirection dir;
|
ScanDirection dir;
|
||||||
Tuplestorestate *tuplestorestate;
|
Tuplestorestate *tuplestorestate;
|
||||||
HeapTuple heapTuple;
|
HeapTuple heapTuple;
|
||||||
@@ -56,10 +55,9 @@ ExecMaterial(Material *node)
|
|||||||
/*
|
/*
|
||||||
* get state info from node
|
* get state info from node
|
||||||
*/
|
*/
|
||||||
matstate = node->matstate;
|
estate = node->ss.ps.state;
|
||||||
estate = node->plan.state;
|
|
||||||
dir = estate->es_direction;
|
dir = estate->es_direction;
|
||||||
tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
|
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If first time through, read all tuples from outer plan and pass
|
* If first time through, read all tuples from outer plan and pass
|
||||||
@@ -69,7 +67,7 @@ ExecMaterial(Material *node)
|
|||||||
|
|
||||||
if (tuplestorestate == NULL)
|
if (tuplestorestate == NULL)
|
||||||
{
|
{
|
||||||
Plan *outerNode;
|
PlanState *outerNode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Want to scan subplan in the forward direction while creating
|
* Want to scan subplan in the forward direction while creating
|
||||||
@@ -84,16 +82,16 @@ ExecMaterial(Material *node)
|
|||||||
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
||||||
SortMem);
|
SortMem);
|
||||||
|
|
||||||
matstate->tuplestorestate = (void *) tuplestorestate;
|
node->tuplestorestate = (void *) tuplestorestate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the subplan and feed all the tuples to tuplestore.
|
* Scan the subplan and feed all the tuples to tuplestore.
|
||||||
*/
|
*/
|
||||||
outerNode = outerPlan((Plan *) node);
|
outerNode = outerPlanState(node);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
slot = ExecProcNode(outerNode, (Plan *) node);
|
slot = ExecProcNode(outerNode);
|
||||||
|
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
break;
|
break;
|
||||||
@@ -117,7 +115,7 @@ ExecMaterial(Material *node)
|
|||||||
* Get the first or next tuple from tuplestore. Returns NULL if no
|
* Get the first or next tuple from tuplestore. Returns NULL if no
|
||||||
* more tuples.
|
* more tuples.
|
||||||
*/
|
*/
|
||||||
slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
|
slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot;
|
||||||
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
heapTuple = tuplestore_getheaptuple(tuplestorestate,
|
||||||
ScanDirectionIsForward(dir),
|
ScanDirectionIsForward(dir),
|
||||||
&should_free);
|
&should_free);
|
||||||
@@ -129,23 +127,20 @@ ExecMaterial(Material *node)
|
|||||||
* ExecInitMaterial
|
* ExecInitMaterial
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool /* initialization status */
|
MaterialState *
|
||||||
ExecInitMaterial(Material *node, EState *estate, Plan *parent)
|
ExecInitMaterial(Material *node, EState *estate)
|
||||||
{
|
{
|
||||||
MaterialState *matstate;
|
MaterialState *matstate;
|
||||||
Plan *outerPlan;
|
Plan *outerPlan;
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
*/
|
*/
|
||||||
matstate = makeNode(MaterialState);
|
matstate = makeNode(MaterialState);
|
||||||
|
matstate->ss.ps.plan = (Plan *) node;
|
||||||
|
matstate->ss.ps.state = estate;
|
||||||
|
|
||||||
matstate->tuplestorestate = NULL;
|
matstate->tuplestorestate = NULL;
|
||||||
node->matstate = matstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
@@ -161,24 +156,24 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
|
|||||||
*
|
*
|
||||||
* material nodes only return tuples from their materialized relation.
|
* material nodes only return tuples from their materialized relation.
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &matstate->ss.ps);
|
||||||
ExecInitScanTupleSlot(estate, &matstate->csstate);
|
ExecInitScanTupleSlot(estate, &matstate->ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initializes child nodes
|
* initializes child nodes
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlan(node);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
outerPlanState(matstate) = ExecInitNode(outerPlan, estate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize tuple type. no need to initialize projection info
|
* initialize tuple type. no need to initialize projection info
|
||||||
* because this node doesn't do projections.
|
* because this node doesn't do projections.
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
|
ExecAssignResultTypeFromOuterPlan(&matstate->ss.ps);
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
|
ExecAssignScanTypeFromOuterPlan(&matstate->ss);
|
||||||
matstate->csstate.cstate.cs_ProjInfo = NULL;
|
matstate->ss.ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
return TRUE;
|
return matstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -194,33 +189,24 @@ ExecCountSlotsMaterial(Material *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
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
|
* shut down the subplan
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
ExecEndNode(outerPlanState(node));
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* clean out the tuple table
|
|
||||||
*/
|
|
||||||
ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release tuplestore resources
|
* Release tuplestore resources
|
||||||
*/
|
*/
|
||||||
if (matstate->tuplestorestate != NULL)
|
if (node->tuplestorestate != NULL)
|
||||||
tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
|
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
||||||
matstate->tuplestorestate = NULL;
|
node->tuplestorestate = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -230,17 +216,15 @@ ExecEndMaterial(Material *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecMaterialMarkPos(Material *node)
|
ExecMaterialMarkPos(MaterialState *node)
|
||||||
{
|
{
|
||||||
MaterialState *matstate = node->matstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we haven't materialized yet, just return.
|
* if we haven't materialized yet, just return.
|
||||||
*/
|
*/
|
||||||
if (!matstate->tuplestorestate)
|
if (!node->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate);
|
tuplestore_markpos((Tuplestorestate *) node->tuplestorestate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -250,20 +234,18 @@ ExecMaterialMarkPos(Material *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecMaterialRestrPos(Material *node)
|
ExecMaterialRestrPos(MaterialState *node)
|
||||||
{
|
{
|
||||||
MaterialState *matstate = node->matstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we haven't materialized yet, just return.
|
* if we haven't materialized yet, just return.
|
||||||
*/
|
*/
|
||||||
if (!matstate->tuplestorestate)
|
if (!node->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* restore the scan to the previously marked position
|
* 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
|
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
|
* If we haven't materialized yet, just return. If outerplan' chgParam
|
||||||
* is not NULL then it will be re-scanned by ExecProcNode, else - no
|
* is not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||||
* reason to re-scan it at all.
|
* reason to re-scan it at all.
|
||||||
*/
|
*/
|
||||||
if (!matstate->tuplestorestate)
|
if (!node->tuplestorestate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If subnode is to be rescanned then we forget previous stored
|
* 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.
|
* 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);
|
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
|
||||||
matstate->tuplestorestate = NULL;
|
node->tuplestorestate = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate);
|
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *
|
TupleTableSlot *
|
||||||
ExecMergeJoin(MergeJoin *node)
|
ExecMergeJoin(MergeJoinState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
MergeJoinState *mergestate;
|
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
List *innerSkipQual;
|
List *innerSkipQual;
|
||||||
List *outerSkipQual;
|
List *outerSkipQual;
|
||||||
@@ -352,9 +351,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
List *otherqual;
|
List *otherqual;
|
||||||
bool qualResult;
|
bool qualResult;
|
||||||
bool compareResult;
|
bool compareResult;
|
||||||
Plan *innerPlan;
|
PlanState *innerPlan;
|
||||||
TupleTableSlot *innerTupleSlot;
|
TupleTableSlot *innerTupleSlot;
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
TupleTableSlot *outerTupleSlot;
|
TupleTableSlot *outerTupleSlot;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
bool doFillOuter;
|
bool doFillOuter;
|
||||||
@@ -363,17 +362,16 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* get information from node
|
* get information from node
|
||||||
*/
|
*/
|
||||||
mergestate = node->mergestate;
|
estate = node->js.ps.state;
|
||||||
estate = node->join.plan.state;
|
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
innerPlan = innerPlan((Plan *) node);
|
innerPlan = innerPlanState(node);
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlan = outerPlanState(node);
|
||||||
econtext = mergestate->jstate.cs_ExprContext;
|
econtext = node->js.ps.ps_ExprContext;
|
||||||
mergeclauses = node->mergeclauses;
|
mergeclauses = node->mergeclauses;
|
||||||
joinqual = node->join.joinqual;
|
joinqual = node->js.joinqual;
|
||||||
otherqual = node->join.plan.qual;
|
otherqual = node->js.ps.qual;
|
||||||
|
|
||||||
switch (node->join.jointype)
|
switch (node->js.jointype)
|
||||||
{
|
{
|
||||||
case JOIN_INNER:
|
case JOIN_INNER:
|
||||||
doFillOuter = false;
|
doFillOuter = false;
|
||||||
@@ -393,7 +391,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecMergeJoin: unsupported join type %d",
|
elog(ERROR, "ExecMergeJoin: unsupported join type %d",
|
||||||
(int) node->join.jointype);
|
(int) node->js.jointype);
|
||||||
doFillOuter = false; /* keep compiler quiet */
|
doFillOuter = false; /* keep compiler quiet */
|
||||||
doFillInner = false;
|
doFillInner = false;
|
||||||
break;
|
break;
|
||||||
@@ -401,13 +399,13 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (ScanDirectionIsForward(direction))
|
if (ScanDirectionIsForward(direction))
|
||||||
{
|
{
|
||||||
outerSkipQual = mergestate->mj_OuterSkipQual;
|
outerSkipQual = node->mj_OuterSkipQual;
|
||||||
innerSkipQual = mergestate->mj_InnerSkipQual;
|
innerSkipQual = node->mj_InnerSkipQual;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
outerSkipQual = mergestate->mj_InnerSkipQual;
|
outerSkipQual = node->mj_InnerSkipQual;
|
||||||
innerSkipQual = mergestate->mj_OuterSkipQual;
|
innerSkipQual = node->mj_OuterSkipQual;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -415,16 +413,16 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* join tuple (because there is a function-returning-set in the
|
* join tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
*/
|
*/
|
||||||
if (mergestate->jstate.cs_TupFromTlist)
|
if (node->js.ps.ps_TupFromTlist)
|
||||||
{
|
{
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
if (isDone == ExprMultipleResult)
|
if (isDone == ExprMultipleResult)
|
||||||
return result;
|
return result;
|
||||||
/* Done with that source tuple... */
|
/* 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
|
* Note: The join states are highlighted with 32-* comments for
|
||||||
* improved readability.
|
* 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
|
* EXEC_MJ_INITIALIZE means that this is the first time
|
||||||
@@ -459,8 +457,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_INITIALIZE:
|
case EXEC_MJ_INITIALIZE:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
|
MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
|
||||||
|
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
MJ_printf("ExecMergeJoin: outer subplan is empty\n");
|
MJ_printf("ExecMergeJoin: outer subplan is empty\n");
|
||||||
@@ -471,16 +469,16 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* inner tuples. We set MatchedInner = true to
|
* inner tuples. We set MatchedInner = true to
|
||||||
* force the ENDOUTER state to advance inner.
|
* force the ENDOUTER state to advance inner.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
|
node->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||||
mergestate->mj_MatchedInner = true;
|
node->mj_MatchedInner = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise we're done. */
|
/* Otherwise we're done. */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
MJ_printf("ExecMergeJoin: inner subplan is empty\n");
|
MJ_printf("ExecMergeJoin: inner subplan is empty\n");
|
||||||
@@ -493,8 +491,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* state to emit this tuple before advancing
|
* state to emit this tuple before advancing
|
||||||
* outer.
|
* outer.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
node->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||||
mergestate->mj_MatchedOuter = false;
|
node->mj_MatchedOuter = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise we're done. */
|
/* Otherwise we're done. */
|
||||||
@@ -505,7 +503,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* OK, we have the initial tuples. Begin by skipping
|
* OK, we have the initial tuples. Begin by skipping
|
||||||
* unmatched inner tuples.
|
* unmatched inner tuples.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
node->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -519,9 +517,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
ExecMarkPos(innerPlan);
|
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;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -538,18 +536,18 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||||
MJ_DEBUG_QUAL(mergeclauses, qualResult);
|
MJ_DEBUG_QUAL(mergeclauses, qualResult);
|
||||||
|
|
||||||
if (qualResult)
|
if (qualResult)
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
else
|
else
|
||||||
mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -560,7 +558,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_JOINTUPLES:
|
case EXEC_MJ_JOINTUPLES:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
|
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
|
* Check the extra qual conditions to see if we actually
|
||||||
@@ -582,8 +580,8 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
if (qualResult)
|
if (qualResult)
|
||||||
{
|
{
|
||||||
mergestate->mj_MatchedOuter = true;
|
node->mj_MatchedOuter = true;
|
||||||
mergestate->mj_MatchedInner = true;
|
node->mj_MatchedInner = true;
|
||||||
|
|
||||||
qualResult = (otherqual == NIL ||
|
qualResult = (otherqual == NIL ||
|
||||||
ExecQual(otherqual, econtext, false));
|
ExecQual(otherqual, econtext, false));
|
||||||
@@ -601,12 +599,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning tuple\n");
|
MJ_printf("ExecMergeJoin: returning tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -625,20 +623,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_NEXTINNER:
|
case EXEC_MJ_NEXTINNER:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
|
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
|
* Generate a fake join tuple with nulls for the outer
|
||||||
* tuple, and return it if it passes the non-join
|
* tuple, and return it if it passes the non-join
|
||||||
* quals.
|
* quals.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
node->mj_MatchedInner = true; /* do it only once */
|
||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
|
outerTupleSlot = node->mj_NullOuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
@@ -653,12 +651,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -668,15 +666,15 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* now we get the next inner tuple, if any
|
* now we get the next inner tuple, if any
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||||
mergestate->mj_MatchedInner = false;
|
node->mj_MatchedInner = false;
|
||||||
|
|
||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
node->mj_JoinState = EXEC_MJ_NEXTOUTER;
|
||||||
else
|
else
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
|
node->mj_JoinState = EXEC_MJ_JOINTEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*-------------------------------------------
|
/*-------------------------------------------
|
||||||
@@ -701,20 +699,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_NEXTOUTER:
|
case EXEC_MJ_NEXTOUTER:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
|
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
|
* Generate a fake join tuple with nulls for the inner
|
||||||
* tuple, and return it if it passes the non-join
|
* tuple, and return it if it passes the non-join
|
||||||
* quals.
|
* quals.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
node->mj_MatchedOuter = true; /* do it only once */
|
||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
|
innerTupleSlot = node->mj_NullInnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
@@ -729,12 +727,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -744,10 +742,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* now we get the next outer tuple, if any
|
* now we get the next outer tuple, if any
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||||
mergestate->mj_MatchedOuter = false;
|
node->mj_MatchedOuter = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the outer tuple is null then we are done with the
|
* if the outer tuple is null then we are done with the
|
||||||
@@ -756,21 +754,21 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
MJ_printf("ExecMergeJoin: end of outer subplan\n");
|
MJ_printf("ExecMergeJoin: end of outer subplan\n");
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Need to emit right-join tuples for remaining
|
* Need to emit right-join tuples for remaining
|
||||||
* inner tuples.
|
* inner tuples.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
|
node->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise we're done. */
|
/* Otherwise we're done. */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_TESTOUTER;
|
node->mj_JoinState = EXEC_MJ_TESTOUTER;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*--------------------------------------------------------
|
/*--------------------------------------------------------
|
||||||
@@ -816,9 +814,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_MarkedTupleSlot;
|
innerTupleSlot = node->mj_MarkedTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||||
@@ -843,7 +841,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* the extra joinquals.
|
* the extra joinquals.
|
||||||
*/
|
*/
|
||||||
ExecRestrPos(innerPlan);
|
ExecRestrPos(innerPlan);
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -862,7 +860,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* larger than our marked inner tuples. So we're done.
|
* larger than our marked inner tuples. So we're done.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
if (doFillOuter)
|
if (doFillOuter)
|
||||||
@@ -871,7 +869,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
* Need to emit left-join tuples for remaining
|
* Need to emit left-join tuples for remaining
|
||||||
* outer tuples.
|
* outer tuples.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
node->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise we're done. */
|
/* Otherwise we're done. */
|
||||||
@@ -879,7 +877,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* continue on to skip outer tuples */
|
/* continue on to skip outer tuples */
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -913,9 +911,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||||
@@ -925,13 +923,13 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
{
|
{
|
||||||
ExecMarkPos(innerPlan);
|
ExecMarkPos(innerPlan);
|
||||||
|
|
||||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
MarkInnerTuple(innerTupleSlot, node);
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_MJ_SKIPOUTER_TEST:
|
case EXEC_MJ_SKIPOUTER_TEST:
|
||||||
@@ -940,9 +938,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* ok, now test the skip qualification
|
* ok, now test the skip qualification
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
compareResult = MergeCompare(mergeclauses,
|
compareResult = MergeCompare(mergeclauses,
|
||||||
@@ -957,7 +955,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
if (compareResult)
|
if (compareResult)
|
||||||
{
|
{
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
|
node->mj_JoinState = EXEC_MJ_SKIPOUTER_ADVANCE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,9 +971,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
|
MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
|
||||||
|
|
||||||
if (compareResult)
|
if (compareResult)
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
node->mj_JoinState = EXEC_MJ_SKIPINNER_BEGIN;
|
||||||
else
|
else
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
node->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -985,20 +983,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_SKIPOUTER_ADVANCE:
|
case EXEC_MJ_SKIPOUTER_ADVANCE:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER_ADVANCE\n");
|
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
|
* Generate a fake join tuple with nulls for the inner
|
||||||
* tuple, and return it if it passes the non-join
|
* tuple, and return it if it passes the non-join
|
||||||
* quals.
|
* quals.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
node->mj_MatchedOuter = true; /* do it only once */
|
||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
|
innerTupleSlot = node->mj_NullInnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
@@ -1013,12 +1011,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1028,10 +1026,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* now we get the next outer tuple, if any
|
* now we get the next outer tuple, if any
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||||
mergestate->mj_MatchedOuter = false;
|
node->mj_MatchedOuter = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the outer tuple is null then we are done with the
|
* if the outer tuple is null then we are done with the
|
||||||
@@ -1040,14 +1038,14 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
MJ_printf("ExecMergeJoin: end of outer subplan\n");
|
MJ_printf("ExecMergeJoin: end of outer subplan\n");
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Need to emit right-join tuples for remaining
|
* Need to emit right-join tuples for remaining
|
||||||
* inner tuples.
|
* inner tuples.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_ENDOUTER;
|
node->mj_JoinState = EXEC_MJ_ENDOUTER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise we're done. */
|
/* Otherwise we're done. */
|
||||||
@@ -1057,7 +1055,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* otherwise test the new tuple against the skip qual.
|
* otherwise test the new tuple against the skip qual.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
node->mj_JoinState = EXEC_MJ_SKIPOUTER_TEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
@@ -1090,9 +1088,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
qualResult = ExecQual(mergeclauses, econtext, false);
|
qualResult = ExecQual(mergeclauses, econtext, false);
|
||||||
@@ -1102,13 +1100,13 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
{
|
{
|
||||||
ExecMarkPos(innerPlan);
|
ExecMarkPos(innerPlan);
|
||||||
|
|
||||||
MarkInnerTuple(innerTupleSlot, mergestate);
|
MarkInnerTuple(innerTupleSlot, node);
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
node->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_MJ_SKIPINNER_TEST:
|
case EXEC_MJ_SKIPINNER_TEST:
|
||||||
@@ -1117,9 +1115,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* ok, now test the skip qualification
|
* ok, now test the skip qualification
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
compareResult = MergeCompare(mergeclauses,
|
compareResult = MergeCompare(mergeclauses,
|
||||||
@@ -1134,7 +1132,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
if (compareResult)
|
if (compareResult)
|
||||||
{
|
{
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
|
node->mj_JoinState = EXEC_MJ_SKIPINNER_ADVANCE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1150,9 +1148,9 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
|
MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
|
||||||
|
|
||||||
if (compareResult)
|
if (compareResult)
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
node->mj_JoinState = EXEC_MJ_SKIPOUTER_BEGIN;
|
||||||
else
|
else
|
||||||
mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
|
node->mj_JoinState = EXEC_MJ_JOINMARK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1162,20 +1160,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
case EXEC_MJ_SKIPINNER_ADVANCE:
|
case EXEC_MJ_SKIPINNER_ADVANCE:
|
||||||
MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER_ADVANCE\n");
|
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
|
* Generate a fake join tuple with nulls for the outer
|
||||||
* tuple, and return it if it passes the non-join
|
* tuple, and return it if it passes the non-join
|
||||||
* quals.
|
* quals.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
node->mj_MatchedInner = true; /* do it only once */
|
||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
|
outerTupleSlot = node->mj_NullOuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
@@ -1190,12 +1188,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1205,10 +1203,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* now we get the next inner tuple, if any
|
* now we get the next inner tuple, if any
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||||
mergestate->mj_MatchedInner = false;
|
node->mj_MatchedInner = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the inner tuple is null then we are done with the
|
* if the inner tuple is null then we are done with the
|
||||||
@@ -1217,14 +1215,14 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
MJ_printf("ExecMergeJoin: end of inner subplan\n");
|
MJ_printf("ExecMergeJoin: end of inner subplan\n");
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
if (doFillOuter && !TupIsNull(outerTupleSlot))
|
if (doFillOuter && !TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Need to emit left-join tuples for remaining
|
* Need to emit left-join tuples for remaining
|
||||||
* outer tuples.
|
* outer tuples.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
node->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Otherwise we're done. */
|
/* Otherwise we're done. */
|
||||||
@@ -1234,7 +1232,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* otherwise test the new tuple against the skip qual.
|
* otherwise test the new tuple against the skip qual.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
node->mj_JoinState = EXEC_MJ_SKIPINNER_TEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1247,20 +1245,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
Assert(doFillInner);
|
Assert(doFillInner);
|
||||||
|
|
||||||
if (!mergestate->mj_MatchedInner)
|
if (!node->mj_MatchedInner)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Generate a fake join tuple with nulls for the outer
|
* Generate a fake join tuple with nulls for the outer
|
||||||
* tuple, and return it if it passes the non-join
|
* tuple, and return it if it passes the non-join
|
||||||
* quals.
|
* quals.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
node->mj_MatchedInner = true; /* do it only once */
|
||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_NullOuterTupleSlot;
|
outerTupleSlot = node->mj_NullOuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
innerTupleSlot = node->mj_InnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
@@ -1275,12 +1273,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1290,10 +1288,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* now we get the next inner tuple, if any
|
* now we get the next inner tuple, if any
|
||||||
*/
|
*/
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan);
|
||||||
mergestate->mj_InnerTupleSlot = innerTupleSlot;
|
node->mj_InnerTupleSlot = innerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
MJ_DEBUG_PROC_NODE(innerTupleSlot);
|
||||||
mergestate->mj_MatchedInner = false;
|
node->mj_MatchedInner = false;
|
||||||
|
|
||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -1314,20 +1312,20 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
Assert(doFillOuter);
|
Assert(doFillOuter);
|
||||||
|
|
||||||
if (!mergestate->mj_MatchedOuter)
|
if (!node->mj_MatchedOuter)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Generate a fake join tuple with nulls for the inner
|
* Generate a fake join tuple with nulls for the inner
|
||||||
* tuple, and return it if it passes the non-join
|
* tuple, and return it if it passes the non-join
|
||||||
* quals.
|
* quals.
|
||||||
*/
|
*/
|
||||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
node->mj_MatchedOuter = true; /* do it only once */
|
||||||
|
|
||||||
ResetExprContext(econtext);
|
ResetExprContext(econtext);
|
||||||
|
|
||||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
outerTupleSlot = node->mj_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
innerTupleSlot = mergestate->mj_NullInnerTupleSlot;
|
innerTupleSlot = node->mj_NullInnerTupleSlot;
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (ExecQual(otherqual, econtext, false))
|
if (ExecQual(otherqual, econtext, false))
|
||||||
@@ -1342,12 +1340,12 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
MJ_printf("ExecMergeJoin: returning fill tuple\n");
|
||||||
|
|
||||||
result = ExecProject(mergestate->jstate.cs_ProjInfo,
|
result = ExecProject(node->js.ps.ps_ProjInfo,
|
||||||
&isDone);
|
&isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
mergestate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1357,10 +1355,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
/*
|
/*
|
||||||
* now we get the next outer tuple, if any
|
* now we get the next outer tuple, if any
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan);
|
||||||
mergestate->mj_OuterTupleSlot = outerTupleSlot;
|
node->mj_OuterTupleSlot = outerTupleSlot;
|
||||||
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
MJ_DEBUG_PROC_NODE(outerTupleSlot);
|
||||||
mergestate->mj_MatchedOuter = false;
|
node->mj_MatchedOuter = false;
|
||||||
|
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -1377,7 +1375,7 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
*/
|
*/
|
||||||
default:
|
default:
|
||||||
elog(WARNING, "ExecMergeJoin: invalid join state %d, aborting",
|
elog(WARNING, "ExecMergeJoin: invalid join state %d, aborting",
|
||||||
mergestate->mj_JoinState);
|
node->mj_JoinState);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1385,14 +1383,10 @@ ExecMergeJoin(MergeJoin *node)
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecInitMergeJoin
|
* ExecInitMergeJoin
|
||||||
*
|
|
||||||
* old comments
|
|
||||||
* Creates the run-time state information for the node and
|
|
||||||
* sets the relation id to contain relevant decriptors.
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
MergeJoinState *
|
||||||
ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
ExecInitMergeJoin(MergeJoin *node, EState *estate)
|
||||||
{
|
{
|
||||||
MergeJoinState *mergestate;
|
MergeJoinState *mergestate;
|
||||||
|
|
||||||
@@ -1400,40 +1394,52 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
"initializing node");
|
"initializing node");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign the node's execution state and get the range table and
|
* create state structure
|
||||||
* direction from it
|
|
||||||
*/
|
|
||||||
node->join.plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new merge state for node
|
|
||||||
*/
|
*/
|
||||||
mergestate = makeNode(MergeJoinState);
|
mergestate = makeNode(MergeJoinState);
|
||||||
node->mergestate = mergestate;
|
mergestate->js.ps.plan = (Plan *) node;
|
||||||
|
mergestate->js.ps.state = estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* 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);
|
mergestate->js.ps.targetlist = (List *)
|
||||||
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
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
|
#define MERGEJOIN_NSLOTS 4
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &mergestate->jstate);
|
ExecInitResultTupleSlot(estate, &mergestate->js.ps);
|
||||||
|
|
||||||
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
|
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
|
||||||
ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
|
ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
|
||||||
ExecGetTupType(innerPlan((Plan *) node)),
|
ExecGetTupType(innerPlanState(mergestate)),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
switch (node->join.jointype)
|
switch (node->join.jointype)
|
||||||
@@ -1443,12 +1449,12 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
case JOIN_LEFT:
|
case JOIN_LEFT:
|
||||||
mergestate->mj_NullInnerTupleSlot =
|
mergestate->mj_NullInnerTupleSlot =
|
||||||
ExecInitNullTupleSlot(estate,
|
ExecInitNullTupleSlot(estate,
|
||||||
ExecGetTupType(innerPlan((Plan *) node)));
|
ExecGetTupType(innerPlanState(mergestate)));
|
||||||
break;
|
break;
|
||||||
case JOIN_RIGHT:
|
case JOIN_RIGHT:
|
||||||
mergestate->mj_NullOuterTupleSlot =
|
mergestate->mj_NullOuterTupleSlot =
|
||||||
ExecInitNullTupleSlot(estate,
|
ExecInitNullTupleSlot(estate,
|
||||||
ExecGetTupType(outerPlan((Plan *) node)));
|
ExecGetTupType(outerPlanState(mergestate)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Can't handle right or full join with non-nil extra
|
* 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:
|
case JOIN_FULL:
|
||||||
mergestate->mj_NullOuterTupleSlot =
|
mergestate->mj_NullOuterTupleSlot =
|
||||||
ExecInitNullTupleSlot(estate,
|
ExecInitNullTupleSlot(estate,
|
||||||
ExecGetTupType(outerPlan((Plan *) node)));
|
ExecGetTupType(outerPlanState(mergestate)));
|
||||||
mergestate->mj_NullInnerTupleSlot =
|
mergestate->mj_NullInnerTupleSlot =
|
||||||
ExecInitNullTupleSlot(estate,
|
ExecInitNullTupleSlot(estate,
|
||||||
ExecGetTupType(innerPlan((Plan *) node)));
|
ExecGetTupType(innerPlanState(mergestate)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Can't handle right or full join with non-nil extra
|
* 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
|
* initialize tuple type and projection info
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
|
ExecAssignResultTypeFromTL(&mergestate->js.ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
|
ExecAssignProjectionInfo(&mergestate->js.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* form merge skip qualifications
|
* form merge skip qualifications
|
||||||
@@ -1500,7 +1506,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
* initialize join state
|
* initialize join state
|
||||||
*/
|
*/
|
||||||
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
||||||
mergestate->jstate.cs_TupFromTlist = false;
|
mergestate->js.ps.ps_TupFromTlist = false;
|
||||||
mergestate->mj_MatchedOuter = false;
|
mergestate->mj_MatchedOuter = false;
|
||||||
mergestate->mj_MatchedInner = false;
|
mergestate->mj_MatchedInner = false;
|
||||||
mergestate->mj_OuterTupleSlot = NULL;
|
mergestate->mj_OuterTupleSlot = NULL;
|
||||||
@@ -1512,7 +1518,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
|||||||
MJ1_printf("ExecInitMergeJoin: %s\n",
|
MJ1_printf("ExecInitMergeJoin: %s\n",
|
||||||
"node initialized");
|
"node initialized");
|
||||||
|
|
||||||
return TRUE;
|
return mergestate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -1531,65 +1537,52 @@ ExecCountSlotsMergeJoin(MergeJoin *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndMergeJoin(MergeJoin *node)
|
ExecEndMergeJoin(MergeJoinState *node)
|
||||||
{
|
{
|
||||||
MergeJoinState *mergestate;
|
|
||||||
|
|
||||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||||
"ending node processing");
|
"ending node processing");
|
||||||
|
|
||||||
/*
|
|
||||||
* get state information from the node
|
|
||||||
*/
|
|
||||||
mergestate = node->mergestate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* 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);
|
ExecFreeProjectionInfo(&node->js.ps);
|
||||||
ExecFreeExprContext(&mergestate->jstate);
|
ExecFreeExprContext(&node->js.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* shut down the subplans
|
* shut down the subplans
|
||||||
*/
|
*/
|
||||||
ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(innerPlanState(node));
|
||||||
ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(outerPlanState(node));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||||
ExecClearTuple(mergestate->mj_MarkedTupleSlot);
|
ExecClearTuple(node->mj_MarkedTupleSlot);
|
||||||
|
|
||||||
MJ1_printf("ExecEndMergeJoin: %s\n",
|
MJ1_printf("ExecEndMergeJoin: %s\n",
|
||||||
"node processing ended");
|
"node processing ended");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
node->mj_JoinState = EXEC_MJ_INITIALIZE;
|
||||||
|
node->js.ps.ps_TupFromTlist = false;
|
||||||
mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
|
node->mj_MatchedOuter = false;
|
||||||
mergestate->jstate.cs_TupFromTlist = false;
|
node->mj_MatchedInner = false;
|
||||||
mergestate->mj_MatchedOuter = false;
|
node->mj_OuterTupleSlot = NULL;
|
||||||
mergestate->mj_MatchedInner = false;
|
node->mj_InnerTupleSlot = NULL;
|
||||||
mergestate->mj_OuterTupleSlot = NULL;
|
|
||||||
mergestate->mj_InnerTupleSlot = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnodes is not null then plans will be re-scanned
|
* if chgParam of subnodes is not null then plans will be re-scanned
|
||||||
* by first ExecProcNode.
|
* by first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
if (((Plan *) node)->righttree->chgParam == NULL)
|
if (((PlanState *) node)->righttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->righttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->righttree, exprCtxt);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *
|
TupleTableSlot *
|
||||||
ExecNestLoop(NestLoop *node)
|
ExecNestLoop(NestLoopState *node)
|
||||||
{
|
{
|
||||||
NestLoopState *nlstate;
|
PlanState *innerPlan;
|
||||||
Plan *innerPlan;
|
PlanState *outerPlan;
|
||||||
Plan *outerPlan;
|
|
||||||
TupleTableSlot *outerTupleSlot;
|
TupleTableSlot *outerTupleSlot;
|
||||||
TupleTableSlot *innerTupleSlot;
|
TupleTableSlot *innerTupleSlot;
|
||||||
List *joinqual;
|
List *joinqual;
|
||||||
@@ -73,17 +72,16 @@ ExecNestLoop(NestLoop *node)
|
|||||||
*/
|
*/
|
||||||
ENL1_printf("getting info from node");
|
ENL1_printf("getting info from node");
|
||||||
|
|
||||||
nlstate = node->nlstate;
|
joinqual = node->js.joinqual;
|
||||||
joinqual = node->join.joinqual;
|
otherqual = node->js.ps.qual;
|
||||||
otherqual = node->join.plan.qual;
|
outerPlan = outerPlanState(node);
|
||||||
outerPlan = outerPlan((Plan *) node);
|
innerPlan = innerPlanState(node);
|
||||||
innerPlan = innerPlan((Plan *) node);
|
econtext = node->js.ps.ps_ExprContext;
|
||||||
econtext = nlstate->jstate.cs_ExprContext;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the current outer tuple
|
* get the current outer tuple
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
|
outerTupleSlot = node->js.ps.ps_OuterTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -91,16 +89,16 @@ ExecNestLoop(NestLoop *node)
|
|||||||
* join tuple (because there is a function-returning-set in the
|
* join tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* projection expressions). If so, try to project another one.
|
||||||
*/
|
*/
|
||||||
if (nlstate->jstate.cs_TupFromTlist)
|
if (node->js.ps.ps_TupFromTlist)
|
||||||
{
|
{
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
|
|
||||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
if (isDone == ExprMultipleResult)
|
if (isDone == ExprMultipleResult)
|
||||||
return result;
|
return result;
|
||||||
/* Done with that source tuple... */
|
/* 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
|
* If we don't have an outer tuple, get the next one and reset the
|
||||||
* inner scan.
|
* inner scan.
|
||||||
*/
|
*/
|
||||||
if (nlstate->nl_NeedNewOuter)
|
if (node->nl_NeedNewOuter)
|
||||||
{
|
{
|
||||||
ENL1_printf("getting new outer tuple");
|
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
|
* 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");
|
ENL1_printf("saving new outer tuple information");
|
||||||
nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
|
node->js.ps.ps_OuterTupleSlot = outerTupleSlot;
|
||||||
econtext->ecxt_outertuple = outerTupleSlot;
|
econtext->ecxt_outertuple = outerTupleSlot;
|
||||||
nlstate->nl_NeedNewOuter = false;
|
node->nl_NeedNewOuter = false;
|
||||||
nlstate->nl_MatchedOuter = false;
|
node->nl_MatchedOuter = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now rescan the inner plan
|
* 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
|
* outer tuple (e.g. in index scans), that's why we pass our
|
||||||
* expr context.
|
* expr context.
|
||||||
*/
|
*/
|
||||||
ExecReScan(innerPlan, econtext, (Plan *) node);
|
ExecReScan(innerPlan, econtext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -161,17 +159,17 @@ ExecNestLoop(NestLoop *node)
|
|||||||
*/
|
*/
|
||||||
ENL1_printf("getting new inner tuple");
|
ENL1_printf("getting new inner tuple");
|
||||||
|
|
||||||
innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
|
innerTupleSlot = ExecProcNode(innerPlan);
|
||||||
econtext->ecxt_innertuple = innerTupleSlot;
|
econtext->ecxt_innertuple = innerTupleSlot;
|
||||||
|
|
||||||
if (TupIsNull(innerTupleSlot))
|
if (TupIsNull(innerTupleSlot))
|
||||||
{
|
{
|
||||||
ENL1_printf("no inner tuple, need new outer tuple");
|
ENL1_printf("no inner tuple, need new outer tuple");
|
||||||
|
|
||||||
nlstate->nl_NeedNewOuter = true;
|
node->nl_NeedNewOuter = true;
|
||||||
|
|
||||||
if (!nlstate->nl_MatchedOuter &&
|
if (!node->nl_MatchedOuter &&
|
||||||
node->join.jointype == JOIN_LEFT)
|
node->js.jointype == JOIN_LEFT)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We are doing an outer join and there were no join
|
* 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
|
* tuple with nulls for the inner tuple, and return it if
|
||||||
* it passes the non-join quals.
|
* it passes the non-join quals.
|
||||||
*/
|
*/
|
||||||
econtext->ecxt_innertuple = nlstate->nl_NullInnerTupleSlot;
|
econtext->ecxt_innertuple = node->nl_NullInnerTupleSlot;
|
||||||
|
|
||||||
ENL1_printf("testing qualification for outer-join tuple");
|
ENL1_printf("testing qualification for outer-join tuple");
|
||||||
|
|
||||||
@@ -195,11 +193,11 @@ ExecNestLoop(NestLoop *node)
|
|||||||
|
|
||||||
ENL1_printf("qualification succeeded, projecting tuple");
|
ENL1_printf("qualification succeeded, projecting tuple");
|
||||||
|
|
||||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
nlstate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -224,7 +222,7 @@ ExecNestLoop(NestLoop *node)
|
|||||||
|
|
||||||
if (ExecQual(joinqual, econtext, false))
|
if (ExecQual(joinqual, econtext, false))
|
||||||
{
|
{
|
||||||
nlstate->nl_MatchedOuter = true;
|
node->nl_MatchedOuter = true;
|
||||||
|
|
||||||
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
||||||
{
|
{
|
||||||
@@ -238,11 +236,11 @@ ExecNestLoop(NestLoop *node)
|
|||||||
|
|
||||||
ENL1_printf("qualification succeeded, projecting tuple");
|
ENL1_printf("qualification succeeded, projecting tuple");
|
||||||
|
|
||||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
|
||||||
|
|
||||||
if (isDone != ExprEndResult)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
nlstate->jstate.cs_TupFromTlist =
|
node->js.ps.ps_TupFromTlist =
|
||||||
(isDone == ExprMultipleResult);
|
(isDone == ExprMultipleResult);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -260,14 +258,10 @@ ExecNestLoop(NestLoop *node)
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecInitNestLoop
|
* ExecInitNestLoop
|
||||||
*
|
|
||||||
* Creates the run-time state information for the nestloop node
|
|
||||||
* produced by the planner and initailizes inner and outer relations
|
|
||||||
* (child nodes).
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
NestLoopState *
|
||||||
ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
ExecInitNestLoop(NestLoop *node, EState *estate)
|
||||||
{
|
{
|
||||||
NestLoopState *nlstate;
|
NestLoopState *nlstate;
|
||||||
|
|
||||||
@@ -275,35 +269,45 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||||||
"initializing node");
|
"initializing node");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
|
||||||
node->join.plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new nest loop state
|
|
||||||
*/
|
*/
|
||||||
nlstate = makeNode(NestLoopState);
|
nlstate = makeNode(NestLoopState);
|
||||||
node->nlstate = nlstate;
|
nlstate->js.ps.plan = (Plan *) node;
|
||||||
|
nlstate->js.ps.state = estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* 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);
|
nlstate->js.ps.targetlist = (List *)
|
||||||
ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
|
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
|
#define NESTLOOP_NSLOTS 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &nlstate->jstate);
|
ExecInitResultTupleSlot(estate, &nlstate->js.ps);
|
||||||
|
|
||||||
switch (node->join.jointype)
|
switch (node->join.jointype)
|
||||||
{
|
{
|
||||||
@@ -312,7 +316,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||||||
case JOIN_LEFT:
|
case JOIN_LEFT:
|
||||||
nlstate->nl_NullInnerTupleSlot =
|
nlstate->nl_NullInnerTupleSlot =
|
||||||
ExecInitNullTupleSlot(estate,
|
ExecInitNullTupleSlot(estate,
|
||||||
ExecGetTupType(innerPlan((Plan *) node)));
|
ExecGetTupType(innerPlanState(nlstate)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecInitNestLoop: unsupported join type %d",
|
elog(ERROR, "ExecInitNestLoop: unsupported join type %d",
|
||||||
@@ -322,20 +326,21 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
|
ExecAssignResultTypeFromTL(&nlstate->js.ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
|
ExecAssignProjectionInfo(&nlstate->js.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finally, wipe the current outer tuple clean.
|
* finally, wipe the current outer tuple clean.
|
||||||
*/
|
*/
|
||||||
nlstate->jstate.cs_OuterTupleSlot = NULL;
|
nlstate->js.ps.ps_OuterTupleSlot = NULL;
|
||||||
nlstate->jstate.cs_TupFromTlist = false;
|
nlstate->js.ps.ps_TupFromTlist = false;
|
||||||
nlstate->nl_NeedNewOuter = true;
|
nlstate->nl_NeedNewOuter = true;
|
||||||
nlstate->nl_MatchedOuter = false;
|
nlstate->nl_MatchedOuter = false;
|
||||||
|
|
||||||
NL1_printf("ExecInitNestLoop: %s\n",
|
NL1_printf("ExecInitNestLoop: %s\n",
|
||||||
"node initialized");
|
"node initialized");
|
||||||
return TRUE;
|
|
||||||
|
return nlstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -353,38 +358,27 @@ ExecCountSlotsNestLoop(NestLoop *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndNestLoop(NestLoop *node)
|
ExecEndNestLoop(NestLoopState *node)
|
||||||
{
|
{
|
||||||
NestLoopState *nlstate;
|
|
||||||
|
|
||||||
NL1_printf("ExecEndNestLoop: %s\n",
|
NL1_printf("ExecEndNestLoop: %s\n",
|
||||||
"ending node processing");
|
"ending node processing");
|
||||||
|
|
||||||
/*
|
|
||||||
* get info from the node
|
|
||||||
*/
|
|
||||||
nlstate = node->nlstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info
|
* 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);
|
ExecFreeProjectionInfo(&node->js.ps);
|
||||||
ExecFreeExprContext(&nlstate->jstate);
|
ExecFreeExprContext(&node->js.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close down subplans
|
* close down subplans
|
||||||
*/
|
*/
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(outerPlanState(node));
|
||||||
ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
|
ExecEndNode(innerPlanState(node));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->js.ps.ps_ResultTupleSlot);
|
||||||
|
|
||||||
NL1_printf("ExecEndNestLoop: %s\n",
|
NL1_printf("ExecEndNestLoop: %s\n",
|
||||||
"node processing ended");
|
"node processing ended");
|
||||||
@@ -395,10 +389,9 @@ ExecEndNestLoop(NestLoop *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
NestLoopState *nlstate = node->nlstate;
|
PlanState *outerPlan = outerPlanState(node);
|
||||||
Plan *outerPlan = outerPlan((Plan *) node);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If outerPlan->chgParam is not null then plan will be automatically
|
* 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...
|
* run-time keys...
|
||||||
*/
|
*/
|
||||||
if (outerPlan->chgParam == NULL)
|
if (outerPlan->chgParam == NULL)
|
||||||
ExecReScan(outerPlan, exprCtxt, (Plan *) node);
|
ExecReScan(outerPlan, exprCtxt);
|
||||||
|
|
||||||
/* let outerPlan to free its result tuple ... */
|
/* let outerPlan to free its result tuple ... */
|
||||||
nlstate->jstate.cs_OuterTupleSlot = NULL;
|
node->js.ps.ps_OuterTupleSlot = NULL;
|
||||||
nlstate->jstate.cs_TupFromTlist = false;
|
node->js.ps.ps_TupFromTlist = false;
|
||||||
nlstate->nl_NeedNewOuter = true;
|
node->nl_NeedNewOuter = true;
|
||||||
nlstate->nl_MatchedOuter = false;
|
node->nl_MatchedOuter = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *
|
TupleTableSlot *
|
||||||
ExecResult(Result *node)
|
ExecResult(ResultState *node)
|
||||||
{
|
{
|
||||||
ResultState *resstate;
|
|
||||||
TupleTableSlot *outerTupleSlot;
|
TupleTableSlot *outerTupleSlot;
|
||||||
TupleTableSlot *resultSlot;
|
TupleTableSlot *resultSlot;
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
ExprDoneCond isDone;
|
ExprDoneCond isDone;
|
||||||
|
|
||||||
/*
|
econtext = node->ps.ps_ExprContext;
|
||||||
* initialize the result node's state
|
|
||||||
*/
|
|
||||||
resstate = node->resstate;
|
|
||||||
econtext = resstate->cstate.cs_ExprContext;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check constant qualifications like (2 > 1), if not already done
|
* check constant qualifications like (2 > 1), if not already done
|
||||||
*/
|
*/
|
||||||
if (resstate->rs_checkqual)
|
if (node->rs_checkqual)
|
||||||
{
|
{
|
||||||
bool qualResult = ExecQual((List *) node->resconstantqual,
|
bool qualResult = ExecQual((List *) node->resconstantqual,
|
||||||
econtext,
|
econtext,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
resstate->rs_checkqual = false;
|
node->rs_checkqual = false;
|
||||||
if (qualResult == false)
|
if (!qualResult)
|
||||||
{
|
{
|
||||||
resstate->rs_done = true;
|
node->rs_done = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,13 +92,13 @@ ExecResult(Result *node)
|
|||||||
* scan tuple (because there is a function-returning-set in the
|
* scan tuple (because there is a function-returning-set in the
|
||||||
* projection expressions). If so, try to project another one.
|
* 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)
|
if (isDone == ExprMultipleResult)
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
/* Done with that source tuple... */
|
/* 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
|
* called, OR that we failed the constant qual check. Either way, now
|
||||||
* we are through.
|
* we are through.
|
||||||
*/
|
*/
|
||||||
while (!resstate->rs_done)
|
while (!node->rs_done)
|
||||||
{
|
{
|
||||||
outerPlan = outerPlan(node);
|
outerPlan = outerPlanState(node);
|
||||||
|
|
||||||
if (outerPlan != NULL)
|
if (outerPlan != NULL)
|
||||||
{
|
{
|
||||||
@@ -129,12 +124,12 @@ ExecResult(Result *node)
|
|||||||
* retrieve tuples from the outer plan until there are no
|
* retrieve tuples from the outer plan until there are no
|
||||||
* more.
|
* more.
|
||||||
*/
|
*/
|
||||||
outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
|
outerTupleSlot = ExecProcNode(outerPlan);
|
||||||
|
|
||||||
if (TupIsNull(outerTupleSlot))
|
if (TupIsNull(outerTupleSlot))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
|
node->ps.ps_OuterTupleSlot = outerTupleSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX gross hack. use outer tuple as scan tuple for
|
* 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
|
* if we don't have an outer plan, then we are just generating
|
||||||
* the results from a constant target list. Do it only once.
|
* 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
|
* unless the projection produces an empty set, in which case we
|
||||||
* must loop back to see if there are more outerPlan tuples.
|
* 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)
|
if (isDone != ExprEndResult)
|
||||||
{
|
{
|
||||||
resstate->cstate.cs_TupFromTlist = (isDone == ExprMultipleResult);
|
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
|
||||||
return resultSlot;
|
return resultSlot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,42 +172,51 @@ ExecResult(Result *node)
|
|||||||
* (child nodes).
|
* (child nodes).
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
ResultState *
|
||||||
ExecInitResult(Result *node, EState *estate, Plan *parent)
|
ExecInitResult(Result *node, EState *estate)
|
||||||
{
|
{
|
||||||
ResultState *resstate;
|
ResultState *resstate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new ResultState for node
|
|
||||||
*/
|
*/
|
||||||
resstate = makeNode(ResultState);
|
resstate = makeNode(ResultState);
|
||||||
|
resstate->ps.plan = (Plan *) node;
|
||||||
|
resstate->ps.state = estate;
|
||||||
|
|
||||||
resstate->rs_done = false;
|
resstate->rs_done = false;
|
||||||
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
||||||
node->resstate = resstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* create expression context for node
|
||||||
*/
|
*/
|
||||||
ExecAssignExprContext(estate, &resstate->cstate);
|
ExecAssignExprContext(estate, &resstate->ps);
|
||||||
|
|
||||||
#define RESULT_NSLOTS 1
|
#define RESULT_NSLOTS 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* 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
|
* we don't use inner plan
|
||||||
@@ -222,10 +226,10 @@ ExecInitResult(Result *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* initialize tuple type and projection info
|
* initialize tuple type and projection info
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
|
ExecAssignResultTypeFromTL(&resstate->ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
|
ExecAssignProjectionInfo(&resstate->ps);
|
||||||
|
|
||||||
return TRUE;
|
return resstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -241,49 +245,37 @@ ExecCountSlotsResult(Result *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndResult(Result *node)
|
ExecEndResult(ResultState *node)
|
||||||
{
|
{
|
||||||
ResultState *resstate;
|
|
||||||
|
|
||||||
resstate = node->resstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info
|
* 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);
|
ExecFreeProjectionInfo(&node->ps);
|
||||||
ExecFreeExprContext(&resstate->cstate);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
/*
|
|
||||||
* shut down subplans
|
|
||||||
*/
|
|
||||||
ExecEndNode(outerPlan(node), (Plan *) node);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* clean out the tuple table
|
||||||
*/
|
*/
|
||||||
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
pfree(resstate);
|
|
||||||
node->resstate = NULL; /* XXX - new for us - er1p */
|
/*
|
||||||
|
* shut down subplans
|
||||||
|
*/
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
ResultState *resstate = node->resstate;
|
node->rs_done = false;
|
||||||
|
node->ps.ps_TupFromTlist = false;
|
||||||
resstate->rs_done = false;
|
node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
||||||
resstate->cstate.cs_TupFromTlist = false;
|
|
||||||
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree &&
|
if (((PlanState *) node)->lefttree &&
|
||||||
((Plan *) node)->lefttree->chgParam == NULL)
|
((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "executor/nodeSeqscan.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
|
|
||||||
static Oid InitScanRelation(SeqScan *node, EState *estate,
|
static void InitScanRelation(SeqScanState *node, EState *estate);
|
||||||
CommonScanState *scanstate);
|
static TupleTableSlot *SeqNext(SeqScanState *node);
|
||||||
static TupleTableSlot *SeqNext(SeqScan *node);
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* Scan Support
|
* Scan Support
|
||||||
@@ -44,11 +43,11 @@ static TupleTableSlot *SeqNext(SeqScan *node);
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
SeqNext(SeqScan *node)
|
SeqNext(SeqScanState *node)
|
||||||
{
|
{
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
HeapScanDesc scandesc;
|
HeapScanDesc scandesc;
|
||||||
CommonScanState *scanstate;
|
Index scanrelid;
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
@@ -56,11 +55,11 @@ SeqNext(SeqScan *node)
|
|||||||
/*
|
/*
|
||||||
* get information from the estate and scan state
|
* get information from the estate and scan state
|
||||||
*/
|
*/
|
||||||
estate = node->plan.state;
|
estate = node->ps.state;
|
||||||
scanstate = node->scanstate;
|
scandesc = node->ss_currentScanDesc;
|
||||||
scandesc = scanstate->css_currentScanDesc;
|
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
slot = scanstate->css_ScanTupleSlot;
|
slot = node->ss_ScanTupleSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||||
@@ -69,13 +68,13 @@ SeqNext(SeqScan *node)
|
|||||||
* switching in Init/ReScan plan...
|
* switching in Init/ReScan plan...
|
||||||
*/
|
*/
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
if (estate->es_evTupleNull[node->scanrelid - 1])
|
if (estate->es_evTupleNull[scanrelid - 1])
|
||||||
return slot; /* return empty slot */
|
return slot; /* return empty slot */
|
||||||
|
|
||||||
ExecStoreTuple(estate->es_evTuple[node->scanrelid - 1],
|
ExecStoreTuple(estate->es_evTuple[scanrelid - 1],
|
||||||
slot, InvalidBuffer, false);
|
slot, InvalidBuffer, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -85,7 +84,7 @@ SeqNext(SeqScan *node)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Flag for the next call that no more tuples */
|
/* Flag for the next call that no more tuples */
|
||||||
estate->es_evTupleNull[node->scanrelid - 1] = true;
|
estate->es_evTupleNull[scanrelid - 1] = true;
|
||||||
return (slot);
|
return (slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,12 +123,12 @@ SeqNext(SeqScan *node)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecSeqScan(SeqScan *node)
|
ExecSeqScan(SeqScanState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* use SeqNext as access method
|
* 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.
|
* subplans of scans.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static Oid
|
static void
|
||||||
InitScanRelation(SeqScan *node, EState *estate,
|
InitScanRelation(SeqScanState *node, EState *estate)
|
||||||
CommonScanState *scanstate)
|
|
||||||
{
|
{
|
||||||
Index relid;
|
Index relid;
|
||||||
List *rangeTable;
|
List *rangeTable;
|
||||||
@@ -156,7 +154,7 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||||||
*
|
*
|
||||||
* We acquire AccessShareLock for the duration of the scan.
|
* We acquire AccessShareLock for the duration of the scan.
|
||||||
*/
|
*/
|
||||||
relid = node->scanrelid;
|
relid = ((SeqScan *) node->ps.plan)->scanrelid;
|
||||||
rangeTable = estate->es_range_table;
|
rangeTable = estate->es_range_table;
|
||||||
rtentry = rt_fetch(relid, rangeTable);
|
rtentry = rt_fetch(relid, rangeTable);
|
||||||
reloid = rtentry->relid;
|
reloid = rtentry->relid;
|
||||||
@@ -168,12 +166,10 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
scanstate->css_currentRelation = currentRelation;
|
node->ss_currentRelation = currentRelation;
|
||||||
scanstate->css_currentScanDesc = currentScanDesc;
|
node->ss_currentScanDesc = currentScanDesc;
|
||||||
|
|
||||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
ExecAssignScanType(node, RelationGetDescr(currentRelation), false);
|
||||||
|
|
||||||
return reloid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -181,59 +177,64 @@ InitScanRelation(SeqScan *node, EState *estate,
|
|||||||
* ExecInitSeqScan
|
* ExecInitSeqScan
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
SeqScanState *
|
||||||
ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
|
ExecInitSeqScan(SeqScan *node, EState *estate)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
SeqScanState *scanstate;
|
||||||
Oid reloid;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Once upon a time it was possible to have an outerPlan of a SeqScan,
|
* Once upon a time it was possible to have an outerPlan of a SeqScan,
|
||||||
* but not any more.
|
* but not any more.
|
||||||
*/
|
*/
|
||||||
Assert(outerPlan((Plan *) node) == NULL);
|
Assert(outerPlan(node) == NULL);
|
||||||
Assert(innerPlan((Plan *) node) == NULL);
|
Assert(innerPlan(node) == NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign the node's execution state
|
* create state structure
|
||||||
*/
|
*/
|
||||||
node->plan.state = estate;
|
scanstate = makeNode(SeqScanState);
|
||||||
|
scanstate->ps.plan = (Plan *) node;
|
||||||
/*
|
scanstate->ps.state = estate;
|
||||||
* create new CommonScanState for node
|
|
||||||
*/
|
|
||||||
scanstate = makeNode(CommonScanState);
|
|
||||||
node->scanstate = scanstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* 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
|
#define SEQSCAN_NSLOTS 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
ExecInitResultTupleSlot(estate, &scanstate->ps);
|
||||||
ExecInitScanTupleSlot(estate, scanstate);
|
ExecInitScanTupleSlot(estate, scanstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize scan relation
|
* initialize scan relation
|
||||||
*/
|
*/
|
||||||
reloid = InitScanRelation(node, estate, scanstate);
|
InitScanRelation(scanstate, estate);
|
||||||
|
|
||||||
scanstate->cstate.cs_TupFromTlist = false;
|
scanstate->ps.ps_TupFromTlist = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
ExecAssignResultTypeFromTL(&scanstate->ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
ExecAssignProjectionInfo(&scanstate->ps);
|
||||||
|
|
||||||
return TRUE;
|
return scanstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -251,34 +252,34 @@ ExecCountSlotsSeqScan(SeqScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndSeqScan(SeqScan *node)
|
ExecEndSeqScan(SeqScanState *node)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
Relation relation;
|
Relation relation;
|
||||||
HeapScanDesc scanDesc;
|
HeapScanDesc scanDesc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from node
|
* get information from node
|
||||||
*/
|
*/
|
||||||
scanstate = node->scanstate;
|
relation = node->ss_currentRelation;
|
||||||
relation = scanstate->css_currentRelation;
|
scanDesc = node->ss_currentScanDesc;
|
||||||
scanDesc = scanstate->css_currentScanDesc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* 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);
|
ExecFreeProjectionInfo(&node->ps);
|
||||||
ExecFreeExprContext(&scanstate->cstate);
|
ExecFreeExprContext(&node->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close heap scan
|
* close heap scan
|
||||||
*/
|
*/
|
||||||
heap_endscan(scanDesc);
|
heap_endscan(scanDesc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clean out the tuple table
|
||||||
|
*/
|
||||||
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
|
ExecClearTuple(node->ss_ScanTupleSlot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close the heap relation.
|
* close the heap relation.
|
||||||
*
|
*
|
||||||
@@ -288,12 +289,6 @@ ExecEndSeqScan(SeqScan *node)
|
|||||||
* locking, however.)
|
* locking, however.)
|
||||||
*/
|
*/
|
||||||
heap_close(relation, NoLock);
|
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
|
void
|
||||||
ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
|
ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
Index scanrelid;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
|
|
||||||
scanstate = node->scanstate;
|
estate = node->ps.state;
|
||||||
estate = node->plan.state;
|
scanrelid = ((SeqScan *) node->ps.plan)->scanrelid;
|
||||||
|
|
||||||
/* If this is re-scanning of PlanQual ... */
|
/* If this is re-scanning of PlanQual ... */
|
||||||
if (estate->es_evTuple != NULL &&
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan = scanstate->css_currentScanDesc;
|
scan = node->ss_currentScanDesc;
|
||||||
|
|
||||||
heap_rescan(scan, /* scan desc */
|
heap_rescan(scan, /* scan desc */
|
||||||
NULL); /* new scan keys */
|
NULL); /* new scan keys */
|
||||||
@@ -338,13 +333,11 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecSeqMarkPos(SeqScan *node)
|
ExecSeqMarkPos(SeqScanState *node)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
|
|
||||||
scanstate = node->scanstate;
|
scan = node->ss_currentScanDesc;
|
||||||
scan = scanstate->css_currentScanDesc;
|
|
||||||
heap_markpos(scan);
|
heap_markpos(scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,12 +348,10 @@ ExecSeqMarkPos(SeqScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecSeqRestrPos(SeqScan *node)
|
ExecSeqRestrPos(SeqScanState *node)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
|
|
||||||
scanstate = node->scanstate;
|
scan = node->ss_currentScanDesc;
|
||||||
scan = scanstate->css_currentScanDesc;
|
|
||||||
heap_restrpos(scan);
|
heap_restrpos(scan);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 */
|
TupleTableSlot * /* return: a tuple or NULL */
|
||||||
ExecSetOp(SetOp *node)
|
ExecSetOp(SetOpState *node)
|
||||||
{
|
{
|
||||||
SetOpState *setopstate;
|
SetOp *plannode = (SetOp *) node->ps.plan;
|
||||||
TupleTableSlot *resultTupleSlot;
|
TupleTableSlot *resultTupleSlot;
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
*/
|
*/
|
||||||
setopstate = node->setopstate;
|
outerPlan = outerPlanState(node);
|
||||||
outerPlan = outerPlan((Plan *) node);
|
resultTupleSlot = node->ps.ps_ResultTupleSlot;
|
||||||
resultTupleSlot = setopstate->cstate.cs_ResultTupleSlot;
|
tupDesc = ExecGetResultType(&node->ps);
|
||||||
tupDesc = ExecGetResultType(&setopstate->cstate);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the previously-returned tuple needs to be returned more than
|
* If the previously-returned tuple needs to be returned more than
|
||||||
* once, keep returning it.
|
* once, keep returning it.
|
||||||
*/
|
*/
|
||||||
if (setopstate->numOutput > 0)
|
if (node->numOutput > 0)
|
||||||
{
|
{
|
||||||
setopstate->numOutput--;
|
node->numOutput--;
|
||||||
return resultTupleSlot;
|
return resultTupleSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,15 +87,15 @@ ExecSetOp(SetOp *node)
|
|||||||
/*
|
/*
|
||||||
* fetch a tuple from the outer subplan, unless we already did.
|
* fetch a tuple from the outer subplan, unless we already did.
|
||||||
*/
|
*/
|
||||||
if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
|
if (node->ps.ps_OuterTupleSlot == NULL &&
|
||||||
!setopstate->subplan_done)
|
!node->subplan_done)
|
||||||
{
|
{
|
||||||
setopstate->cstate.cs_OuterTupleSlot =
|
node->ps.ps_OuterTupleSlot =
|
||||||
ExecProcNode(outerPlan, (Plan *) node);
|
ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(setopstate->cstate.cs_OuterTupleSlot))
|
if (TupIsNull(node->ps.ps_OuterTupleSlot))
|
||||||
setopstate->subplan_done = true;
|
node->subplan_done = true;
|
||||||
}
|
}
|
||||||
inputTupleSlot = setopstate->cstate.cs_OuterTupleSlot;
|
inputTupleSlot = node->ps.ps_OuterTupleSlot;
|
||||||
|
|
||||||
if (TupIsNull(resultTupleSlot))
|
if (TupIsNull(resultTupleSlot))
|
||||||
{
|
{
|
||||||
@@ -104,18 +103,18 @@ ExecSetOp(SetOp *node)
|
|||||||
* First of group: save a copy in result slot, and reset
|
* First of group: save a copy in result slot, and reset
|
||||||
* duplicate-counters for new group.
|
* duplicate-counters for new group.
|
||||||
*/
|
*/
|
||||||
if (setopstate->subplan_done)
|
if (node->subplan_done)
|
||||||
return NULL; /* no more tuples */
|
return NULL; /* no more tuples */
|
||||||
ExecStoreTuple(heap_copytuple(inputTupleSlot->val),
|
ExecStoreTuple(heap_copytuple(inputTupleSlot->val),
|
||||||
resultTupleSlot,
|
resultTupleSlot,
|
||||||
InvalidBuffer,
|
InvalidBuffer,
|
||||||
true); /* free copied tuple at
|
true); /* free copied tuple at
|
||||||
* ExecClearTuple */
|
* ExecClearTuple */
|
||||||
setopstate->numLeft = 0;
|
node->numLeft = 0;
|
||||||
setopstate->numRight = 0;
|
node->numRight = 0;
|
||||||
endOfGroup = false;
|
endOfGroup = false;
|
||||||
}
|
}
|
||||||
else if (setopstate->subplan_done)
|
else if (node->subplan_done)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Reached end of input, so finish processing final group
|
* Reached end of input, so finish processing final group
|
||||||
@@ -131,9 +130,9 @@ ExecSetOp(SetOp *node)
|
|||||||
if (execTuplesMatch(inputTupleSlot->val,
|
if (execTuplesMatch(inputTupleSlot->val,
|
||||||
resultTupleSlot->val,
|
resultTupleSlot->val,
|
||||||
tupDesc,
|
tupDesc,
|
||||||
node->numCols, node->dupColIdx,
|
plannode->numCols, plannode->dupColIdx,
|
||||||
setopstate->eqfunctions,
|
node->eqfunctions,
|
||||||
setopstate->tempContext))
|
node->tempContext))
|
||||||
endOfGroup = false;
|
endOfGroup = false;
|
||||||
else
|
else
|
||||||
endOfGroup = true;
|
endOfGroup = true;
|
||||||
@@ -146,37 +145,37 @@ ExecSetOp(SetOp *node)
|
|||||||
* Decide how many copies (if any) to emit. This logic is
|
* Decide how many copies (if any) to emit. This logic is
|
||||||
* straight from the SQL92 specification.
|
* straight from the SQL92 specification.
|
||||||
*/
|
*/
|
||||||
switch (node->cmd)
|
switch (plannode->cmd)
|
||||||
{
|
{
|
||||||
case SETOPCMD_INTERSECT:
|
case SETOPCMD_INTERSECT:
|
||||||
if (setopstate->numLeft > 0 && setopstate->numRight > 0)
|
if (node->numLeft > 0 && node->numRight > 0)
|
||||||
setopstate->numOutput = 1;
|
node->numOutput = 1;
|
||||||
else
|
else
|
||||||
setopstate->numOutput = 0;
|
node->numOutput = 0;
|
||||||
break;
|
break;
|
||||||
case SETOPCMD_INTERSECT_ALL:
|
case SETOPCMD_INTERSECT_ALL:
|
||||||
setopstate->numOutput =
|
node->numOutput =
|
||||||
(setopstate->numLeft < setopstate->numRight) ?
|
(node->numLeft < node->numRight) ?
|
||||||
setopstate->numLeft : setopstate->numRight;
|
node->numLeft : node->numRight;
|
||||||
break;
|
break;
|
||||||
case SETOPCMD_EXCEPT:
|
case SETOPCMD_EXCEPT:
|
||||||
if (setopstate->numLeft > 0 && setopstate->numRight == 0)
|
if (node->numLeft > 0 && node->numRight == 0)
|
||||||
setopstate->numOutput = 1;
|
node->numOutput = 1;
|
||||||
else
|
else
|
||||||
setopstate->numOutput = 0;
|
node->numOutput = 0;
|
||||||
break;
|
break;
|
||||||
case SETOPCMD_EXCEPT_ALL:
|
case SETOPCMD_EXCEPT_ALL:
|
||||||
setopstate->numOutput =
|
node->numOutput =
|
||||||
(setopstate->numLeft < setopstate->numRight) ?
|
(node->numLeft < node->numRight) ?
|
||||||
0 : (setopstate->numLeft - setopstate->numRight);
|
0 : (node->numLeft - node->numRight);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "ExecSetOp: bogus command code %d",
|
elog(ERROR, "ExecSetOp: bogus command code %d",
|
||||||
(int) node->cmd);
|
(int) plannode->cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Fall out of for-loop if we have tuples to emit */
|
/* Fall out of for-loop if we have tuples to emit */
|
||||||
if (setopstate->numOutput > 0)
|
if (node->numOutput > 0)
|
||||||
break;
|
break;
|
||||||
/* Else flag that we have no current tuple, and loop around */
|
/* Else flag that we have no current tuple, and loop around */
|
||||||
ExecClearTuple(resultTupleSlot);
|
ExecClearTuple(resultTupleSlot);
|
||||||
@@ -191,16 +190,16 @@ ExecSetOp(SetOp *node)
|
|||||||
bool isNull;
|
bool isNull;
|
||||||
|
|
||||||
flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
|
flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
|
||||||
node->flagColIdx,
|
plannode->flagColIdx,
|
||||||
tupDesc,
|
tupDesc,
|
||||||
&isNull));
|
&isNull));
|
||||||
Assert(!isNull);
|
Assert(!isNull);
|
||||||
if (flag)
|
if (flag)
|
||||||
setopstate->numRight++;
|
node->numRight++;
|
||||||
else
|
else
|
||||||
setopstate->numLeft++;
|
node->numLeft++;
|
||||||
/* Set flag to fetch a new input tuple, and loop around */
|
/* 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
|
* If we fall out of loop, then we need to emit at least one copy of
|
||||||
* resultTuple.
|
* resultTuple.
|
||||||
*/
|
*/
|
||||||
Assert(setopstate->numOutput > 0);
|
Assert(node->numOutput > 0);
|
||||||
setopstate->numOutput--;
|
node->numOutput--;
|
||||||
return resultTupleSlot;
|
return resultTupleSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,23 +219,19 @@ ExecSetOp(SetOp *node)
|
|||||||
* the node's subplan.
|
* the node's subplan.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool /* return: initialization status */
|
SetOpState *
|
||||||
ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
ExecInitSetOp(SetOp *node, EState *estate)
|
||||||
{
|
{
|
||||||
SetOpState *setopstate;
|
SetOpState *setopstate;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new SetOpState for node
|
|
||||||
*/
|
*/
|
||||||
setopstate = makeNode(SetOpState);
|
setopstate = makeNode(SetOpState);
|
||||||
node->setopstate = setopstate;
|
setopstate->ps.plan = (Plan *) node;
|
||||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
setopstate->ps.state = estate;
|
||||||
|
|
||||||
|
setopstate->ps.ps_OuterTupleSlot = NULL;
|
||||||
setopstate->subplan_done = false;
|
setopstate->subplan_done = false;
|
||||||
setopstate->numOutput = 0;
|
setopstate->numOutput = 0;
|
||||||
|
|
||||||
@@ -259,30 +254,29 @@ ExecInitSetOp(SetOp *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* Tuple table initialization
|
* Tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &setopstate->cstate);
|
ExecInitResultTupleSlot(estate, &setopstate->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* then initialize outer plan
|
* then initialize outer plan
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlanState(setopstate) = ExecInitNode(outerPlan(node), estate);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setop nodes do no projections, so initialize projection info for
|
* setop nodes do no projections, so initialize projection info for
|
||||||
* this node appropriately
|
* this node appropriately
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &setopstate->cstate);
|
ExecAssignResultTypeFromOuterPlan(&setopstate->ps);
|
||||||
setopstate->cstate.cs_ProjInfo = NULL;
|
setopstate->ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precompute fmgr lookup data for inner loop
|
* Precompute fmgr lookup data for inner loop
|
||||||
*/
|
*/
|
||||||
setopstate->eqfunctions =
|
setopstate->eqfunctions =
|
||||||
execTuplesMatchPrepare(ExecGetResultType(&setopstate->cstate),
|
execTuplesMatchPrepare(ExecGetResultType(&setopstate->ps),
|
||||||
node->numCols,
|
node->numCols,
|
||||||
node->dupColIdx);
|
node->dupColIdx);
|
||||||
|
|
||||||
return TRUE;
|
return setopstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -301,34 +295,30 @@ ExecCountSlotsSetOp(SetOp *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndSetOp(SetOp *node)
|
ExecEndSetOp(SetOpState *node)
|
||||||
{
|
{
|
||||||
SetOpState *setopstate = node->setopstate;
|
|
||||||
|
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
|
||||||
|
|
||||||
MemoryContextDelete(setopstate->tempContext);
|
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
node->ps.ps_OuterTupleSlot = NULL;
|
||||||
|
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
|
|
||||||
|
MemoryContextDelete(node->tempContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
SetOpState *setopstate = node->setopstate;
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
|
node->ps.ps_OuterTupleSlot = NULL;
|
||||||
ExecClearTuple(setopstate->cstate.cs_ResultTupleSlot);
|
node->subplan_done = false;
|
||||||
setopstate->cstate.cs_OuterTupleSlot = NULL;
|
node->numOutput = 0;
|
||||||
setopstate->subplan_done = false;
|
|
||||||
setopstate->numOutput = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *
|
TupleTableSlot *
|
||||||
ExecSort(Sort *node)
|
ExecSort(SortState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
SortState *sortstate;
|
|
||||||
ScanDirection dir;
|
ScanDirection dir;
|
||||||
Tuplesortstate *tuplesortstate;
|
Tuplesortstate *tuplesortstate;
|
||||||
HeapTuple heapTuple;
|
HeapTuple heapTuple;
|
||||||
@@ -104,10 +103,9 @@ ExecSort(Sort *node)
|
|||||||
SO1_printf("ExecSort: %s\n",
|
SO1_printf("ExecSort: %s\n",
|
||||||
"entering routine");
|
"entering routine");
|
||||||
|
|
||||||
sortstate = node->sortstate;
|
estate = node->ss.ps.state;
|
||||||
estate = node->plan.state;
|
|
||||||
dir = estate->es_direction;
|
dir = estate->es_direction;
|
||||||
tuplesortstate = (Tuplesortstate *) sortstate->tuplesortstate;
|
tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If first time through, read all tuples from outer plan and pass
|
* If first time through, read all tuples from outer plan and pass
|
||||||
@@ -115,9 +113,10 @@ ExecSort(Sort *node)
|
|||||||
* tuplesort.
|
* tuplesort.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!sortstate->sort_Done)
|
if (!node->sort_Done)
|
||||||
{
|
{
|
||||||
Plan *outerNode;
|
Sort *plannode = (Sort *) node->ss.ps.plan;
|
||||||
|
PlanState *outerNode;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
Oid *sortOperators;
|
Oid *sortOperators;
|
||||||
AttrNumber *attNums;
|
AttrNumber *attNums;
|
||||||
@@ -127,8 +126,7 @@ ExecSort(Sort *node)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Want to scan subplan in the forward direction while creating
|
* Want to scan subplan in the forward direction while creating
|
||||||
* the sorted data. (Does setting my direction actually affect
|
* the sorted data.
|
||||||
* the subplan? I bet this is useless code...)
|
|
||||||
*/
|
*/
|
||||||
estate->es_direction = ForwardScanDirection;
|
estate->es_direction = ForwardScanDirection;
|
||||||
|
|
||||||
@@ -138,15 +136,15 @@ ExecSort(Sort *node)
|
|||||||
SO1_printf("ExecSort: %s\n",
|
SO1_printf("ExecSort: %s\n",
|
||||||
"calling tuplesort_begin");
|
"calling tuplesort_begin");
|
||||||
|
|
||||||
outerNode = outerPlan((Plan *) node);
|
outerNode = outerPlanState(node);
|
||||||
tupDesc = ExecGetTupType(outerNode);
|
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,
|
sortOperators, attNums,
|
||||||
true /* randomAccess */ );
|
true /* randomAccess */ );
|
||||||
sortstate->tuplesortstate = (void *) tuplesortstate;
|
node->tuplesortstate = (void *) tuplesortstate;
|
||||||
|
|
||||||
pfree(sortOperators);
|
pfree(sortOperators);
|
||||||
pfree(attNums);
|
pfree(attNums);
|
||||||
@@ -157,7 +155,7 @@ ExecSort(Sort *node)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
slot = ExecProcNode(outerNode, (Plan *) node);
|
slot = ExecProcNode(outerNode);
|
||||||
|
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
break;
|
break;
|
||||||
@@ -178,12 +176,12 @@ ExecSort(Sort *node)
|
|||||||
/*
|
/*
|
||||||
* make sure the tuple descriptor is up to date (is this needed?)
|
* 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
|
* finally set the sorted flag to true
|
||||||
*/
|
*/
|
||||||
sortstate->sort_Done = true;
|
node->sort_Done = true;
|
||||||
SO1_printf("ExecSort: %s\n", "sorting done");
|
SO1_printf("ExecSort: %s\n", "sorting done");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +196,7 @@ ExecSort(Sort *node)
|
|||||||
ScanDirectionIsForward(dir),
|
ScanDirectionIsForward(dir),
|
||||||
&should_free);
|
&should_free);
|
||||||
|
|
||||||
slot = sortstate->csstate.cstate.cs_ResultTupleSlot;
|
slot = node->ss.ps.ps_ResultTupleSlot;
|
||||||
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
|
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,29 +207,24 @@ ExecSort(Sort *node)
|
|||||||
* produced by the planner and initailizes its outer subtree.
|
* produced by the planner and initailizes its outer subtree.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
SortState *
|
||||||
ExecInitSort(Sort *node, EState *estate, Plan *parent)
|
ExecInitSort(Sort *node, EState *estate)
|
||||||
{
|
{
|
||||||
SortState *sortstate;
|
SortState *sortstate;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
SO1_printf("ExecInitSort: %s\n",
|
SO1_printf("ExecInitSort: %s\n",
|
||||||
"initializing sort node");
|
"initializing sort node");
|
||||||
|
|
||||||
/*
|
|
||||||
* assign the node's execution state
|
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create state structure
|
* create state structure
|
||||||
*/
|
*/
|
||||||
sortstate = makeNode(SortState);
|
sortstate = makeNode(SortState);
|
||||||
|
sortstate->ss.ps.plan = (Plan *) node;
|
||||||
|
sortstate->ss.ps.state = estate;
|
||||||
|
|
||||||
sortstate->sort_Done = false;
|
sortstate->sort_Done = false;
|
||||||
sortstate->tuplesortstate = NULL;
|
sortstate->tuplesortstate = NULL;
|
||||||
|
|
||||||
node->sortstate = sortstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
@@ -246,27 +239,26 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
|
|||||||
*
|
*
|
||||||
* sort nodes only return scan tuples from their sorted relation.
|
* sort nodes only return scan tuples from their sorted relation.
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &sortstate->ss.ps);
|
||||||
ExecInitScanTupleSlot(estate, &sortstate->csstate);
|
ExecInitScanTupleSlot(estate, &sortstate->ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initializes child nodes
|
* initializes child nodes
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize tuple type. no need to initialize projection info
|
* initialize tuple type. no need to initialize projection info
|
||||||
* because this node doesn't do projections.
|
* because this node doesn't do projections.
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &sortstate->csstate.cstate);
|
ExecAssignResultTypeFromOuterPlan(&sortstate->ss.ps);
|
||||||
ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
|
ExecAssignScanTypeFromOuterPlan(&sortstate->ss);
|
||||||
sortstate->csstate.cstate.cs_ProjInfo = NULL;
|
sortstate->ss.ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
SO1_printf("ExecInitSort: %s\n",
|
SO1_printf("ExecInitSort: %s\n",
|
||||||
"sort node initialized");
|
"sort node initialized");
|
||||||
|
|
||||||
return TRUE;
|
return sortstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -282,39 +274,27 @@ ExecCountSlotsSort(Sort *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndSort(Sort *node)
|
ExecEndSort(SortState *node)
|
||||||
{
|
{
|
||||||
SortState *sortstate;
|
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* get info from the sort state
|
|
||||||
*/
|
|
||||||
SO1_printf("ExecEndSort: %s\n",
|
SO1_printf("ExecEndSort: %s\n",
|
||||||
"shutting down sort node");
|
"shutting down sort node");
|
||||||
|
|
||||||
sortstate = node->sortstate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* shut down the subplan
|
|
||||||
*/
|
|
||||||
outerPlan = outerPlan((Plan *) node);
|
|
||||||
ExecEndNode(outerPlan, (Plan *) node);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the tuple table
|
* 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
|
* Release tuplesort resources
|
||||||
*/
|
*/
|
||||||
if (sortstate->tuplesortstate != NULL)
|
if (node->tuplesortstate != NULL)
|
||||||
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
|
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
||||||
sortstate->tuplesortstate = NULL;
|
node->tuplesortstate = NULL;
|
||||||
|
|
||||||
pfree(sortstate);
|
|
||||||
node->sortstate = NULL;
|
|
||||||
|
|
||||||
SO1_printf("ExecEndSort: %s\n",
|
SO1_printf("ExecEndSort: %s\n",
|
||||||
"sort node shutdown");
|
"sort node shutdown");
|
||||||
@@ -327,17 +307,15 @@ ExecEndSort(Sort *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecSortMarkPos(Sort *node)
|
ExecSortMarkPos(SortState *node)
|
||||||
{
|
{
|
||||||
SortState *sortstate = node->sortstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we haven't sorted yet, just return
|
* if we haven't sorted yet, just return
|
||||||
*/
|
*/
|
||||||
if (!sortstate->sort_Done)
|
if (!node->sort_Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tuplesort_markpos((Tuplesortstate *) sortstate->tuplesortstate);
|
tuplesort_markpos((Tuplesortstate *) node->tuplesortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -347,36 +325,32 @@ ExecSortMarkPos(Sort *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecSortRestrPos(Sort *node)
|
ExecSortRestrPos(SortState *node)
|
||||||
{
|
{
|
||||||
SortState *sortstate = node->sortstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we haven't sorted yet, just return.
|
* if we haven't sorted yet, just return.
|
||||||
*/
|
*/
|
||||||
if (!sortstate->sort_Done)
|
if (!node->sort_Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* restore the scan to the previously marked position
|
* restore the scan to the previously marked position
|
||||||
*/
|
*/
|
||||||
tuplesort_restorepos((Tuplesortstate *) sortstate->tuplesortstate);
|
tuplesort_restorepos((Tuplesortstate *) node->tuplesortstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
* If we haven't sorted yet, just return. If outerplan' chgParam is
|
||||||
* not NULL then it will be re-scanned by ExecProcNode, else - no
|
* not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||||
* reason to re-scan it at all.
|
* reason to re-scan it at all.
|
||||||
*/
|
*/
|
||||||
if (!sortstate->sort_Done)
|
if (!node->sort_Done)
|
||||||
return;
|
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;
|
* 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.
|
* 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;
|
node->sort_Done = false;
|
||||||
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
|
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
||||||
sortstate->tuplesortstate = NULL;
|
node->tuplesortstate = NULL;
|
||||||
}
|
}
|
||||||
else
|
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
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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)
|
* ExecSubPlan(node)
|
||||||
*
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
ExecSubPlan(SubPlanState *node, List *pvar,
|
||||||
|
ExprContext *econtext, bool *isNull)
|
||||||
{
|
{
|
||||||
Plan *plan = node->plan;
|
PlanState *planstate = node->planstate;
|
||||||
SubLink *sublink = node->sublink;
|
SubPlan *subplan = (SubPlan *) node->ps.plan;
|
||||||
|
SubLink *sublink = subplan->sublink;
|
||||||
SubLinkType subLinkType = sublink->subLinkType;
|
SubLinkType subLinkType = sublink->subLinkType;
|
||||||
bool useor = sublink->useor;
|
bool useor = sublink->useor;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
@@ -49,15 +50,15 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
|
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");
|
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set Params of this plan from parent plan correlation Vars
|
* 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;
|
ParamExecData *prm;
|
||||||
|
|
||||||
@@ -69,11 +70,12 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||||||
NULL);
|
NULL);
|
||||||
pvar = lnext(pvar);
|
pvar = lnext(pvar);
|
||||||
}
|
}
|
||||||
plan->chgParam = nconc(plan->chgParam, listCopy(node->parParam));
|
planstate->chgParam = nconc(planstate->chgParam,
|
||||||
|
listCopy(subplan->parParam));
|
||||||
}
|
}
|
||||||
Assert(pvar == NIL);
|
Assert(pvar == NIL);
|
||||||
|
|
||||||
ExecReScan(plan, NULL, NULL);
|
ExecReScan(planstate, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For all sublink types except EXPR_SUBLINK, the result is boolean as
|
* 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);
|
result = BoolGetDatum(subLinkType == ALL_SUBLINK);
|
||||||
*isNull = false;
|
*isNull = false;
|
||||||
|
|
||||||
for (slot = ExecProcNode(plan, NULL);
|
for (slot = ExecProcNode(planstate);
|
||||||
!TupIsNull(slot);
|
!TupIsNull(slot);
|
||||||
slot = ExecProcNode(plan, NULL))
|
slot = ExecProcNode(planstate))
|
||||||
{
|
{
|
||||||
HeapTuple tup = slot->val;
|
HeapTuple tup = slot->val;
|
||||||
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
||||||
@@ -283,13 +285,37 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecInitSubPlan
|
* ExecInitSubPlan
|
||||||
*
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
SubPlanState *
|
||||||
ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
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_range_table = node->rtable;
|
||||||
sp_estate->es_param_list_info = estate->es_param_list_info;
|
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 =
|
sp_estate->es_tupleTable =
|
||||||
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
|
ExecCreateTupleTable(ExecCountSlotsNode(node->plan) + 10);
|
||||||
sp_estate->es_snapshot = estate->es_snapshot;
|
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))
|
subplanstate->needShutdown = true; /* now we need to shutdown the subplan */
|
||||||
return false;
|
|
||||||
|
|
||||||
node->needShutdown = true; /* now we need to shutdown the subplan */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this plan is un-correlated or undirect correlated one and want
|
* 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)]);
|
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
|
void
|
||||||
ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
||||||
{
|
{
|
||||||
Plan *plan = node->plan;
|
PlanState *planstate = node->planstate;
|
||||||
SubLink *sublink = node->sublink;
|
SubPlan *subplan = (SubPlan *) node->ps.plan;
|
||||||
|
SubLink *sublink = subplan->sublink;
|
||||||
|
EState *estate = node->ps.state;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
List *lst;
|
List *lst;
|
||||||
@@ -364,12 +392,12 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||||||
sublink->subLinkType == ALL_SUBLINK)
|
sublink->subLinkType == ALL_SUBLINK)
|
||||||
elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
|
elog(ERROR, "ExecSetParamPlan: ANY/ALL subselect unsupported");
|
||||||
|
|
||||||
if (plan->chgParam != NULL)
|
if (planstate->chgParam != NULL)
|
||||||
ExecReScan(plan, NULL, NULL);
|
ExecReScan(planstate, NULL);
|
||||||
|
|
||||||
for (slot = ExecProcNode(plan, NULL);
|
for (slot = ExecProcNode(planstate);
|
||||||
!TupIsNull(slot);
|
!TupIsNull(slot);
|
||||||
slot = ExecProcNode(plan, NULL))
|
slot = ExecProcNode(planstate))
|
||||||
{
|
{
|
||||||
HeapTuple tup = slot->val;
|
HeapTuple tup = slot->val;
|
||||||
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
||||||
@@ -377,7 +405,7 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||||||
|
|
||||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
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->execPlan = NULL;
|
||||||
prm->value = BoolGetDatum(true);
|
prm->value = BoolGetDatum(true);
|
||||||
@@ -404,9 +432,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||||||
heap_freetuple(node->curTuple);
|
heap_freetuple(node->curTuple);
|
||||||
node->curTuple = tup;
|
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->execPlan = NULL;
|
||||||
prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
|
prm->value = heap_getattr(tup, i, tdesc, &(prm->isnull));
|
||||||
@@ -418,7 +446,7 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||||||
{
|
{
|
||||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
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->execPlan = NULL;
|
||||||
prm->value = BoolGetDatum(false);
|
prm->value = BoolGetDatum(false);
|
||||||
@@ -426,9 +454,9 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||||||
}
|
}
|
||||||
else
|
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->execPlan = NULL;
|
||||||
prm->value = (Datum) 0;
|
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;
|
node->needShutdown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,11 +479,11 @@ ExecSetParamPlan(SubPlan *node, ExprContext *econtext)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndSubPlan(SubPlan *node)
|
ExecEndSubPlan(SubPlanState *node)
|
||||||
{
|
{
|
||||||
if (node->needShutdown)
|
if (node->needShutdown)
|
||||||
{
|
{
|
||||||
ExecEndNode(node->plan, NULL);
|
ExecEndNode(node->planstate);
|
||||||
node->needShutdown = false;
|
node->needShutdown = false;
|
||||||
}
|
}
|
||||||
if (node->curTuple)
|
if (node->curTuple)
|
||||||
@@ -466,33 +494,34 @@ ExecEndSubPlan(SubPlan *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
List *lst;
|
||||||
|
|
||||||
if (node->parParam != NULL)
|
if (subplan->parParam != NULL)
|
||||||
elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
|
elog(ERROR, "ExecReScanSetParamPlan: direct correlated subquery unsupported, yet");
|
||||||
if (node->setParam == NULL)
|
if (subplan->setParam == NULL)
|
||||||
elog(ERROR, "ExecReScanSetParamPlan: setParam list is 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");
|
elog(ERROR, "ExecReScanSetParamPlan: extParam list of plan is NULL");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't actual re-scan: ExecSetParamPlan does re-scan if
|
* 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
|
* 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;
|
prm->execPlan = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->chgParam = nconc(parent->chgParam, listCopy(node->setParam));
|
parent->chgParam = nconc(parent->chgParam, listCopy(subplan->setParam));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "parser/parsetree.h"
|
||||||
#include "tcop/pquery.h"
|
#include "tcop/pquery.h"
|
||||||
|
|
||||||
static TupleTableSlot *SubqueryNext(SubqueryScan *node);
|
static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* Scan Support
|
* Scan Support
|
||||||
@@ -48,9 +48,8 @@ static TupleTableSlot *SubqueryNext(SubqueryScan *node);
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
SubqueryNext(SubqueryScan *node)
|
SubqueryNext(SubqueryScanState *node)
|
||||||
{
|
{
|
||||||
SubqueryScanState *subquerystate;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
@@ -58,8 +57,7 @@ SubqueryNext(SubqueryScan *node)
|
|||||||
/*
|
/*
|
||||||
* get information from the estate and scan state
|
* get information from the estate and scan state
|
||||||
*/
|
*/
|
||||||
estate = node->scan.plan.state;
|
estate = node->ss.ps.state;
|
||||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -70,11 +68,11 @@ SubqueryNext(SubqueryScan *node)
|
|||||||
/*
|
/*
|
||||||
* get the next tuple from the sub-query
|
* 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;
|
return slot;
|
||||||
}
|
}
|
||||||
@@ -90,20 +88,20 @@ SubqueryNext(SubqueryScan *node)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecSubqueryScan(SubqueryScan *node)
|
ExecSubqueryScan(SubqueryScanState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* use SubqueryNext as access method
|
* use SubqueryNext as access method
|
||||||
*/
|
*/
|
||||||
return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
|
return ExecScan(&node->ss, (ExecScanAccessMtd) SubqueryNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecInitSubqueryScan
|
* ExecInitSubqueryScan
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
SubqueryScanState *
|
||||||
ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
|
||||||
{
|
{
|
||||||
SubqueryScanState *subquerystate;
|
SubqueryScanState *subquerystate;
|
||||||
RangeTblEntry *rte;
|
RangeTblEntry *rte;
|
||||||
@@ -112,33 +110,39 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* SubqueryScan should not have any "normal" children.
|
* SubqueryScan should not have any "normal" children.
|
||||||
*/
|
*/
|
||||||
Assert(outerPlan((Plan *) node) == NULL);
|
Assert(outerPlan(node) == NULL);
|
||||||
Assert(innerPlan((Plan *) node) == NULL);
|
Assert(innerPlan(node) == NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign the node's execution state
|
* create state structure
|
||||||
*/
|
|
||||||
node->scan.plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new SubqueryScanState for node
|
|
||||||
*/
|
*/
|
||||||
subquerystate = makeNode(SubqueryScanState);
|
subquerystate = makeNode(SubqueryScanState);
|
||||||
node->scan.scanstate = (CommonScanState *) subquerystate;
|
subquerystate->ss.ps.plan = (Plan *) node;
|
||||||
|
subquerystate->ss.ps.state = estate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* 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
|
#define SUBQUERYSCAN_NSLOTS 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
|
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize subquery
|
* initialize subquery
|
||||||
@@ -157,20 +161,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
|||||||
sp_estate->es_tupleTable =
|
sp_estate->es_tupleTable =
|
||||||
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
|
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
|
||||||
sp_estate->es_snapshot = estate->es_snapshot;
|
sp_estate->es_snapshot = estate->es_snapshot;
|
||||||
|
sp_estate->es_instrument = estate->es_instrument;
|
||||||
|
|
||||||
if (!ExecInitNode(node->subplan, sp_estate, (Plan *) node))
|
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
|
||||||
return false;
|
|
||||||
|
|
||||||
subquerystate->csstate.css_ScanTupleSlot = NULL;
|
subquerystate->ss.ss_ScanTupleSlot = NULL;
|
||||||
subquerystate->csstate.cstate.cs_TupFromTlist = false;
|
subquerystate->ss.ps.ps_TupFromTlist = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize tuple type
|
* initialize tuple type
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
|
ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
|
||||||
ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
|
ExecAssignProjectionInfo(&subquerystate->ss.ps);
|
||||||
|
|
||||||
return TRUE;
|
return subquerystate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -191,42 +195,31 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
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
|
* 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);
|
ExecFreeProjectionInfo(&node->ss.ps);
|
||||||
ExecFreeExprContext(&subquerystate->csstate.cstate);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
/*
|
|
||||||
* 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... */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clean out the upper tuple table
|
* 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
|
void
|
||||||
ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
|
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
SubqueryScanState *subquerystate;
|
|
||||||
EState *estate;
|
EState *estate;
|
||||||
|
|
||||||
subquerystate = (SubqueryScanState *) node->scan.scanstate;
|
estate = node->ss.ps.state;
|
||||||
estate = node->scan.plan.state;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecReScan doesn't know about my subplan, so I have to do
|
* ExecReScan doesn't know about my subplan, so I have to do
|
||||||
* changed-parameter signaling myself.
|
* changed-parameter signaling myself.
|
||||||
*/
|
*/
|
||||||
if (node->scan.plan.chgParam != NULL)
|
if (node->ss.ps.chgParam != NULL)
|
||||||
SetChangedParamList(node->subplan, node->scan.plan.chgParam);
|
SetChangedParamList(node->subplan, node->ss.ps.chgParam);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (node->subplan->chgParam == NULL)
|
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
|
* 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"
|
#include "parser/parsetree.h"
|
||||||
|
|
||||||
static int TidListCreate(List *, ExprContext *, ItemPointerData[]);
|
static int TidListCreate(List *, ExprContext *, ItemPointerData[]);
|
||||||
static TupleTableSlot *TidNext(TidScan *node);
|
static TupleTableSlot *TidNext(TidScanState *node);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
|
TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
|
||||||
@@ -65,19 +65,17 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointerData tidList[])
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
TidNext(TidScan *node)
|
TidNext(TidScanState *node)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
CommonScanState *scanstate;
|
|
||||||
TidScanState *tidstate;
|
|
||||||
ScanDirection direction;
|
ScanDirection direction;
|
||||||
Snapshot snapshot;
|
Snapshot snapshot;
|
||||||
Relation heapRelation;
|
Relation heapRelation;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
Index scanrelid;
|
||||||
Buffer buffer = InvalidBuffer;
|
Buffer buffer = InvalidBuffer;
|
||||||
int numTids;
|
int numTids;
|
||||||
|
|
||||||
bool bBackward;
|
bool bBackward;
|
||||||
int tidNumber;
|
int tidNumber;
|
||||||
ItemPointerData *tidList;
|
ItemPointerData *tidList;
|
||||||
@@ -85,15 +83,14 @@ TidNext(TidScan *node)
|
|||||||
/*
|
/*
|
||||||
* extract necessary information from tid scan node
|
* extract necessary information from tid scan node
|
||||||
*/
|
*/
|
||||||
estate = node->scan.plan.state;
|
estate = node->ss.ps.state;
|
||||||
direction = estate->es_direction;
|
direction = estate->es_direction;
|
||||||
snapshot = estate->es_snapshot;
|
snapshot = estate->es_snapshot;
|
||||||
scanstate = node->scan.scanstate;
|
heapRelation = node->ss.ss_currentRelation;
|
||||||
tidstate = node->tidstate;
|
numTids = node->tss_NumTids;
|
||||||
heapRelation = scanstate->css_currentRelation;
|
tidList = node->tss_TidList;
|
||||||
numTids = tidstate->tss_NumTids;
|
slot = node->ss.ss_ScanTupleSlot;
|
||||||
tidList = tidstate->tss_TidList;
|
scanrelid = ((TidScan *) node->ss.ps.plan)->scan.scanrelid;
|
||||||
slot = scanstate->css_ScanTupleSlot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||||
@@ -102,10 +99,10 @@ TidNext(TidScan *node)
|
|||||||
* switching in Init/ReScan plan...
|
* switching in Init/ReScan plan...
|
||||||
*/
|
*/
|
||||||
if (estate->es_evTuple != NULL &&
|
if (estate->es_evTuple != NULL &&
|
||||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
estate->es_evTuple[scanrelid - 1] != NULL)
|
||||||
{
|
{
|
||||||
ExecClearTuple(slot);
|
ExecClearTuple(slot);
|
||||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
if (estate->es_evTupleNull[scanrelid - 1])
|
||||||
return slot; /* return empty slot */
|
return slot; /* return empty slot */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -113,15 +110,15 @@ TidNext(TidScan *node)
|
|||||||
* list? In runtime-key case this is not certain, is it?
|
* 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);
|
slot, InvalidBuffer, false);
|
||||||
|
|
||||||
/* Flag for the next call that no more tuples */
|
/* 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);
|
return (slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple = &(tidstate->tss_htup);
|
tuple = &(node->tss_htup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ok, now that we have what we need, fetch an tid tuple. if scanning
|
* ok, now that we have what we need, fetch an tid tuple. if scanning
|
||||||
@@ -131,26 +128,26 @@ TidNext(TidScan *node)
|
|||||||
bBackward = ScanDirectionIsBackward(direction);
|
bBackward = ScanDirectionIsBackward(direction);
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
{
|
{
|
||||||
tidNumber = numTids - tidstate->tss_TidPtr - 1;
|
tidNumber = numTids - node->tss_TidPtr - 1;
|
||||||
if (tidNumber < 0)
|
if (tidNumber < 0)
|
||||||
{
|
{
|
||||||
tidNumber = 0;
|
tidNumber = 0;
|
||||||
tidstate->tss_TidPtr = numTids - 1;
|
node->tss_TidPtr = numTids - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((tidNumber = tidstate->tss_TidPtr) < 0)
|
if ((tidNumber = node->tss_TidPtr) < 0)
|
||||||
{
|
{
|
||||||
tidNumber = 0;
|
tidNumber = 0;
|
||||||
tidstate->tss_TidPtr = 0;
|
node->tss_TidPtr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (tidNumber < numTids)
|
while (tidNumber < numTids)
|
||||||
{
|
{
|
||||||
bool slot_is_valid = false;
|
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))
|
if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
|
||||||
{
|
{
|
||||||
bool prev_matches = false;
|
bool prev_matches = false;
|
||||||
@@ -181,7 +178,7 @@ TidNext(TidScan *node)
|
|||||||
* do this by passing the tuple through ExecQual and look for
|
* do this by passing the tuple through ExecQual and look for
|
||||||
* failure with all previous qualifications.
|
* 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++)
|
prev_tid++)
|
||||||
{
|
{
|
||||||
if (ItemPointerEquals(&tidList[prev_tid], &tuple->t_self))
|
if (ItemPointerEquals(&tidList[prev_tid], &tuple->t_self))
|
||||||
@@ -197,9 +194,9 @@ TidNext(TidScan *node)
|
|||||||
}
|
}
|
||||||
tidNumber++;
|
tidNumber++;
|
||||||
if (bBackward)
|
if (bBackward)
|
||||||
tidstate->tss_TidPtr--;
|
node->tss_TidPtr--;
|
||||||
else
|
else
|
||||||
tidstate->tss_TidPtr++;
|
node->tss_TidPtr++;
|
||||||
if (slot_is_valid)
|
if (slot_is_valid)
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
@@ -231,12 +228,12 @@ TidNext(TidScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecTidScan(TidScan *node)
|
ExecTidScan(TidScanState *node)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* use TidNext as access method
|
* 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
|
void
|
||||||
ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
ExecTidReScan(TidScanState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
EState *estate;
|
EState *estate;
|
||||||
TidScanState *tidstate;
|
|
||||||
ItemPointerData *tidList;
|
ItemPointerData *tidList;
|
||||||
|
Index scanrelid;
|
||||||
|
|
||||||
estate = node->scan.plan.state;
|
estate = node->ss.ps.state;
|
||||||
tidstate = node->tidstate;
|
tidList = node->tss_TidList;
|
||||||
tidList = tidstate->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 we are being passed an outer tuple, save it for runtime key calc */
|
||||||
if (exprCtxt != NULL)
|
if (exprCtxt != NULL)
|
||||||
node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple =
|
node->ss.ps.ps_ExprContext->ecxt_outertuple =
|
||||||
exprCtxt->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 this is re-scanning of PlanQual ... */
|
||||||
if (estate->es_evTuple != NULL &&
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tidstate->tss_TidPtr = -1;
|
node->tss_TidPtr = -1;
|
||||||
|
|
||||||
/*
|
|
||||||
* perhaps return something meaningful
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -290,18 +275,13 @@ ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndTidScan(TidScan *node)
|
ExecEndTidScan(TidScanState *node)
|
||||||
{
|
{
|
||||||
CommonScanState *scanstate;
|
|
||||||
TidScanState *tidstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extract information from the node
|
* extract information from the node
|
||||||
*/
|
*/
|
||||||
scanstate = node->scan.scanstate;
|
if (node && node->tss_TidList)
|
||||||
tidstate = node->tidstate;
|
pfree(node->tss_TidList);
|
||||||
if (tidstate && tidstate->tss_TidList)
|
|
||||||
pfree(tidstate->tss_TidList);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the projection info and the scan attribute info
|
* 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
|
* depends on the tupType returned by ExecMain(). So for now, this is
|
||||||
* freed at end-transaction time. -cim 6/2/91
|
* freed at end-transaction time. -cim 6/2/91
|
||||||
*/
|
*/
|
||||||
ExecFreeProjectionInfo(&scanstate->cstate);
|
ExecFreeProjectionInfo(&node->ss.ps);
|
||||||
ExecFreeExprContext(&scanstate->cstate);
|
ExecFreeExprContext(&node->ss.ps);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clear out tuple table slots
|
||||||
|
*/
|
||||||
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
||||||
|
ExecClearTuple(node->ss.ss_ScanTupleSlot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* close the heap relation.
|
* close the heap relation.
|
||||||
@@ -320,13 +306,7 @@ ExecEndTidScan(TidScan *node)
|
|||||||
* ExecInitTidScan. This lock should be held till end of transaction.
|
* ExecInitTidScan. This lock should be held till end of transaction.
|
||||||
* (There is a faction that considers this too much locking, however.)
|
* (There is a faction that considers this too much locking, however.)
|
||||||
*/
|
*/
|
||||||
heap_close(scanstate->css_currentRelation, NoLock);
|
heap_close(node->ss.ss_currentRelation, NoLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* clear out tuple table slots
|
|
||||||
*/
|
|
||||||
ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
|
|
||||||
ExecClearTuple(scanstate->css_ScanTupleSlot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -337,12 +317,9 @@ ExecEndTidScan(TidScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecTidMarkPos(TidScan *node)
|
ExecTidMarkPos(TidScanState *node)
|
||||||
{
|
{
|
||||||
TidScanState *tidstate;
|
node->tss_MarkTidPtr = node->tss_TidPtr;
|
||||||
|
|
||||||
tidstate = node->tidstate;
|
|
||||||
tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -355,12 +332,9 @@ ExecTidMarkPos(TidScan *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecTidRestrPos(TidScan *node)
|
ExecTidRestrPos(TidScanState *node)
|
||||||
{
|
{
|
||||||
TidScanState *tidstate;
|
node->tss_TidPtr = node->tss_MarkTidPtr;
|
||||||
|
|
||||||
tidstate = node->tidstate;
|
|
||||||
tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -374,11 +348,10 @@ ExecTidRestrPos(TidScan *node)
|
|||||||
* estate: the execution state initialized in InitPlan.
|
* estate: the execution state initialized in InitPlan.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool
|
TidScanState *
|
||||||
ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
ExecInitTidScan(TidScan *node, EState *estate)
|
||||||
{
|
{
|
||||||
TidScanState *tidstate;
|
TidScanState *tidstate;
|
||||||
CommonScanState *scanstate;
|
|
||||||
ItemPointerData *tidList;
|
ItemPointerData *tidList;
|
||||||
int numTids;
|
int numTids;
|
||||||
int tidPtr;
|
int tidPtr;
|
||||||
@@ -390,56 +363,50 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||||||
List *execParam = NIL;
|
List *execParam = NIL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
*/
|
||||||
node->scan.plan.state = estate;
|
tidstate = makeNode(TidScanState);
|
||||||
|
tidstate->ss.ps.plan = (Plan *) node;
|
||||||
/*
|
tidstate->ss.ps.state = estate;
|
||||||
* Part 1) initialize scan state
|
|
||||||
*
|
|
||||||
* create new CommonScanState for node
|
|
||||||
*/
|
|
||||||
scanstate = makeNode(CommonScanState);
|
|
||||||
node->scan.scanstate = scanstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous initialization
|
* Miscellaneous initialization
|
||||||
*
|
*
|
||||||
* create expression context for node
|
* 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
|
#define TIDSCAN_NSLOTS 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tuple table initialization
|
* tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &scanstate->cstate);
|
ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
|
||||||
ExecInitScanTupleSlot(estate, scanstate);
|
ExecInitScanTupleSlot(estate, &tidstate->ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize projection info. result type comes from scan desc
|
* initialize projection info. result type comes from scan desc
|
||||||
* below..
|
* below..
|
||||||
*/
|
*/
|
||||||
ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
|
ExecAssignProjectionInfo(&tidstate->ss.ps);
|
||||||
|
|
||||||
/*
|
|
||||||
* Part 2) initialize tid scan state
|
|
||||||
*
|
|
||||||
* create new TidScanState for node
|
|
||||||
*/
|
|
||||||
tidstate = makeNode(TidScanState);
|
|
||||||
node->tidstate = tidstate;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the tid node information
|
* get the tid node information
|
||||||
*/
|
*/
|
||||||
tidList = (ItemPointerData *) palloc(length(node->tideval) * sizeof(ItemPointerData));
|
tidList = (ItemPointerData *) palloc(length(node->tideval) * sizeof(ItemPointerData));
|
||||||
numTids = 0;
|
numTids = TidListCreate(node->tideval,
|
||||||
if (!node->needRescan)
|
tidstate->ss.ps.ps_ExprContext,
|
||||||
numTids = TidListCreate(node->tideval,
|
tidList);
|
||||||
scanstate->cstate.cs_ExprContext,
|
|
||||||
tidList);
|
|
||||||
tidPtr = -1;
|
tidPtr = -1;
|
||||||
|
|
||||||
CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
|
CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext);
|
||||||
@@ -465,25 +432,25 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
|||||||
|
|
||||||
currentRelation = heap_open(reloid, AccessShareLock);
|
currentRelation = heap_open(reloid, AccessShareLock);
|
||||||
|
|
||||||
scanstate->css_currentRelation = currentRelation;
|
tidstate->ss.ss_currentRelation = currentRelation;
|
||||||
scanstate->css_currentScanDesc = NULL; /* no heap scan here */
|
tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the scan type from the relation descriptor.
|
* get the scan type from the relation descriptor.
|
||||||
*/
|
*/
|
||||||
ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
|
ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation), false);
|
||||||
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
|
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if there are some PARAM_EXEC in skankeys then force tid rescan on
|
* if there are some PARAM_EXEC in skankeys then force tid rescan on
|
||||||
* first scan.
|
* first scan.
|
||||||
*/
|
*/
|
||||||
((Plan *) node)->chgParam = execParam;
|
tidstate->ss.ps.chgParam = execParam;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* all done.
|
* all done.
|
||||||
*/
|
*/
|
||||||
return TRUE;
|
return tidstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Assumes tuples returned from subplan arrive in
|
* Assumes tuples returned from subplan arrive in
|
||||||
* sorted order.
|
* sorted order.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@@ -39,21 +38,20 @@
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot * /* return: a tuple or NULL */
|
TupleTableSlot * /* return: a tuple or NULL */
|
||||||
ExecUnique(Unique *node)
|
ExecUnique(UniqueState *node)
|
||||||
{
|
{
|
||||||
UniqueState *uniquestate;
|
Unique *plannode = (Unique *) node->ps.plan;
|
||||||
TupleTableSlot *resultTupleSlot;
|
TupleTableSlot *resultTupleSlot;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
Plan *outerPlan;
|
PlanState *outerPlan;
|
||||||
TupleDesc tupDesc;
|
TupleDesc tupDesc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get information from the node
|
* get information from the node
|
||||||
*/
|
*/
|
||||||
uniquestate = node->uniquestate;
|
outerPlan = outerPlanState(node);
|
||||||
outerPlan = outerPlan((Plan *) node);
|
resultTupleSlot = node->ps.ps_ResultTupleSlot;
|
||||||
resultTupleSlot = uniquestate->cstate.cs_ResultTupleSlot;
|
tupDesc = ExecGetResultType(&node->ps);
|
||||||
tupDesc = ExecGetResultType(&uniquestate->cstate);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now loop, returning only non-duplicate tuples. We assume that the
|
* 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
|
* fetch a tuple from the outer subplan
|
||||||
*/
|
*/
|
||||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
slot = ExecProcNode(outerPlan);
|
||||||
if (TupIsNull(slot))
|
if (TupIsNull(slot))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Always return the first tuple from the subplan.
|
* Always return the first tuple from the subplan.
|
||||||
*/
|
*/
|
||||||
if (uniquestate->priorTuple == NULL)
|
if (node->priorTuple == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -79,11 +77,11 @@ ExecUnique(Unique *node)
|
|||||||
* match. If so then we loop back and fetch another new tuple
|
* match. If so then we loop back and fetch another new tuple
|
||||||
* from the subplan.
|
* from the subplan.
|
||||||
*/
|
*/
|
||||||
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
|
if (!execTuplesMatch(slot->val, node->priorTuple,
|
||||||
tupDesc,
|
tupDesc,
|
||||||
node->numCols, node->uniqColIdx,
|
plannode->numCols, plannode->uniqColIdx,
|
||||||
uniquestate->eqfunctions,
|
node->eqfunctions,
|
||||||
uniquestate->tempContext))
|
node->tempContext))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +97,11 @@ ExecUnique(Unique *node)
|
|||||||
* handling in execMain.c). We assume that the caller will no longer
|
* handling in execMain.c). We assume that the caller will no longer
|
||||||
* be interested in the current tuple after he next calls us.
|
* be interested in the current tuple after he next calls us.
|
||||||
*/
|
*/
|
||||||
if (uniquestate->priorTuple != NULL)
|
if (node->priorTuple != NULL)
|
||||||
heap_freetuple(uniquestate->priorTuple);
|
heap_freetuple(node->priorTuple);
|
||||||
uniquestate->priorTuple = heap_copytuple(slot->val);
|
node->priorTuple = heap_copytuple(slot->val);
|
||||||
|
|
||||||
ExecStoreTuple(uniquestate->priorTuple,
|
ExecStoreTuple(node->priorTuple,
|
||||||
resultTupleSlot,
|
resultTupleSlot,
|
||||||
InvalidBuffer,
|
InvalidBuffer,
|
||||||
false); /* tuple does not belong to slot */
|
false); /* tuple does not belong to slot */
|
||||||
@@ -118,22 +116,18 @@ ExecUnique(Unique *node)
|
|||||||
* the node's subplan.
|
* the node's subplan.
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
bool /* return: initialization status */
|
UniqueState *
|
||||||
ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
ExecInitUnique(Unique *node, EState *estate)
|
||||||
{
|
{
|
||||||
UniqueState *uniquestate;
|
UniqueState *uniquestate;
|
||||||
Plan *outerPlan;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assign execution state to node
|
* create state structure
|
||||||
*/
|
|
||||||
node->plan.state = estate;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create new UniqueState for node
|
|
||||||
*/
|
*/
|
||||||
uniquestate = makeNode(UniqueState);
|
uniquestate = makeNode(UniqueState);
|
||||||
node->uniquestate = uniquestate;
|
uniquestate->ps.plan = (Plan *) node;
|
||||||
|
uniquestate->ps.state = estate;
|
||||||
|
|
||||||
uniquestate->priorTuple = NULL;
|
uniquestate->priorTuple = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -155,30 +149,29 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
|||||||
/*
|
/*
|
||||||
* Tuple table initialization
|
* Tuple table initialization
|
||||||
*/
|
*/
|
||||||
ExecInitResultTupleSlot(estate, &uniquestate->cstate);
|
ExecInitResultTupleSlot(estate, &uniquestate->ps);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* then initialize outer plan
|
* then initialize outer plan
|
||||||
*/
|
*/
|
||||||
outerPlan = outerPlan((Plan *) node);
|
outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate);
|
||||||
ExecInitNode(outerPlan, estate, (Plan *) node);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unique nodes do no projections, so initialize projection info for
|
* unique nodes do no projections, so initialize projection info for
|
||||||
* this node appropriately
|
* this node appropriately
|
||||||
*/
|
*/
|
||||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &uniquestate->cstate);
|
ExecAssignResultTypeFromOuterPlan(&uniquestate->ps);
|
||||||
uniquestate->cstate.cs_ProjInfo = NULL;
|
uniquestate->ps.ps_ProjInfo = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precompute fmgr lookup data for inner loop
|
* Precompute fmgr lookup data for inner loop
|
||||||
*/
|
*/
|
||||||
uniquestate->eqfunctions =
|
uniquestate->eqfunctions =
|
||||||
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->cstate),
|
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->ps),
|
||||||
node->numCols,
|
node->numCols,
|
||||||
node->uniqColIdx);
|
node->uniqColIdx);
|
||||||
|
|
||||||
return TRUE;
|
return uniquestate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -197,41 +190,36 @@ ExecCountSlotsUnique(Unique *node)
|
|||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ExecEndUnique(Unique *node)
|
ExecEndUnique(UniqueState *node)
|
||||||
{
|
{
|
||||||
UniqueState *uniquestate = node->uniquestate;
|
|
||||||
|
|
||||||
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
|
||||||
|
|
||||||
MemoryContextDelete(uniquestate->tempContext);
|
|
||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
if (uniquestate->priorTuple != NULL)
|
if (node->priorTuple != NULL)
|
||||||
{
|
{
|
||||||
heap_freetuple(uniquestate->priorTuple);
|
heap_freetuple(node->priorTuple);
|
||||||
uniquestate->priorTuple = NULL;
|
node->priorTuple = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExecEndNode(outerPlanState(node));
|
||||||
|
|
||||||
|
MemoryContextDelete(node->tempContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent)
|
ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt)
|
||||||
{
|
{
|
||||||
UniqueState *uniquestate = node->uniquestate;
|
ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
||||||
|
if (node->priorTuple != NULL)
|
||||||
ExecClearTuple(uniquestate->cstate.cs_ResultTupleSlot);
|
|
||||||
if (uniquestate->priorTuple != NULL)
|
|
||||||
{
|
{
|
||||||
heap_freetuple(uniquestate->priorTuple);
|
heap_freetuple(node->priorTuple);
|
||||||
uniquestate->priorTuple = NULL;
|
node->priorTuple = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
* first ExecProcNode.
|
* first ExecProcNode.
|
||||||
*/
|
*/
|
||||||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
if (((PlanState *) node)->lefttree->chgParam == NULL)
|
||||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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_curid = -1;
|
||||||
|
|
||||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
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,
|
static int _SPI_execute_plan(_SPI_plan *plan,
|
||||||
Datum *Values, char *Nulls, int tcount);
|
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;
|
List *ptlist = spiplan->ptlist;
|
||||||
Query *queryTree;
|
Query *queryTree;
|
||||||
Plan *planTree;
|
Plan *planTree;
|
||||||
|
ParamListInfo paramLI;
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
EState *eState;
|
|
||||||
TupleDesc attinfo;
|
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
Portal portal;
|
Portal portal;
|
||||||
char portalname[64];
|
char portalname[64];
|
||||||
@@ -774,28 +773,21 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||||||
queryTree->into->relname = pstrdup(name);
|
queryTree->into->relname = pstrdup(name);
|
||||||
queryTree->isBinary = false;
|
queryTree->isBinary = false;
|
||||||
|
|
||||||
/* Create the QueryDesc object and the executor state */
|
/* If the plan has parameters, set them up */
|
||||||
queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL);
|
|
||||||
eState = CreateExecutorState();
|
|
||||||
|
|
||||||
/* If the plan has parameters, put them into the executor state */
|
|
||||||
if (spiplan->nargs > 0)
|
if (spiplan->nargs > 0)
|
||||||
{
|
{
|
||||||
ParamListInfo paramLI;
|
|
||||||
|
|
||||||
paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
|
paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
|
||||||
sizeof(ParamListInfoData));
|
sizeof(ParamListInfoData));
|
||||||
|
|
||||||
eState->es_param_list_info = paramLI;
|
for (k = 0; k < spiplan->nargs; k++)
|
||||||
for (k = 0; k < spiplan->nargs; paramLI++, k++)
|
|
||||||
{
|
{
|
||||||
paramLI->kind = PARAM_NUM;
|
paramLI[k].kind = PARAM_NUM;
|
||||||
paramLI->id = k + 1;
|
paramLI[k].id = k + 1;
|
||||||
paramLI->isnull = (Nulls && Nulls[k] == 'n');
|
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
|
||||||
if (paramLI->isnull)
|
if (paramLI[k].isnull)
|
||||||
{
|
{
|
||||||
/* nulls just copy */
|
/* nulls just copy */
|
||||||
paramLI->value = Values[k];
|
paramLI[k].value = Values[k];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -805,20 +797,24 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
|
|||||||
|
|
||||||
get_typlenbyval(spiplan->argtypes[k],
|
get_typlenbyval(spiplan->argtypes[k],
|
||||||
¶mTypLen, ¶mTypByVal);
|
¶mTypLen, ¶mTypByVal);
|
||||||
paramLI->value = datumCopy(Values[k],
|
paramLI[k].value = datumCopy(Values[k],
|
||||||
paramTypByVal, paramTypLen);
|
paramTypByVal, paramTypLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
paramLI->kind = PARAM_INVALID;
|
paramLI[k].kind = PARAM_INVALID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
eState->es_param_list_info = NULL;
|
paramLI = NULL;
|
||||||
|
|
||||||
|
/* Create the QueryDesc object */
|
||||||
|
queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL,
|
||||||
|
paramLI, false);
|
||||||
|
|
||||||
/* Start the executor */
|
/* Start the executor */
|
||||||
attinfo = ExecutorStart(queryDesc, eState);
|
ExecutorStart(queryDesc);
|
||||||
|
|
||||||
/* Put all the objects into the portal */
|
/* Arrange to shut down the executor if portal is dropped */
|
||||||
PortalSetQuery(portal, queryDesc, attinfo, eState, PortalCleanup);
|
PortalSetQuery(portal, queryDesc, PortalCleanup);
|
||||||
|
|
||||||
/* Switch back to the callers memory context */
|
/* Switch back to the callers memory context */
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
@@ -1042,7 +1038,6 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||||||
Plan *planTree;
|
Plan *planTree;
|
||||||
bool canSetResult;
|
bool canSetResult;
|
||||||
QueryDesc *qdesc;
|
QueryDesc *qdesc;
|
||||||
EState *state;
|
|
||||||
|
|
||||||
planTree = pg_plan_query(queryTree);
|
planTree = pg_plan_query(queryTree);
|
||||||
plan_list = lappend(plan_list, planTree);
|
plan_list = lappend(plan_list, planTree);
|
||||||
@@ -1089,9 +1084,9 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||||||
else if (plan == NULL)
|
else if (plan == NULL)
|
||||||
{
|
{
|
||||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||||
canSetResult ? SPI : None, NULL);
|
canSetResult ? SPI : None,
|
||||||
state = CreateExecutorState();
|
NULL, NULL, false);
|
||||||
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
|
res = _SPI_pquery(qdesc, true, canSetResult ? tcount : 0);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
@@ -1099,8 +1094,9 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||||
canSetResult ? SPI : None, NULL);
|
canSetResult ? SPI : None,
|
||||||
res = _SPI_pquery(qdesc, NULL, 0);
|
NULL, NULL, false);
|
||||||
|
res = _SPI_pquery(qdesc, false, 0);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -1152,7 +1148,6 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||||||
Plan *planTree;
|
Plan *planTree;
|
||||||
bool canSetResult;
|
bool canSetResult;
|
||||||
QueryDesc *qdesc;
|
QueryDesc *qdesc;
|
||||||
EState *state;
|
|
||||||
|
|
||||||
planTree = lfirst(plan_list);
|
planTree = lfirst(plan_list);
|
||||||
plan_list = lnext(plan_list);
|
plan_list = lnext(plan_list);
|
||||||
@@ -1183,30 +1178,31 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qdesc = CreateQueryDesc(queryTree, planTree,
|
ParamListInfo paramLI;
|
||||||
canSetResult ? SPI : None, NULL);
|
|
||||||
state = CreateExecutorState();
|
|
||||||
if (nargs > 0)
|
if (nargs > 0)
|
||||||
{
|
{
|
||||||
ParamListInfo paramLI;
|
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
paramLI = (ParamListInfo)
|
paramLI = (ParamListInfo)
|
||||||
palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
palloc0((nargs + 1) * sizeof(ParamListInfoData));
|
||||||
|
|
||||||
state->es_param_list_info = paramLI;
|
for (k = 0; k < plan->nargs; k++)
|
||||||
for (k = 0; k < plan->nargs; paramLI++, k++)
|
|
||||||
{
|
{
|
||||||
paramLI->kind = PARAM_NUM;
|
paramLI[k].kind = PARAM_NUM;
|
||||||
paramLI->id = k + 1;
|
paramLI[k].id = k + 1;
|
||||||
paramLI->isnull = (Nulls && Nulls[k] == 'n');
|
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
|
||||||
paramLI->value = Values[k];
|
paramLI[k].value = Values[k];
|
||||||
}
|
}
|
||||||
paramLI->kind = PARAM_INVALID;
|
paramLI[k].kind = PARAM_INVALID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
state->es_param_list_info = NULL;
|
paramLI = NULL;
|
||||||
res = _SPI_pquery(qdesc, state, canSetResult ? tcount : 0);
|
|
||||||
|
qdesc = CreateQueryDesc(queryTree, planTree,
|
||||||
|
canSetResult ? SPI : None,
|
||||||
|
NULL, paramLI, false);
|
||||||
|
res = _SPI_pquery(qdesc, true, canSetResult ? tcount : 0);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
@@ -1218,7 +1214,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
_SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
|
||||||
{
|
{
|
||||||
Query *parseTree = queryDesc->parsetree;
|
Query *parseTree = queryDesc->parsetree;
|
||||||
int operation = queryDesc->operation;
|
int operation = queryDesc->operation;
|
||||||
@@ -1262,7 +1258,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
return SPI_ERROR_OPUNKNOWN;
|
return SPI_ERROR_OPUNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == NULL) /* plan preparation, don't execute */
|
if (!runit) /* plan preparation, don't execute */
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
#ifdef SPI_EXECUTOR_STATS
|
#ifdef SPI_EXECUTOR_STATS
|
||||||
@@ -1270,20 +1266,20 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
ResetUsage();
|
ResetUsage();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ExecutorStart(queryDesc, state);
|
ExecutorStart(queryDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't work currently --- need to rearrange callers so that we
|
* 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.
|
* pquery.c for the correct order of operations.
|
||||||
*/
|
*/
|
||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
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;
|
_SPI_current->processed = queryDesc->estate->es_processed;
|
||||||
save_lastoid = state->es_lastoid;
|
save_lastoid = queryDesc->estate->es_lastoid;
|
||||||
|
|
||||||
if (operation == CMD_SELECT && queryDesc->dest == SPI)
|
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");
|
elog(FATAL, "SPI_select: # of processed tuples check failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorEnd(queryDesc, state);
|
ExecutorEnd(queryDesc);
|
||||||
|
|
||||||
#ifdef SPI_EXECUTOR_STATS
|
#ifdef SPI_EXECUTOR_STATS
|
||||||
if (ShowExecutorStats)
|
if (ShowExecutorStats)
|
||||||
@@ -1342,7 +1338,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
querydesc = PortalGetQueryDesc(portal);
|
querydesc = PortalGetQueryDesc(portal);
|
||||||
estate = PortalGetState(portal);
|
estate = querydesc->estate;
|
||||||
|
|
||||||
/* Save the queries command destination and set it to SPI (for fetch) */
|
/* Save the queries command destination and set it to SPI (for fetch) */
|
||||||
/* or None (for move) */
|
/* or None (for move) */
|
||||||
@@ -1357,7 +1353,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
else
|
else
|
||||||
direction = ForwardScanDirection;
|
direction = ForwardScanDirection;
|
||||||
|
|
||||||
ExecutorRun(querydesc, estate, direction, (long) count);
|
ExecutorRun(querydesc, direction, (long) count);
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
if (estate->es_processed > 0)
|
||||||
portal->atStart = false; /* OK to back up now */
|
portal->atStart = false; /* OK to back up now */
|
||||||
@@ -1371,7 +1367,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
|
|||||||
else
|
else
|
||||||
direction = BackwardScanDirection;
|
direction = BackwardScanDirection;
|
||||||
|
|
||||||
ExecutorRun(querydesc, estate, direction, (long) count);
|
ExecutorRun(querydesc, direction, (long) count);
|
||||||
|
|
||||||
if (estate->es_processed > 0)
|
if (estate->es_processed > 0)
|
||||||
portal->atEnd = false; /* OK to go forward now */
|
portal->atEnd = false; /* OK to go forward now */
|
||||||
|
|||||||
@@ -3,27 +3,28 @@
|
|||||||
* copyfuncs.c
|
* copyfuncs.c
|
||||||
* Copy functions for Postgres tree nodes.
|
* Copy functions for Postgres tree nodes.
|
||||||
*
|
*
|
||||||
* NOTE: a general convention when copying or comparing plan nodes is
|
* NOTE: we currently support copying all node types found in parse and
|
||||||
* that we ignore the executor state subnode. We do not need to look
|
* plan trees. We do not support copying executor state trees; there
|
||||||
* at it because no current uses of copyObject() or equal() need to
|
* is no need for that, and no point in maintaining all the code that
|
||||||
* deal with already-executing plan trees. By leaving the state subnodes
|
* would be needed. We also do not support copying Path trees, mainly
|
||||||
* out, we avoid needing to write copy/compare routines for all the
|
* because the circular linkages between RelOptInfo and Path nodes can't
|
||||||
* different executor state node types.
|
* be handled easily in a simple depth-first traversal.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "postgres.h"
|
||||||
|
|
||||||
#include "optimizer/clauses.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "optimizer/planmain.h"
|
#include "nodes/plannodes.h"
|
||||||
|
#include "nodes/relation.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -58,15 +59,6 @@
|
|||||||
memcpy(newnode->fldname, from->fldname, _size); \
|
memcpy(newnode->fldname, from->fldname, _size); \
|
||||||
} while (0)
|
} 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
|
* listCopy
|
||||||
@@ -119,19 +111,13 @@ CopyPlanFields(Plan *from, Plan *newnode)
|
|||||||
COPY_SCALAR_FIELD(total_cost);
|
COPY_SCALAR_FIELD(total_cost);
|
||||||
COPY_SCALAR_FIELD(plan_rows);
|
COPY_SCALAR_FIELD(plan_rows);
|
||||||
COPY_SCALAR_FIELD(plan_width);
|
COPY_SCALAR_FIELD(plan_width);
|
||||||
/* execution state is NOT copied */
|
|
||||||
COPY_NODE_FIELD(targetlist);
|
COPY_NODE_FIELD(targetlist);
|
||||||
COPY_NODE_FIELD(qual);
|
COPY_NODE_FIELD(qual);
|
||||||
COPY_NODE_FIELD(lefttree);
|
COPY_NODE_FIELD(lefttree);
|
||||||
COPY_NODE_FIELD(righttree);
|
COPY_NODE_FIELD(righttree);
|
||||||
|
COPY_NODE_FIELD(initPlan);
|
||||||
COPY_INTLIST_FIELD(extParam);
|
COPY_INTLIST_FIELD(extParam);
|
||||||
COPY_INTLIST_FIELD(locParam);
|
COPY_INTLIST_FIELD(locParam);
|
||||||
COPY_INTLIST_FIELD(chgParam);
|
|
||||||
COPY_NODE_FIELD(initPlan);
|
|
||||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
|
||||||
newnode->subPlan = NIL;
|
|
||||||
FIX_SUBPLAN_LINKS(subPlan, targetlist);
|
|
||||||
FIX_SUBPLAN_LINKS(subPlan, qual);
|
|
||||||
COPY_SCALAR_FIELD(nParamExec);
|
COPY_SCALAR_FIELD(nParamExec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,9 +156,6 @@ _copyResult(Result *from)
|
|||||||
*/
|
*/
|
||||||
COPY_NODE_FIELD(resconstantqual);
|
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;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,10 +249,6 @@ _copyIndexScan(IndexScan *from)
|
|||||||
COPY_NODE_FIELD(indxqualorig);
|
COPY_NODE_FIELD(indxqualorig);
|
||||||
COPY_SCALAR_FIELD(indxorderdir);
|
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;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,12 +268,8 @@ _copyTidScan(TidScan *from)
|
|||||||
/*
|
/*
|
||||||
* copy remainder of node
|
* copy remainder of node
|
||||||
*/
|
*/
|
||||||
COPY_SCALAR_FIELD(needRescan);
|
|
||||||
COPY_NODE_FIELD(tideval);
|
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;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,9 +323,6 @@ CopyJoinFields(Join *from, Join *newnode)
|
|||||||
|
|
||||||
COPY_SCALAR_FIELD(jointype);
|
COPY_SCALAR_FIELD(jointype);
|
||||||
COPY_NODE_FIELD(joinqual);
|
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);
|
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;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,9 +399,6 @@ _copyHashJoin(HashJoin *from)
|
|||||||
*/
|
*/
|
||||||
COPY_NODE_FIELD(hashclauses);
|
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;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +496,27 @@ _copyUnique(Unique *from)
|
|||||||
return newnode;
|
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
|
* _copySetOp
|
||||||
*/
|
*/
|
||||||
@@ -576,29 +563,6 @@ _copyLimit(Limit *from)
|
|||||||
return newnode;
|
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 *
|
static SubPlan *
|
||||||
_copySubPlan(SubPlan *from)
|
_copySubPlan(SubPlan *from)
|
||||||
{
|
{
|
||||||
@@ -611,10 +575,6 @@ _copySubPlan(SubPlan *from)
|
|||||||
COPY_INTLIST_FIELD(parParam);
|
COPY_INTLIST_FIELD(parParam);
|
||||||
COPY_NODE_FIELD(sublink);
|
COPY_NODE_FIELD(sublink);
|
||||||
|
|
||||||
/* do not copy execution state */
|
|
||||||
newnode->needShutdown = false;
|
|
||||||
newnode->curTuple = NULL;
|
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -933,313 +893,11 @@ _copyArrayRef(ArrayRef *from)
|
|||||||
/* ****************************************************************
|
/* ****************************************************************
|
||||||
* relation.h copy functions
|
* relation.h copy functions
|
||||||
*
|
*
|
||||||
* XXX the code to copy RelOptInfo and Path nodes is really completely bogus,
|
* We don't support copying RelOptInfo, IndexOptInfo, or Path nodes.
|
||||||
* because it makes no attempt to deal with multiple links from RelOptInfo
|
* There are some subsidiary structs that are useful to copy, though.
|
||||||
* 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.
|
|
||||||
* ****************************************************************
|
* ****************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* _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
|
* _copyPathKeyItem
|
||||||
*/
|
*/
|
||||||
@@ -1301,21 +959,6 @@ _copyJoinInfo(JoinInfo *from)
|
|||||||
return newnode;
|
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
|
* parsenodes.h copy functions
|
||||||
* ****************************************************************
|
* ****************************************************************
|
||||||
@@ -1737,7 +1380,8 @@ _copyQuery(Query *from)
|
|||||||
/*
|
/*
|
||||||
* We do not copy the planner internal fields: base_rel_list,
|
* We do not copy the planner internal fields: base_rel_list,
|
||||||
* other_rel_list, join_rel_list, equi_key_list, query_pathkeys,
|
* 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;
|
return newnode;
|
||||||
@@ -2683,15 +2327,15 @@ copyObject(void *from)
|
|||||||
case T_Unique:
|
case T_Unique:
|
||||||
retval = _copyUnique(from);
|
retval = _copyUnique(from);
|
||||||
break;
|
break;
|
||||||
|
case T_Hash:
|
||||||
|
retval = _copyHash(from);
|
||||||
|
break;
|
||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
retval = _copySetOp(from);
|
retval = _copySetOp(from);
|
||||||
break;
|
break;
|
||||||
case T_Limit:
|
case T_Limit:
|
||||||
retval = _copyLimit(from);
|
retval = _copyLimit(from);
|
||||||
break;
|
break;
|
||||||
case T_Hash:
|
|
||||||
retval = _copyHash(from);
|
|
||||||
break;
|
|
||||||
case T_SubPlan:
|
case T_SubPlan:
|
||||||
retval = _copySubPlan(from);
|
retval = _copySubPlan(from);
|
||||||
break;
|
break;
|
||||||
@@ -2757,39 +2401,6 @@ copyObject(void *from)
|
|||||||
/*
|
/*
|
||||||
* RELATION NODES
|
* 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:
|
case T_PathKeyItem:
|
||||||
retval = _copyPathKeyItem(from);
|
retval = _copyPathKeyItem(from);
|
||||||
break;
|
break;
|
||||||
@@ -2799,9 +2410,6 @@ copyObject(void *from)
|
|||||||
case T_JoinInfo:
|
case T_JoinInfo:
|
||||||
retval = _copyJoinInfo(from);
|
retval = _copyJoinInfo(from);
|
||||||
break;
|
break;
|
||||||
case T_InnerIndexscanInfo:
|
|
||||||
retval = _copyInnerIndexscanInfo(from);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VALUE NODES
|
* VALUE NODES
|
||||||
|
|||||||
@@ -3,30 +3,30 @@
|
|||||||
* equalfuncs.c
|
* equalfuncs.c
|
||||||
* Equality functions to compare node trees.
|
* Equality functions to compare node trees.
|
||||||
*
|
*
|
||||||
* NOTE: a general convention when copying or comparing plan nodes is
|
* NOTE: we currently support comparing all node types found in parse
|
||||||
* that we ignore the executor state subnode. We do not need to look
|
* trees. We do not support comparing executor state trees; there
|
||||||
* at it because no current uses of copyObject() or equal() need to
|
* is no need for that, and no point in maintaining all the code that
|
||||||
* deal with already-executing plan trees. By leaving the state subnodes
|
* would be needed. We also do not support comparing Path trees, mainly
|
||||||
* out, we avoid needing to write copy/compare routines for all the
|
* because the circular linkages between RelOptInfo and Path nodes can't
|
||||||
* different executor state node types.
|
* be handled easily in a simple depth-first traversal.
|
||||||
*
|
*
|
||||||
* Currently, in fact, equal() doesn't know how to compare Plan nodes
|
* Currently, in fact, equal() doesn't know how to compare Plan trees
|
||||||
* at all, let alone their executor-state subnodes. This will probably
|
* either. This might need to be fixed someday.
|
||||||
* need to be fixed someday, but presently there is no need to compare
|
|
||||||
* plan trees.
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "postgres.h"
|
||||||
|
|
||||||
|
#include "nodes/params.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
#include "nodes/plannodes.h"
|
#include "nodes/plannodes.h"
|
||||||
#include "nodes/relation.h"
|
#include "nodes/relation.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
@@ -369,147 +369,6 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
|
|||||||
* Stuff from relation.h
|
* Stuff from relation.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We treat RelOptInfos as equal if they refer to the same base rels
|
|
||||||
* joined in the same order. Is this appropriate/sufficient?
|
|
||||||
*/
|
|
||||||
COMPARE_INTLIST_FIELD(relids);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalIndexOptInfo(IndexOptInfo *a, IndexOptInfo *b)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We treat IndexOptInfos as equal if they refer to the same index. Is
|
|
||||||
* this sufficient?
|
|
||||||
*/
|
|
||||||
COMPARE_SCALAR_FIELD(indexoid);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalPath(Path *a, Path *b)
|
|
||||||
{
|
|
||||||
/* This is safe only because _equalRelOptInfo is incomplete... */
|
|
||||||
COMPARE_NODE_FIELD(parent);
|
|
||||||
/*
|
|
||||||
* do not check path costs, since they may not be set yet, and being
|
|
||||||
* float values there are roundoff error issues anyway...
|
|
||||||
*/
|
|
||||||
COMPARE_SCALAR_FIELD(pathtype);
|
|
||||||
COMPARE_NODE_FIELD(pathkeys);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalIndexPath(IndexPath *a, IndexPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(indexinfo);
|
|
||||||
COMPARE_NODE_FIELD(indexqual);
|
|
||||||
COMPARE_SCALAR_FIELD(indexscandir);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip 'rows' because of possibility of floating-point roundoff
|
|
||||||
* error. It should be derivable from the other fields anyway.
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalTidPath(TidPath *a, TidPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(tideval);
|
|
||||||
COMPARE_INTLIST_FIELD(unjoined_relids);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalAppendPath(AppendPath *a, AppendPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(subpaths);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalResultPath(ResultPath *a, ResultPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(subpath);
|
|
||||||
COMPARE_NODE_FIELD(constantqual);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalMaterialPath(MaterialPath *a, MaterialPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(subpath);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalJoinPath(JoinPath *a, JoinPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_SCALAR_FIELD(jointype);
|
|
||||||
COMPARE_NODE_FIELD(outerjoinpath);
|
|
||||||
COMPARE_NODE_FIELD(innerjoinpath);
|
|
||||||
COMPARE_NODE_FIELD(joinrestrictinfo);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalNestPath(NestPath *a, NestPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalMergePath(MergePath *a, MergePath *b)
|
|
||||||
{
|
|
||||||
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(path_mergeclauses);
|
|
||||||
COMPARE_NODE_FIELD(outersortkeys);
|
|
||||||
COMPARE_NODE_FIELD(innersortkeys);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalHashPath(HashPath *a, HashPath *b)
|
|
||||||
{
|
|
||||||
if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
|
|
||||||
return false;
|
|
||||||
COMPARE_NODE_FIELD(path_hashclauses);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
|
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
|
||||||
{
|
{
|
||||||
@@ -547,16 +406,6 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
|||||||
return true;
|
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
|
* Stuff from parsenodes.h
|
||||||
@@ -1711,39 +1560,6 @@ equal(void *a, void *b)
|
|||||||
retval = _equalJoinExpr(a, b);
|
retval = _equalJoinExpr(a, b);
|
||||||
break;
|
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:
|
case T_PathKeyItem:
|
||||||
retval = _equalPathKeyItem(a, b);
|
retval = _equalPathKeyItem(a, b);
|
||||||
break;
|
break;
|
||||||
@@ -1753,9 +1569,6 @@ equal(void *a, void *b)
|
|||||||
case T_JoinInfo:
|
case T_JoinInfo:
|
||||||
retval = _equalJoinInfo(a, b);
|
retval = _equalJoinInfo(a, b);
|
||||||
break;
|
break;
|
||||||
case T_InnerIndexscanInfo:
|
|
||||||
retval = _equalInnerIndexscanInfo(a, b);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_List:
|
case T_List:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Every node type that can appear in stored rules' parsetrees *must*
|
* Every node type that can appear in stored rules' parsetrees *must*
|
||||||
* have an output function defined here (as well as an input function
|
* have an output function defined here (as well as an input function
|
||||||
* in readfuncs.c). For use in debugging, we also provide output
|
* 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.
|
* These nodes however need not have input functions.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
@@ -24,10 +24,8 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "nodes/nodes.h"
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "nodes/plannodes.h"
|
#include "nodes/plannodes.h"
|
||||||
#include "nodes/primnodes.h"
|
|
||||||
#include "nodes/relation.h"
|
#include "nodes/relation.h"
|
||||||
#include "parser/parse.h"
|
#include "parser/parse.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
@@ -385,11 +383,9 @@ _outPlanInfo(StringInfo str, Plan *node)
|
|||||||
WRITE_NODE_FIELD(qual);
|
WRITE_NODE_FIELD(qual);
|
||||||
WRITE_NODE_FIELD(lefttree);
|
WRITE_NODE_FIELD(lefttree);
|
||||||
WRITE_NODE_FIELD(righttree);
|
WRITE_NODE_FIELD(righttree);
|
||||||
|
WRITE_NODE_FIELD(initPlan);
|
||||||
WRITE_INTLIST_FIELD(extParam);
|
WRITE_INTLIST_FIELD(extParam);
|
||||||
WRITE_INTLIST_FIELD(locParam);
|
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);
|
WRITE_INT_FIELD(nParamExec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +478,6 @@ _outTidScan(StringInfo str, TidScan *node)
|
|||||||
|
|
||||||
_outScanInfo(str, (Scan *) node);
|
_outScanInfo(str, (Scan *) node);
|
||||||
|
|
||||||
WRITE_BOOL_FIELD(needRescan);
|
|
||||||
WRITE_NODE_FIELD(tideval);
|
WRITE_NODE_FIELD(tideval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -930,6 +925,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* print the basic stuff of all nodes that inherit from Path
|
* 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
|
static void
|
||||||
_outPathInfo(StringInfo str, Path *node)
|
_outPathInfo(StringInfo str, Path *node)
|
||||||
@@ -986,7 +983,6 @@ _outTidPath(StringInfo str, TidPath *node)
|
|||||||
_outPathInfo(str, (Path *) node);
|
_outPathInfo(str, (Path *) node);
|
||||||
|
|
||||||
WRITE_NODE_FIELD(tideval);
|
WRITE_NODE_FIELD(tideval);
|
||||||
WRITE_INTLIST_FIELD(unjoined_relids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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,
|
scan_relid,
|
||||||
best_path->tideval);
|
best_path->tideval);
|
||||||
|
|
||||||
if (best_path->unjoined_relids)
|
|
||||||
scan_plan->needRescan = true;
|
|
||||||
|
|
||||||
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
|
copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
|
||||||
|
|
||||||
return scan_plan;
|
return scan_plan;
|
||||||
@@ -1302,13 +1299,11 @@ make_seqscan(List *qptlist,
|
|||||||
Plan *plan = &node->plan;
|
Plan *plan = &node->plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = qptlist;
|
plan->targetlist = qptlist;
|
||||||
plan->qual = qpqual;
|
plan->qual = qpqual;
|
||||||
plan->lefttree = NULL;
|
plan->lefttree = NULL;
|
||||||
plan->righttree = NULL;
|
plan->righttree = NULL;
|
||||||
node->scanrelid = scanrelid;
|
node->scanrelid = scanrelid;
|
||||||
node->scanstate = (CommonScanState *) NULL;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -1326,7 +1321,6 @@ make_indexscan(List *qptlist,
|
|||||||
Plan *plan = &node->scan.plan;
|
Plan *plan = &node->scan.plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = qptlist;
|
plan->targetlist = qptlist;
|
||||||
plan->qual = qpqual;
|
plan->qual = qpqual;
|
||||||
plan->lefttree = NULL;
|
plan->lefttree = NULL;
|
||||||
@@ -1336,7 +1330,6 @@ make_indexscan(List *qptlist,
|
|||||||
node->indxqual = indxqual;
|
node->indxqual = indxqual;
|
||||||
node->indxqualorig = indxqualorig;
|
node->indxqualorig = indxqualorig;
|
||||||
node->indxorderdir = indexscandir;
|
node->indxorderdir = indexscandir;
|
||||||
node->scan.scanstate = (CommonScanState *) NULL;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -1351,16 +1344,12 @@ make_tidscan(List *qptlist,
|
|||||||
Plan *plan = &node->scan.plan;
|
Plan *plan = &node->scan.plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = qptlist;
|
plan->targetlist = qptlist;
|
||||||
plan->qual = qpqual;
|
plan->qual = qpqual;
|
||||||
plan->lefttree = NULL;
|
plan->lefttree = NULL;
|
||||||
plan->righttree = NULL;
|
plan->righttree = NULL;
|
||||||
node->scan.scanrelid = scanrelid;
|
node->scan.scanrelid = scanrelid;
|
||||||
node->tideval = copyObject(tideval); /* XXX do we really need a
|
node->tideval = tideval;
|
||||||
* copy? */
|
|
||||||
node->needRescan = false;
|
|
||||||
node->scan.scanstate = (CommonScanState *) NULL;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -1375,14 +1364,12 @@ make_subqueryscan(List *qptlist,
|
|||||||
Plan *plan = &node->scan.plan;
|
Plan *plan = &node->scan.plan;
|
||||||
|
|
||||||
copy_plan_costsize(plan, subplan);
|
copy_plan_costsize(plan, subplan);
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = qptlist;
|
plan->targetlist = qptlist;
|
||||||
plan->qual = qpqual;
|
plan->qual = qpqual;
|
||||||
plan->lefttree = NULL;
|
plan->lefttree = NULL;
|
||||||
plan->righttree = NULL;
|
plan->righttree = NULL;
|
||||||
node->scan.scanrelid = scanrelid;
|
node->scan.scanrelid = scanrelid;
|
||||||
node->subplan = subplan;
|
node->subplan = subplan;
|
||||||
node->scan.scanstate = (CommonScanState *) NULL;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -1396,13 +1383,11 @@ make_functionscan(List *qptlist,
|
|||||||
Plan *plan = &node->scan.plan;
|
Plan *plan = &node->scan.plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = qptlist;
|
plan->targetlist = qptlist;
|
||||||
plan->qual = qpqual;
|
plan->qual = qpqual;
|
||||||
plan->lefttree = NULL;
|
plan->lefttree = NULL;
|
||||||
plan->righttree = NULL;
|
plan->righttree = NULL;
|
||||||
node->scan.scanrelid = scanrelid;
|
node->scan.scanrelid = scanrelid;
|
||||||
node->scan.scanstate = (CommonScanState *) NULL;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -1430,7 +1415,6 @@ make_append(List *appendplans, bool isTarget, List *tlist)
|
|||||||
if (plan->plan_width < subplan->plan_width)
|
if (plan->plan_width < subplan->plan_width)
|
||||||
plan->plan_width = subplan->plan_width;
|
plan->plan_width = subplan->plan_width;
|
||||||
}
|
}
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = NULL;
|
plan->lefttree = NULL;
|
||||||
@@ -1453,7 +1437,6 @@ make_nestloop(List *tlist,
|
|||||||
Plan *plan = &node->join.plan;
|
Plan *plan = &node->join.plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = otherclauses;
|
plan->qual = otherclauses;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1477,7 +1460,6 @@ make_hashjoin(List *tlist,
|
|||||||
Plan *plan = &node->join.plan;
|
Plan *plan = &node->join.plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = otherclauses;
|
plan->qual = otherclauses;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1502,7 +1484,6 @@ make_hash(List *tlist, List *hashkeys, Plan *lefttree)
|
|||||||
* input plan; this only affects EXPLAIN display not decisions.
|
* input plan; this only affects EXPLAIN display not decisions.
|
||||||
*/
|
*/
|
||||||
plan->startup_cost = plan->total_cost;
|
plan->startup_cost = plan->total_cost;
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NULL;
|
plan->qual = NULL;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1525,7 +1506,6 @@ make_mergejoin(List *tlist,
|
|||||||
Plan *plan = &node->join.plan;
|
Plan *plan = &node->join.plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = otherclauses;
|
plan->qual = otherclauses;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1557,7 +1537,6 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
|
|||||||
lefttree->plan_width);
|
lefttree->plan_width);
|
||||||
plan->startup_cost = sort_path.startup_cost;
|
plan->startup_cost = sort_path.startup_cost;
|
||||||
plan->total_cost = sort_path.total_cost;
|
plan->total_cost = sort_path.total_cost;
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1646,7 +1625,6 @@ make_material(List *tlist, Plan *lefttree)
|
|||||||
Plan *plan = &node->plan;
|
Plan *plan = &node->plan;
|
||||||
|
|
||||||
/* cost should be inserted by caller */
|
/* cost should be inserted by caller */
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1690,7 +1668,6 @@ make_agg(Query *root, List *tlist, List *qual,
|
|||||||
else
|
else
|
||||||
plan->plan_rows = numGroups;
|
plan->plan_rows = numGroups;
|
||||||
|
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->qual = qual;
|
plan->qual = qual;
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1726,7 +1703,6 @@ make_group(Query *root,
|
|||||||
/* One output tuple per estimated result group */
|
/* One output tuple per estimated result group */
|
||||||
plan->plan_rows = numGroups;
|
plan->plan_rows = numGroups;
|
||||||
|
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->qual = NULL;
|
plan->qual = NULL;
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1765,7 +1741,6 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
|
|||||||
* if he has a better idea.
|
* if he has a better idea.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1824,7 +1799,6 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
|
|||||||
if (plan->plan_rows < 1)
|
if (plan->plan_rows < 1)
|
||||||
plan->plan_rows = 1;
|
plan->plan_rows = 1;
|
||||||
|
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1905,7 +1879,6 @@ make_limit(List *tlist, Plan *lefttree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = lefttree;
|
plan->lefttree = lefttree;
|
||||||
@@ -1935,13 +1908,11 @@ make_result(List *tlist,
|
|||||||
plan->plan_width = 0; /* XXX try to be smarter? */
|
plan->plan_width = 0; /* XXX try to be smarter? */
|
||||||
}
|
}
|
||||||
|
|
||||||
plan->state = (EState *) NULL;
|
|
||||||
plan->targetlist = tlist;
|
plan->targetlist = tlist;
|
||||||
plan->qual = NIL;
|
plan->qual = NIL;
|
||||||
plan->lefttree = subplan;
|
plan->lefttree = subplan;
|
||||||
plan->righttree = NULL;
|
plan->righttree = NULL;
|
||||||
node->resconstantqual = resconstantqual;
|
node->resconstantqual = resconstantqual;
|
||||||
node->resstate = NULL;
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
} replace_vars_with_subplan_refs_context;
|
||||||
|
|
||||||
static void fix_expr_references(Plan *plan, Node *node);
|
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_join_references(Join *join, List *rtable);
|
||||||
static void set_uppernode_references(Plan *plan, Index subvarno);
|
static void set_uppernode_references(Plan *plan, Index subvarno);
|
||||||
static Node *join_references_mutator(Node *node,
|
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
|
* 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
|
* 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).
|
* 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.
|
* set_plan_references recursively traverses the whole plan tree.
|
||||||
*
|
*
|
||||||
@@ -81,12 +80,6 @@ set_plan_references(Plan *plan, List *rtable)
|
|||||||
if (plan == NULL)
|
if (plan == NULL)
|
||||||
return;
|
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
|
* Plan-type-specific fixes
|
||||||
*/
|
*/
|
||||||
@@ -107,6 +100,8 @@ set_plan_references(Plan *plan, List *rtable)
|
|||||||
case T_TidScan:
|
case T_TidScan:
|
||||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||||
fix_expr_references(plan, (Node *) plan->qual);
|
fix_expr_references(plan, (Node *) plan->qual);
|
||||||
|
fix_expr_references(plan,
|
||||||
|
(Node *) ((TidScan *) plan)->tideval);
|
||||||
break;
|
break;
|
||||||
case T_SubqueryScan:
|
case T_SubqueryScan:
|
||||||
{
|
{
|
||||||
@@ -175,9 +170,9 @@ set_plan_references(Plan *plan, List *rtable)
|
|||||||
* unmodified input tuples). The optimizer is lazy about
|
* unmodified input tuples). The optimizer is lazy about
|
||||||
* creating really valid targetlists for them. Best to just
|
* creating really valid targetlists for them. Best to just
|
||||||
* leave the targetlist alone. In particular, we do not want
|
* leave the targetlist alone. In particular, we do not want
|
||||||
* to pull a subplan list for them, since we will likely end
|
* to process subplans for them, since we will likely end
|
||||||
* up with duplicate list entries for subplans that also
|
* up reprocessing subplans that also appear in lower levels
|
||||||
* appear in lower levels of the plan tree!
|
* of the plan tree!
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case T_Agg:
|
case T_Agg:
|
||||||
@@ -206,7 +201,7 @@ set_plan_references(Plan *plan, List *rtable)
|
|||||||
* Append, like Sort et al, doesn't actually evaluate its
|
* Append, like Sort et al, doesn't actually evaluate its
|
||||||
* targetlist or quals, and we haven't bothered to give it its
|
* targetlist or quals, and we haven't bothered to give it its
|
||||||
* own tlist copy. So, don't fix targetlist/qual. But do
|
* own tlist copy. So, don't fix targetlist/qual. But do
|
||||||
* recurse into subplans.
|
* recurse into child plans.
|
||||||
*/
|
*/
|
||||||
foreach(pl, ((Append *) plan)->appendplans)
|
foreach(pl, ((Append *) plan)->appendplans)
|
||||||
set_plan_references((Plan *) lfirst(pl), rtable);
|
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
|
* subplan references in this plan's tlist and quals. If we did the
|
||||||
* reference-adjustments bottom-up, then we would fail to match this
|
* reference-adjustments bottom-up, then we would fail to match this
|
||||||
* plan's var nodes against the already-modified nodes of the
|
* 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->lefttree, rtable);
|
||||||
set_plan_references(plan->righttree, rtable);
|
set_plan_references(plan->righttree, rtable);
|
||||||
foreach(pl, plan->initPlan)
|
|
||||||
{
|
|
||||||
SubPlan *sp = (SubPlan *) lfirst(pl);
|
|
||||||
|
|
||||||
Assert(IsA(sp, SubPlan));
|
foreach(pl, plan->initPlan)
|
||||||
set_plan_references(sp->plan, sp->rtable);
|
|
||||||
}
|
|
||||||
foreach(pl, plan->subPlan)
|
|
||||||
{
|
{
|
||||||
SubPlan *sp = (SubPlan *) lfirst(pl);
|
SubPlan *sp = (SubPlan *) lfirst(pl);
|
||||||
|
|
||||||
@@ -249,13 +239,38 @@ set_plan_references(Plan *plan, List *rtable)
|
|||||||
* Do final cleanup on expressions (targetlists or quals).
|
* Do final cleanup on expressions (targetlists or quals).
|
||||||
*
|
*
|
||||||
* This consists of looking up operator opcode info for Oper nodes
|
* 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
|
static void
|
||||||
fix_expr_references(Plan *plan, Node *node)
|
fix_expr_references(Plan *plan, Node *node)
|
||||||
{
|
{
|
||||||
fix_opids(node);
|
/* This tree walk requires no special setup, so away we go... */
|
||||||
plan->subPlan = nconc(plan->subPlan, pull_subplans(node));
|
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
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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_operator.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "nodes/params.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/cost.h"
|
#include "optimizer/cost.h"
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
@@ -297,7 +298,7 @@ make_subplan(SubLink *slink)
|
|||||||
switch (nodeTag(plan))
|
switch (nodeTag(plan))
|
||||||
{
|
{
|
||||||
case T_SeqScan:
|
case T_SeqScan:
|
||||||
if (plan->initPlan || plan->subPlan)
|
if (plan->initPlan)
|
||||||
use_material = true;
|
use_material = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -453,20 +454,13 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* finalize_primnode: build lists of subplans and params appearing
|
* finalize_primnode: build lists of params appearing
|
||||||
* in the given expression tree. NOTE: items are added to lists passed in,
|
* in the given expression tree. NOTE: items are added to list passed in,
|
||||||
* so caller must initialize lists to NIL before first call!
|
* so caller must initialize list 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct finalize_primnode_results
|
typedef struct finalize_primnode_results
|
||||||
{
|
{
|
||||||
List *subplans; /* List of subplans found in expr */
|
|
||||||
List *paramids; /* List of PARAM_EXEC paramids found */
|
List *paramids; /* List of PARAM_EXEC paramids found */
|
||||||
} finalize_primnode_results;
|
} finalize_primnode_results;
|
||||||
|
|
||||||
@@ -491,8 +485,6 @@ finalize_primnode(Node *node, finalize_primnode_results *results)
|
|||||||
SubPlan *subplan = (SubPlan *) ((Expr *) node)->oper;
|
SubPlan *subplan = (SubPlan *) ((Expr *) node)->oper;
|
||||||
List *lst;
|
List *lst;
|
||||||
|
|
||||||
/* Add subplan to subplans list */
|
|
||||||
results->subplans = lappend(results->subplans, subplan);
|
|
||||||
/* Check extParam list for params to add to paramids */
|
/* Check extParam list for params to add to paramids */
|
||||||
foreach(lst, subplan->plan->extParam)
|
foreach(lst, subplan->plan->extParam)
|
||||||
{
|
{
|
||||||
@@ -595,18 +587,16 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||||||
if (plan == NULL)
|
if (plan == NULL)
|
||||||
return NIL;
|
return NIL;
|
||||||
|
|
||||||
results.subplans = NIL; /* initialize lists to NIL */
|
results.paramids = NIL; /* initialize list to NIL */
|
||||||
results.paramids = NIL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we call finalize_primnode, results.paramids lists are
|
* When we call finalize_primnode, results.paramids lists are
|
||||||
* automatically merged together. But when recursing to self, we have
|
* automatically merged together. But when recursing to self, we have
|
||||||
* to do it the hard way. We want the paramids list to include params
|
* 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
|
* in subplans as well as at this level.
|
||||||
* subplans of subplans, though.)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Find params and subplans in targetlist and qual */
|
/* Find params in targetlist and qual */
|
||||||
finalize_primnode((Node *) plan->targetlist, &results);
|
finalize_primnode((Node *) plan->targetlist, &results);
|
||||||
finalize_primnode((Node *) plan->qual, &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
|
* we need not look at indxqualorig, since it will have the
|
||||||
* same param references as indxqual, and we aren't really
|
* same param references as indxqual.
|
||||||
* concerned yet about having a complete subplan list.
|
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -704,7 +693,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||||||
nodeTag(plan));
|
nodeTag(plan));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process left and right subplans, if any */
|
/* Process left and right child plans, if any */
|
||||||
results.paramids = set_unioni(results.paramids,
|
results.paramids = set_unioni(results.paramids,
|
||||||
SS_finalize_plan(plan->lefttree,
|
SS_finalize_plan(plan->lefttree,
|
||||||
rtable));
|
rtable));
|
||||||
@@ -712,7 +701,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||||||
SS_finalize_plan(plan->righttree,
|
SS_finalize_plan(plan->righttree,
|
||||||
rtable));
|
rtable));
|
||||||
|
|
||||||
/* Now we have all the paramids and subplans */
|
/* Now we have all the paramids */
|
||||||
|
|
||||||
foreach(lst, results.paramids)
|
foreach(lst, results.paramids)
|
||||||
{
|
{
|
||||||
@@ -733,7 +722,6 @@ SS_finalize_plan(Plan *plan, List *rtable)
|
|||||||
|
|
||||||
plan->extParam = extParam;
|
plan->extParam = extParam;
|
||||||
plan->locParam = locParam;
|
plan->locParam = locParam;
|
||||||
plan->subPlan = results.subplans;
|
|
||||||
|
|
||||||
return results.paramids;
|
return results.paramids;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.pathtype = T_TidScan;
|
||||||
pathnode->path.parent = rel;
|
pathnode->path.parent = rel;
|
||||||
pathnode->path.pathkeys = NIL;
|
pathnode->path.pathkeys = NIL;
|
||||||
pathnode->tideval = copyObject(tideval); /* is copy really
|
pathnode->tideval = tideval;
|
||||||
* necessary? */
|
|
||||||
pathnode->unjoined_relids = NIL;
|
|
||||||
|
|
||||||
cost_tidscan(&pathnode->path, root, rel, tideval);
|
cost_tidscan(&pathnode->path, root, rel, tideval);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"
|
#include "utils/ps_status.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/*
|
||||||
* CreateQueryDesc
|
* CreateQueryDesc
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
*/
|
||||||
QueryDesc *
|
QueryDesc *
|
||||||
CreateQueryDesc(Query *parsetree,
|
CreateQueryDesc(Query *parsetree,
|
||||||
Plan *plantree,
|
Plan *plantree,
|
||||||
CommandDest dest,
|
CommandDest dest,
|
||||||
const char *portalName)
|
const char *portalName,
|
||||||
|
ParamListInfo params,
|
||||||
|
bool doInstrument)
|
||||||
{
|
{
|
||||||
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
|
||||||
|
|
||||||
@@ -40,56 +41,17 @@ CreateQueryDesc(Query *parsetree,
|
|||||||
qd->plantree = plantree; /* plan */
|
qd->plantree = plantree; /* plan */
|
||||||
qd->dest = dest; /* output dest */
|
qd->dest = dest; /* output dest */
|
||||||
qd->portalName = portalName; /* name, if dest is a portal */
|
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;
|
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
|
* PreparePortal
|
||||||
* ----------------
|
* ----------------
|
||||||
@@ -147,8 +109,6 @@ ProcessQuery(Query *parsetree,
|
|||||||
Portal portal = NULL;
|
Portal portal = NULL;
|
||||||
MemoryContext oldContext = NULL;
|
MemoryContext oldContext = NULL;
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
EState *state;
|
|
||||||
TupleDesc attinfo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for special-case destinations
|
* 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,
|
* 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.
|
* context.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
@@ -201,17 +161,12 @@ ProcessQuery(Query *parsetree,
|
|||||||
/*
|
/*
|
||||||
* Now we can create the QueryDesc object.
|
* Now we can create the QueryDesc object.
|
||||||
*/
|
*/
|
||||||
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
|
queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName, NULL, false);
|
||||||
|
|
||||||
/*
|
|
||||||
* create a default executor state.
|
|
||||||
*/
|
|
||||||
state = CreateExecutorState();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call ExecStart to prepare the plan for execution
|
* call ExecStart to prepare the plan for execution
|
||||||
*/
|
*/
|
||||||
attinfo = ExecutorStart(queryDesc, state);
|
ExecutorStart(queryDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If retrieve into portal, stop now; we do not run the plan until a
|
* If retrieve into portal, stop now; we do not run the plan until a
|
||||||
@@ -219,11 +174,8 @@ ProcessQuery(Query *parsetree,
|
|||||||
*/
|
*/
|
||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
{
|
{
|
||||||
PortalSetQuery(portal,
|
/* Arrange to shut down the executor if portal is dropped */
|
||||||
queryDesc,
|
PortalSetQuery(portal, queryDesc, PortalCleanup);
|
||||||
attinfo,
|
|
||||||
state,
|
|
||||||
PortalCleanup);
|
|
||||||
|
|
||||||
/* Now we can return to caller's memory context. */
|
/* Now we can return to caller's memory context. */
|
||||||
MemoryContextSwitchTo(oldContext);
|
MemoryContextSwitchTo(oldContext);
|
||||||
@@ -239,7 +191,7 @@ ProcessQuery(Query *parsetree,
|
|||||||
* Now we get to the important call to ExecutorRun() where we actually
|
* Now we get to the important call to ExecutorRun() where we actually
|
||||||
* run the plan..
|
* run the plan..
|
||||||
*/
|
*/
|
||||||
ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
|
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build command completion status string, if caller wants one.
|
* Build command completion status string, if caller wants one.
|
||||||
@@ -254,20 +206,20 @@ ProcessQuery(Query *parsetree,
|
|||||||
strcpy(completionTag, "SELECT");
|
strcpy(completionTag, "SELECT");
|
||||||
break;
|
break;
|
||||||
case CMD_INSERT:
|
case CMD_INSERT:
|
||||||
if (state->es_processed == 1)
|
if (queryDesc->estate->es_processed == 1)
|
||||||
lastOid = state->es_lastoid;
|
lastOid = queryDesc->estate->es_lastoid;
|
||||||
else
|
else
|
||||||
lastOid = InvalidOid;
|
lastOid = InvalidOid;
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||||
"INSERT %u %u", lastOid, state->es_processed);
|
"INSERT %u %u", lastOid, queryDesc->estate->es_processed);
|
||||||
break;
|
break;
|
||||||
case CMD_UPDATE:
|
case CMD_UPDATE:
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||||
"UPDATE %u", state->es_processed);
|
"UPDATE %u", queryDesc->estate->es_processed);
|
||||||
break;
|
break;
|
||||||
case CMD_DELETE:
|
case CMD_DELETE:
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||||
"DELETE %u", state->es_processed);
|
"DELETE %u", queryDesc->estate->es_processed);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
strcpy(completionTag, "???");
|
strcpy(completionTag, "???");
|
||||||
@@ -278,5 +230,5 @@ ProcessQuery(Query *parsetree,
|
|||||||
/*
|
/*
|
||||||
* Now, we close down all the scans and free allocated resources.
|
* Now, we close down all the scans and free allocated resources.
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(queryDesc, state);
|
ExecutorEnd(queryDesc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* PortalSetQuery
|
||||||
* Attaches a "query" to portal.
|
* 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
|
void
|
||||||
PortalSetQuery(Portal portal,
|
PortalSetQuery(Portal portal,
|
||||||
QueryDesc *queryDesc,
|
QueryDesc *queryDesc,
|
||||||
TupleDesc attinfo,
|
|
||||||
EState *state,
|
|
||||||
void (*cleanup) (Portal portal))
|
void (*cleanup) (Portal portal))
|
||||||
{
|
{
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
AssertArg(IsA((Node *) state, EState));
|
|
||||||
|
|
||||||
portal->queryDesc = queryDesc;
|
portal->queryDesc = queryDesc;
|
||||||
portal->attinfo = attinfo;
|
|
||||||
portal->state = state;
|
|
||||||
portal->atStart = true; /* Allow fetch forward only */
|
portal->atStart = true; /* Allow fetch forward only */
|
||||||
portal->atEnd = false;
|
portal->atEnd = false;
|
||||||
portal->cleanup = cleanup;
|
portal->cleanup = cleanup;
|
||||||
@@ -212,8 +201,6 @@ CreatePortal(char *name)
|
|||||||
|
|
||||||
/* initialize portal query */
|
/* initialize portal query */
|
||||||
portal->queryDesc = NULL;
|
portal->queryDesc = NULL;
|
||||||
portal->attinfo = NULL;
|
|
||||||
portal->state = NULL;
|
|
||||||
portal->atStart = true; /* disallow fetches until query is set */
|
portal->atStart = true; /* disallow fetches until query is set */
|
||||||
portal->atEnd = true;
|
portal->atEnd = true;
|
||||||
portal->cleanup = NULL;
|
portal->cleanup = NULL;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#define EXECDESC_H
|
||||||
|
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "nodes/plannodes.h"
|
#include "nodes/execnodes.h"
|
||||||
#include "tcop/dest.h"
|
#include "tcop/dest.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* query descriptor:
|
* query descriptor:
|
||||||
|
*
|
||||||
* a QueryDesc encapsulates everything that the executor
|
* a QueryDesc encapsulates everything that the executor
|
||||||
* needs to execute the query
|
* needs to execute the query
|
||||||
* ---------------------
|
* ---------------------
|
||||||
*/
|
*/
|
||||||
typedef struct QueryDesc
|
typedef struct QueryDesc
|
||||||
{
|
{
|
||||||
|
/* These fields are provided by CreateQueryDesc */
|
||||||
CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */
|
CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */
|
||||||
Query *parsetree;
|
Query *parsetree; /* rewritten parsetree */
|
||||||
Plan *plantree;
|
Plan *plantree; /* planner's output */
|
||||||
CommandDest dest; /* the destination output of the execution */
|
CommandDest dest; /* the destination output of the execution */
|
||||||
const char *portalName; /* name of portal, or NULL */
|
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;
|
} QueryDesc;
|
||||||
|
|
||||||
/* in pquery.c */
|
/* in pquery.c */
|
||||||
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
||||||
CommandDest dest, const char *portalName);
|
CommandDest dest, const char *portalName,
|
||||||
|
ParamListInfo params,
|
||||||
|
bool doInstrument);
|
||||||
|
|
||||||
#endif /* EXECDESC_H */
|
#endif /* EXECDESC_H */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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"
|
#include "executor/execdesc.h"
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* TupIsNull
|
* TupIsNull
|
||||||
*
|
*
|
||||||
@@ -30,9 +31,9 @@
|
|||||||
/*
|
/*
|
||||||
* prototypes from functions in execAmi.c
|
* prototypes from functions in execAmi.c
|
||||||
*/
|
*/
|
||||||
extern void ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent);
|
extern void ExecReScan(PlanState *node, ExprContext *exprCtxt);
|
||||||
extern void ExecMarkPos(Plan *node);
|
extern void ExecMarkPos(PlanState *node);
|
||||||
extern void ExecRestrPos(Plan *node);
|
extern void ExecRestrPos(PlanState *node);
|
||||||
extern bool ExecSupportsMarkRestore(NodeTag plantype);
|
extern bool ExecSupportsMarkRestore(NodeTag plantype);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -49,10 +50,12 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
|
|||||||
/*
|
/*
|
||||||
* prototypes from functions in execMain.c
|
* prototypes from functions in execMain.c
|
||||||
*/
|
*/
|
||||||
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
|
extern void ExecutorStart(QueryDesc *queryDesc);
|
||||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
||||||
ScanDirection direction, long count);
|
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,
|
extern void ExecConstraints(const char *caller, ResultRelInfo *resultRelInfo,
|
||||||
TupleTableSlot *slot, EState *estate);
|
TupleTableSlot *slot, EState *estate);
|
||||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
||||||
@@ -61,11 +64,11 @@ extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
|||||||
/*
|
/*
|
||||||
* prototypes from functions in execProcnode.c
|
* prototypes from functions in execProcnode.c
|
||||||
*/
|
*/
|
||||||
extern bool ExecInitNode(Plan *node, EState *estate, Plan *parent);
|
extern PlanState *ExecInitNode(Plan *node, EState *estate);
|
||||||
extern TupleTableSlot *ExecProcNode(Plan *node, Plan *parent);
|
extern TupleTableSlot *ExecProcNode(PlanState *node);
|
||||||
extern int ExecCountSlotsNode(Plan *node);
|
extern int ExecCountSlotsNode(Plan *node);
|
||||||
extern void ExecEndNode(Plan *node, Plan *parent);
|
extern void ExecEndNode(PlanState *node);
|
||||||
extern TupleDesc ExecGetTupType(Plan *node);
|
extern TupleDesc ExecGetTupType(PlanState *node);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prototypes from functions in execQual.c
|
* prototypes from functions in execQual.c
|
||||||
@@ -89,6 +92,7 @@ extern Datum ExecEvalExpr(Node *expression, ExprContext *econtext,
|
|||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
extern Datum ExecEvalExprSwitchContext(Node *expression, ExprContext *econtext,
|
extern Datum ExecEvalExprSwitchContext(Node *expression, ExprContext *econtext,
|
||||||
bool *isNull, ExprDoneCond *isDone);
|
bool *isNull, ExprDoneCond *isDone);
|
||||||
|
extern Node *ExecInitExpr(Node *node, PlanState *parent);
|
||||||
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
|
extern bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull);
|
||||||
extern int ExecTargetListLength(List *targetlist);
|
extern int ExecTargetListLength(List *targetlist);
|
||||||
extern int ExecCleanTargetListLength(List *targetlist);
|
extern int ExecCleanTargetListLength(List *targetlist);
|
||||||
@@ -98,9 +102,9 @@ extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
|
|||||||
/*
|
/*
|
||||||
* prototypes from functions in execScan.c
|
* 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
|
* prototypes from functions in execTuples.c
|
||||||
@@ -117,14 +121,13 @@ extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
|
|||||||
extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
|
extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
|
||||||
TupleDesc tupdesc, bool shouldFree);
|
TupleDesc tupdesc, bool shouldFree);
|
||||||
extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
|
extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
|
||||||
extern void ExecInitResultTupleSlot(EState *estate, CommonState *commonstate);
|
extern void ExecInitResultTupleSlot(EState *estate, PlanState *planstate);
|
||||||
extern void ExecInitScanTupleSlot(EState *estate,
|
extern void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate);
|
||||||
CommonScanState *commonscanstate);
|
|
||||||
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
|
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
|
||||||
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
|
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
|
||||||
TupleDesc tupType);
|
TupleDesc tupType);
|
||||||
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
|
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
|
||||||
extern void SetChangedParamList(Plan *node, List *newchg);
|
extern void SetChangedParamList(PlanState *node, List *newchg);
|
||||||
|
|
||||||
typedef struct TupOutputState
|
typedef struct TupOutputState
|
||||||
{
|
{
|
||||||
@@ -155,21 +158,19 @@ extern void end_tup_output(TupOutputState *tstate);
|
|||||||
* prototypes from functions in execUtils.c
|
* prototypes from functions in execUtils.c
|
||||||
*/
|
*/
|
||||||
extern void ResetTupleCount(void);
|
extern void ResetTupleCount(void);
|
||||||
extern void ExecAssignExprContext(EState *estate, CommonState *commonstate);
|
extern void ExecAssignExprContext(EState *estate, PlanState *planstate);
|
||||||
extern void ExecAssignResultType(CommonState *commonstate,
|
extern void ExecAssignResultType(PlanState *planstate,
|
||||||
TupleDesc tupDesc, bool shouldFree);
|
TupleDesc tupDesc, bool shouldFree);
|
||||||
extern void ExecAssignResultTypeFromOuterPlan(Plan *node,
|
extern void ExecAssignResultTypeFromOuterPlan(PlanState *planstate);
|
||||||
CommonState *commonstate);
|
extern void ExecAssignResultTypeFromTL(PlanState *planstate);
|
||||||
extern void ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate);
|
extern TupleDesc ExecGetResultType(PlanState *planstate);
|
||||||
extern TupleDesc ExecGetResultType(CommonState *commonstate);
|
extern void ExecAssignProjectionInfo(PlanState *planstate);
|
||||||
extern void ExecAssignProjectionInfo(Plan *node, CommonState *commonstate);
|
extern void ExecFreeProjectionInfo(PlanState *planstate);
|
||||||
extern void ExecFreeProjectionInfo(CommonState *commonstate);
|
extern void ExecFreeExprContext(PlanState *planstate);
|
||||||
extern void ExecFreeExprContext(CommonState *commonstate);
|
extern TupleDesc ExecGetScanType(ScanState *scanstate);
|
||||||
extern TupleDesc ExecGetScanType(CommonScanState *csstate);
|
extern void ExecAssignScanType(ScanState *scanstate,
|
||||||
extern void ExecAssignScanType(CommonScanState *csstate,
|
|
||||||
TupleDesc tupDesc, bool shouldFree);
|
TupleDesc tupDesc, bool shouldFree);
|
||||||
extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
|
extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate);
|
||||||
CommonScanState *csstate);
|
|
||||||
|
|
||||||
extern ExprContext *MakeExprContext(TupleTableSlot *slot,
|
extern ExprContext *MakeExprContext(TupleTableSlot *slot,
|
||||||
MemoryContext queryContext);
|
MemoryContext queryContext);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#define NODEAGG_H
|
||||||
|
|
||||||
#include "fmgr.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 int ExecCountSlotsAgg(Agg *node);
|
||||||
extern void ExecEndAgg(Agg *node);
|
extern AggState *ExecInitAgg(Agg *node, EState *estate);
|
||||||
extern void ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecAgg(AggState *node);
|
||||||
|
extern void ExecEndAgg(AggState *node);
|
||||||
|
extern void ExecReScanAgg(AggState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
extern Datum aggregate_dummy(PG_FUNCTION_ARGS);
|
extern Datum aggregate_dummy(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEAPPEND_H
|
||||||
#define 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 int ExecCountSlotsAppend(Append *node);
|
||||||
extern TupleTableSlot *ExecProcAppend(Append *node);
|
extern AppendState *ExecInitAppend(Append *node, EState *estate);
|
||||||
extern void ExecEndAppend(Append *node);
|
extern TupleTableSlot *ExecProcAppend(AppendState *node);
|
||||||
extern void ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent);
|
extern void ExecEndAppend(AppendState *node);
|
||||||
|
extern void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODEAPPEND_H */
|
#endif /* NODEAPPEND_H */
|
||||||
|
|||||||
@@ -7,21 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEFUNCTIONSCAN_H
|
||||||
#define 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 int ExecCountSlotsFunctionScan(FunctionScan *node);
|
||||||
extern void ExecFunctionMarkPos(FunctionScan *node);
|
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate);
|
||||||
extern void ExecFunctionRestrPos(FunctionScan *node);
|
extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
|
||||||
extern void ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent);
|
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 */
|
#endif /* NODEFUNCTIONSCAN_H */
|
||||||
|
|||||||
@@ -7,20 +7,20 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEGROUP_H
|
||||||
#define 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 int ExecCountSlotsGroup(Group *node);
|
||||||
extern void ExecEndGroup(Group *node);
|
extern GroupState *ExecInitGroup(Group *node, EState *estate);
|
||||||
extern void ExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecGroup(GroupState *node);
|
||||||
|
extern void ExecEndGroup(GroupState *node);
|
||||||
|
extern void ExecReScanGroup(GroupState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
extern bool execTuplesMatch(HeapTuple tuple1,
|
extern bool execTuplesMatch(HeapTuple tuple1,
|
||||||
HeapTuple tuple2,
|
HeapTuple tuple2,
|
||||||
|
|||||||
@@ -7,19 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEHASH_H
|
||||||
#define 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 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 HashJoinTable ExecHashTableCreate(Hash *node);
|
||||||
extern void ExecHashTableDestroy(HashJoinTable hashtable);
|
extern void ExecHashTableDestroy(HashJoinTable hashtable);
|
||||||
extern void ExecHashTableInsert(HashJoinTable hashtable,
|
extern void ExecHashTableInsert(HashJoinTable hashtable,
|
||||||
@@ -31,7 +33,6 @@ extern int ExecHashGetBucket(HashJoinTable hashtable,
|
|||||||
extern HeapTuple ExecScanHashBucket(HashJoinState *hjstate, List *hjclauses,
|
extern HeapTuple ExecScanHashBucket(HashJoinState *hjstate, List *hjclauses,
|
||||||
ExprContext *econtext);
|
ExprContext *econtext);
|
||||||
extern void ExecHashTableReset(HashJoinTable hashtable, long ntuples);
|
extern void ExecHashTableReset(HashJoinTable hashtable, long ntuples);
|
||||||
extern void ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent);
|
|
||||||
extern void ExecChooseHashTableSize(double ntuples, int tupwidth,
|
extern void ExecChooseHashTableSize(double ntuples, int tupwidth,
|
||||||
int *virtualbuckets,
|
int *virtualbuckets,
|
||||||
int *physicalbuckets,
|
int *physicalbuckets,
|
||||||
|
|||||||
@@ -7,20 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEHASHJOIN_H
|
||||||
#define 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 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 ExecHashJoinSaveTuple(HeapTuple heapTuple, BufFile *file);
|
||||||
extern void ExecReScanHashJoin(HashJoin *node, ExprContext *exprCtxt, Plan *parent);
|
|
||||||
|
|
||||||
#endif /* NODEHASHJOIN_H */
|
#endif /* NODEHASHJOIN_H */
|
||||||
|
|||||||
@@ -7,22 +7,23 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEINDEXSCAN_H
|
||||||
#define 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 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 */
|
#endif /* NODEINDEXSCAN_H */
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODELIMIT_H
|
||||||
#define 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 int ExecCountSlotsLimit(Limit *node);
|
||||||
extern void ExecEndLimit(Limit *node);
|
extern LimitState *ExecInitLimit(Limit *node, EState *estate);
|
||||||
extern void ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecLimit(LimitState *node);
|
||||||
|
extern void ExecEndLimit(LimitState *node);
|
||||||
|
extern void ExecReScanLimit(LimitState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODELIMIT_H */
|
#endif /* NODELIMIT_H */
|
||||||
|
|||||||
@@ -7,21 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEMATERIAL_H
|
||||||
#define 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 int ExecCountSlotsMaterial(Material *node);
|
||||||
extern void ExecEndMaterial(Material *node);
|
extern MaterialState *ExecInitMaterial(Material *node, EState *estate);
|
||||||
extern void ExecMaterialMarkPos(Material *node);
|
extern TupleTableSlot *ExecMaterial(MaterialState *node);
|
||||||
extern void ExecMaterialRestrPos(Material *node);
|
extern void ExecEndMaterial(MaterialState *node);
|
||||||
extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
|
extern void ExecMaterialMarkPos(MaterialState *node);
|
||||||
|
extern void ExecMaterialRestrPos(MaterialState *node);
|
||||||
|
extern void ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODEMATERIAL_H */
|
#endif /* NODEMATERIAL_H */
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEMERGEJOIN_H
|
||||||
#define 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 int ExecCountSlotsMergeJoin(MergeJoin *node);
|
||||||
extern void ExecEndMergeJoin(MergeJoin *node);
|
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate);
|
||||||
extern void ExecReScanMergeJoin(MergeJoin *node, ExprContext *exprCtxt, Plan *parent);
|
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) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODENESTLOOP_H
|
||||||
#define 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 int ExecCountSlotsNestLoop(NestLoop *node);
|
||||||
extern void ExecEndNestLoop(NestLoop *node);
|
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate);
|
||||||
extern void ExecReScanNestLoop(NestLoop *node, ExprContext *exprCtxt,
|
extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
|
||||||
Plan *parent);
|
extern void ExecEndNestLoop(NestLoopState *node);
|
||||||
|
extern void ExecReScanNestLoop(NestLoopState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODENESTLOOP_H */
|
#endif /* NODENESTLOOP_H */
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODERESULT_H
|
||||||
#define 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 int ExecCountSlotsResult(Result *node);
|
||||||
extern void ExecEndResult(Result *node);
|
extern ResultState *ExecInitResult(Result *node, EState *estate);
|
||||||
extern void ExecReScanResult(Result *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecResult(ResultState *node);
|
||||||
|
extern void ExecEndResult(ResultState *node);
|
||||||
|
extern void ExecReScanResult(ResultState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODERESULT_H */
|
#endif /* NODERESULT_H */
|
||||||
|
|||||||
@@ -7,21 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODESEQSCAN_H
|
||||||
#define 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 int ExecCountSlotsSeqScan(SeqScan *node);
|
||||||
extern void ExecEndSeqScan(SeqScan *node);
|
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate);
|
||||||
extern void ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
|
||||||
extern void ExecSeqMarkPos(SeqScan *node);
|
extern void ExecEndSeqScan(SeqScanState *node);
|
||||||
extern void ExecSeqRestrPos(SeqScan *node);
|
extern void ExecSeqMarkPos(SeqScanState *node);
|
||||||
|
extern void ExecSeqRestrPos(SeqScanState *node);
|
||||||
|
extern void ExecSeqReScan(SeqScanState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODESEQSCAN_H */
|
#endif /* NODESEQSCAN_H */
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODESETOP_H
|
||||||
#define 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 int ExecCountSlotsSetOp(SetOp *node);
|
||||||
extern void ExecEndSetOp(SetOp *node);
|
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate);
|
||||||
extern void ExecReScanSetOp(SetOp *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecSetOp(SetOpState *node);
|
||||||
|
extern void ExecEndSetOp(SetOpState *node);
|
||||||
|
extern void ExecReScanSetOp(SetOpState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODESETOP_H */
|
#endif /* NODESETOP_H */
|
||||||
|
|||||||
@@ -7,21 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODESORT_H
|
||||||
#define 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 int ExecCountSlotsSort(Sort *node);
|
||||||
extern void ExecEndSort(Sort *node);
|
extern SortState *ExecInitSort(Sort *node, EState *estate);
|
||||||
extern void ExecSortMarkPos(Sort *node);
|
extern TupleTableSlot *ExecSort(SortState *node);
|
||||||
extern void ExecSortRestrPos(Sort *node);
|
extern void ExecEndSort(SortState *node);
|
||||||
extern void ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent);
|
extern void ExecSortMarkPos(SortState *node);
|
||||||
|
extern void ExecSortRestrPos(SortState *node);
|
||||||
|
extern void ExecReScanSort(SortState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODESORT_H */
|
#endif /* NODESORT_H */
|
||||||
|
|||||||
@@ -2,18 +2,26 @@
|
|||||||
*
|
*
|
||||||
* nodeSubplan.h
|
* nodeSubplan.h
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* $Id: nodeSubplan.h,v 1.12 2002/12/05 15:50:38 tgl Exp $
|
||||||
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef NODESUBPLAN_H
|
#ifndef NODESUBPLAN_H
|
||||||
#define 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);
|
bool *isNull);
|
||||||
extern bool ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent);
|
extern void ExecEndSubPlan(SubPlanState *node);
|
||||||
extern void ExecReScanSetParamPlan(SubPlan *node, Plan *parent);
|
extern void ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent);
|
||||||
extern void ExecSetParamPlan(SubPlan *node, ExprContext *econtext);
|
|
||||||
extern void ExecEndSubPlan(SubPlan *node);
|
extern void ExecSetParamPlan(SubPlanState *node, ExprContext *econtext);
|
||||||
|
|
||||||
#endif /* NODESUBPLAN_H */
|
#endif /* NODESUBPLAN_H */
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODESUBQUERYSCAN_H
|
||||||
#define 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 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 */
|
#endif /* NODESUBQUERYSCAN_H */
|
||||||
|
|||||||
@@ -7,22 +7,21 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODETIDSCAN_H
|
||||||
#define 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 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 */
|
#endif /* NODETIDSCAN_H */
|
||||||
|
|||||||
@@ -7,19 +7,19 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef NODEUNIQUE_H
|
||||||
#define 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 int ExecCountSlotsUnique(Unique *node);
|
||||||
extern void ExecEndUnique(Unique *node);
|
extern UniqueState *ExecInitUnique(Unique *node, EState *estate);
|
||||||
extern void ExecReScanUnique(Unique *node, ExprContext *exprCtxt, Plan *parent);
|
extern TupleTableSlot *ExecUnique(UniqueState *node);
|
||||||
|
extern void ExecEndUnique(UniqueState *node);
|
||||||
|
extern void ExecReScanUnique(UniqueState *node, ExprContext *exprCtxt);
|
||||||
|
|
||||||
#endif /* NODEUNIQUE_H */
|
#endif /* NODEUNIQUE_H */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#define EXECNODES_H
|
||||||
|
|
||||||
#include "access/relscan.h"
|
#include "access/relscan.h"
|
||||||
#include "access/sdir.h"
|
|
||||||
#include "executor/hashjoin.h"
|
#include "executor/hashjoin.h"
|
||||||
#include "executor/tuptable.h"
|
#include "executor/tuptable.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "nodes/params.h"
|
#include "nodes/params.h"
|
||||||
#include "nodes/primnodes.h"
|
#include "nodes/plannodes.h"
|
||||||
#include "utils/tuplestore.h"
|
#include "utils/tuplestore.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -316,6 +315,8 @@ typedef struct EState
|
|||||||
List *es_rowMark; /* not good place, but there is no other */
|
List *es_rowMark; /* not good place, but there is no other */
|
||||||
MemoryContext es_query_cxt; /* per-query context in which EState lives */
|
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
|
* this ExprContext is for per-output-tuple operations, such as
|
||||||
* constraint checks and index-value computations. It will be reset
|
* constraint checks and index-value computations. It will be reset
|
||||||
@@ -332,98 +333,101 @@ typedef struct EState
|
|||||||
bool es_useEvalPlan;
|
bool es_useEvalPlan;
|
||||||
} EState;
|
} 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.
|
* We never actually instantiate any PlanState nodes; this is just the common
|
||||||
*
|
* abstract superclass for all PlanState-type nodes.
|
||||||
* 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?)
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct CommonState
|
typedef struct PlanState
|
||||||
{
|
{
|
||||||
NodeTag type; /* its first field is NodeTag */
|
NodeTag type;
|
||||||
TupleTableSlot *cs_OuterTupleSlot;
|
|
||||||
TupleTableSlot *cs_ResultTupleSlot;
|
|
||||||
ExprContext *cs_ExprContext;
|
|
||||||
ProjectionInfo *cs_ProjInfo;
|
|
||||||
bool cs_TupFromTlist;
|
|
||||||
} CommonState;
|
|
||||||
|
|
||||||
|
Plan *plan; /* associated Plan node */
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
EState *state; /* at execution time, state's of
|
||||||
* Control Node State Information
|
* 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
|
* ResultState information
|
||||||
*
|
|
||||||
* done flag which tells us to quit when we
|
|
||||||
* have already returned a constant tuple.
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct ResultState
|
typedef struct ResultState
|
||||||
{
|
{
|
||||||
CommonState cstate; /* its first field is NodeTag */
|
PlanState ps; /* its first field is NodeTag */
|
||||||
bool rs_done;
|
Node *resconstantqual;
|
||||||
bool rs_checkqual;
|
bool rs_done; /* are we done? */
|
||||||
|
bool rs_checkqual; /* do we need to check the qual? */
|
||||||
} ResultState;
|
} ResultState;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* AppendState information
|
* AppendState information
|
||||||
*
|
*
|
||||||
|
* nplans how many plans are in the list
|
||||||
* whichplan which plan is being executed (0 .. n-1)
|
* whichplan which plan is being executed (0 .. n-1)
|
||||||
* firstplan first plan to execute (usually 0)
|
* firstplan first plan to execute (usually 0)
|
||||||
* lastplan last plan to execute (usually n-1)
|
* lastplan last plan to execute (usually n-1)
|
||||||
* nplans how many plans are in the list
|
|
||||||
* initialized array of ExecInitNode() results
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct AppendState
|
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_whichplan;
|
||||||
int as_firstplan;
|
int as_firstplan;
|
||||||
int as_lastplan;
|
int as_lastplan;
|
||||||
int as_nplans;
|
|
||||||
bool *as_initialized;
|
|
||||||
} AppendState;
|
} 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
|
* scans of an underlying relation. It can also be used for nodes
|
||||||
* that scan the output of an underlying plan node --- in that case,
|
* that scan the output of an underlying plan node --- in that case,
|
||||||
* only ScanTupleSlot is actually useful, and it refers to the tuple
|
* 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
|
* ScanTupleSlot pointer to slot in tuple table holding scan tuple
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct CommonScanState
|
typedef struct ScanState
|
||||||
{
|
{
|
||||||
CommonState cstate; /* its first field is NodeTag */
|
PlanState ps; /* its first field is NodeTag */
|
||||||
Relation css_currentRelation;
|
Relation ss_currentRelation;
|
||||||
HeapScanDesc css_currentScanDesc;
|
HeapScanDesc ss_currentScanDesc;
|
||||||
TupleTableSlot *css_ScanTupleSlot;
|
TupleTableSlot *ss_ScanTupleSlot;
|
||||||
} CommonScanState;
|
} 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.
|
* no additional fields.
|
||||||
*/
|
*/
|
||||||
|
typedef ScanState SeqScanState;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* IndexScanState information
|
* 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
|
* NumIndices number of indices in this scan
|
||||||
* IndexPtr current index in use
|
* IndexPtr current index in use
|
||||||
* ScanKeys Skey structures to scan index rels
|
* ScanKeys Skey structures to scan index rels
|
||||||
@@ -479,7 +479,9 @@ typedef struct CommonScanState
|
|||||||
*/
|
*/
|
||||||
typedef struct IndexScanState
|
typedef struct IndexScanState
|
||||||
{
|
{
|
||||||
NodeTag type;
|
ScanState ss; /* its first field is NodeTag */
|
||||||
|
List *indxqual;
|
||||||
|
List *indxqualorig;
|
||||||
int iss_NumIndices;
|
int iss_NumIndices;
|
||||||
int iss_IndexPtr;
|
int iss_IndexPtr;
|
||||||
int iss_MarkIndexPtr;
|
int iss_MarkIndexPtr;
|
||||||
@@ -495,10 +497,6 @@ typedef struct IndexScanState
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* TidScanState information
|
* 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
|
* NumTids number of tids in this scan
|
||||||
* TidPtr current tid in use
|
* TidPtr current tid in use
|
||||||
* TidList evaluated item pointers
|
* TidList evaluated item pointers
|
||||||
@@ -506,7 +504,7 @@ typedef struct IndexScanState
|
|||||||
*/
|
*/
|
||||||
typedef struct TidScanState
|
typedef struct TidScanState
|
||||||
{
|
{
|
||||||
NodeTag type;
|
ScanState ss; /* its first field is NodeTag */
|
||||||
int tss_NumTids;
|
int tss_NumTids;
|
||||||
int tss_TidPtr;
|
int tss_TidPtr;
|
||||||
int tss_MarkTidPtr;
|
int tss_MarkTidPtr;
|
||||||
@@ -526,7 +524,8 @@ typedef struct TidScanState
|
|||||||
*/
|
*/
|
||||||
typedef struct SubqueryScanState
|
typedef struct SubqueryScanState
|
||||||
{
|
{
|
||||||
CommonScanState csstate; /* its first field is NodeTag */
|
ScanState ss; /* its first field is NodeTag */
|
||||||
|
PlanState *subplan;
|
||||||
EState *sss_SubEState;
|
EState *sss_SubEState;
|
||||||
} SubqueryScanState;
|
} SubqueryScanState;
|
||||||
|
|
||||||
@@ -538,12 +537,12 @@ typedef struct SubqueryScanState
|
|||||||
*
|
*
|
||||||
* tupdesc expected return tuple description
|
* tupdesc expected return tuple description
|
||||||
* tuplestorestate private state of tuplestore.c
|
* tuplestorestate private state of tuplestore.c
|
||||||
* funcexpr function expression being evaluated
|
* funcexpr state for function expression being evaluated
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct FunctionScanState
|
typedef struct FunctionScanState
|
||||||
{
|
{
|
||||||
CommonScanState csstate; /* its first field is NodeTag */
|
ScanState ss; /* its first field is NodeTag */
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
Tuplestorestate *tuplestorestate;
|
Tuplestorestate *tuplestorestate;
|
||||||
Node *funcexpr;
|
Node *funcexpr;
|
||||||
@@ -557,11 +556,15 @@ typedef struct FunctionScanState
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* JoinState information
|
* JoinState information
|
||||||
*
|
*
|
||||||
* Superclass for state items of join nodes.
|
* Superclass for state nodes of join plans.
|
||||||
* Currently this is the same as CommonState.
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef CommonState JoinState;
|
typedef struct JoinState
|
||||||
|
{
|
||||||
|
PlanState ps;
|
||||||
|
JoinType jointype;
|
||||||
|
List *joinqual; /* JOIN quals (in addition to ps.qual) */
|
||||||
|
} JoinState;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* NestLoopState information
|
* NestLoopState information
|
||||||
@@ -573,7 +576,7 @@ typedef CommonState JoinState;
|
|||||||
*/
|
*/
|
||||||
typedef struct NestLoopState
|
typedef struct NestLoopState
|
||||||
{
|
{
|
||||||
JoinState jstate; /* its first field is NodeTag */
|
JoinState js; /* its first field is NodeTag */
|
||||||
bool nl_NeedNewOuter;
|
bool nl_NeedNewOuter;
|
||||||
bool nl_MatchedOuter;
|
bool nl_MatchedOuter;
|
||||||
TupleTableSlot *nl_NullInnerTupleSlot;
|
TupleTableSlot *nl_NullInnerTupleSlot;
|
||||||
@@ -596,7 +599,8 @@ typedef struct NestLoopState
|
|||||||
*/
|
*/
|
||||||
typedef struct MergeJoinState
|
typedef struct MergeJoinState
|
||||||
{
|
{
|
||||||
JoinState jstate; /* its first field is NodeTag */
|
JoinState js; /* its first field is NodeTag */
|
||||||
|
List *mergeclauses;
|
||||||
List *mj_OuterSkipQual;
|
List *mj_OuterSkipQual;
|
||||||
List *mj_InnerSkipQual;
|
List *mj_InnerSkipQual;
|
||||||
int mj_JoinState;
|
int mj_JoinState;
|
||||||
@@ -630,7 +634,8 @@ typedef struct MergeJoinState
|
|||||||
*/
|
*/
|
||||||
typedef struct HashJoinState
|
typedef struct HashJoinState
|
||||||
{
|
{
|
||||||
JoinState jstate; /* its first field is NodeTag */
|
JoinState js; /* its first field is NodeTag */
|
||||||
|
List *hashclauses;
|
||||||
HashJoinTable hj_HashTable;
|
HashJoinTable hj_HashTable;
|
||||||
int hj_CurBucketNo;
|
int hj_CurBucketNo;
|
||||||
HashJoinTuple hj_CurTuple;
|
HashJoinTuple hj_CurTuple;
|
||||||
@@ -656,23 +661,46 @@ typedef struct HashJoinState
|
|||||||
* materialize nodes are used to materialize the results
|
* materialize nodes are used to materialize the results
|
||||||
* of a subplan into a temporary file.
|
* 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
|
* tuplestorestate private state of tuplestore.c
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
typedef struct MaterialState
|
typedef struct MaterialState
|
||||||
{
|
{
|
||||||
CommonScanState csstate; /* its first field is NodeTag */
|
ScanState ss; /* its first field is NodeTag */
|
||||||
void *tuplestorestate;
|
void *tuplestorestate;
|
||||||
} MaterialState;
|
} 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
|
* 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
|
* input group during evaluation of an Agg node's output tuple(s). We
|
||||||
* create a second ExprContext, tmpcontext, in which to evaluate input
|
* create a second ExprContext, tmpcontext, in which to evaluate input
|
||||||
@@ -687,7 +715,7 @@ typedef struct AggHashTableData *AggHashTable;
|
|||||||
|
|
||||||
typedef struct AggState
|
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 */
|
List *aggs; /* all Aggref nodes in targetlist & quals */
|
||||||
int numaggs; /* length of list (could be zero!) */
|
int numaggs; /* length of list (could be zero!) */
|
||||||
FmgrInfo *eqfunctions; /* per-grouping-field equality fns */
|
FmgrInfo *eqfunctions; /* per-grouping-field equality fns */
|
||||||
@@ -705,32 +733,6 @@ typedef struct AggState
|
|||||||
int next_hash_bucket; /* next chain */
|
int next_hash_bucket; /* next chain */
|
||||||
} AggState;
|
} 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
|
* UniqueState information
|
||||||
*
|
*
|
||||||
@@ -744,12 +746,22 @@ typedef struct SortState
|
|||||||
*/
|
*/
|
||||||
typedef struct UniqueState
|
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 */
|
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
|
||||||
HeapTuple priorTuple; /* most recently returned tuple, or NULL */
|
HeapTuple priorTuple; /* most recently returned tuple, or NULL */
|
||||||
MemoryContext tempContext; /* short-term context for comparisons */
|
MemoryContext tempContext; /* short-term context for comparisons */
|
||||||
} UniqueState;
|
} UniqueState;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* HashState information
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef struct HashState
|
||||||
|
{
|
||||||
|
PlanState ps; /* its first field is NodeTag */
|
||||||
|
HashJoinTable hashtable; /* hash table for the hashjoin */
|
||||||
|
} HashState;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* SetOpState information
|
* SetOpState information
|
||||||
*
|
*
|
||||||
@@ -761,7 +773,7 @@ typedef struct UniqueState
|
|||||||
*/
|
*/
|
||||||
typedef struct SetOpState
|
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 */
|
FmgrInfo *eqfunctions; /* per-field lookup data for equality fns */
|
||||||
bool subplan_done; /* has subplan returned EOF? */
|
bool subplan_done; /* has subplan returned EOF? */
|
||||||
long numLeft; /* number of left-input dups of cur group */
|
long numLeft; /* number of left-input dups of cur group */
|
||||||
@@ -794,7 +806,9 @@ typedef enum
|
|||||||
|
|
||||||
typedef struct LimitState
|
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 offset; /* current OFFSET value */
|
||||||
long count; /* current COUNT, if any */
|
long count; /* current COUNT, if any */
|
||||||
bool noCount; /* if true, ignore count */
|
bool noCount; /* if true, ignore count */
|
||||||
@@ -803,46 +817,16 @@ typedef struct LimitState
|
|||||||
TupleTableSlot *subSlot; /* tuple last obtained from subplan */
|
TupleTableSlot *subSlot; /* tuple last obtained from subplan */
|
||||||
} LimitState;
|
} LimitState;
|
||||||
|
|
||||||
|
/* ---------------------
|
||||||
/* ----------------
|
* SubPlanState information
|
||||||
* HashState information
|
* ---------------------
|
||||||
*
|
|
||||||
* hashtable hash table for the hashjoin
|
|
||||||
* ----------------
|
|
||||||
*/
|
*/
|
||||||
typedef struct HashState
|
typedef struct SubPlanState
|
||||||
{
|
{
|
||||||
CommonState cstate; /* its first field is NodeTag */
|
PlanState ps; /* its first field is NodeTag */
|
||||||
HashJoinTable hashtable;
|
PlanState *planstate; /* subselect plan's state tree */
|
||||||
} HashState;
|
bool needShutdown; /* TRUE = need to shutdown subplan */
|
||||||
|
HeapTuple curTuple; /* copy of most recent tuple from subplan */
|
||||||
#ifdef NOT_USED
|
} SubPlanState;
|
||||||
/* -----------------------
|
|
||||||
* 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
|
|
||||||
|
|
||||||
#endif /* EXECNODES_H */
|
#endif /* EXECNODES_H */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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)
|
* 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.
|
* 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.
|
* 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
|
typedef enum NodeTag
|
||||||
{
|
{
|
||||||
T_Invalid = 0,
|
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)
|
* TAGS FOR PLAN NODES (plannodes.h)
|
||||||
*/
|
*/
|
||||||
T_Plan = 10,
|
T_Plan = 100,
|
||||||
T_Result,
|
T_Result,
|
||||||
T_Append,
|
T_Append,
|
||||||
T_Scan,
|
T_Scan,
|
||||||
T_SeqScan,
|
T_SeqScan,
|
||||||
T_IndexScan,
|
T_IndexScan,
|
||||||
|
T_TidScan,
|
||||||
|
T_SubqueryScan,
|
||||||
|
T_FunctionScan,
|
||||||
T_Join,
|
T_Join,
|
||||||
T_NestLoop,
|
T_NestLoop,
|
||||||
T_MergeJoin,
|
T_MergeJoin,
|
||||||
T_HashJoin,
|
T_HashJoin,
|
||||||
T_Limit,
|
|
||||||
T_Material,
|
T_Material,
|
||||||
T_Sort,
|
T_Sort,
|
||||||
|
T_Group,
|
||||||
T_Agg,
|
T_Agg,
|
||||||
T_Unique,
|
T_Unique,
|
||||||
T_Hash,
|
T_Hash,
|
||||||
T_SetOp,
|
T_SetOp,
|
||||||
T_Group,
|
T_Limit,
|
||||||
T_SubPlan,
|
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)
|
* TAGS FOR PRIMITIVE NODES (primnodes.h)
|
||||||
*/
|
*/
|
||||||
T_Resdom = 100,
|
T_Resdom = 300,
|
||||||
T_Fjoin,
|
T_Fjoin,
|
||||||
T_Expr,
|
T_Expr,
|
||||||
T_Var,
|
T_Var,
|
||||||
@@ -74,7 +115,7 @@ typedef enum NodeTag
|
|||||||
/*
|
/*
|
||||||
* TAGS FOR PLANNER NODES (relation.h)
|
* TAGS FOR PLANNER NODES (relation.h)
|
||||||
*/
|
*/
|
||||||
T_RelOptInfo = 200,
|
T_RelOptInfo = 400,
|
||||||
T_IndexOptInfo,
|
T_IndexOptInfo,
|
||||||
T_Path,
|
T_Path,
|
||||||
T_IndexPath,
|
T_IndexPath,
|
||||||
@@ -90,48 +131,16 @@ typedef enum NodeTag
|
|||||||
T_JoinInfo,
|
T_JoinInfo,
|
||||||
T_InnerIndexscanInfo,
|
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)
|
* TAGS FOR MEMORY NODES (memnodes.h)
|
||||||
*/
|
*/
|
||||||
T_MemoryContext = 400,
|
T_MemoryContext = 500,
|
||||||
T_AllocSetContext,
|
T_AllocSetContext,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TAGS FOR VALUE NODES (pg_list.h)
|
* TAGS FOR VALUE NODES (pg_list.h)
|
||||||
*/
|
*/
|
||||||
T_Value = 500,
|
T_Value = 600,
|
||||||
T_List,
|
T_List,
|
||||||
T_Integer,
|
T_Integer,
|
||||||
T_Float,
|
T_Float,
|
||||||
@@ -142,7 +151,7 @@ typedef enum NodeTag
|
|||||||
/*
|
/*
|
||||||
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
||||||
*/
|
*/
|
||||||
T_Query = 600,
|
T_Query = 700,
|
||||||
T_InsertStmt,
|
T_InsertStmt,
|
||||||
T_DeleteStmt,
|
T_DeleteStmt,
|
||||||
T_UpdateStmt,
|
T_UpdateStmt,
|
||||||
@@ -208,7 +217,7 @@ typedef enum NodeTag
|
|||||||
T_ExecuteStmt,
|
T_ExecuteStmt,
|
||||||
T_DeallocateStmt,
|
T_DeallocateStmt,
|
||||||
|
|
||||||
T_A_Expr = 700,
|
T_A_Expr = 800,
|
||||||
T_ColumnRef,
|
T_ColumnRef,
|
||||||
T_ParamRef,
|
T_ParamRef,
|
||||||
T_A_Const,
|
T_A_Const,
|
||||||
@@ -248,7 +257,7 @@ typedef enum NodeTag
|
|||||||
/*
|
/*
|
||||||
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
|
* 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 */
|
T_ReturnSetInfo /* in nodes/execnodes.h */
|
||||||
|
|
||||||
} NodeTag;
|
} NodeTag;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* array of ParamExecData records, which is referenced through
|
||||||
* es_param_exec_vals or ecxt_param_exec_vals.
|
* 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
|
* 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
|
* lazy evaluation of InitPlans: they aren't executed until/unless a
|
||||||
* result value is needed.) Otherwise the value is assumed to be valid
|
* result value is needed.) Otherwise the value is assumed to be valid
|
||||||
@@ -98,7 +98,7 @@ typedef ParamListInfoData *ParamListInfo;
|
|||||||
|
|
||||||
typedef struct ParamExecData
|
typedef struct ParamExecData
|
||||||
{
|
{
|
||||||
void *execPlan; /* should be "SubPlan *" */
|
void *execPlan; /* should be "SubPlanState *" */
|
||||||
Datum value;
|
Datum value;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
} ParamExecData;
|
} ParamExecData;
|
||||||
|
|||||||
@@ -7,52 +7,15 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef PLANNODES_H
|
||||||
#define PLANNODES_H
|
#define PLANNODES_H
|
||||||
|
|
||||||
#include "nodes/execnodes.h"
|
#include "access/sdir.h"
|
||||||
|
#include "nodes/primnodes.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;
|
|
||||||
*
|
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@@ -62,45 +25,47 @@
|
|||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Plan node
|
* 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
|
typedef struct Plan
|
||||||
{
|
{
|
||||||
NodeTag type;
|
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
|
Cost startup_cost; /* cost expended before fetching any
|
||||||
* tuples */
|
* tuples */
|
||||||
Cost total_cost; /* total cost (assuming all tuples
|
Cost total_cost; /* total cost (assuming all tuples
|
||||||
* fetched) */
|
* fetched) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* planner's estimate of result size (note: LIMIT, if any, is not
|
* planner's estimate of result size of this plan step
|
||||||
* considered in setting plan_rows)
|
|
||||||
*/
|
*/
|
||||||
double plan_rows; /* number of rows plan is expected to emit */
|
double plan_rows; /* number of rows plan is expected to emit */
|
||||||
int plan_width; /* average row width in bytes */
|
int plan_width; /* average row width in bytes */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* execution state data. Having Plan point to this, rather than the
|
* Common structural data for all Plan types.
|
||||||
* other way round, is 100% bogus.
|
|
||||||
*/
|
*/
|
||||||
EState *state; /* at execution time, state's of
|
List *targetlist; /* target list to be computed at this node */
|
||||||
* individual nodes point to one EState
|
List *qual; /* implicitly-ANDed qual conditions */
|
||||||
* for the whole top-level plan */
|
struct Plan *lefttree; /* input plan tree(s) */
|
||||||
|
struct Plan *righttree;
|
||||||
struct Instrumentation *instrument; /* Optional runtime stats for this
|
List *initPlan; /* Init Plan nodes (un-correlated expr
|
||||||
* plan node */
|
* subselects) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common structural data for all Plan types. XXX chgParam is runtime
|
* Information for management of parameter-change-driven rescanning
|
||||||
* data and should be in the EState, not here.
|
|
||||||
*/
|
*/
|
||||||
List *targetlist;
|
|
||||||
List *qual; /* implicitly-ANDed qual conditions */
|
|
||||||
struct Plan *lefttree;
|
|
||||||
struct Plan *righttree;
|
|
||||||
List *extParam; /* indices of _all_ _external_ PARAM_EXEC
|
List *extParam; /* indices of _all_ _external_ PARAM_EXEC
|
||||||
* for this plan in global
|
* for this plan in global
|
||||||
* es_param_exec_vals. Params from
|
* es_param_exec_vals. Params from
|
||||||
@@ -108,10 +73,6 @@ typedef struct Plan
|
|||||||
* included, but their execParam-s are
|
* included, but their execParam-s are
|
||||||
* here!!! */
|
* here!!! */
|
||||||
List *locParam; /* someones from setParam-s */
|
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
|
* 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)
|
#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 -
|
* Result node -
|
||||||
* If no outer plan, evaluate a variable-free targetlist.
|
* If no outer plan, evaluate a variable-free targetlist.
|
||||||
@@ -163,7 +110,6 @@ typedef struct Result
|
|||||||
{
|
{
|
||||||
Plan plan;
|
Plan plan;
|
||||||
Node *resconstantqual;
|
Node *resconstantqual;
|
||||||
ResultState *resstate;
|
|
||||||
} Result;
|
} Result;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -182,7 +128,6 @@ typedef struct Append
|
|||||||
Plan plan;
|
Plan plan;
|
||||||
List *appendplans;
|
List *appendplans;
|
||||||
bool isTarget;
|
bool isTarget;
|
||||||
AppendState *appendstate;
|
|
||||||
} Append;
|
} Append;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -194,7 +139,6 @@ typedef struct Scan
|
|||||||
{
|
{
|
||||||
Plan plan;
|
Plan plan;
|
||||||
Index scanrelid; /* relid is index into the range table */
|
Index scanrelid; /* relid is index into the range table */
|
||||||
CommonScanState *scanstate;
|
|
||||||
} Scan;
|
} Scan;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -214,7 +158,6 @@ typedef struct IndexScan
|
|||||||
List *indxqual;
|
List *indxqual;
|
||||||
List *indxqualorig;
|
List *indxqualorig;
|
||||||
ScanDirection indxorderdir;
|
ScanDirection indxorderdir;
|
||||||
IndexScanState *indxstate;
|
|
||||||
} IndexScan;
|
} IndexScan;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -224,9 +167,7 @@ typedef struct IndexScan
|
|||||||
typedef struct TidScan
|
typedef struct TidScan
|
||||||
{
|
{
|
||||||
Scan scan;
|
Scan scan;
|
||||||
bool needRescan;
|
|
||||||
List *tideval;
|
List *tideval;
|
||||||
TidScanState *tidstate;
|
|
||||||
} TidScan;
|
} TidScan;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -257,7 +198,6 @@ typedef struct FunctionScan
|
|||||||
{
|
{
|
||||||
Scan scan;
|
Scan scan;
|
||||||
/* no other fields needed at present */
|
/* no other fields needed at present */
|
||||||
/* scan.scanstate actually points at a FunctionScanState node */
|
|
||||||
} FunctionScan;
|
} FunctionScan;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -296,7 +236,6 @@ typedef struct Join
|
|||||||
typedef struct NestLoop
|
typedef struct NestLoop
|
||||||
{
|
{
|
||||||
Join join;
|
Join join;
|
||||||
NestLoopState *nlstate;
|
|
||||||
} NestLoop;
|
} NestLoop;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -307,7 +246,6 @@ typedef struct MergeJoin
|
|||||||
{
|
{
|
||||||
Join join;
|
Join join;
|
||||||
List *mergeclauses;
|
List *mergeclauses;
|
||||||
MergeJoinState *mergestate;
|
|
||||||
} MergeJoin;
|
} MergeJoin;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -318,9 +256,40 @@ typedef struct HashJoin
|
|||||||
{
|
{
|
||||||
Join join;
|
Join join;
|
||||||
List *hashclauses;
|
List *hashclauses;
|
||||||
HashJoinState *hashjoinstate;
|
|
||||||
} HashJoin;
|
} 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
|
* aggregate node
|
||||||
*
|
*
|
||||||
@@ -349,44 +318,8 @@ typedef struct Agg
|
|||||||
int numCols; /* number of grouping columns */
|
int numCols; /* number of grouping columns */
|
||||||
AttrNumber *grpColIdx; /* their indexes in the target list */
|
AttrNumber *grpColIdx; /* their indexes in the target list */
|
||||||
long numGroups; /* estimated number of groups in input */
|
long numGroups; /* estimated number of groups in input */
|
||||||
AggState *aggstate;
|
|
||||||
} Agg;
|
} 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
|
* unique node
|
||||||
* ----------------
|
* ----------------
|
||||||
@@ -397,9 +330,18 @@ typedef struct Unique
|
|||||||
int numCols; /* number of columns to check for
|
int numCols; /* number of columns to check for
|
||||||
* uniqueness */
|
* uniqueness */
|
||||||
AttrNumber *uniqColIdx; /* indexes into the target list */
|
AttrNumber *uniqColIdx; /* indexes into the target list */
|
||||||
UniqueState *uniquestate;
|
|
||||||
} Unique;
|
} Unique;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* hash build node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef struct Hash
|
||||||
|
{
|
||||||
|
Plan plan;
|
||||||
|
List *hashkeys;
|
||||||
|
} Hash;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* setop node
|
* setop node
|
||||||
* ----------------
|
* ----------------
|
||||||
@@ -420,7 +362,6 @@ typedef struct SetOp
|
|||||||
* duplicate-ness */
|
* duplicate-ness */
|
||||||
AttrNumber *dupColIdx; /* indexes into the target list */
|
AttrNumber *dupColIdx; /* indexes into the target list */
|
||||||
AttrNumber flagColIdx;
|
AttrNumber flagColIdx;
|
||||||
SetOpState *setopstate;
|
|
||||||
} SetOp;
|
} SetOp;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@@ -432,44 +373,13 @@ typedef struct Limit
|
|||||||
Plan plan;
|
Plan plan;
|
||||||
Node *limitOffset; /* OFFSET parameter, or NULL if none */
|
Node *limitOffset; /* OFFSET parameter, or NULL if none */
|
||||||
Node *limitCount; /* COUNT parameter, or NULL if none */
|
Node *limitCount; /* COUNT parameter, or NULL if none */
|
||||||
LimitState *limitstate;
|
|
||||||
} Limit;
|
} 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
|
* 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
|
typedef struct SubPlan
|
||||||
@@ -489,12 +399,7 @@ typedef struct SubPlan
|
|||||||
* about what to do with subselect's
|
* about what to do with subselect's
|
||||||
* results */
|
* results */
|
||||||
|
|
||||||
/*
|
struct SubPlanState *pstate; /* XXX TEMPORARY HACK */
|
||||||
* 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 */
|
|
||||||
} SubPlan;
|
} SubPlan;
|
||||||
|
|
||||||
#endif /* PLANNODES_H */
|
#endif /* PLANNODES_H */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#define PRINT_H
|
||||||
|
|
||||||
#include "nodes/parsenodes.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 print(void *obj);
|
||||||
extern void pprint(void *obj);
|
extern void pprint(void *obj);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
typedef struct TidPath
|
||||||
{
|
{
|
||||||
Path path;
|
Path path;
|
||||||
List *tideval; /* qual(s) involving CTID = something */
|
List *tideval; /* qual(s) involving CTID = something */
|
||||||
Relids unjoined_relids; /* some rels not yet part of my Path */
|
|
||||||
} TidPath;
|
} TidPath;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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,
|
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest,
|
||||||
char *completionTag);
|
char *completionTag);
|
||||||
|
|
||||||
extern EState *CreateExecutorState(void);
|
|
||||||
|
|
||||||
extern Portal PreparePortal(char *portalName);
|
extern Portal PreparePortal(char *portalName);
|
||||||
|
|
||||||
#endif /* PQUERY_H */
|
#endif /* PQUERY_H */
|
||||||
|
|||||||
@@ -3,19 +3,16 @@
|
|||||||
* portal.h
|
* portal.h
|
||||||
* POSTGRES portal definitions.
|
* 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) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
#ifndef PORTAL_H
|
||||||
#define PORTAL_H
|
#define PORTAL_H
|
||||||
|
|
||||||
@@ -30,8 +27,6 @@ typedef struct PortalData
|
|||||||
char *name; /* Portal's name */
|
char *name; /* Portal's name */
|
||||||
MemoryContext heap; /* subsidiary memory */
|
MemoryContext heap; /* subsidiary memory */
|
||||||
QueryDesc *queryDesc; /* Info about query associated with portal */
|
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 atStart; /* T => fetch backwards is not allowed */
|
||||||
bool atEnd; /* T => fetch forwards is not allowed */
|
bool atEnd; /* T => fetch forwards is not allowed */
|
||||||
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
||||||
@@ -47,8 +42,6 @@ typedef struct PortalData
|
|||||||
* Access macros for Portal ... use these in preference to field access.
|
* Access macros for Portal ... use these in preference to field access.
|
||||||
*/
|
*/
|
||||||
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
|
#define PortalGetQueryDesc(portal) ((portal)->queryDesc)
|
||||||
#define PortalGetTupleDesc(portal) ((portal)->attinfo)
|
|
||||||
#define PortalGetState(portal) ((portal)->state)
|
|
||||||
#define PortalGetHeapMemory(portal) ((portal)->heap)
|
#define PortalGetHeapMemory(portal) ((portal)->heap)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -64,7 +57,6 @@ extern Portal CreatePortal(char *name);
|
|||||||
extern void PortalDrop(Portal portal);
|
extern void PortalDrop(Portal portal);
|
||||||
extern Portal GetPortalByName(char *name);
|
extern Portal GetPortalByName(char *name);
|
||||||
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
|
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
|
||||||
TupleDesc attinfo, EState *state,
|
void (*cleanup) (Portal portal));
|
||||||
void (*cleanup) (Portal portal));
|
|
||||||
|
|
||||||
#endif /* PORTAL_H */
|
#endif /* PORTAL_H */
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@@ -3583,7 +3583,6 @@ exec_simple_check_plan(PLpgSQL_expr * expr)
|
|||||||
if (plan->lefttree != NULL ||
|
if (plan->lefttree != NULL ||
|
||||||
plan->righttree != NULL ||
|
plan->righttree != NULL ||
|
||||||
plan->initPlan != NULL ||
|
plan->initPlan != NULL ||
|
||||||
plan->subPlan != NULL ||
|
|
||||||
plan->qual != NULL ||
|
plan->qual != NULL ||
|
||||||
((Result *) plan)->resconstantqual != NULL)
|
((Result *) plan)->resconstantqual != NULL)
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user