77 * Portions Copyright (c) 1994-5, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.193 2009/11/04 22:26:04 tgl Exp $
10+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.194 2009/12/11 01:33:35 adunstan Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -95,7 +95,9 @@ static void ExplainBeginOutput(ExplainState *es);
9595static void ExplainEndOutput (ExplainState * es );
9696static void ExplainXMLTag (const char * tagname ,int flags ,ExplainState * es );
9797static void ExplainJSONLineEnding (ExplainState * es );
98+ static void ExplainYAMLLineStarting (ExplainState * es );
9899static void escape_json (StringInfo buf ,const char * str );
100+ static void escape_yaml (StringInfo buf ,const char * str );
99101
100102
101103/*
@@ -135,6 +137,8 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
135137es .format = EXPLAIN_FORMAT_XML ;
136138else if (strcmp (p ,"json" )== 0 )
137139es .format = EXPLAIN_FORMAT_JSON ;
140+ else if (strcmp (p ,"yaml" )== 0 )
141+ es .format = EXPLAIN_FORMAT_YAML ;
138142else
139143ereport (ERROR ,
140144(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
@@ -1537,6 +1541,19 @@ ExplainPropertyList(const char *qlabel, List *data, ExplainState *es)
15371541}
15381542appendStringInfoChar (es -> str ,']' );
15391543break ;
1544+
1545+ case EXPLAIN_FORMAT_YAML :
1546+ ExplainYAMLLineStarting (es );
1547+ escape_yaml (es -> str ,qlabel );
1548+ appendStringInfoChar (es -> str ,':' );
1549+ foreach (lc ,data )
1550+ {
1551+ appendStringInfoChar (es -> str ,'\n' );
1552+ appendStringInfoSpaces (es -> str ,es -> indent * 2 + 2 );
1553+ appendStringInfoString (es -> str ,"- " );
1554+ escape_yaml (es -> str , (const char * )lfirst (lc ));
1555+ }
1556+ break ;
15401557}
15411558}
15421559
@@ -1584,6 +1601,15 @@ ExplainProperty(const char *qlabel, const char *value, bool numeric,
15841601else
15851602escape_json (es -> str ,value );
15861603break ;
1604+
1605+ case EXPLAIN_FORMAT_YAML :
1606+ ExplainYAMLLineStarting (es );
1607+ appendStringInfo (es -> str ,"%s: " ,qlabel );
1608+ if (numeric )
1609+ appendStringInfoString (es -> str ,value );
1610+ else
1611+ escape_yaml (es -> str ,value );
1612+ break ;
15871613}
15881614}
15891615
@@ -1668,6 +1694,21 @@ ExplainOpenGroup(const char *objtype, const char *labelname,
16681694es -> grouping_stack = lcons_int (0 ,es -> grouping_stack );
16691695es -> indent ++ ;
16701696break ;
1697+
1698+ case EXPLAIN_FORMAT_YAML :
1699+ ExplainYAMLLineStarting (es );
1700+ if (labelname )
1701+ {
1702+ appendStringInfo (es -> str ,"%s:" ,labelname );
1703+ es -> grouping_stack = lcons_int (1 ,es -> grouping_stack );
1704+ }
1705+ else
1706+ {
1707+ appendStringInfoChar (es -> str ,'-' );
1708+ es -> grouping_stack = lcons_int (0 ,es -> grouping_stack );
1709+ }
1710+ es -> indent ++ ;
1711+ break ;
16711712}
16721713}
16731714
@@ -1697,6 +1738,11 @@ ExplainCloseGroup(const char *objtype, const char *labelname,
16971738appendStringInfoChar (es -> str ,labeled ?'}' :']' );
16981739es -> grouping_stack = list_delete_first (es -> grouping_stack );
16991740break ;
1741+
1742+ case EXPLAIN_FORMAT_YAML :
1743+ es -> indent -- ;
1744+ es -> grouping_stack = list_delete_first (es -> grouping_stack );
1745+ break ;
17001746}
17011747}
17021748
@@ -1729,6 +1775,13 @@ ExplainDummyGroup(const char *objtype, const char *labelname, ExplainState *es)
17291775}
17301776escape_json (es -> str ,objtype );
17311777break ;
1778+
1779+ case EXPLAIN_FORMAT_YAML :
1780+ ExplainYAMLLineStarting (es );
1781+ if (labelname )
1782+ appendStringInfo (es -> str ,"%s:" ,labelname );
1783+ appendStringInfoString (es -> str ,objtype );
1784+ break ;
17321785}
17331786}
17341787
@@ -1759,6 +1812,10 @@ ExplainBeginOutput(ExplainState *es)
17591812es -> grouping_stack = lcons_int (0 ,es -> grouping_stack );
17601813es -> indent ++ ;
17611814break ;
1815+
1816+ case EXPLAIN_FORMAT_YAML :
1817+ es -> grouping_stack = lcons_int (0 ,es -> grouping_stack );
1818+ break ;
17621819}
17631820}
17641821
@@ -1784,6 +1841,10 @@ ExplainEndOutput(ExplainState *es)
17841841appendStringInfoString (es -> str ,"\n]" );
17851842es -> grouping_stack = list_delete_first (es -> grouping_stack );
17861843break ;
1844+
1845+ case EXPLAIN_FORMAT_YAML :
1846+ es -> grouping_stack = list_delete_first (es -> grouping_stack );
1847+ break ;
17871848}
17881849}
17891850
@@ -1796,6 +1857,7 @@ ExplainSeparatePlans(ExplainState *es)
17961857switch (es -> format )
17971858{
17981859case EXPLAIN_FORMAT_TEXT :
1860+ case EXPLAIN_FORMAT_YAML :
17991861/* add a blank line */
18001862appendStringInfoChar (es -> str ,'\n' );
18011863break ;
@@ -1858,6 +1920,25 @@ ExplainJSONLineEnding(ExplainState *es)
18581920appendStringInfoChar (es -> str ,'\n' );
18591921}
18601922
1923+ /*
1924+ * Indent a YAML line.
1925+ */
1926+ static void
1927+ ExplainYAMLLineStarting (ExplainState * es )
1928+ {
1929+ Assert (es -> format == EXPLAIN_FORMAT_YAML );
1930+ if (linitial_int (es -> grouping_stack )== 0 )
1931+ {
1932+ appendStringInfoChar (es -> str ,' ' );
1933+ linitial_int (es -> grouping_stack )= 1 ;
1934+ }
1935+ else
1936+ {
1937+ appendStringInfoChar (es -> str ,'\n' );
1938+ appendStringInfoSpaces (es -> str ,es -> indent * 2 );
1939+ }
1940+ }
1941+
18611942/*
18621943 * Produce a JSON string literal, properly escaping characters in the text.
18631944 */
@@ -1902,3 +1983,23 @@ escape_json(StringInfo buf, const char *str)
19021983}
19031984appendStringInfoCharMacro (buf ,'\"' );
19041985}
1986+
1987+ /*
1988+ * YAML is a superset of JSON: if we find quotable characters, we call escape_json
1989+ */
1990+ static void
1991+ escape_yaml (StringInfo buf ,const char * str )
1992+ {
1993+ const char * p ;
1994+
1995+ for (p = str ;* p ;p ++ )
1996+ {
1997+ if ((unsignedchar )* p < ' ' || strchr ("\"\\\b\f\n\r\t" ,* p ))
1998+ {
1999+ escape_json (buf ,str );
2000+ return ;
2001+ }
2002+ }
2003+
2004+ appendStringInfo (buf ,"%s" ,str );
2005+ }