@@ -667,15 +667,35 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
667
667
Instrumentation * instr = rInfo -> ri_TrigInstrument + nt ;
668
668
char * relname ;
669
669
char * conname = NULL ;
670
+ instr_time starttimespan ;
671
+ double total ;
672
+ double ntuples ;
673
+ double ncalls ;
670
674
671
- /* Must clean up instrumentation state */
672
- InstrEndLoop (instr );
675
+ if (!es -> runtime )
676
+ {
677
+ /* Must clean up instrumentation state */
678
+ InstrEndLoop (instr );
679
+ }
680
+
681
+ /* Collect statistic variables */
682
+ if (!INSTR_TIME_IS_ZERO (instr -> starttime ))
683
+ {
684
+ INSTR_TIME_SET_CURRENT (starttimespan );
685
+ INSTR_TIME_SUBTRACT (starttimespan ,instr -> starttime );
686
+ }
687
+ else
688
+ INSTR_TIME_SET_ZERO (starttimespan );
689
+ total = instr -> total + INSTR_TIME_GET_DOUBLE (instr -> counter )
690
+ + INSTR_TIME_GET_DOUBLE (starttimespan );
691
+ ntuples = instr -> ntuples + instr -> tuplecount ;
692
+ ncalls = ntuples + !INSTR_TIME_IS_ZERO (starttimespan );
673
693
674
694
/*
675
695
* We ignore triggers that were never invoked; they likely aren't
676
696
* relevant to the current query type.
677
697
*/
678
- if (instr -> ntuples == 0 )
698
+ if (ncalls == 0 )
679
699
continue ;
680
700
681
701
ExplainOpenGroup ("Trigger" ,NULL , true,es );
@@ -701,9 +721,9 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
701
721
appendStringInfo (es -> str ," on %s" ,relname );
702
722
if (es -> timing )
703
723
appendStringInfo (es -> str ,": time=%.3f calls=%.0f\n" ,
704
- 1000.0 * instr -> total ,instr -> ntuples );
724
+ 1000.0 * total ,ncalls );
705
725
else
706
- appendStringInfo (es -> str ,": calls=%.0f\n" ,instr -> ntuples );
726
+ appendStringInfo (es -> str ,": calls=%.0f\n" ,ncalls );
707
727
}
708
728
else
709
729
{
@@ -712,8 +732,8 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
712
732
ExplainPropertyText ("Constraint Name" ,conname ,es );
713
733
ExplainPropertyText ("Relation" ,relname ,es );
714
734
if (es -> timing )
715
- ExplainPropertyFloat ("Time" ,1000.0 * instr -> total ,3 ,es );
716
- ExplainPropertyFloat ("Calls" ,instr -> ntuples ,0 ,es );
735
+ ExplainPropertyFloat ("Time" ,1000.0 * total ,3 ,es );
736
+ ExplainPropertyFloat ("Calls" ,ncalls ,0 ,es );
717
737
}
718
738
719
739
if (conname )
@@ -1225,8 +1245,11 @@ ExplainNode(PlanState *planstate, List *ancestors,
1225
1245
* instrumentation results the user didn't ask for. But we do the
1226
1246
* InstrEndLoop call anyway, if possible, to reduce the number of cases
1227
1247
* auto_explain has to contend with.
1248
+ *
1249
+ * if flag es->stateinfo is set i.e. when printing the current execution state
1250
+ * this step of cleaning up is miss
1228
1251
*/
1229
- if (planstate -> instrument )
1252
+ if (planstate -> instrument && ! es -> runtime )
1230
1253
InstrEndLoop (planstate -> instrument );
1231
1254
1232
1255
if (es -> analyze &&
@@ -1259,7 +1282,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
1259
1282
ExplainPropertyFloat ("Actual Loops" ,nloops ,0 ,es );
1260
1283
}
1261
1284
}
1262
- else if (es -> analyze )
1285
+ else if (es -> analyze && ! es -> runtime )
1263
1286
{
1264
1287
if (es -> format == EXPLAIN_FORMAT_TEXT )
1265
1288
appendStringInfoString (es -> str ," (never executed)" );
@@ -1275,6 +1298,75 @@ ExplainNode(PlanState *planstate, List *ancestors,
1275
1298
}
1276
1299
}
1277
1300
1301
+ /*
1302
+ * print the progress of node execution at current loop
1303
+ */
1304
+ if (planstate -> instrument && es -> analyze && es -> runtime )
1305
+ {
1306
+ instr_time starttimespan ;
1307
+ double startup_sec ;
1308
+ double total_sec ;
1309
+ double rows ;
1310
+ double loop_num ;
1311
+ bool finished ;
1312
+
1313
+ if (!INSTR_TIME_IS_ZERO (planstate -> instrument -> starttime ))
1314
+ {
1315
+ INSTR_TIME_SET_CURRENT (starttimespan );
1316
+ INSTR_TIME_SUBTRACT (starttimespan ,planstate -> instrument -> starttime );
1317
+ }
1318
+ else
1319
+ INSTR_TIME_SET_ZERO (starttimespan );
1320
+ startup_sec = 1000.0 * planstate -> instrument -> firsttuple ;
1321
+ total_sec = 1000.0 * (INSTR_TIME_GET_DOUBLE (planstate -> instrument -> counter )
1322
+ + INSTR_TIME_GET_DOUBLE (starttimespan ));
1323
+ rows = planstate -> instrument -> tuplecount ;
1324
+ loop_num = planstate -> instrument -> nloops + 1 ;
1325
+
1326
+ finished = planstate -> instrument -> nloops > 0
1327
+ && !planstate -> instrument -> running
1328
+ && INSTR_TIME_IS_ZERO (starttimespan );
1329
+
1330
+ if (!finished )
1331
+ {
1332
+ ExplainOpenGroup ("Current loop" ,"Current loop" , true,es );
1333
+ if (es -> format == EXPLAIN_FORMAT_TEXT )
1334
+ {
1335
+ if (es -> timing )
1336
+ {
1337
+ if (planstate -> instrument -> running )
1338
+ appendStringInfo (es -> str ,
1339
+ " (Current loop: actual time=%.3f..%.3f rows=%.0f, loop number=%.0f)" ,
1340
+ startup_sec ,total_sec ,rows ,loop_num );
1341
+ else
1342
+ appendStringInfo (es -> str ,
1343
+ " (Current loop: running time=%.3f actual rows=0, loop number=%.0f)" ,
1344
+ total_sec ,loop_num );
1345
+ }
1346
+ else
1347
+ appendStringInfo (es -> str ,
1348
+ " (Current loop: actual rows=%.0f, loop number=%.0f)" ,
1349
+ rows ,loop_num );
1350
+ }
1351
+ else
1352
+ {
1353
+ ExplainPropertyFloat ("Actual Loop Number" ,loop_num ,0 ,es );
1354
+ if (es -> timing )
1355
+ {
1356
+ if (planstate -> instrument -> running )
1357
+ {
1358
+ ExplainPropertyFloat ("Actual Startup Time" ,startup_sec ,3 ,es );
1359
+ ExplainPropertyFloat ("Actual Total Time" ,total_sec ,3 ,es );
1360
+ }
1361
+ else
1362
+ ExplainPropertyFloat ("Running Time" ,total_sec ,3 ,es );
1363
+ }
1364
+ ExplainPropertyFloat ("Actual Rows" ,rows ,0 ,es );
1365
+ }
1366
+ ExplainCloseGroup ("Current loop" ,"Current loop" , true,es );
1367
+ }
1368
+ }
1369
+
1278
1370
/* in text format, first line ends here */
1279
1371
if (es -> format == EXPLAIN_FORMAT_TEXT )
1280
1372
appendStringInfoChar (es -> str ,'\n' );
@@ -1508,8 +1600,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
1508
1600
if (es -> buffers && planstate -> instrument )
1509
1601
show_buffer_usage (es ,& planstate -> instrument -> bufusage );
1510
1602
1511
- /* Show worker detail */
1512
- if (es -> analyze && es -> verbose && planstate -> worker_instrument )
1603
+ /* Show worker detail after query execution */
1604
+ if (es -> analyze && es -> verbose && planstate -> worker_instrument
1605
+ && !es -> runtime )
1513
1606
{
1514
1607
WorkerInstrumentation * w = planstate -> worker_instrument ;
1515
1608
bool opened_group = false;
@@ -2269,20 +2362,17 @@ show_instrumentation_count(const char *qlabel, int which,
2269
2362
if (!es -> analyze || !planstate -> instrument )
2270
2363
return ;
2271
2364
2365
+ nloops = planstate -> instrument -> nloops ;
2272
2366
if (which == 2 )
2273
- nfiltered = planstate -> instrument -> nfiltered2 ;
2367
+ nfiltered = ((nloops > 0 ) ?planstate -> instrument -> accum_nfiltered2 /nloops :0 )
2368
+ + planstate -> instrument -> nfiltered2 ;
2274
2369
else
2275
- nfiltered = planstate -> instrument -> nfiltered1 ;
2276
- nloops = planstate -> instrument -> nloops ;
2370
+ nfiltered = (( nloops > 0 ) ? planstate -> instrument -> accum_nfiltered1 / nloops : 0 )
2371
+ + planstate -> instrument -> nfiltered1 ;
2277
2372
2278
2373
/* In text mode, suppress zero counts; they're not interesting enough */
2279
2374
if (nfiltered > 0 || es -> format != EXPLAIN_FORMAT_TEXT )
2280
- {
2281
- if (nloops > 0 )
2282
- ExplainPropertyFloat (qlabel ,nfiltered /nloops ,0 ,es );
2283
- else
2284
- ExplainPropertyFloat (qlabel ,0.0 ,0 ,es );
2285
- }
2375
+ ExplainPropertyFloat (qlabel ,nfiltered ,0 ,es );
2286
2376
}
2287
2377
2288
2378
/*
@@ -2754,14 +2844,28 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
2754
2844
double insert_path ;
2755
2845
double other_path ;
2756
2846
2757
- InstrEndLoop (mtstate -> mt_plans [0 ]-> instrument );
2847
+ if (!es -> runtime )
2848
+ InstrEndLoop (mtstate -> mt_plans [0 ]-> instrument );
2758
2849
2759
2850
/* count the number of source rows */
2760
- total = mtstate -> mt_plans [0 ]-> instrument -> ntuples ;
2761
- other_path = mtstate -> ps .instrument -> nfiltered2 ;
2762
- insert_path = total - other_path ;
2851
+ other_path = mtstate -> ps .instrument -> accum_nfiltered2
2852
+ + mtstate -> ps .instrument -> nfiltered2 ;
2853
+
2854
+ /*
2855
+ * Insert occurs after extracting row from subplan and in runtime mode
2856
+ * we can appear between these two operations - situation when
2857
+ * total > insert_path + other_path. Therefore we don't know exactly
2858
+ * whether last row from subplan is inserted.
2859
+ * We don't print inserted tuples in runtime mode in order to not print
2860
+ * inconsistent data
2861
+ */
2862
+ if (!es -> runtime )
2863
+ {
2864
+ total = mtstate -> mt_plans [0 ]-> instrument -> ntuples ;
2865
+ insert_path = total - other_path ;
2866
+ ExplainPropertyFloat ("Tuples Inserted" ,insert_path ,0 ,es );
2867
+ }
2763
2868
2764
- ExplainPropertyFloat ("Tuples Inserted" ,insert_path ,0 ,es );
2765
2869
ExplainPropertyFloat ("Conflicting Tuples" ,other_path ,0 ,es );
2766
2870
}
2767
2871
}