diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 2cd54ec33fef6e6a9094b82d9b41977b2134e261..b0559ca5bcd2c71d32272a687b1eebcfec48a193 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -61,6 +61,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"
@@ -2597,11 +2598,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 7a7ac479c14fe7f87a9a07e0ba1dbf80ea15b04c..398680ab12cc6c99c719cf04a7957c0f7504f9fe 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -796,8 +796,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.
  */
 
 
@@ -6859,6 +6859,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 7f5bb1343e01617e52475e0a2c70cd662c041ab3..875545f69954c02db82643c79810caa4c758b618 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -850,6 +850,29 @@ buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
 	}
 }
 
+/*
+ * 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;
+}
+
 /*
  * Helper function for dumping "ALTER DATABASE/ROLE SET ..." commands.
  *
@@ -887,11 +910,15 @@ makeAlterConfigCommand(PGconn *conn, const char *configitem,
 	appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
 
 	/*
-	 * Some GUC variable names are 'LIST' type and hence must not be quoted.
-	 * XXX this list is incomplete ...
+	 * 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);
 	else
 		appendStringLiteralConn(buf, pos, conn);
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index a9e26ae72a8d2f8ce96cf0c7987c6c0c4784f1b2..7bd3e1d5eb05c8d61e1cb82b59e804b250100f99 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -56,6 +56,8 @@ extern void buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery,
 				const char *acl_column, const char *acl_owner,
 				const char *obj_kind, bool binary_upgrade);
 
+extern bool variable_is_guc_list_quote(const char *name);
+
 extern void makeAlterConfigCommand(PGconn *conn, const char *configitem,
 					   const char *type, const char *name,
 					   const char *type2, const char *name2,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 566cbf2cdae273147cb0fabca2cdb776e6eb5a97..b8d65a9ee39c212aa7ad8e88fde8092cb42f0170 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -11877,11 +11877,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/include/utils/guc.h b/src/include/utils/guc.h
index 2e03640c0b055f6c13b6d343d1108739ea845f65..3d13a33b94e4ff0f728b1d48642e56860a9583b7 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -349,6 +349,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 5e0597e091a9eb0e4e17cda44d0753a380ab49cd..5149b72fe9110cb5f823ad888c7e8ac2895be505 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -3149,6 +3149,33 @@ 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)
+
 -- tests for pg_get_*def with invalid objects
 SELECT pg_get_constraintdef(0);
  pg_get_constraintdef 
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index 60212129a2748cecfb9dc0d0f5f61fb7c7146467..a82f52d154849f2de14f23a2924171d02a8aad6a 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -1155,6 +1155,19 @@ 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);
+
 -- tests for pg_get_*def with invalid objects
 SELECT pg_get_constraintdef(0);
 SELECT pg_get_functiondef(0);