aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/adt/ruleutils.c13
-rw-r--r--src/backend/utils/misc/guc.c28
-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
-rw-r--r--src/include/utils/guc.h1
-rw-r--r--src/test/regress/expected/rules.out27
-rw-r--r--src/test/regress/sql/rules.sql13
9 files changed, 117 insertions, 13 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 07b6e0e92ae..378544009fc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -56,6 +56,7 @@
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
+#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
@@ -2063,11 +2064,15 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
quote_identifier(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 guc.c, 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 (GetConfigOptionFlags(configitem, true) & GUC_LIST_QUOTE)
appendStringInfoString(&buf, pos);
else
simple_quote_literal(&buf, pos);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index f2f8310f5b7..85e78f0deb1 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -756,8 +756,8 @@ static const unit_conversion time_unit_conversion_table[] =
*
* 6. Don't forget to document the option (at least in config.sgml).
*
- * 7. If it's a new GUC_LIST option you must edit pg_dumpall.c to ensure
- * it is not single quoted at dump time.
+ * 7. If it's a new GUC_LIST_QUOTE option, you must add it to
+ * variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c.
*/
@@ -6512,6 +6512,30 @@ GetConfigOptionResetString(const char *name)
return NULL;
}
+/*
+ * Get the GUC flags associated with the given option.
+ *
+ * If the option doesn't exist, return 0 if missing_ok is true,
+ * otherwise throw an ereport and don't return.
+ */
+int
+GetConfigOptionFlags(const char *name, bool missing_ok)
+{
+ struct config_generic *record;
+
+ record = find_option(name, false, WARNING);
+ if (record == NULL)
+ {
+ if (missing_ok)
+ return 0;
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("unrecognized configuration parameter \"%s\"",
+ name)));
+ }
+ return record->flags;
+}
+
/*
* flatten_set_variable_args
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index a4c91e63a0b..0bb4150eb5c 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -1521,3 +1521,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 40584a66efe..6b51b68d95c 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -109,4 +109,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 dbe2b6560a4..c4005a4cc3c 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -10688,11 +10688,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 bf2937e82db..88cf92e09a7 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -1623,10 +1623,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);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 368375925a4..ec1da5e4353 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -348,6 +348,7 @@ extern void EmitWarningsOnPlaceholders(const char *className);
extern const char *GetConfigOption(const char *name, bool missing_ok,
bool restrict_superuser);
extern const char *GetConfigOptionResetString(const char *name);
+extern int GetConfigOptionFlags(const char *name, bool missing_ok);
extern void ProcessConfigFile(GucContext context);
extern void InitializeGUCOptions(void);
extern bool SelectConfigFiles(const char *userDoption, const char *progname);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index bc400cb80c0..63094c03b99 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -3018,3 +3018,30 @@ SELECT * FROM hat_data WHERE hat_name IN ('h8', 'h9', 'h7') ORDER BY hat_name;
DROP RULE hat_upsert ON hats;
drop table hats;
drop table hat_data;
+-- test for pg_get_functiondef properly regurgitating SET parameters
+-- Note that the function is kept around to stress pg_dump.
+CREATE FUNCTION func_with_set_params() RETURNS integer
+ AS 'select 1;'
+ LANGUAGE SQL
+ SET search_path TO PG_CATALOG
+ SET extra_float_digits TO 2
+ SET work_mem TO '4MB'
+ SET datestyle to iso, mdy
+ SET local_preload_libraries TO "Mixed/Case", 'c:/"a"/path'
+ IMMUTABLE STRICT;
+SELECT pg_get_functiondef('func_with_set_params()'::regprocedure);
+ pg_get_functiondef
+---------------------------------------------------------------
+ CREATE OR REPLACE FUNCTION public.func_with_set_params() +
+ RETURNS integer +
+ LANGUAGE sql +
+ IMMUTABLE STRICT +
+ SET search_path TO pg_catalog +
+ SET extra_float_digits TO '2' +
+ SET work_mem TO '4MB' +
+ SET "DateStyle" TO 'iso, mdy' +
+ SET local_preload_libraries TO "Mixed/Case", "c:/""a""/path"+
+ AS $function$select 1;$function$ +
+
+(1 row)
+
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index eb4176d1785..1d43c8b2058 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -1144,3 +1144,16 @@ DROP RULE hat_upsert ON hats;
drop table hats;
drop table hat_data;
+
+-- test for pg_get_functiondef properly regurgitating SET parameters
+-- Note that the function is kept around to stress pg_dump.
+CREATE FUNCTION func_with_set_params() RETURNS integer
+ AS 'select 1;'
+ LANGUAGE SQL
+ SET search_path TO PG_CATALOG
+ SET extra_float_digits TO 2
+ SET work_mem TO '4MB'
+ SET datestyle to iso, mdy
+ SET local_preload_libraries TO "Mixed/Case", 'c:/"a"/path'
+ IMMUTABLE STRICT;
+SELECT pg_get_functiondef('func_with_set_params()'::regprocedure);