1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Attempt to fix EXPLAIN (FORMAT YAML) quoting to behave sanely.

The previous code failed to quote in many cases where quoting was necessary -
YAML has loads of special characters, including -:[]{},"'|*& - so quote much
more aggressively, and only refrain from quoting things where it seems fairly
clear that it isn't necessary.

Per report from Dean Rasheed.
This commit is contained in:
Robert Haas
2010-06-09 02:39:34 +00:00
parent a624356072
commit d6e503a493

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.204 2010/02/26 02:00:39 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.205 2010/06/09 02:39:34 rhaas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -2152,22 +2152,48 @@ escape_json(StringInfo buf, const char *str)
} }
/* /*
* YAML is a superset of JSON: if we find quotable characters, we call * YAML is a superset of JSON, so we can use JSON escaping when escaping is
* escape_json. If not, we emit the property unquoted for better readability. * needed. However, some things that need to be quoted in JSON don't require
* quoting in YAML, and we prefer not to quote unnecessarily, to improve
* readability.
*
* Unfortunately, the YAML quoting rules are ridiculously complicated -- as
* documented in sections 5.3 and 7.3.3 of http://yaml.org/spec/1.2/spec.html
* -- and it doesn't seem worth expending a large amount of energy to avoid
* all unnecessary quoting, so we just do something (sort of) simple: we quote
* any string which is empty; any string which contains characters other than
* alphanumerics, period, underscore, or space; or begins or ends with a
* space. The exception for period is mostly so that floating-point numbers
* (e.g., cost values) won't be quoted.
*/ */
static void static void
escape_yaml(StringInfo buf, const char *str) escape_yaml(StringInfo buf, const char *str)
{ {
const char *p; bool needs_quoting = false;
for (p = str; *p; p++) #define is_safe_yaml(x) \
(isalnum(((unsigned char) x)) || (x) == '.' || (x) == '_')
if (!is_safe_yaml(str[0]))
needs_quoting = true;
else
{ {
if ((unsigned char) *p < ' ' || strchr("\"\\\b\f\n\r\t", *p)) const char *p;
for (p = str; *p; p++)
{ {
escape_json(buf, str); if (*p != ' ' && !is_safe_yaml(*p))
return; {
needs_quoting = true;
break;
}
} }
if (!*p && p[-1] == ' ')
needs_quoting = true;
} }
appendStringInfo(buf, "%s", str); if (needs_quoting)
escape_json(buf, str);
else
appendStringInfoString(buf, str);
} }