1/*-------------------------------------------------------------------------
4 * Code for initializing and accessing ExplainState objects
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
9 * In-core options have hard-coded fields inside ExplainState; e.g. if
10 * the user writes EXPLAIN (BUFFERS) then ExplainState's "buffers" member
11 * will be set to true. Extensions can also register options using
12 * RegisterExtensionExplainOption; so that e.g. EXPLAIN (BICYCLE 'red')
13 * will invoke a designated handler that knows what the legal values are
14 * for the BICYCLE option. However, it's not enough for an extension to be
15 * able to parse new options: it also needs a place to store the results
16 * of that parsing, and an ExplainState has no 'bicycle' field.
18 * To solve this problem, an ExplainState can contain an array of opaque
19 * pointers, one per extension. An extension can use GetExplainExtensionId
20 * to acquire an integer ID to acquire an offset into this array that is
21 * reserved for its exclusive use, and then use GetExplainExtensionState
22 * and SetExplainExtensionState to read and write its own private state
23 * within an ExplainState.
25 * Note that there is no requirement that the name of the option match
26 * the name of the extension; e.g. a pg_explain_conveyance extension could
27 * implement options for BICYCLE, MONORAIL, etc.
30 * src/backend/commands/explain_state.c
32 *-------------------------------------------------------------------------
40/* Hook to perform additional EXPLAIN options validation */
58 * Create a new ExplainState struct initialized with default options.
65 /* Set default options (most fields can be left as zeroes). */
67 /* Prepare output buffer. */
74 * Parse a list of EXPLAIN options and update an ExplainState accordingly.
80 bool timing_set =
false;
81 bool buffers_set =
false;
82 bool summary_set =
false;
84 /* Parse options list. */
89 if (strcmp(opt->
defname,
"analyze") == 0)
91 else if (strcmp(opt->
defname,
"verbose") == 0)
93 else if (strcmp(opt->
defname,
"costs") == 0)
95 else if (strcmp(opt->
defname,
"buffers") == 0)
100 else if (strcmp(opt->
defname,
"wal") == 0)
102 else if (strcmp(opt->
defname,
"settings") == 0)
104 else if (strcmp(opt->
defname,
"generic_plan") == 0)
106 else if (strcmp(opt->
defname,
"timing") == 0)
111 else if (strcmp(opt->
defname,
"summary") == 0)
116 else if (strcmp(opt->
defname,
"memory") == 0)
118 else if (strcmp(opt->
defname,
"serialize") == 0)
124 if (strcmp(p,
"off") == 0 || strcmp(p,
"none") == 0)
126 else if (strcmp(p,
"text") == 0)
128 else if (strcmp(p,
"binary") == 0)
132 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
133 errmsg(
"unrecognized value for EXPLAIN option \"%s\": \"%s\"",
139 /* SERIALIZE without an argument is taken as 'text' */
143 else if (strcmp(opt->
defname,
"format") == 0)
147 if (strcmp(p,
"text") == 0)
149 else if (strcmp(p,
"xml") == 0)
151 else if (strcmp(p,
"json") == 0)
153 else if (strcmp(p,
"yaml") == 0)
157 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
158 errmsg(
"unrecognized value for EXPLAIN option \"%s\": \"%s\"",
164 (
errcode(ERRCODE_SYNTAX_ERROR),
165 errmsg(
"unrecognized EXPLAIN option \"%s\"",
170 /* check that WAL is used with EXPLAIN ANALYZE */
173 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
174 errmsg(
"EXPLAIN option %s requires ANALYZE",
"WAL")));
176 /* if the timing was not set explicitly, set default value */
179 /* if the buffers was not set explicitly, set default value */
182 /* check that timing is used with EXPLAIN ANALYZE */
185 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
186 errmsg(
"EXPLAIN option %s requires ANALYZE",
"TIMING")));
188 /* check that serialize is used with EXPLAIN ANALYZE */
191 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
192 errmsg(
"EXPLAIN option %s requires ANALYZE",
"SERIALIZE")));
194 /* check that GENERIC_PLAN is not used with EXPLAIN ANALYZE */
197 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
198 errmsg(
"EXPLAIN options ANALYZE and GENERIC_PLAN cannot be used together")));
200 /* if the summary was not set explicitly, set default value */
203 /* plugin specific option validation */
205 (*explain_validate_options_hook) (es,
options, pstate);
209 * Map the name of an EXPLAIN extension to an integer ID.
211 * Within the lifetime of a particular backend, the same name will be mapped
212 * to the same ID every time. IDs are not stable across backends. Use the ID
213 * that you get from this function to call GetExplainExtensionState and
214 * SetExplainExtensionState.
216 * extension_name is assumed to be a constant string or allocated in storage
217 * that will never be freed.
222 /* Search for an existing extension by this name; if found, return ID. */
227 /* If there is no array yet, create one. */
237 /* If there's an array but it's currently full, expand it. */
247 /* Assign and return new ID. */
253 * Get extension-specific state from an ExplainState.
255 * See comments for SetExplainExtensionState, below.
260 Assert(extension_id >= 0);
269 * Store extension-specific state into an ExplainState.
271 * To use this function, first obtain an integer extension_id using
272 * GetExplainExtensionId. Then use this function to store an opaque pointer
273 * in the ExplainState. Later, you can retrieve the opaque pointer using
274 * GetExplainExtensionState.
279 Assert(extension_id >= 0);
281 /* If there is no array yet, create one. */
290 /* If there's an array but it's currently full, expand it. */
307 * Register a new EXPLAIN option.
309 * When option_name is used as an EXPLAIN option, handler will be called and
310 * should update the ExplainState passed to it. See comments at top of file
311 * for a more detailed explanation.
313 * option_name is assumed to be a constant string or allocated in storage
314 * that will never be freed.
322 /* Search for an existing option by this name; if found, update handler. */
333 /* If there is no array yet, create one. */
343 /* If there's an array but it's currently full, expand it. */
353 /* Assign and return new ID. */
360 * Apply an EXPLAIN option registered by an extension.
362 * If no extension has registered the named option, returns false. Otherwise,
363 * calls the appropriate handler function and then returns true.
char * defGetString(DefElem *def)
bool defGetBoolean(DefElem *def)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
static ExplainExtensionOption * ExplainExtensionOptionArray
ExplainState * NewExplainState(void)
static const char ** ExplainExtensionNameArray
static int ExplainExtensionNamesAssigned
int GetExplainExtensionId(const char *extension_name)
void * GetExplainExtensionState(ExplainState *es, int extension_id)
static int ExplainExtensionNamesAllocated
void SetExplainExtensionState(ExplainState *es, int extension_id, void *opaque)
void RegisterExtensionExplainOption(const char *option_name, ExplainOptionHandler handler)
static int ExplainExtensionOptionsAllocated
explain_validate_options_hook_type explain_validate_options_hook
void ParseExplainOptionList(ExplainState *es, List *options, ParseState *pstate)
bool ApplyExtensionExplainOption(ExplainState *es, DefElem *opt, ParseState *pstate)
static int ExplainExtensionOptionsAssigned
@ EXPLAIN_SERIALIZE_BINARY
void(* ExplainOptionHandler)(ExplainState *, DefElem *, ParseState *)
void(* explain_validate_options_hook_type)(ExplainState *es, List *options, ParseState *pstate)
Assert(PointerIsAligned(start, uint64))
if(TABLE==NULL||TABLE_index==NULL)
void * repalloc0(void *pointer, Size oldsize, Size size)
void * MemoryContextAlloc(MemoryContext context, Size size)
void * repalloc(void *pointer, Size size)
void * palloc0(Size size)
MemoryContext TopMemoryContext
int parser_errposition(ParseState *pstate, int location)
static uint32 pg_nextpower2_32(uint32 num)
StringInfo makeStringInfo(void)
ExplainOptionHandler option_handler
int extension_state_allocated
ExplainSerializeOption serialize