From b4c53c20bf2a83006a255a5783c334b93a8291a7 Mon Sep 17 00:00:00 2001 From: shihao zhong 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)