#include "postgres.h"
#include <limits.h>
#include "commands/explain.h"
#include "executor/instrument.h"
#include "utils/guc.h"
Go to the source code of this file.
#define auto_explain_enabled | ( | ) |
(auto_explain_log_min_duration >= 0 && \ (nesting_level == 0 || auto_explain_log_nested_statements))
Definition at line 49 of file auto_explain.c.
Referenced by explain_ExecutorEnd(), and explain_ExecutorStart().
void _PG_fini | ( | void | ) |
Definition at line 167 of file auto_explain.c.
References ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, and prev_ExecutorStart.
{ /* Uninstall hooks. */ ExecutorStart_hook = prev_ExecutorStart; ExecutorRun_hook = prev_ExecutorRun; ExecutorFinish_hook = prev_ExecutorFinish; ExecutorEnd_hook = prev_ExecutorEnd; }
void _PG_init | ( | void | ) |
Definition at line 68 of file auto_explain.c.
References auto_explain_log_analyze, auto_explain_log_buffers, auto_explain_log_format, auto_explain_log_min_duration, auto_explain_log_nested_statements, auto_explain_log_timing, auto_explain_log_verbose, DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomIntVariable(), EmitWarningsOnPlaceholders(), ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, EXPLAIN_FORMAT_TEXT, GUC_UNIT_MS, NULL, PGC_SUSET, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, and prev_ExecutorStart.
{ /* Define custom GUC variables. */ DefineCustomIntVariable("auto_explain.log_min_duration", "Sets the minimum execution time above which plans will be logged.", "Zero prints all plans. -1 turns this feature off.", &auto_explain_log_min_duration, -1, -1, INT_MAX / 1000, PGC_SUSET, GUC_UNIT_MS, NULL, NULL, NULL); DefineCustomBoolVariable("auto_explain.log_analyze", "Use EXPLAIN ANALYZE for plan logging.", NULL, &auto_explain_log_analyze, false, PGC_SUSET, 0, NULL, NULL, NULL); DefineCustomBoolVariable("auto_explain.log_verbose", "Use EXPLAIN VERBOSE for plan logging.", NULL, &auto_explain_log_verbose, false, PGC_SUSET, 0, NULL, NULL, NULL); DefineCustomBoolVariable("auto_explain.log_buffers", "Log buffers usage.", NULL, &auto_explain_log_buffers, false, PGC_SUSET, 0, NULL, NULL, NULL); DefineCustomEnumVariable("auto_explain.log_format", "EXPLAIN format to be used for plan logging.", NULL, &auto_explain_log_format, EXPLAIN_FORMAT_TEXT, format_options, PGC_SUSET, 0, NULL, NULL, NULL); DefineCustomBoolVariable("auto_explain.log_nested_statements", "Log nested statements.", NULL, &auto_explain_log_nested_statements, false, PGC_SUSET, 0, NULL, NULL, NULL); DefineCustomBoolVariable("auto_explain.log_timing", "Collect timing data, not just row counts.", NULL, &auto_explain_log_timing, true, PGC_SUSET, 0, NULL, NULL, NULL); EmitWarningsOnPlaceholders("auto_explain"); /* Install hooks. */ prev_ExecutorStart = ExecutorStart_hook; ExecutorStart_hook = explain_ExecutorStart; prev_ExecutorRun = ExecutorRun_hook; ExecutorRun_hook = explain_ExecutorRun; prev_ExecutorFinish = ExecutorFinish_hook; ExecutorFinish_hook = explain_ExecutorFinish; prev_ExecutorEnd = ExecutorEnd_hook; ExecutorEnd_hook = explain_ExecutorEnd; }
static void explain_ExecutorEnd | ( | QueryDesc * | queryDesc | ) | [static] |
Definition at line 271 of file auto_explain.c.
References ExplainState::analyze, auto_explain_enabled, auto_explain_log_analyze, auto_explain_log_buffers, auto_explain_log_format, auto_explain_log_min_duration, auto_explain_log_verbose, ExplainState::buffers, StringInfoData::data, ereport, errhidestmt(), errmsg(), EXPLAIN_FORMAT_JSON, ExplainBeginOutput(), ExplainEndOutput(), ExplainInitState(), ExplainPrintPlan(), ExplainQueryText(), ExplainState::format, InstrEndLoop(), QueryDesc::instrument_options, StringInfoData::len, LOG, pfree(), prev_ExecutorEnd, standard_ExecutorEnd(), ExplainState::str, Instrumentation::total, QueryDesc::totaltime, and ExplainState::verbose.
{ if (queryDesc->totaltime && auto_explain_enabled()) { double msec; /* * Make sure stats accumulation is done. (Note: it's okay if several * levels of hook all do this.) */ InstrEndLoop(queryDesc->totaltime); /* Log plan if duration is exceeded. */ msec = queryDesc->totaltime->total * 1000.0; if (msec >= auto_explain_log_min_duration) { ExplainState es; ExplainInitState(&es); es.analyze = (queryDesc->instrument_options && auto_explain_log_analyze); es.verbose = auto_explain_log_verbose; es.buffers = (es.analyze && auto_explain_log_buffers); es.format = auto_explain_log_format; ExplainBeginOutput(&es); ExplainQueryText(&es, queryDesc); ExplainPrintPlan(&es, queryDesc); ExplainEndOutput(&es); /* Remove last line break */ if (es.str->len > 0 && es.str->data[es.str->len - 1] == '\n') es.str->data[--es.str->len] = '\0'; /* Fix JSON to output an object */ if (auto_explain_log_format == EXPLAIN_FORMAT_JSON) { es.str->data[0] = '{'; es.str->data[es.str->len - 1] = '}'; } /* * Note: we rely on the existing logging of context or * debug_query_string to identify just which statement is being * reported. This isn't ideal but trying to do it here would * often result in duplication. */ ereport(LOG, (errmsg("duration: %.3f ms plan:\n%s", msec, es.str->data), errhidestmt(true))); pfree(es.str->data); } } if (prev_ExecutorEnd) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); }
static void explain_ExecutorFinish | ( | QueryDesc * | queryDesc | ) | [static] |
Definition at line 248 of file auto_explain.c.
References nesting_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, prev_ExecutorFinish, and standard_ExecutorFinish().
{ nesting_level++; PG_TRY(); { if (prev_ExecutorFinish) prev_ExecutorFinish(queryDesc); else standard_ExecutorFinish(queryDesc); nesting_level--; } PG_CATCH(); { nesting_level--; PG_RE_THROW(); } PG_END_TRY(); }
static void explain_ExecutorRun | ( | QueryDesc * | queryDesc, | |
ScanDirection | direction, | |||
long | count | |||
) | [static] |
Definition at line 225 of file auto_explain.c.
References nesting_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, prev_ExecutorRun, and standard_ExecutorRun().
{ nesting_level++; PG_TRY(); { if (prev_ExecutorRun) prev_ExecutorRun(queryDesc, direction, count); else standard_ExecutorRun(queryDesc, direction, count); nesting_level--; } PG_CATCH(); { nesting_level--; PG_RE_THROW(); } PG_END_TRY(); }
static void explain_ExecutorStart | ( | QueryDesc * | queryDesc, | |
int | eflags | |||
) | [static] |
Definition at line 180 of file auto_explain.c.
References auto_explain_enabled, auto_explain_log_analyze, auto_explain_log_buffers, auto_explain_log_timing, EState::es_query_cxt, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, InstrAlloc(), INSTRUMENT_ALL, QueryDesc::instrument_options, MemoryContextSwitchTo(), NULL, prev_ExecutorStart, standard_ExecutorStart(), and QueryDesc::totaltime.
{ if (auto_explain_enabled()) { /* Enable per-node instrumentation iff log_analyze is required. */ if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0) { if (auto_explain_log_timing) queryDesc->instrument_options |= INSTRUMENT_TIMER; else queryDesc->instrument_options |= INSTRUMENT_ROWS; if (auto_explain_log_buffers) queryDesc->instrument_options |= INSTRUMENT_BUFFERS; } } if (prev_ExecutorStart) prev_ExecutorStart(queryDesc, eflags); else standard_ExecutorStart(queryDesc, eflags); if (auto_explain_enabled()) { /* * Set up to track total elapsed time in ExecutorRun. Make sure the * space is allocated in the per-query context so it will go away at * ExecutorEnd. */ if (queryDesc->totaltime == NULL) { MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt); queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL); MemoryContextSwitchTo(oldcxt); } } }
bool auto_explain_log_analyze = false [static] |
Definition at line 25 of file auto_explain.c.
Referenced by _PG_init(), explain_ExecutorEnd(), and explain_ExecutorStart().
bool auto_explain_log_buffers = false [static] |
Definition at line 27 of file auto_explain.c.
Referenced by _PG_init(), explain_ExecutorEnd(), and explain_ExecutorStart().
int auto_explain_log_format = EXPLAIN_FORMAT_TEXT [static] |
Definition at line 29 of file auto_explain.c.
Referenced by _PG_init(), and explain_ExecutorEnd().
int auto_explain_log_min_duration = -1 [static] |
Definition at line 24 of file auto_explain.c.
Referenced by _PG_init(), and explain_ExecutorEnd().
bool auto_explain_log_nested_statements = false [static] |
Definition at line 30 of file auto_explain.c.
Referenced by _PG_init().
bool auto_explain_log_timing = false [static] |
Definition at line 28 of file auto_explain.c.
Referenced by _PG_init(), and explain_ExecutorStart().
bool auto_explain_log_verbose = false [static] |
Definition at line 26 of file auto_explain.c.
Referenced by _PG_init(), and explain_ExecutorEnd().
struct config_enum_entry format_options[] [static] |
{ {"text", EXPLAIN_FORMAT_TEXT, false}, {"xml", EXPLAIN_FORMAT_XML, false}, {"json", EXPLAIN_FORMAT_JSON, false}, {"yaml", EXPLAIN_FORMAT_YAML, false}, {NULL, 0, false} }
Definition at line 32 of file auto_explain.c.
int nesting_level = 0 [static] |
Definition at line 41 of file auto_explain.c.
Referenced by explain_ExecutorFinish(), and explain_ExecutorRun().
Definition at line 21 of file auto_explain.c.
ExecutorEnd_hook_type prev_ExecutorEnd = NULL [static] |
Definition at line 47 of file auto_explain.c.
Referenced by _PG_fini(), _PG_init(), and explain_ExecutorEnd().
ExecutorFinish_hook_type prev_ExecutorFinish = NULL [static] |
Definition at line 46 of file auto_explain.c.
Referenced by _PG_fini(), _PG_init(), and explain_ExecutorFinish().
ExecutorRun_hook_type prev_ExecutorRun = NULL [static] |
Definition at line 45 of file auto_explain.c.
Referenced by _PG_fini(), _PG_init(), and explain_ExecutorRun().
ExecutorStart_hook_type prev_ExecutorStart = NULL [static] |
Definition at line 44 of file auto_explain.c.
Referenced by _PG_fini(), _PG_init(), and explain_ExecutorStart().