5
5
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
6
6
* Portions Copyright (c) 1994-5, Regents of the University of California
7
7
*
8
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.93 2002/11/13 00:39:46 momjian Exp $
8
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.94 2002/12/05 15:50:30 tgl Exp $
9
9
*
10
10
*/
11
11
@@ -34,17 +34,19 @@ typedef struct ExplainState
34
34
{
35
35
/* options */
36
36
bool printCost ; /* print cost */
37
- bool printNodes ; /* do nodeToString() instead */
38
- bool printAnalyze ; /* print actual times */
37
+ bool printNodes ; /* do nodeToString() too */
38
+ bool printAnalyze ; /* print actual times */
39
39
/* other states */
40
40
List * rtable ; /* range table */
41
41
} ExplainState ;
42
42
43
- static StringInfo Explain_PlanToString (Plan * plan , ExplainState * es );
44
43
static void ExplainOneQuery (Query * query , ExplainStmt * stmt ,
45
44
TupOutputState * tstate );
46
- static void explain_outNode (StringInfo str , Plan * plan , Plan * outer_plan ,
47
- int indent , ExplainState * es );
45
+ static double elapsed_time (struct timeval * starttime );
46
+ static void explain_outNode (StringInfo str ,
47
+ Plan * plan , PlanState * planstate ,
48
+ Plan * outer_plan ,
49
+ int indent , ExplainState * es );
48
50
static void show_scan_qual (List * qual , bool is_or_qual , const char * qlabel ,
49
51
int scanrelid , Plan * outer_plan ,
50
52
StringInfo str , int indent , ExplainState * es );
@@ -116,8 +118,11 @@ static void
116
118
ExplainOneQuery (Query * query , ExplainStmt * stmt , TupOutputState * tstate )
117
119
{
118
120
Plan * plan ;
121
+ QueryDesc * queryDesc ;
119
122
ExplainState * es ;
123
+ StringInfo str ;
120
124
double totaltime = 0 ;
125
+ struct timeval starttime ;
121
126
122
127
/* planner will not cope with utility statements */
123
128
if (query -> commandType == CMD_UTILITY )
@@ -136,41 +141,34 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
136
141
if (plan == NULL )
137
142
return ;
138
143
144
+ /* We don't support DECLARE CURSOR here */
145
+ Assert (!query -> isPortal );
146
+
147
+ gettimeofday (& starttime , NULL );
148
+
149
+ /* Create a QueryDesc requesting no output */
150
+ queryDesc = CreateQueryDesc (query , plan , None , NULL , NULL ,
151
+ stmt -> analyze );
152
+
153
+ /* call ExecutorStart to prepare the plan for execution */
154
+ ExecutorStart (queryDesc );
155
+
139
156
/* Execute the plan for statistics if asked for */
140
157
if (stmt -> analyze )
141
158
{
142
- struct timeval starttime ;
143
- struct timeval endtime ;
144
-
145
- /*
146
- * Set up the instrumentation for the top node. This will cascade
147
- * during plan initialisation
148
- */
149
- plan -> instrument = InstrAlloc ();
159
+ /* run the plan */
160
+ ExecutorRun (queryDesc , ForwardScanDirection , 0L );
150
161
151
- gettimeofday (& starttime , NULL );
152
- ProcessQuery (query , plan , None , NULL );
153
- CommandCounterIncrement ();
154
- gettimeofday (& endtime , NULL );
162
+ /* We can't clean up 'till we're done printing the stats... */
155
163
156
- endtime .tv_sec -= starttime .tv_sec ;
157
- endtime .tv_usec -= starttime .tv_usec ;
158
- while (endtime .tv_usec < 0 )
159
- {
160
- endtime .tv_usec += 1000000 ;
161
- endtime .tv_sec -- ;
162
- }
163
- totaltime = (double ) endtime .tv_sec +
164
- (double ) endtime .tv_usec / 1000000.0 ;
164
+ totaltime += elapsed_time (& starttime );
165
165
}
166
166
167
167
es = (ExplainState * ) palloc0 (sizeof (ExplainState ));
168
168
169
169
es -> printCost = true; /* default */
170
-
171
- if (stmt -> verbose )
172
- es -> printNodes = true;
173
-
170
+ es -> printNodes = stmt -> verbose ;
171
+ es -> printAnalyze = stmt -> analyze ;
174
172
es -> rtable = query -> rtable ;
175
173
176
174
if (es -> printNodes )
@@ -193,33 +191,73 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
193
191
}
194
192
}
195
193
194
+ str = makeStringInfo ();
195
+
196
196
if (es -> printCost )
197
197
{
198
- StringInfo str ;
198
+ explain_outNode (str , plan , queryDesc -> planstate ,
199
+ NULL , 0 , es );
200
+ }
199
201
200
- str = Explain_PlanToString (plan , es );
202
+ /*
203
+ * Close down the query and free resources. Include time for this
204
+ * in the total runtime.
205
+ */
206
+ gettimeofday (& starttime , NULL );
207
+
208
+ ExecutorEnd (queryDesc );
209
+ CommandCounterIncrement ();
210
+
211
+ totaltime += elapsed_time (& starttime );
212
+
213
+ if (es -> printCost )
214
+ {
201
215
if (stmt -> analyze )
202
216
appendStringInfo (str , "Total runtime: %.2f msec\n" ,
203
217
1000.0 * totaltime );
204
218
do_text_output_multiline (tstate , str -> data );
205
- pfree (str -> data );
206
- pfree (str );
207
219
}
208
220
221
+ pfree (str -> data );
222
+ pfree (str );
209
223
pfree (es );
210
224
}
211
225
226
+ /* Compute elapsed time in seconds since given gettimeofday() timestamp */
227
+ static double
228
+ elapsed_time (struct timeval * starttime )
229
+ {
230
+ struct timeval endtime ;
231
+
232
+ gettimeofday (& endtime , NULL );
233
+
234
+ endtime .tv_sec -= starttime -> tv_sec ;
235
+ endtime .tv_usec -= starttime -> tv_usec ;
236
+ while (endtime .tv_usec < 0 )
237
+ {
238
+ endtime .tv_usec += 1000000 ;
239
+ endtime .tv_sec -- ;
240
+ }
241
+ return (double ) endtime .tv_sec +
242
+ (double ) endtime .tv_usec / 1000000.0 ;
243
+ }
212
244
213
245
/*
214
246
* explain_outNode -
215
247
* converts a Plan node into ascii string and appends it to 'str'
216
248
*
249
+ * planstate points to the executor state node corresponding to the plan node.
250
+ * We need this to get at the instrumentation data (if any) as well as the
251
+ * list of subplans.
252
+ *
217
253
* outer_plan, if not null, references another plan node that is the outer
218
254
* side of a join with the current node. This is only interesting for
219
255
* deciphering runtime keys of an inner indexscan.
220
256
*/
221
257
static void
222
- explain_outNode (StringInfo str , Plan * plan , Plan * outer_plan ,
258
+ explain_outNode (StringInfo str ,
259
+ Plan * plan , PlanState * planstate ,
260
+ Plan * outer_plan ,
223
261
int indent , ExplainState * es )
224
262
{
225
263
List * l ;
@@ -410,18 +448,23 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
410
448
plan -> startup_cost , plan -> total_cost ,
411
449
plan -> plan_rows , plan -> plan_width );
412
450
413
- if (plan -> instrument && plan -> instrument -> nloops > 0 )
451
+ /*
452
+ * We have to forcibly clean up the instrumentation state because
453
+ * we haven't done ExecutorEnd yet. This is pretty grotty ...
454
+ */
455
+ InstrEndLoop (planstate -> instrument );
456
+
457
+ if (planstate -> instrument && planstate -> instrument -> nloops > 0 )
414
458
{
415
- double nloops = plan -> instrument -> nloops ;
459
+ double nloops = planstate -> instrument -> nloops ;
416
460
417
461
appendStringInfo (str , " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)" ,
418
- 1000.0 * plan -> instrument -> startup / nloops ,
419
- 1000.0 * plan -> instrument -> total / nloops ,
420
- plan -> instrument -> ntuples / nloops ,
421
- plan -> instrument -> nloops );
422
- es -> printAnalyze = true;
462
+ 1000.0 * planstate -> instrument -> startup / nloops ,
463
+ 1000.0 * planstate -> instrument -> total / nloops ,
464
+ planstate -> instrument -> ntuples / nloops ,
465
+ planstate -> instrument -> nloops );
423
466
}
424
- else if ( es -> printAnalyze )
467
+ else if ( es -> printAnalyze )
425
468
{
426
469
appendStringInfo (str , " (never executed)" );
427
470
}
@@ -538,19 +581,26 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
538
581
if (plan -> initPlan )
539
582
{
540
583
List * saved_rtable = es -> rtable ;
584
+ List * pslist = planstate -> initPlan ;
541
585
List * lst ;
542
586
543
587
for (i = 0 ; i < indent ; i ++ )
544
588
appendStringInfo (str , " " );
545
589
appendStringInfo (str , " InitPlan\n" );
546
590
foreach (lst , plan -> initPlan )
547
591
{
548
- es -> rtable = ((SubPlan * ) lfirst (lst ))-> rtable ;
592
+ SubPlan * subplan = (SubPlan * ) lfirst (lst );
593
+ SubPlanState * subplanstate = (SubPlanState * ) lfirst (pslist );
594
+
595
+ es -> rtable = subplan -> rtable ;
549
596
for (i = 0 ; i < indent ; i ++ )
550
597
appendStringInfo (str , " " );
551
598
appendStringInfo (str , " -> " );
552
- explain_outNode (str , ((SubPlan * ) lfirst (lst ))-> plan , NULL ,
599
+ explain_outNode (str , subplan -> plan ,
600
+ subplanstate -> planstate ,
601
+ NULL ,
553
602
indent + 4 , es );
603
+ pslist = lnext (pslist );
554
604
}
555
605
es -> rtable = saved_rtable ;
556
606
}
@@ -561,7 +611,10 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
561
611
for (i = 0 ; i < indent ; i ++ )
562
612
appendStringInfo (str , " " );
563
613
appendStringInfo (str , " -> " );
564
- explain_outNode (str , outerPlan (plan ), NULL , indent + 3 , es );
614
+ explain_outNode (str , outerPlan (plan ),
615
+ outerPlanState (planstate ),
616
+ NULL ,
617
+ indent + 3 , es );
565
618
}
566
619
567
620
/* righttree */
@@ -570,15 +623,20 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
570
623
for (i = 0 ; i < indent ; i ++ )
571
624
appendStringInfo (str , " " );
572
625
appendStringInfo (str , " -> " );
573
- explain_outNode (str , innerPlan (plan ), outerPlan (plan ),
626
+ explain_outNode (str , innerPlan (plan ),
627
+ innerPlanState (planstate ),
628
+ outerPlan (plan ),
574
629
indent + 3 , es );
575
630
}
576
631
577
632
if (IsA (plan , Append ))
578
633
{
579
634
Append * appendplan = (Append * ) plan ;
635
+ AppendState * appendstate = (AppendState * ) planstate ;
580
636
List * lst ;
637
+ int j ;
581
638
639
+ j = 0 ;
582
640
foreach (lst , appendplan -> appendplans )
583
641
{
584
642
Plan * subnode = (Plan * ) lfirst (lst );
@@ -587,13 +645,18 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
587
645
appendStringInfo (str , " " );
588
646
appendStringInfo (str , " -> " );
589
647
590
- explain_outNode (str , subnode , NULL , indent + 3 , es );
648
+ explain_outNode (str , subnode ,
649
+ appendstate -> appendplans [j ],
650
+ NULL ,
651
+ indent + 3 , es );
652
+ j ++ ;
591
653
}
592
654
}
593
655
594
656
if (IsA (plan , SubqueryScan ))
595
657
{
596
658
SubqueryScan * subqueryscan = (SubqueryScan * ) plan ;
659
+ SubqueryScanState * subquerystate = (SubqueryScanState * ) planstate ;
597
660
Plan * subnode = subqueryscan -> subplan ;
598
661
RangeTblEntry * rte = rt_fetch (subqueryscan -> scan .scanrelid ,
599
662
es -> rtable );
@@ -606,43 +669,41 @@ explain_outNode(StringInfo str, Plan *plan, Plan *outer_plan,
606
669
appendStringInfo (str , " " );
607
670
appendStringInfo (str , " -> " );
608
671
609
- explain_outNode (str , subnode , NULL , indent + 3 , es );
672
+ explain_outNode (str , subnode ,
673
+ subquerystate -> subplan ,
674
+ NULL ,
675
+ indent + 3 , es );
610
676
611
677
es -> rtable = saved_rtable ;
612
678
}
613
679
614
680
/* subPlan-s */
615
- if (plan -> subPlan )
681
+ if (planstate -> subPlan )
616
682
{
617
683
List * saved_rtable = es -> rtable ;
618
684
List * lst ;
619
685
620
686
for (i = 0 ; i < indent ; i ++ )
621
687
appendStringInfo (str , " " );
622
688
appendStringInfo (str , " SubPlan\n" );
623
- foreach (lst , plan -> subPlan )
689
+ foreach (lst , planstate -> subPlan )
624
690
{
625
- es -> rtable = ((SubPlan * ) lfirst (lst ))-> rtable ;
691
+ SubPlanState * sps = (SubPlanState * ) lfirst (lst );
692
+ SubPlan * sp = (SubPlan * ) sps -> ps .plan ;
693
+
694
+ es -> rtable = sp -> rtable ;
626
695
for (i = 0 ; i < indent ; i ++ )
627
696
appendStringInfo (str , " " );
628
697
appendStringInfo (str , " -> " );
629
- explain_outNode (str , ((SubPlan * ) lfirst (lst ))-> plan , NULL ,
698
+ explain_outNode (str , sp -> plan ,
699
+ sps -> planstate ,
700
+ NULL ,
630
701
indent + 4 , es );
631
702
}
632
703
es -> rtable = saved_rtable ;
633
704
}
634
705
}
635
706
636
- static StringInfo
637
- Explain_PlanToString (Plan * plan , ExplainState * es )
638
- {
639
- StringInfo str = makeStringInfo ();
640
-
641
- if (plan != NULL )
642
- explain_outNode (str , plan , NULL , 0 , es );
643
- return str ;
644
- }
645
-
646
707
/*
647
708
* Show a qualifier expression for a scan plan node
648
709
*/
0 commit comments