@@ -667,15 +667,35 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
667667Instrumentation * instr = rInfo -> ri_TrigInstrument + nt ;
668668char * relname ;
669669char * conname = NULL ;
670+ instr_time starttimespan ;
671+ double total ;
672+ double ntuples ;
673+ double ncalls ;
670674
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 );
673693
674694/*
675695 * We ignore triggers that were never invoked; they likely aren't
676696 * relevant to the current query type.
677697 */
678- if (instr -> ntuples == 0 )
698+ if (ncalls == 0 )
679699continue ;
680700
681701ExplainOpenGroup ("Trigger" ,NULL , true,es );
@@ -701,9 +721,9 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
701721appendStringInfo (es -> str ," on %s" ,relname );
702722if (es -> timing )
703723appendStringInfo (es -> str ,": time=%.3f calls=%.0f\n" ,
704- 1000.0 * instr -> total ,instr -> ntuples );
724+ 1000.0 * total ,ncalls );
705725else
706- appendStringInfo (es -> str ,": calls=%.0f\n" ,instr -> ntuples );
726+ appendStringInfo (es -> str ,": calls=%.0f\n" ,ncalls );
707727}
708728else
709729{
@@ -712,8 +732,8 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es)
712732ExplainPropertyText ("Constraint Name" ,conname ,es );
713733ExplainPropertyText ("Relation" ,relname ,es );
714734if (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 );
717737}
718738
719739if (conname )
@@ -1225,8 +1245,11 @@ ExplainNode(PlanState *planstate, List *ancestors,
12251245 * instrumentation results the user didn't ask for. But we do the
12261246 * InstrEndLoop call anyway, if possible, to reduce the number of cases
12271247 * 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
12281251 */
1229- if (planstate -> instrument )
1252+ if (planstate -> instrument && ! es -> runtime )
12301253InstrEndLoop (planstate -> instrument );
12311254
12321255if (es -> analyze &&
@@ -1259,7 +1282,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
12591282ExplainPropertyFloat ("Actual Loops" ,nloops ,0 ,es );
12601283}
12611284}
1262- else if (es -> analyze )
1285+ else if (es -> analyze && ! es -> runtime )
12631286{
12641287if (es -> format == EXPLAIN_FORMAT_TEXT )
12651288appendStringInfoString (es -> str ," (never executed)" );
@@ -1275,6 +1298,75 @@ ExplainNode(PlanState *planstate, List *ancestors,
12751298}
12761299}
12771300
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+
12781370/* in text format, first line ends here */
12791371if (es -> format == EXPLAIN_FORMAT_TEXT )
12801372appendStringInfoChar (es -> str ,'\n' );
@@ -1508,8 +1600,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
15081600if (es -> buffers && planstate -> instrument )
15091601show_buffer_usage (es ,& planstate -> instrument -> bufusage );
15101602
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 )
15131606{
15141607WorkerInstrumentation * w = planstate -> worker_instrument ;
15151608bool opened_group = false;
@@ -2269,20 +2362,17 @@ show_instrumentation_count(const char *qlabel, int which,
22692362if (!es -> analyze || !planstate -> instrument )
22702363return ;
22712364
2365+ nloops = planstate -> instrument -> nloops ;
22722366if (which == 2 )
2273- nfiltered = planstate -> instrument -> nfiltered2 ;
2367+ nfiltered = ((nloops > 0 ) ?planstate -> instrument -> accum_nfiltered2 /nloops :0 )
2368+ + planstate -> instrument -> nfiltered2 ;
22742369else
2275- nfiltered = planstate -> instrument -> nfiltered1 ;
2276- nloops = planstate -> instrument -> nloops ;
2370+ nfiltered = (( nloops > 0 ) ? planstate -> instrument -> accum_nfiltered1 / nloops : 0 )
2371+ + planstate -> instrument -> nfiltered1 ;
22772372
22782373/* In text mode, suppress zero counts; they're not interesting enough */
22792374if (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 );
22862376}
22872377
22882378/*
@@ -2754,14 +2844,28 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
27542844double insert_path ;
27552845double other_path ;
27562846
2757- InstrEndLoop (mtstate -> mt_plans [0 ]-> instrument );
2847+ if (!es -> runtime )
2848+ InstrEndLoop (mtstate -> mt_plans [0 ]-> instrument );
27582849
27592850/* 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+ }
27632868
2764- ExplainPropertyFloat ("Tuples Inserted" ,insert_path ,0 ,es );
27652869ExplainPropertyFloat ("Conflicting Tuples" ,other_path ,0 ,es );
27662870}
27672871}