summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorTom Lane2018-03-22 00:03:28 +0000
committerTom Lane2018-03-22 00:03:28 +0000
commit67e02cde7373b09a8f6897b7fea3800ceb91ad9e (patch)
tree8c598a37bd8710359d773500eb09ffa60f09e3b1 /src/bin
parent9312fcf03b4889f9f2ba1c9b4a3447951a5bb6fb (diff)
Fix mishandling of quoted-list GUC values in pg_dump and ruleutils.c.
Code that prints out the contents of setconfig or proconfig arrays in SQL format needs to handle GUC_LIST_QUOTE variables differently from other ones, because for those variables, flatten_set_variable_args() already applied a layer of quoting. The value can therefore safely be printed as-is, and indeed must be, or flatten_set_variable_args() will muck it up completely on reload. For all other GUC variables, it's necessary and sufficient to quote the value as a SQL literal. We'd recognized the need for this long ago, but mis-analyzed the need slightly, thinking that all GUC_LIST_INPUT variables needed the special treatment. That's actually wrong, since a valid value of a LIST variable might include characters that need quoting, although no existing variables accept such values. More to the point, we hadn't made any particular effort to keep the various places that deal with this up-to-date with the set of variables that actually need special treatment, meaning that we'd do the wrong thing with, for example, temp_tablespaces values. This affects dumping of SET clauses attached to functions, as well as ALTER DATABASE/ROLE SET commands. In ruleutils.c we can fix it reasonably honestly by exporting a guc.c function that allows discovering the flags for a given GUC variable. But pg_dump doesn't have easy access to that, so continue the old method of having a hard-wired list of affected variable names. At least we can fix it to have just one list not two, and update the list to match current reality. A remaining problem with this is that it only works for built-in GUC variables. pg_dump's list obvious knows nothing of third-party extensions, and even the "ask guc.c" method isn't bulletproof since the relevant extension might not be loaded. There's no obvious solution to that, so for now, we'll just have to discourage extension authors from inventing custom GUCs that need GUC_LIST_QUOTE. This has been busted for a long time, so back-patch to all supported branches. Michael Paquier and Tom Lane, reviewed by Kyotaro Horiguchi and Pavel Stehule Discussion: https://postgr.es/m/20180111064900.GA51030@paquier.xyz
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/pg_dump/dumputils.c23
-rw-r--r--src/bin/pg_dump/dumputils.h2
-rw-r--r--src/bin/pg_dump/pg_dump.c12
-rw-r--r--src/bin/pg_dump/pg_dumpall.c11
4 files changed, 41 insertions, 7 deletions
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 8eb9e0c9926..46fc56e86b2 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -1522,3 +1522,26 @@ simple_string_list_member(SimpleStringList *list, const char *val)
}
return false;
}
+
+/*
+ * Detect whether the given GUC variable is of GUC_LIST_QUOTE type.
+ *
+ * It'd be better if we could inquire this directly from the backend; but even
+ * if there were a function for that, it could only tell us about variables
+ * currently known to guc.c, so that it'd be unsafe for extensions to declare
+ * GUC_LIST_QUOTE variables anyway. Lacking a solution for that, it doesn't
+ * seem worth the work to do more than have this list, which must be kept in
+ * sync with the variables actually marked GUC_LIST_QUOTE in guc.c.
+ */
+bool
+variable_is_guc_list_quote(const char *name)
+{
+ if (pg_strcasecmp(name, "temp_tablespaces") == 0 ||
+ pg_strcasecmp(name, "session_preload_libraries") == 0 ||
+ pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
+ pg_strcasecmp(name, "local_preload_libraries") == 0 ||
+ pg_strcasecmp(name, "search_path") == 0)
+ return true;
+ else
+ return false;
+}
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index 24dc404ed1f..25da30284e8 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -75,4 +75,6 @@ extern void set_dump_section(const char *arg, int *dumpSections);
extern void simple_string_list_append(SimpleStringList *list, const char *val);
extern bool simple_string_list_member(SimpleStringList *list, const char *val);
+extern bool variable_is_guc_list_quote(const char *name);
+
#endif /* DUMPUTILS_H */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4501c8bed8e..523a12f3585 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -10149,11 +10149,15 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
/*
- * Some GUC variable names are 'LIST' type and hence must not be
- * quoted.
+ * Variables that are marked GUC_LIST_QUOTE were already fully quoted
+ * by flatten_set_variable_args() before they were put into the
+ * proconfig array; we mustn't re-quote them or we'll make a mess.
+ * Variables that are not so marked should just be emitted as simple
+ * string literals. If the variable is not known to
+ * variable_is_guc_list_quote(), we'll do the latter; this makes it
+ * unsafe to use GUC_LIST_QUOTE for extension variables.
*/
- if (pg_strcasecmp(configitem, "DateStyle") == 0
- || pg_strcasecmp(configitem, "search_path") == 0)
+ if (variable_is_guc_list_quote(configitem))
appendPQExpBufferStr(q, pos);
else
appendStringLiteralAH(q, pos, fout);
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index fc2ee0a07e3..0b493c04830 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1610,10 +1610,15 @@ makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
/*
- * Some GUC variable names are 'LIST' type and hence must not be quoted.
+ * Variables that are marked GUC_LIST_QUOTE were already fully quoted by
+ * flatten_set_variable_args() before they were put into the setconfig
+ * array; we mustn't re-quote them or we'll make a mess. Variables that
+ * are not so marked should just be emitted as simple string literals. If
+ * the variable is not known to variable_is_guc_list_quote(), we'll do the
+ * latter; this makes it unsafe to use GUC_LIST_QUOTE for extension
+ * variables.
*/
- if (pg_strcasecmp(mine, "DateStyle") == 0
- || pg_strcasecmp(mine, "search_path") == 0)
+ if (variable_is_guc_list_quote(mine))
appendPQExpBufferStr(buf, pos + 1);
else
appendStringLiteralConn(buf, pos + 1, conn);