aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/explain.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-12-05 15:50:39 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-12-05 15:50:39 +0000
commit1fd0c59e25063e664f8a5cee6f723470c5979544 (patch)
treed7c1ba5ee25323021a65d0e419299162a9db9c19 /src/backend/commands/explain.c
parent0f3b83edfaf65b6105b455f601c11af6e12170ca (diff)
downloadpostgresql-1fd0c59e25063e664f8a5cee6f723470c5979544.tar.gz
postgresql-1fd0c59e25063e664f8a5cee6f723470c5979544.zip
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.
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r--src/backend/commands/explain.c189
1 files changed, 125 insertions, 64 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 0e6ca88fd45..e2d1a6eeab1 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -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;
-
- /*
- * Set up the instrumentation for the top node. This will cascade
- * during plan initialisation
- */
- plan->instrument = InstrAlloc();
+ /* run the plan */
+ ExecutorRun(queryDesc, ForwardScanDirection, 0L);
- gettimeofday(&starttime, NULL);
- ProcessQuery(query, plan, None, NULL);
- CommandCounterIncrement();
- gettimeofday(&endtime, NULL);
+ /* We can't clean up 'till we're done printing the stats... */
- endtime.tv_sec -= starttime.tv_sec;
- endtime.tv_usec -= starttime.tv_usec;
- while (endtime.tv_usec < 0)
- {
- endtime.tv_usec += 1000000;
- endtime.tv_sec--;
- }
- totaltime = (double) endtime.tv_sec +
- (double) endtime.tv_usec / 1000000.0;
+ totaltime += elapsed_time(&starttime);
}
es = (ExplainState *) palloc0(sizeof(ExplainState));
es->printCost = true; /* default */
-
- if (stmt->verbose)
- es->printNodes = true;
-
+ es->printNodes = stmt->verbose;
+ es->printAnalyze = stmt->analyze;
es->rtable = query->rtable;
if (es->printNodes)
@@ -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
*/