const char *relationship, ExplainState *es);
static void ExplainCustomChildren(CustomScanState *css,
List *ancestors, ExplainState *es);
-static void ExplainProperty(const char *qlabel, const char *value,
- bool numeric, ExplainState *es);
+static void ExplainProperty(const char *qlabel, const char *unit,
+ const char *value, bool numeric, ExplainState *es);
static void ExplainDummyGroup(const char *objtype, const char *labelname,
ExplainState *es);
static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es);
{
double plantime = INSTR_TIME_GET_DOUBLE(*planduration);
- if (es->format == EXPLAIN_FORMAT_TEXT)
- appendStringInfo(es->str, "Planning time: %.3f ms\n",
- 1000.0 * plantime);
- else
- ExplainPropertyFloat("Planning Time", 1000.0 * plantime, 3, es);
+ ExplainPropertyFloat("Planning Time", "ms", 1000.0 * plantime, 3, es);
}
/* Print info about runtime of triggers */
* the output). By default, ANALYZE sets SUMMARY to true.
*/
if (es->summary && es->analyze)
- {
- if (es->format == EXPLAIN_FORMAT_TEXT)
- appendStringInfo(es->str, "Execution time: %.3f ms\n",
- 1000.0 * totaltime);
- else
- ExplainPropertyFloat("Execution Time", 1000.0 * totaltime,
- 3, es);
- }
+ ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
+ es);
ExplainCloseGroup("Query", NULL, true, es);
}
ExplainPropertyText("Constraint Name", conname, es);
ExplainPropertyText("Relation", relname, es);
if (es->timing)
- ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es);
- ExplainPropertyFloat("Calls", instr->ntuples, 0, es);
+ ExplainPropertyFloat("Time", "ms", 1000.0 * instr->total, 3,
+ es);
+ ExplainPropertyFloat("Calls", NULL, instr->ntuples, 0, es);
}
if (conname)
}
else
{
- ExplainPropertyFloat("Startup Cost", plan->startup_cost, 2, es);
- ExplainPropertyFloat("Total Cost", plan->total_cost, 2, es);
- ExplainPropertyFloat("Plan Rows", plan->plan_rows, 0, es);
- ExplainPropertyInteger("Plan Width", plan->plan_width, es);
+ ExplainPropertyFloat("Startup Cost", NULL, plan->startup_cost,
+ 2, es);
+ ExplainPropertyFloat("Total Cost", NULL, plan->total_cost,
+ 2, es);
+ ExplainPropertyFloat("Plan Rows", NULL, plan->plan_rows,
+ 0, es);
+ ExplainPropertyInteger("Plan Width", NULL, plan->plan_width,
+ es);
}
}
planstate->instrument && planstate->instrument->nloops > 0)
{
double nloops = planstate->instrument->nloops;
- double startup_sec = 1000.0 * planstate->instrument->startup / nloops;
- double total_sec = 1000.0 * planstate->instrument->total / nloops;
+ double startup_ms = 1000.0 * planstate->instrument->startup / nloops;
+ double total_ms = 1000.0 * planstate->instrument->total / nloops;
double rows = planstate->instrument->ntuples / nloops;
if (es->format == EXPLAIN_FORMAT_TEXT)
if (es->timing)
appendStringInfo(es->str,
" (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
- startup_sec, total_sec, rows, nloops);
+ startup_ms, total_ms, rows, nloops);
else
appendStringInfo(es->str,
" (actual rows=%.0f loops=%.0f)",
{
if (es->timing)
{
- ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es);
- ExplainPropertyFloat("Actual Total Time", total_sec, 3, es);
+ ExplainPropertyFloat("Actual Startup Time", "s", startup_ms,
+ 3, es);
+ ExplainPropertyFloat("Actual Total Time", "s", total_ms,
+ 3, es);
}
- ExplainPropertyFloat("Actual Rows", rows, 0, es);
- ExplainPropertyFloat("Actual Loops", nloops, 0, es);
+ ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
+ ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
}
}
else if (es->analyze)
{
if (es->timing)
{
- ExplainPropertyFloat("Actual Startup Time", 0.0, 3, es);
- ExplainPropertyFloat("Actual Total Time", 0.0, 3, es);
+ ExplainPropertyFloat("Actual Startup Time", "ms", 0.0, 3, es);
+ ExplainPropertyFloat("Actual Total Time", "ms", 0.0, 3, es);
}
- ExplainPropertyFloat("Actual Rows", 0.0, 0, es);
- ExplainPropertyFloat("Actual Loops", 0.0, 0, es);
+ ExplainPropertyFloat("Actual Rows", NULL, 0.0, 0, es);
+ ExplainPropertyFloat("Actual Loops", NULL, 0.0, 0, es);
}
}
show_instrumentation_count("Rows Removed by Filter", 1,
planstate, es);
if (es->analyze)
- ExplainPropertyInteger("Heap Fetches",
- ((IndexOnlyScanState *) planstate)->ioss_HeapFetches,
- es);
+ {
+ long heapFetches =
+ ((IndexOnlyScanState *) planstate)->ioss_HeapFetches;
+
+ ExplainPropertyInteger("Heap Fetches", NULL, heapFetches, es);
+ }
break;
case T_BitmapIndexScan:
show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
if (plan->qual)
show_instrumentation_count("Rows Removed by Filter", 1,
planstate, es);
- ExplainPropertyInteger("Workers Planned",
+ ExplainPropertyInteger("Workers Planned", NULL,
gather->num_workers, es);
/* Show params evaluated at gather node */
int nworkers;
nworkers = ((GatherState *) planstate)->nworkers_launched;
- ExplainPropertyInteger("Workers Launched",
+ ExplainPropertyInteger("Workers Launched", NULL,
nworkers, es);
}
if (gather->single_copy || es->format != EXPLAIN_FORMAT_TEXT)
if (plan->qual)
show_instrumentation_count("Rows Removed by Filter", 1,
planstate, es);
- ExplainPropertyInteger("Workers Planned",
+ ExplainPropertyInteger("Workers Planned", NULL,
gm->num_workers, es);
/* Show params evaluated at gather-merge node */
int nworkers;
nworkers = ((GatherMergeState *) planstate)->nworkers_launched;
- ExplainPropertyInteger("Workers Launched",
+ ExplainPropertyInteger("Workers Launched", NULL,
nworkers, es);
}
}
{
Instrumentation *instrument = &w->instrument[n];
double nloops = instrument->nloops;
- double startup_sec;
- double total_sec;
+ double startup_ms;
+ double total_ms;
double rows;
if (nloops <= 0)
continue;
- startup_sec = 1000.0 * instrument->startup / nloops;
- total_sec = 1000.0 * instrument->total / nloops;
+ startup_ms = 1000.0 * instrument->startup / nloops;
+ total_ms = 1000.0 * instrument->total / nloops;
rows = instrument->ntuples / nloops;
if (es->format == EXPLAIN_FORMAT_TEXT)
if (es->timing)
appendStringInfo(es->str,
"actual time=%.3f..%.3f rows=%.0f loops=%.0f\n",
- startup_sec, total_sec, rows, nloops);
+ startup_ms, total_ms, rows, nloops);
else
appendStringInfo(es->str,
"actual rows=%.0f loops=%.0f\n",
opened_group = true;
}
ExplainOpenGroup("Worker", NULL, true, es);
- ExplainPropertyInteger("Worker Number", n, es);
+ ExplainPropertyInteger("Worker Number", NULL, n, es);
if (es->timing)
{
- ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es);
- ExplainPropertyFloat("Actual Total Time", total_sec, 3, es);
+ ExplainPropertyFloat("Actual Startup Time", "ms",
+ startup_ms, 3, es);
+ ExplainPropertyFloat("Actual Total Time", "ms",
+ total_ms, 3, es);
}
- ExplainPropertyFloat("Actual Rows", rows, 0, es);
- ExplainPropertyFloat("Actual Loops", nloops, 0, es);
+ ExplainPropertyFloat("Actual Rows", NULL, rows, 0, es);
+ ExplainPropertyFloat("Actual Loops", NULL, nloops, 0, es);
if (es->buffers)
show_buffer_usage(es, &instrument->bufusage);
else
{
ExplainPropertyText("Sort Method", sortMethod, es);
- ExplainPropertyInteger("Sort Space Used", spaceUsed, es);
+ ExplainPropertyInteger("Sort Space Used", "kB", spaceUsed, es);
ExplainPropertyText("Sort Space Type", spaceType, es);
}
}
opened_group = true;
}
ExplainOpenGroup("Worker", NULL, true, es);
- ExplainPropertyInteger("Worker Number", n, es);
+ ExplainPropertyInteger("Worker Number", NULL, n, es);
ExplainPropertyText("Sort Method", sortMethod, es);
- ExplainPropertyInteger("Sort Space Used", spaceUsed, es);
+ ExplainPropertyInteger("Sort Space Used", "kB", spaceUsed, es);
ExplainPropertyText("Sort Space Type", spaceType, es);
ExplainCloseGroup("Worker", NULL, true, es);
}
if (es->format != EXPLAIN_FORMAT_TEXT)
{
- ExplainPropertyInteger("Hash Buckets", hinstrument.nbuckets, es);
- ExplainPropertyInteger("Original Hash Buckets",
- hinstrument.nbuckets_original, es);
- ExplainPropertyInteger("Hash Batches", hinstrument.nbatch, es);
- ExplainPropertyInteger("Original Hash Batches",
- hinstrument.nbatch_original, es);
- ExplainPropertyInteger("Peak Memory Usage", spacePeakKb, es);
+ ExplainPropertyInteger("Hash Buckets", NULL,
+ hinstrument.nbuckets, es);
+ ExplainPropertyInteger("Original Hash Buckets", NULL,
+ hinstrument.nbuckets_original, es);
+ ExplainPropertyInteger("Hash Batches", NULL,
+ hinstrument.nbatch, es);
+ ExplainPropertyInteger("Original Hash Batches", NULL,
+ hinstrument.nbatch_original, es);
+ ExplainPropertyInteger("Peak Memory Usage", "kB",
+ spacePeakKb, es);
}
else if (hinstrument.nbatch_original != hinstrument.nbatch ||
hinstrument.nbuckets_original != hinstrument.nbuckets)
{
if (es->format != EXPLAIN_FORMAT_TEXT)
{
- ExplainPropertyInteger("Exact Heap Blocks",
+ ExplainPropertyInteger("Exact Heap Blocks", NULL,
planstate->exact_pages, es);
- ExplainPropertyInteger("Lossy Heap Blocks",
+ ExplainPropertyInteger("Lossy Heap Blocks", NULL,
planstate->lossy_pages, es);
}
else
if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT)
{
if (nloops > 0)
- ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es);
+ ExplainPropertyFloat(qlabel, NULL, nfiltered / nloops, 0, es);
else
- ExplainPropertyFloat(qlabel, 0.0, 0, es);
+ ExplainPropertyFloat(qlabel, NULL, 0.0, 0, es);
}
}
}
else
{
- ExplainPropertyInteger("Shared Hit Blocks",
+ ExplainPropertyInteger("Shared Hit Blocks", NULL,
usage->shared_blks_hit, es);
- ExplainPropertyInteger("Shared Read Blocks",
+ ExplainPropertyInteger("Shared Read Blocks", NULL,
usage->shared_blks_read, es);
- ExplainPropertyInteger("Shared Dirtied Blocks",
+ ExplainPropertyInteger("Shared Dirtied Blocks", NULL,
usage->shared_blks_dirtied, es);
- ExplainPropertyInteger("Shared Written Blocks",
+ ExplainPropertyInteger("Shared Written Blocks", NULL,
usage->shared_blks_written, es);
- ExplainPropertyInteger("Local Hit Blocks",
+ ExplainPropertyInteger("Local Hit Blocks", NULL,
usage->local_blks_hit, es);
- ExplainPropertyInteger("Local Read Blocks",
+ ExplainPropertyInteger("Local Read Blocks", NULL,
usage->local_blks_read, es);
- ExplainPropertyInteger("Local Dirtied Blocks",
+ ExplainPropertyInteger("Local Dirtied Blocks", NULL,
usage->local_blks_dirtied, es);
- ExplainPropertyInteger("Local Written Blocks",
+ ExplainPropertyInteger("Local Written Blocks", NULL,
usage->local_blks_written, es);
- ExplainPropertyInteger("Temp Read Blocks",
+ ExplainPropertyInteger("Temp Read Blocks", NULL,
usage->temp_blks_read, es);
- ExplainPropertyInteger("Temp Written Blocks",
+ ExplainPropertyInteger("Temp Written Blocks", NULL,
usage->temp_blks_written, es);
if (track_io_timing)
{
- ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es);
- ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es);
+ ExplainPropertyFloat("I/O Read Time", "ms",
+ INSTR_TIME_GET_MILLISEC(usage->blk_read_time),
+ 3, es);
+ ExplainPropertyFloat("I/O Write Time", "ms",
+ INSTR_TIME_GET_MILLISEC(usage->blk_write_time),
+ 3, es);
}
}
}
if (node->onConflictAction != ONCONFLICT_NONE)
{
- ExplainProperty("Conflict Resolution",
- node->onConflictAction == ONCONFLICT_NOTHING ?
- "NOTHING" : "UPDATE",
- false, es);
+ ExplainPropertyText("Conflict Resolution",
+ node->onConflictAction == ONCONFLICT_NOTHING ?
+ "NOTHING" : "UPDATE",
+ es);
/*
* Don't display arbiter indexes at all when DO NOTHING variant
other_path = mtstate->ps.instrument->nfiltered2;
insert_path = total - other_path;
- ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es);
- ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es);
+ ExplainPropertyFloat("Tuples Inserted", NULL,
+ insert_path, 0, es);
+ ExplainPropertyFloat("Conflicting Tuples", NULL,
+ other_path, 0, es);
}
}
* If "numeric" is true, the value is a number (or other value that
* doesn't need quoting in JSON).
*
+ * If unit is is non-NULL the text format will display it after the value.
+ *
* This usually should not be invoked directly, but via one of the datatype
* specific routines ExplainPropertyText, ExplainPropertyInteger, etc.
*/
static void
-ExplainProperty(const char *qlabel, const char *value, bool numeric,
- ExplainState *es)
+ExplainProperty(const char *qlabel, const char *unit, const char *value,
+ bool numeric, ExplainState *es)
{
switch (es->format)
{
case EXPLAIN_FORMAT_TEXT:
appendStringInfoSpaces(es->str, es->indent * 2);
- appendStringInfo(es->str, "%s: %s\n", qlabel, value);
+ if (unit)
+ appendStringInfo(es->str, "%s: %s %s\n", qlabel, value, unit);
+ else
+ appendStringInfo(es->str, "%s: %s\n", qlabel, value);
break;
case EXPLAIN_FORMAT_XML:
void
ExplainPropertyText(const char *qlabel, const char *value, ExplainState *es)
{
- ExplainProperty(qlabel, value, false, es);
+ ExplainProperty(qlabel, NULL, value, false, es);
}
/*
* Explain an integer-valued property.
*/
void
-ExplainPropertyInteger(const char *qlabel, int64 value, ExplainState *es)
+ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value,
+ ExplainState *es)
{
char buf[32];
snprintf(buf, sizeof(buf), INT64_FORMAT, value);
- ExplainProperty(qlabel, buf, true, es);
+ ExplainProperty(qlabel, unit, buf, true, es);
}
/*
* fractional digits.
*/
void
-ExplainPropertyFloat(const char *qlabel, double value, int ndigits,
- ExplainState *es)
+ExplainPropertyFloat(const char *qlabel, const char *unit, double value,
+ int ndigits, ExplainState *es)
{
char *buf;
buf = psprintf("%.*f", ndigits, value);
- ExplainProperty(qlabel, buf, true, es);
+ ExplainProperty(qlabel, unit, buf, true, es);
pfree(buf);
}
void
ExplainPropertyBool(const char *qlabel, bool value, ExplainState *es)
{
- ExplainProperty(qlabel, value ? "true" : "false", true, es);
+ ExplainProperty(qlabel, NULL, value ? "true" : "false", true, es);
}
/*