From 324385d67fe87e182325decdef1756a8f76733a8 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Fri, 11 Dec 2009 01:33:35 +0000 Subject: [PATCH] Add YAML to list of EXPLAIN formats. Greg Sabino Mullane, reviewed by Takahiro Itagaki. --- contrib/auto_explain/auto_explain.c | 3 +- doc/src/sgml/auto-explain.sgml | 4 +- doc/src/sgml/ref/explain.sgml | 8 +-- doc/src/sgml/release-8.5.sgml | 4 +- src/backend/commands/explain.c | 103 +++++++++++++++++++++++++++- src/include/commands/explain.h | 5 +- 6 files changed, 115 insertions(+), 12 deletions(-) diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index 6d3435be1f..531f076525 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -6,7 +6,7 @@ * Copyright (c) 2008-2009, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/contrib/auto_explain/auto_explain.c,v 1.7 2009/08/10 05:46:49 tgl Exp $ + * $PostgreSQL: pgsql/contrib/auto_explain/auto_explain.c,v 1.8 2009/12/11 01:33:35 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,7 @@ static const struct config_enum_entry format_options[] = { {"text", EXPLAIN_FORMAT_TEXT, false}, {"xml", EXPLAIN_FORMAT_XML, false}, {"json", EXPLAIN_FORMAT_JSON, false}, + {"yaml", EXPLAIN_FORMAT_YAML, false}, {NULL, 0, false} }; diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml index 72487f944c..39c7bc20f5 100644 --- a/doc/src/sgml/auto-explain.sgml +++ b/doc/src/sgml/auto-explain.sgml @@ -1,4 +1,4 @@ - + auto_explain @@ -114,7 +114,7 @@ LOAD 'auto_explain'; auto_explain.log_format selects the EXPLAIN output format to be used. The allowed values are text, xml, - and json. The default is text. + json, and yaml. The default is text. Only superusers can change this setting. diff --git a/doc/src/sgml/ref/explain.sgml b/doc/src/sgml/ref/explain.sgml index 9670bd06f1..4de5a4aba6 100644 --- a/doc/src/sgml/ref/explain.sgml +++ b/doc/src/sgml/ref/explain.sgml @@ -1,5 +1,5 @@ @@ -31,7 +31,7 @@ PostgreSQL documentation -EXPLAIN [ ( { ANALYZE boolean | VERBOSE boolean | COSTS boolean | FORMAT { TEXT | XML | JSON } } [, ...] ) ] statement +EXPLAIN [ ( { ANALYZE boolean | VERBOSE boolean | COSTS boolean | FORMAT { TEXT | XML | JSON | YAML } } [, ...] ) ] statement EXPLAIN [ ANALYZE ] [ VERBOSE ] statement @@ -143,8 +143,8 @@ ROLLBACK; FORMAT - Specify the output format, which can be TEXT, XML, or JSON. - XML or JSON output contains the same information as the text output + Specify the output format, which can be TEXT, XML, JSON, or YAML. + Non-text output contains the same information as the text output format, but is easier for programs to parse. This parameter defaults to TEXT. diff --git a/doc/src/sgml/release-8.5.sgml b/doc/src/sgml/release-8.5.sgml index caca750825..f95b35505c 100644 --- a/doc/src/sgml/release-8.5.sgml +++ b/doc/src/sgml/release-8.5.sgml @@ -1,4 +1,4 @@ - + Release 8.5alpha2 @@ -176,7 +176,7 @@ - EXPLAIN allows output of plans in XML or JSON format for automated + EXPLAIN allows output of plans in XML, JSON, or YAML format for automated processing of explain plans by analysis or visualization tools. diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 21fa3add4f..0970723a6d 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.193 2009/11/04 22:26:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.194 2009/12/11 01:33:35 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -95,7 +95,9 @@ static void ExplainBeginOutput(ExplainState *es); static void ExplainEndOutput(ExplainState *es); static void ExplainXMLTag(const char *tagname, int flags, ExplainState *es); static void ExplainJSONLineEnding(ExplainState *es); +static void ExplainYAMLLineStarting(ExplainState *es); static void escape_json(StringInfo buf, const char *str); +static void escape_yaml(StringInfo buf, const char *str); /* @@ -135,6 +137,8 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString, es.format = EXPLAIN_FORMAT_XML; else if (strcmp(p, "json") == 0) es.format = EXPLAIN_FORMAT_JSON; + else if (strcmp(p, "yaml") == 0) + es.format = EXPLAIN_FORMAT_YAML; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1537,6 +1541,19 @@ ExplainPropertyList(const char *qlabel, List *data, ExplainState *es) } appendStringInfoChar(es->str, ']'); break; + + case EXPLAIN_FORMAT_YAML: + ExplainYAMLLineStarting(es); + escape_yaml(es->str, qlabel); + appendStringInfoChar(es->str, ':'); + foreach(lc, data) + { + appendStringInfoChar(es->str, '\n'); + appendStringInfoSpaces(es->str, es->indent * 2 + 2); + appendStringInfoString(es->str, "- "); + escape_yaml(es->str, (const char *) lfirst(lc)); + } + break; } } @@ -1584,6 +1601,15 @@ ExplainProperty(const char *qlabel, const char *value, bool numeric, else escape_json(es->str, value); break; + + case EXPLAIN_FORMAT_YAML: + ExplainYAMLLineStarting(es); + appendStringInfo(es->str, "%s: ", qlabel); + if (numeric) + appendStringInfoString(es->str, value); + else + escape_yaml(es->str, value); + break; } } @@ -1668,6 +1694,21 @@ ExplainOpenGroup(const char *objtype, const char *labelname, es->grouping_stack = lcons_int(0, es->grouping_stack); es->indent++; break; + + case EXPLAIN_FORMAT_YAML: + ExplainYAMLLineStarting(es); + if (labelname) + { + appendStringInfo(es->str, "%s:", labelname); + es->grouping_stack = lcons_int(1, es->grouping_stack); + } + else + { + appendStringInfoChar(es->str, '-'); + es->grouping_stack = lcons_int(0, es->grouping_stack); + } + es->indent++; + break; } } @@ -1697,6 +1738,11 @@ ExplainCloseGroup(const char *objtype, const char *labelname, appendStringInfoChar(es->str, labeled ? '}' : ']'); es->grouping_stack = list_delete_first(es->grouping_stack); break; + + case EXPLAIN_FORMAT_YAML: + es->indent--; + es->grouping_stack = list_delete_first(es->grouping_stack); + break; } } @@ -1729,6 +1775,13 @@ ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es) } escape_json(es->str, objtype); break; + + case EXPLAIN_FORMAT_YAML: + ExplainYAMLLineStarting(es); + if (labelname) + appendStringInfo(es->str, "%s:", labelname); + appendStringInfoString(es->str, objtype); + break; } } @@ -1759,6 +1812,10 @@ ExplainBeginOutput(ExplainState *es) es->grouping_stack = lcons_int(0, es->grouping_stack); es->indent++; break; + + case EXPLAIN_FORMAT_YAML: + es->grouping_stack = lcons_int(0, es->grouping_stack); + break; } } @@ -1784,6 +1841,10 @@ ExplainEndOutput(ExplainState *es) appendStringInfoString(es->str, "\n]"); es->grouping_stack = list_delete_first(es->grouping_stack); break; + + case EXPLAIN_FORMAT_YAML: + es->grouping_stack = list_delete_first(es->grouping_stack); + break; } } @@ -1796,6 +1857,7 @@ ExplainSeparatePlans(ExplainState *es) switch (es->format) { case EXPLAIN_FORMAT_TEXT: + case EXPLAIN_FORMAT_YAML: /* add a blank line */ appendStringInfoChar(es->str, '\n'); break; @@ -1858,6 +1920,25 @@ ExplainJSONLineEnding(ExplainState *es) appendStringInfoChar(es->str, '\n'); } +/* + * Indent a YAML line. + */ +static void +ExplainYAMLLineStarting(ExplainState *es) +{ + Assert(es->format == EXPLAIN_FORMAT_YAML); + if (linitial_int(es->grouping_stack) == 0) + { + appendStringInfoChar(es->str, ' '); + linitial_int(es->grouping_stack) = 1; + } + else + { + appendStringInfoChar(es->str, '\n'); + appendStringInfoSpaces(es->str, es->indent * 2); + } +} + /* * Produce a JSON string literal, properly escaping characters in the text. */ @@ -1902,3 +1983,23 @@ escape_json(StringInfo buf, const char *str) } appendStringInfoCharMacro(buf, '\"'); } + +/* + * YAML is a superset of JSON: if we find quotable characters, we call escape_json + */ +static void +escape_yaml(StringInfo buf, const char *str) +{ + const char *p; + + for (p = str; *p; p++) + { + if ((unsigned char) *p < ' ' || strchr("\"\\\b\f\n\r\t", *p)) + { + escape_json(buf, str); + return; + } + } + + appendStringInfo(buf, "%s", str); +} diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index fa2c8aac66..7137a7ab41 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.41 2009/08/10 05:46:50 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/explain.h,v 1.42 2009/12/11 01:33:35 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,8 @@ typedef enum ExplainFormat { EXPLAIN_FORMAT_TEXT, EXPLAIN_FORMAT_XML, - EXPLAIN_FORMAT_JSON + EXPLAIN_FORMAT_JSON, + EXPLAIN_FORMAT_YAML } ExplainFormat; typedef struct ExplainState