From d6e503a493d2a54221531654d48a62fddc8ae9a2 Mon Sep 17 00:00:00 2001 From: Robert Haas <rhaas@postgresql.org> Date: Wed, 9 Jun 2010 02:39:34 +0000 Subject: [PATCH] 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. --- src/backend/commands/explain.c | 44 +++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 2409a01e2dd..d6a0f65acff 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.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 - * escape_json. If not, we emit the property unquoted for better readability. + * YAML is a superset of JSON, so we can use JSON escaping when escaping is + * 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 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); - return; + if (*p != ' ' && !is_safe_yaml(*p)) + { + 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); } -- GitLab