1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-30 21:42:05 +03:00

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

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

View File

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