@@ -653,15 +653,35 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
653
653
Instrumentation * instr = rInfo -> ri_TrigInstrument + nt ;
654
654
char * relname ;
655
655
char * conname = NULL ;
656
+ instr_time starttimespan ;
657
+ double total ;
658
+ double ntuples ;
659
+ double ncalls ;
656
660
657
- /* Must clean up instrumentation state */
658
- InstrEndLoop (instr );
661
+ if (!es -> runtime )
662
+ {
663
+ /* Must clean up instrumentation state */
664
+ InstrEndLoop (instr );
665
+ }
666
+
667
+ /* Collect statistic variables */
668
+ if (!INSTR_TIME_IS_ZERO (instr -> starttime ))
669
+ {
670
+ INSTR_TIME_SET_CURRENT (starttimespan );
671
+ INSTR_TIME_SUBTRACT (starttimespan ,instr -> starttime );
672
+ }
673
+ else
674
+ INSTR_TIME_SET_ZERO (starttimespan );
675
+ total = instr -> total + INSTR_TIME_GET_DOUBLE (instr -> counter )
676
+ + INSTR_TIME_GET_DOUBLE (starttimespan );
677
+ ntuples = instr -> ntuples + instr -> tuplecount ;
678
+ ncalls = ntuples + !INSTR_TIME_IS_ZERO (starttimespan );
659
679
660
680
/*
661
681
* We ignore triggers that were never invoked; they likely aren't
662
682
* relevant to the current query type.
663
683
*/
664
- if (instr -> ntuples == 0 )
684
+ if (ncalls == 0 )
665
685
continue ;
666
686
667
687
ExplainOpenGroup ("Trigger" ,NULL , true,es );
@@ -687,9 +707,9 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
687
707
appendStringInfo (es -> str ," on %s" ,relname );
688
708
if (es -> timing )
689
709
appendStringInfo (es -> str ,": time=%.3f calls=%.0f\n" ,
690
- 1000.0 * instr -> total ,instr -> ntuples );
710
+ 1000.0 * total ,ncalls );
691
711
else
692
- appendStringInfo (es -> str ,": calls=%.0f\n" ,instr -> ntuples );
712
+ appendStringInfo (es -> str ,": calls=%.0f\n" ,ncalls );
693
713
}
694
714
else
695
715
{
@@ -698,8 +718,8 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
698
718
ExplainPropertyText ("Constraint Name" ,conname ,es );
699
719
ExplainPropertyText ("Relation" ,relname ,es );
700
720
if (es -> timing )
701
- ExplainPropertyFloat ("Time" ,1000.0 * instr -> total ,3 ,es );
702
- ExplainPropertyFloat ("Calls" ,instr -> ntuples ,0 ,es );
721
+ ExplainPropertyFloat ("Time" ,1000.0 * total ,3 ,es );
722
+ ExplainPropertyFloat ("Calls" ,ncalls ,0 ,es );
703
723
}
704
724
705
725
if (conname )
@@ -1247,8 +1267,11 @@ ExplainNode(PlanState *planstate, List *ancestors,
1247
1267
* instrumentation results the user didn't ask for. But we do the
1248
1268
* InstrEndLoop call anyway, if possible, to reduce the number of cases
1249
1269
* auto_explain has to contend with.
1270
+ *
1271
+ * if flag es->stateinfo is set i.e. when printing the current execution state
1272
+ * this step of cleaning up is miss
1250
1273
*/
1251
- if (planstate -> instrument )
1274
+ if (planstate -> instrument && ! es -> runtime )
1252
1275
InstrEndLoop (planstate -> instrument );
1253
1276
1254
1277
if (es -> analyze &&
@@ -1281,7 +1304,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
1281
1304
ExplainPropertyFloat ("Actual Loops" ,nloops ,0 ,es );
1282
1305
}
1283
1306
}
1284
- else if (es -> analyze )
1307
+ else if (es -> analyze && ! es -> runtime )
1285
1308
{
1286
1309
if (es -> format == EXPLAIN_FORMAT_TEXT )
1287
1310
appendStringInfoString (es -> str ," (never executed)" );
@@ -1297,6 +1320,75 @@ ExplainNode(PlanState *planstate, List *ancestors,
1297
1320
}
1298
1321
}
1299
1322
1323
+ /*
1324
+ * print the progress of node execution at current loop
1325
+ */
1326
+ if (planstate -> instrument && es -> analyze && es -> runtime )
1327
+ {
1328
+ instr_time starttimespan ;
1329
+ double startup_sec ;
1330
+ double total_sec ;
1331
+ double rows ;
1332
+ double loop_num ;
1333
+ bool finished ;
1334
+
1335
+ if (!INSTR_TIME_IS_ZERO (planstate -> instrument -> starttime ))
1336
+ {
1337
+ INSTR_TIME_SET_CURRENT (starttimespan );
1338
+ INSTR_TIME_SUBTRACT (starttimespan ,planstate -> instrument -> starttime );
1339
+ }
1340
+ else
1341
+ INSTR_TIME_SET_ZERO (starttimespan );
1342
+ startup_sec = 1000.0 * planstate -> instrument -> firsttuple ;
1343
+ total_sec = 1000.0 * (INSTR_TIME_GET_DOUBLE (planstate -> instrument -> counter )
1344
+ + INSTR_TIME_GET_DOUBLE (starttimespan ));
1345
+ rows = planstate -> instrument -> tuplecount ;
1346
+ loop_num = planstate -> instrument -> nloops + 1 ;
1347
+
1348
+ finished = planstate -> instrument -> nloops > 0
1349
+ && !planstate -> instrument -> running
1350
+ && INSTR_TIME_IS_ZERO (starttimespan );
1351
+
1352
+ if (!finished )
1353
+ {
1354
+ ExplainOpenGroup ("Current loop" ,"Current loop" , true,es );
1355
+ if (es -> format == EXPLAIN_FORMAT_TEXT )
1356
+ {
1357
+ if (es -> timing )
1358
+ {
1359
+ if (planstate -> instrument -> running )
1360
+ appendStringInfo (es -> str ,
1361
+ " (Current loop: actual time=%.3f..%.3f rows=%.0f, loop number=%.0f)" ,
1362
+ startup_sec ,total_sec ,rows ,loop_num );
1363
+ else
1364
+ appendStringInfo (es -> str ,
1365
+ " (Current loop: running time=%.3f actual rows=0, loop number=%.0f)" ,
1366
+ total_sec ,loop_num );
1367
+ }
1368
+ else
1369
+ appendStringInfo (es -> str ,
1370
+ " (Current loop: actual rows=%.0f, loop number=%.0f)" ,
1371
+ rows ,loop_num );
1372
+ }
1373
+ else
1374
+ {
1375
+ ExplainPropertyFloat ("Actual Loop Number" ,loop_num ,0 ,es );
1376
+ if (es -> timing )
1377
+ {
1378
+ if (planstate -> instrument -> running )
1379
+ {
1380
+ ExplainPropertyFloat ("Actual Startup Time" ,startup_sec ,3 ,es );
1381
+ ExplainPropertyFloat ("Actual Total Time" ,total_sec ,3 ,es );
1382
+ }
1383
+ else
1384
+ ExplainPropertyFloat ("Running Time" ,total_sec ,3 ,es );
1385
+ }
1386
+ ExplainPropertyFloat ("Actual Rows" ,rows ,0 ,es );
1387
+ }
1388
+ ExplainCloseGroup ("Current loop" ,"Current loop" , true,es );
1389
+ }
1390
+ }
1391
+
1300
1392
/* in text format, first line ends here */
1301
1393
if (es -> format == EXPLAIN_FORMAT_TEXT )
1302
1394
appendStringInfoChar (es -> str ,'\n' );
@@ -2293,20 +2385,17 @@ show_instrumentation_count(const char *qlabel, int which,
2293
2385
if (!es -> analyze || !planstate -> instrument )
2294
2386
return ;
2295
2387
2388
+ nloops = planstate -> instrument -> nloops ;
2296
2389
if (which == 2 )
2297
- nfiltered = planstate -> instrument -> nfiltered2 ;
2390
+ nfiltered = ((nloops > 0 ) ?planstate -> instrument -> accum_nfiltered2 /nloops :0 )
2391
+ + planstate -> instrument -> nfiltered2 ;
2298
2392
else
2299
- nfiltered = planstate -> instrument -> nfiltered1 ;
2300
- nloops = planstate -> instrument -> nloops ;
2393
+ nfiltered = (( nloops > 0 ) ? planstate -> instrument -> accum_nfiltered1 / nloops : 0 )
2394
+ + planstate -> instrument -> nfiltered1 ;
2301
2395
2302
2396
/* In text mode, suppress zero counts; they're not interesting enough */
2303
2397
if (nfiltered > 0 || es -> format != EXPLAIN_FORMAT_TEXT )
2304
- {
2305
- if (nloops > 0 )
2306
- ExplainPropertyFloat (qlabel ,nfiltered /nloops ,0 ,es );
2307
- else
2308
- ExplainPropertyFloat (qlabel ,0.0 ,0 ,es );
2309
- }
2398
+ ExplainPropertyFloat (qlabel ,nfiltered ,0 ,es );
2310
2399
}
2311
2400
2312
2401
/*
@@ -2658,14 +2747,28 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
2658
2747
double insert_path ;
2659
2748
double other_path ;
2660
2749
2661
- InstrEndLoop (mtstate -> mt_plans [0 ]-> instrument );
2750
+ if (!es -> runtime )
2751
+ InstrEndLoop (mtstate -> mt_plans [0 ]-> instrument );
2662
2752
2663
2753
/* count the number of source rows */
2664
- total = mtstate -> mt_plans [0 ]-> instrument -> ntuples ;
2665
- other_path = mtstate -> ps .instrument -> nfiltered2 ;
2666
- insert_path = total - other_path ;
2754
+ other_path = mtstate -> ps .instrument -> accum_nfiltered2
2755
+ + mtstate -> ps .instrument -> nfiltered2 ;
2756
+
2757
+ /*
2758
+ * Insert occurs after extracting row from subplan and in runtime mode
2759
+ * we can appear between these two operations - situation when
2760
+ * total > insert_path + other_path. Therefore we don't know exactly
2761
+ * whether last row from subplan is inserted.
2762
+ * We don't print inserted tuples in runtime mode in order to not print
2763
+ * inconsistent data
2764
+ */
2765
+ if (!es -> runtime )
2766
+ {
2767
+ total = mtstate -> mt_plans [0 ]-> instrument -> ntuples ;
2768
+ insert_path = total - other_path ;
2769
+ ExplainPropertyFloat ("Tuples Inserted" ,insert_path ,0 ,es );
2770
+ }
2667
2771
2668
- ExplainPropertyFloat ("Tuples Inserted" ,insert_path ,0 ,es );
2669
2772
ExplainPropertyFloat ("Conflicting Tuples" ,other_path ,0 ,es );
2670
2773
}
2671
2774
}