1/*-------------------------------------------------------------------------
4 * Format routines for explaining query execution plans
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994-5, Regents of the University of California
10 * src/backend/commands/explain_format.c
12 *-------------------------------------------------------------------------
22/* OR-able flags for ExplainXMLTag() */
25 #define X_CLOSE_IMMEDIATE 2
26 #define X_NOWHITESPACE 4
34 * Explain a property, such as sort keys or targets, that takes the form of
35 * a list of unlabeled items. "data" is a list of C strings.
104 * Explain a property that takes the form of a list of unlabeled items within
105 * another list. "data" is a list of C strings.
150 * Explain a simple property.
152 * If "numeric" is true, the value is a number (or other value that
153 * doesn't need quoting in JSON).
155 * If unit is non-NULL the text format will display it after the value.
157 * This usually should not be invoked directly, but via one of the datatype
158 * specific routines ExplainPropertyText, ExplainPropertyInteger, etc.
211 * Explain a string-valued property.
220 * Explain an integer-valued property.
233 * Explain an unsigned integer-valued property.
246 * Explain a float-valued property, using the specified number of
261 * Explain a bool-valued property.
270 * Open a group of related objects.
272 * objtype is the type of the group object, labelname is its label within
273 * a containing object (if any).
275 * If labeled is true, the group members will be labeled properties,
276 * while if it's false, they'll be unlabeled objects.
304 * In JSON format, the grouping_stack is an integer list. 0 means
305 * we've emitted nothing at this grouping level, 1 means we've
306 * emitted something (and so the next item needs a comma). See
307 * ExplainJSONLineEnding().
316 * In YAML format, the grouping stack is an integer list. 0 means
317 * we've emitted nothing at this grouping level AND this grouping
318 * level is unlabeled and must be marked with "- ". See
319 * ExplainYAMLLineStarting().
338 * Close a group of related objects.
339 * Parameters must match the corresponding ExplainOpenGroup call.
372 * Open a group of related objects, without emitting actual data.
374 * Prepare the formatting state as though we were beginning a group with
375 * the identified properties, but don't actually emit anything. Output
376 * subsequent to this call can be redirected into a separate output buffer,
377 * and then eventually appended to the main output buffer after doing a
378 * regular ExplainOpenGroup call (with the same parameters).
380 * The extra "depth" parameter is the new group's depth compared to current.
381 * It could be more than one, in case the eventual output will be enclosed
382 * in additional nesting group levels. We assume we don't need to track
383 * formatting state for those levels while preparing this group's output.
385 * There is no ExplainCloseSetAsideGroup --- in current usage, we always
386 * pop this state with ExplainSaveGroup.
418 * Pop one level of grouping state, allowing for a re-push later.
420 * This is typically used after ExplainOpenSetAsideGroup; pass the
421 * same "depth" used for that.
423 * This should not emit any output. If state needs to be saved,
424 * save it at *state_save. Currently, an integer save area is sufficient
425 * for all formats, but we might need to revisit that someday.
455 * Re-push one level of grouping state, undoing the effects of ExplainSaveGroup.
483 * Emit a "dummy" group that never has any members.
485 * objtype is the type of the group object, labelname is its label within
486 * a containing object (if any).
529 * Emit the start-of-output boilerplate.
531 * This is just enough different from processing a subgroup that we need
532 * a separate pair of subroutines.
545 "<explain xmlns=\"http://www.postgresql.org/2009/explain\">\n");
550 /* top-level structure is an array of plans */
563 * Emit the end-of-output boilerplate.
592 * Put an appropriate separator between multiple plans
600 /* add a blank line */
613 * Emit opening or closing XML tag.
615 * "flags" must contain X_OPENING, X_CLOSING, or X_CLOSE_IMMEDIATE.
616 * Optionally, OR in X_NOWHITESPACE to suppress the whitespace we'd normally
619 * XML restricts tag names more than our other output formats, eg they can't
620 * contain white space or slashes. Replace invalid characters with dashes,
621 * so that for example "I/O Read Time" becomes "I-O-Read-Time".
627 const char *valid =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
634 for (s = tagname; *s; s++)
644 * Indent a text-format line.
646 * We indent by two spaces per indentation level. However, when emitting
647 * data for a parallel worker there might already be data on the current line
648 * (cf. ExplainOpenWorker); in that case, don't indent any more.
659 * Emit a JSON line ending.
661 * JSON requires a comma after each property but the last. To facilitate this,
662 * in JSON format, the text emitted for each property begins just prior to the
663 * preceding line-break (and comma, if applicable).
677 * Indent a YAML line.
679 * YAML lines are ordinarily indented by two spaces per indentation level.
680 * The text emitted for each property begins just prior to the preceding
681 * line-break, except for the first property in an unlabeled group, for which
682 * it begins immediately after the "- " that introduces the group. The first
683 * property of the group appears on the same line as the opening "- ".
701 * YAML is a superset of JSON; unfortunately, the YAML quoting rules are
702 * ridiculously complicated -- as documented in sections 5.3 and 7.3.3 of
703 * http://yaml.org/spec/1.2/spec.html -- so we chose to just quote everything.
704 * Empty strings, strings with leading or trailing whitespace, and strings
705 * containing a variety of special characters must certainly be quoted or the
706 * output is invalid; and other seemingly harmless strings like "0xa" or
707 * "true" must be quoted, lest they be interpreted as a hexadecimal or Boolean
708 * constant rather than a string.
Assert(PointerIsAligned(start, uint64))
void escape_json(StringInfo buf, const char *str)
List * list_delete_first(List *list)
List * lcons_int(int datum, List *list)
void pfree(void *pointer)
char * psprintf(const char *fmt,...)
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendStringInfoSpaces(StringInfo str, int count)
void appendStringInfoString(StringInfo str, const char *s)
void appendStringInfoChar(StringInfo str, char ch)
#define appendStringInfoCharMacro(str, ch)
char * escape_xml(const char *str)