00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "postgres.h"
00014
00015 #include <limits.h>
00016
00017 #include "commands/explain.h"
00018 #include "executor/instrument.h"
00019 #include "utils/guc.h"
00020
00021 PG_MODULE_MAGIC;
00022
00023
00024 static int auto_explain_log_min_duration = -1;
00025 static bool auto_explain_log_analyze = false;
00026 static bool auto_explain_log_verbose = false;
00027 static bool auto_explain_log_buffers = false;
00028 static bool auto_explain_log_timing = false;
00029 static int auto_explain_log_format = EXPLAIN_FORMAT_TEXT;
00030 static bool auto_explain_log_nested_statements = false;
00031
00032 static const struct config_enum_entry format_options[] = {
00033 {"text", EXPLAIN_FORMAT_TEXT, false},
00034 {"xml", EXPLAIN_FORMAT_XML, false},
00035 {"json", EXPLAIN_FORMAT_JSON, false},
00036 {"yaml", EXPLAIN_FORMAT_YAML, false},
00037 {NULL, 0, false}
00038 };
00039
00040
00041 static int nesting_level = 0;
00042
00043
00044 static ExecutorStart_hook_type prev_ExecutorStart = NULL;
00045 static ExecutorRun_hook_type prev_ExecutorRun = NULL;
00046 static ExecutorFinish_hook_type prev_ExecutorFinish = NULL;
00047 static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
00048
00049 #define auto_explain_enabled() \
00050 (auto_explain_log_min_duration >= 0 && \
00051 (nesting_level == 0 || auto_explain_log_nested_statements))
00052
00053 void _PG_init(void);
00054 void _PG_fini(void);
00055
00056 static void explain_ExecutorStart(QueryDesc *queryDesc, int eflags);
00057 static void explain_ExecutorRun(QueryDesc *queryDesc,
00058 ScanDirection direction,
00059 long count);
00060 static void explain_ExecutorFinish(QueryDesc *queryDesc);
00061 static void explain_ExecutorEnd(QueryDesc *queryDesc);
00062
00063
00064
00065
00066
00067 void
00068 _PG_init(void)
00069 {
00070
00071 DefineCustomIntVariable("auto_explain.log_min_duration",
00072 "Sets the minimum execution time above which plans will be logged.",
00073 "Zero prints all plans. -1 turns this feature off.",
00074 &auto_explain_log_min_duration,
00075 -1,
00076 -1, INT_MAX / 1000,
00077 PGC_SUSET,
00078 GUC_UNIT_MS,
00079 NULL,
00080 NULL,
00081 NULL);
00082
00083 DefineCustomBoolVariable("auto_explain.log_analyze",
00084 "Use EXPLAIN ANALYZE for plan logging.",
00085 NULL,
00086 &auto_explain_log_analyze,
00087 false,
00088 PGC_SUSET,
00089 0,
00090 NULL,
00091 NULL,
00092 NULL);
00093
00094 DefineCustomBoolVariable("auto_explain.log_verbose",
00095 "Use EXPLAIN VERBOSE for plan logging.",
00096 NULL,
00097 &auto_explain_log_verbose,
00098 false,
00099 PGC_SUSET,
00100 0,
00101 NULL,
00102 NULL,
00103 NULL);
00104
00105 DefineCustomBoolVariable("auto_explain.log_buffers",
00106 "Log buffers usage.",
00107 NULL,
00108 &auto_explain_log_buffers,
00109 false,
00110 PGC_SUSET,
00111 0,
00112 NULL,
00113 NULL,
00114 NULL);
00115
00116 DefineCustomEnumVariable("auto_explain.log_format",
00117 "EXPLAIN format to be used for plan logging.",
00118 NULL,
00119 &auto_explain_log_format,
00120 EXPLAIN_FORMAT_TEXT,
00121 format_options,
00122 PGC_SUSET,
00123 0,
00124 NULL,
00125 NULL,
00126 NULL);
00127
00128 DefineCustomBoolVariable("auto_explain.log_nested_statements",
00129 "Log nested statements.",
00130 NULL,
00131 &auto_explain_log_nested_statements,
00132 false,
00133 PGC_SUSET,
00134 0,
00135 NULL,
00136 NULL,
00137 NULL);
00138
00139 DefineCustomBoolVariable("auto_explain.log_timing",
00140 "Collect timing data, not just row counts.",
00141 NULL,
00142 &auto_explain_log_timing,
00143 true,
00144 PGC_SUSET,
00145 0,
00146 NULL,
00147 NULL,
00148 NULL);
00149
00150 EmitWarningsOnPlaceholders("auto_explain");
00151
00152
00153 prev_ExecutorStart = ExecutorStart_hook;
00154 ExecutorStart_hook = explain_ExecutorStart;
00155 prev_ExecutorRun = ExecutorRun_hook;
00156 ExecutorRun_hook = explain_ExecutorRun;
00157 prev_ExecutorFinish = ExecutorFinish_hook;
00158 ExecutorFinish_hook = explain_ExecutorFinish;
00159 prev_ExecutorEnd = ExecutorEnd_hook;
00160 ExecutorEnd_hook = explain_ExecutorEnd;
00161 }
00162
00163
00164
00165
00166 void
00167 _PG_fini(void)
00168 {
00169
00170 ExecutorStart_hook = prev_ExecutorStart;
00171 ExecutorRun_hook = prev_ExecutorRun;
00172 ExecutorFinish_hook = prev_ExecutorFinish;
00173 ExecutorEnd_hook = prev_ExecutorEnd;
00174 }
00175
00176
00177
00178
00179 static void
00180 explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
00181 {
00182 if (auto_explain_enabled())
00183 {
00184
00185 if (auto_explain_log_analyze && (eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0)
00186 {
00187 if (auto_explain_log_timing)
00188 queryDesc->instrument_options |= INSTRUMENT_TIMER;
00189 else
00190 queryDesc->instrument_options |= INSTRUMENT_ROWS;
00191
00192
00193 if (auto_explain_log_buffers)
00194 queryDesc->instrument_options |= INSTRUMENT_BUFFERS;
00195 }
00196 }
00197
00198 if (prev_ExecutorStart)
00199 prev_ExecutorStart(queryDesc, eflags);
00200 else
00201 standard_ExecutorStart(queryDesc, eflags);
00202
00203 if (auto_explain_enabled())
00204 {
00205
00206
00207
00208
00209
00210 if (queryDesc->totaltime == NULL)
00211 {
00212 MemoryContext oldcxt;
00213
00214 oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
00215 queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
00216 MemoryContextSwitchTo(oldcxt);
00217 }
00218 }
00219 }
00220
00221
00222
00223
00224 static void
00225 explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count)
00226 {
00227 nesting_level++;
00228 PG_TRY();
00229 {
00230 if (prev_ExecutorRun)
00231 prev_ExecutorRun(queryDesc, direction, count);
00232 else
00233 standard_ExecutorRun(queryDesc, direction, count);
00234 nesting_level--;
00235 }
00236 PG_CATCH();
00237 {
00238 nesting_level--;
00239 PG_RE_THROW();
00240 }
00241 PG_END_TRY();
00242 }
00243
00244
00245
00246
00247 static void
00248 explain_ExecutorFinish(QueryDesc *queryDesc)
00249 {
00250 nesting_level++;
00251 PG_TRY();
00252 {
00253 if (prev_ExecutorFinish)
00254 prev_ExecutorFinish(queryDesc);
00255 else
00256 standard_ExecutorFinish(queryDesc);
00257 nesting_level--;
00258 }
00259 PG_CATCH();
00260 {
00261 nesting_level--;
00262 PG_RE_THROW();
00263 }
00264 PG_END_TRY();
00265 }
00266
00267
00268
00269
00270 static void
00271 explain_ExecutorEnd(QueryDesc *queryDesc)
00272 {
00273 if (queryDesc->totaltime && auto_explain_enabled())
00274 {
00275 double msec;
00276
00277
00278
00279
00280
00281 InstrEndLoop(queryDesc->totaltime);
00282
00283
00284 msec = queryDesc->totaltime->total * 1000.0;
00285 if (msec >= auto_explain_log_min_duration)
00286 {
00287 ExplainState es;
00288
00289 ExplainInitState(&es);
00290 es.analyze = (queryDesc->instrument_options && auto_explain_log_analyze);
00291 es.verbose = auto_explain_log_verbose;
00292 es.buffers = (es.analyze && auto_explain_log_buffers);
00293 es.format = auto_explain_log_format;
00294
00295 ExplainBeginOutput(&es);
00296 ExplainQueryText(&es, queryDesc);
00297 ExplainPrintPlan(&es, queryDesc);
00298 ExplainEndOutput(&es);
00299
00300
00301 if (es.str->len > 0 && es.str->data[es.str->len - 1] == '\n')
00302 es.str->data[--es.str->len] = '\0';
00303
00304
00305 if (auto_explain_log_format == EXPLAIN_FORMAT_JSON)
00306 {
00307 es.str->data[0] = '{';
00308 es.str->data[es.str->len - 1] = '}';
00309 }
00310
00311
00312
00313
00314
00315
00316
00317 ereport(LOG,
00318 (errmsg("duration: %.3f ms plan:\n%s",
00319 msec, es.str->data),
00320 errhidestmt(true)));
00321
00322 pfree(es.str->data);
00323 }
00324 }
00325
00326 if (prev_ExecutorEnd)
00327 prev_ExecutorEnd(queryDesc);
00328 else
00329 standard_ExecutorEnd(queryDesc);
00330 }