From b4c53c20bf2a83006a255a5783c334b93a8291a7 Mon Sep 17 00:00:00 2001
From: shihao zhong <zhong950419@gmail.com>
Date: Fri, 30 Oct 2026 23:31:36 -0400
Subject: [PATCH v1 1/2] Move makeAlterConfigCommand() to fe_utils

pg_upgrade wants to build the same ALTER ... SET commands that pg_dump
and pg_dumpall emit, so that it can try them against the new cluster
before the upgrade starts.  Move makeAlterConfigCommand() and its helper
variable_is_guc_list_quote() from pg_dump's dumputils.c to
fe_utils/string_utils.c, next to SplitGUCList(), which they already use.
No functional change.
---
 src/backend/utils/misc/guc_parameters.dat |   2 +-
 src/bin/pg_dump/dumputils.c               | 106 ----------------------
 src/bin/pg_dump/dumputils.h               |   6 --
 src/fe_utils/string_utils.c               | 106 ++++++++++++++++++++++
 src/include/fe_utils/string_utils.h       |   5 +
 5 files changed, 112 insertions(+), 113 deletions(-)

diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index 1d0d73074a1..5c7566ffc9a 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -31,7 +31,7 @@
 # 6. Don't forget to document the option (at least in config.sgml).
 #
 # 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.
+#    variable_is_guc_list_quote() in src/fe_utils/string_utils.c.
 
 # This setting itself cannot be set by ALTER SYSTEM to avoid an
 # operator turning this setting off by using ALTER SYSTEM, without a
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 1847782998e..701641f0864 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -716,112 +716,6 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
 }
 
 
-/*
- * 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_parameters.dat.
- */
-bool
-variable_is_guc_list_quote(const char *name)
-{
-	if (pg_strcasecmp(name, "local_preload_libraries") == 0 ||
-		pg_strcasecmp(name, "oauth_validator_libraries") == 0 ||
-		pg_strcasecmp(name, "output_plugin_libraries") == 0 ||
-		pg_strcasecmp(name, "search_path") == 0 ||
-		pg_strcasecmp(name, "session_preload_libraries") == 0 ||
-		pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
-		pg_strcasecmp(name, "temp_tablespaces") == 0 ||
-		pg_strcasecmp(name, "unix_socket_directories") == 0)
-		return true;
-	else
-		return false;
-}
-
-/*
- * Helper function for dumping "ALTER DATABASE/ROLE SET ..." commands.
- *
- * Parse the contents of configitem (a "name=value" string), wrap it in
- * a complete ALTER command, and append it to buf.
- *
- * type is DATABASE or ROLE, and name is the name of the database or role.
- * If we need an "IN" clause, type2 and name2 similarly define what to put
- * there; otherwise they should be NULL.
- * conn is used only to determine string-literal quoting conventions.
- */
-void
-makeAlterConfigCommand(PGconn *conn, const char *configitem,
-					   const char *type, const char *name,
-					   const char *type2, const char *name2,
-					   PQExpBuffer buf)
-{
-	char	   *mine;
-	char	   *pos;
-
-	/* Parse the configitem.  If we can't find an "=", silently do nothing. */
-	mine = pg_strdup(configitem);
-	pos = strchr(mine, '=');
-	if (pos == NULL)
-	{
-		pg_free(mine);
-		return;
-	}
-	*pos++ = '\0';
-
-	/* Build the command, with suitable quoting for everything. */
-	appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
-	if (type2 != NULL && name2 != NULL)
-		appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
-	appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
-
-	/*
-	 * Variables that are marked GUC_LIST_QUOTE were already fully quoted by
-	 * flatten_set_variable_args() before they were put into the setconfig
-	 * array.  However, because the quoting rules used there aren't exactly
-	 * like SQL's, we have to break the list value apart and then quote the
-	 * elements as string literals.  (The elements may be double-quoted as-is,
-	 * but we can't just feed them to the SQL parser; it would do the wrong
-	 * thing with elements that are zero-length or longer than NAMEDATALEN.)
-	 * Also, we need a special case for empty lists.
-	 *
-	 * 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 that; this makes it unsafe to
-	 * use GUC_LIST_QUOTE for extension variables.
-	 */
-	if (variable_is_guc_list_quote(mine))
-	{
-		char	  **namelist;
-		char	  **nameptr;
-
-		/* Parse string into list of identifiers */
-		/* this shouldn't fail really */
-		if (SplitGUCList(pos, ',', &namelist))
-		{
-			/* Special case: represent an empty list as NULL */
-			if (*namelist == NULL)
-				appendPQExpBufferStr(buf, "NULL");
-			for (nameptr = namelist; *nameptr; nameptr++)
-			{
-				if (nameptr != namelist)
-					appendPQExpBufferStr(buf, ", ");
-				appendStringLiteralConn(buf, *nameptr, conn);
-			}
-		}
-		pg_free(namelist);
-	}
-	else
-		appendStringLiteralConn(buf, pos, conn);
-
-	appendPQExpBufferStr(buf, ";\n");
-
-	pg_free(mine);
-}
-
 /*
  * create_or_open_dir
  *
diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h
index de84bea38be..6f037c6bc73 100644
--- a/src/bin/pg_dump/dumputils.h
+++ b/src/bin/pg_dump/dumputils.h
@@ -55,12 +55,6 @@ extern void buildShSecLabelQuery(const char *catalog_name,
 extern void emitShSecLabels(PGconn *conn, PGresult *res,
 							PQExpBuffer buffer, const char *objtype, const char *objname);
 
-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,
-								   PQExpBuffer buf);
 extern void create_or_open_dir(const char *dirname);
 
 extern char *generate_restrict_key(void);
diff --git a/src/fe_utils/string_utils.c b/src/fe_utils/string_utils.c
index 78ffe6c890a..3d1fbef50b0 100644
--- a/src/fe_utils/string_utils.c
+++ b/src/fe_utils/string_utils.c
@@ -903,6 +903,112 @@ SplitGUCList(char *rawstring, char separator,
 	return true;
 }
 
+/*
+ * 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_parameters.dat.
+ */
+bool
+variable_is_guc_list_quote(const char *name)
+{
+	if (pg_strcasecmp(name, "local_preload_libraries") == 0 ||
+		pg_strcasecmp(name, "oauth_validator_libraries") == 0 ||
+		pg_strcasecmp(name, "output_plugin_libraries") == 0 ||
+		pg_strcasecmp(name, "search_path") == 0 ||
+		pg_strcasecmp(name, "session_preload_libraries") == 0 ||
+		pg_strcasecmp(name, "shared_preload_libraries") == 0 ||
+		pg_strcasecmp(name, "temp_tablespaces") == 0 ||
+		pg_strcasecmp(name, "unix_socket_directories") == 0)
+		return true;
+	else
+		return false;
+}
+
+/*
+ * Helper function for dumping "ALTER DATABASE/ROLE SET ..." commands.
+ *
+ * Parse the contents of configitem (a "name=value" string), wrap it in
+ * a complete ALTER command, and append it to buf.
+ *
+ * type is DATABASE or ROLE, and name is the name of the database or role.
+ * If we need an "IN" clause, type2 and name2 similarly define what to put
+ * there; otherwise they should be NULL.
+ * conn is used only to determine string-literal quoting conventions.
+ */
+void
+makeAlterConfigCommand(PGconn *conn, const char *configitem,
+					   const char *type, const char *name,
+					   const char *type2, const char *name2,
+					   PQExpBuffer buf)
+{
+	char	   *mine;
+	char	   *pos;
+
+	/* Parse the configitem.  If we can't find an "=", silently do nothing. */
+	mine = pg_strdup(configitem);
+	pos = strchr(mine, '=');
+	if (pos == NULL)
+	{
+		pg_free(mine);
+		return;
+	}
+	*pos++ = '\0';
+
+	/* Build the command, with suitable quoting for everything. */
+	appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
+	if (type2 != NULL && name2 != NULL)
+		appendPQExpBuffer(buf, "IN %s %s ", type2, fmtId(name2));
+	appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
+
+	/*
+	 * Variables that are marked GUC_LIST_QUOTE were already fully quoted by
+	 * flatten_set_variable_args() before they were put into the setconfig
+	 * array.  However, because the quoting rules used there aren't exactly
+	 * like SQL's, we have to break the list value apart and then quote the
+	 * elements as string literals.  (The elements may be double-quoted as-is,
+	 * but we can't just feed them to the SQL parser; it would do the wrong
+	 * thing with elements that are zero-length or longer than NAMEDATALEN.)
+	 * Also, we need a special case for empty lists.
+	 *
+	 * 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 that; this makes it unsafe to
+	 * use GUC_LIST_QUOTE for extension variables.
+	 */
+	if (variable_is_guc_list_quote(mine))
+	{
+		char	  **namelist;
+		char	  **nameptr;
+
+		/* Parse string into list of identifiers */
+		/* this shouldn't fail really */
+		if (SplitGUCList(pos, ',', &namelist))
+		{
+			/* Special case: represent an empty list as NULL */
+			if (*namelist == NULL)
+				appendPQExpBufferStr(buf, "NULL");
+			for (nameptr = namelist; *nameptr; nameptr++)
+			{
+				if (nameptr != namelist)
+					appendPQExpBufferStr(buf, ", ");
+				appendStringLiteralConn(buf, *nameptr, conn);
+			}
+		}
+		pg_free(namelist);
+	}
+	else
+		appendStringLiteralConn(buf, pos, conn);
+
+	appendPQExpBufferStr(buf, ";\n");
+
+	pg_free(mine);
+}
+
 
 /*
  * Deconstruct the text representation of a 1-dimensional Postgres array
diff --git a/src/include/fe_utils/string_utils.h b/src/include/fe_utils/string_utils.h
index 3e455c8a415..2344724bf7b 100644
--- a/src/include/fe_utils/string_utils.h
+++ b/src/include/fe_utils/string_utils.h
@@ -49,6 +49,11 @@ extern void appendConnStrVal(PQExpBuffer buf, const char *str);
 extern void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname);
 
 extern bool SplitGUCList(char *rawstring, char separator, char ***namelist);
+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,
+								   PQExpBuffer buf);
 
 extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
 extern void appendPGArray(PQExpBuffer buffer, const char *value);
-- 
2.37.1 (Apple Git-137.1)

