From 49b24b4c67b43765d06ff699cd481c2abe094c8d Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Wed, 2 Oct 2024 15:11:23 -0700 Subject: [PATCH v2 3/5] pg_upgrade: Inherit default char signedness from old cluster. Commit XXX introduced the 'default_char_signedness' field in controlfile. Newly created database clusters always set this field to 'signed'. This change ensures that pg_upgrade updates the 'default_char_signedness' to 'unsigned' if the source database cluster has signedness=false. For source clusters from v17 or earlier, which lack the 'default_char_signedness' information, pg_upgrade assumes the source cluster was initialized on the same platform where pg_upgrae is running. It then sets the 'default_char_signedness' value according to the current platform's default character signedness. Reviewed-by: Discussion: https://postgr.es/m/CB11ADBC-0C3F-4FE0-A678-666EE80CBB07%40amazon.com --- src/bin/pg_upgrade/controldata.c | 26 ++++++++++++++++++++- src/bin/pg_upgrade/pg_upgrade.c | 40 ++++++++++++++++++++++++++++++++ src/bin/pg_upgrade/pg_upgrade.h | 1 + 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c index 854c6887a2..6c63b25647 100644 --- a/src/bin/pg_upgrade/controldata.c +++ b/src/bin/pg_upgrade/controldata.c @@ -62,6 +62,7 @@ get_control_data(ClusterInfo *cluster) bool got_date_is_int = false; bool got_data_checksum_version = false; bool got_cluster_state = false; + bool got_default_char_signedness = false; char *lc_collate = NULL; char *lc_ctype = NULL; char *lc_monetary = NULL; @@ -206,6 +207,13 @@ get_control_data(ClusterInfo *cluster) got_data_checksum_version = true; } + /* Only in <= 17 */ + if (GET_MAJOR_VERSION(cluster->major_version) <= 1700) + { + cluster->controldata.default_char_signedness = true; + got_default_char_signedness = true; + } + /* we have the result of cmd in "output". so parse it line by line now */ while (fgets(bufin, sizeof(bufin), output)) { @@ -501,6 +509,17 @@ get_control_data(ClusterInfo *cluster) cluster->controldata.data_checksum_version = str2uint(p); got_data_checksum_version = true; } + else if ((p = strstr(bufin, "char data signedness:")) != NULL) + { + p = strchr(p, ':'); + + if (p == NULL || strlen(p) <= 1) + pg_fatal("%d: controldata retrieval problem", __LINE__); + + p++; /* remove ':' char */ + cluster->controldata.default_char_signedness = strstr(p, "signed") != NULL; + got_default_char_signedness = true; + } } rc = pclose(output); @@ -572,7 +591,8 @@ get_control_data(ClusterInfo *cluster) !got_index || !got_toast || (!got_large_object && cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) || - !got_date_is_int || !got_data_checksum_version) + !got_date_is_int || !got_data_checksum_version || + !got_default_char_signedness) { if (cluster == &old_cluster) pg_log(PG_REPORT, @@ -641,6 +661,10 @@ get_control_data(ClusterInfo *cluster) if (!got_data_checksum_version) pg_log(PG_REPORT, " data checksum version"); + /* value added in Postgres 18 */ + if (!got_default_char_signedness) + pg_log(PG_REPORT, " default char signedness"); + pg_fatal("Cannot continue without required control information, terminating"); } } diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 663235816f..68cbac46ce 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -39,6 +39,7 @@ #include "postgres_fe.h" #include +#include /* for CHAR_MIN */ #include "catalog/pg_class_d.h" #include "common/file_perm.h" @@ -54,6 +55,7 @@ */ #define RESTORE_TRANSACTION_SIZE 1000 +static void set_new_cluster_char_signedness(void); static void set_locale_and_encoding(void); static void prepare_new_cluster(void); static void prepare_new_globals(void); @@ -154,6 +156,7 @@ main(int argc, char **argv) */ copy_xact_xlog_xid(); + set_new_cluster_char_signedness(); /* New now using xids of the old system */ @@ -388,6 +391,43 @@ setup(char *argv0) } } +static void +set_new_cluster_char_signedness(void) +{ + bool new_char_signedness; + + prep_status("Setting the default char signedness for new cluster"); + + if (GET_MAJOR_VERSION(old_cluster.major_version) <= 17) + { + /* + * Pre-v18 database clusters don't have the default char signedness + * information. We use the char signedness of the platform where + * pg_upgrade was built. + */ +#if CHAR_MIN != 0 + new_char_signedness = true; +#else + new_char_signedness = false; +#endif + } + else + { + /* Set the source database signedness */ + new_char_signedness = old_cluster.controldata.default_char_signedness; + } + + /* Change the char signedness of the new cluster, if necessary */ + if (new_cluster.controldata.default_char_signedness != new_char_signedness) + { + exec_prog(UTILITY_LOG_FILE, NULL, true, true, + "\"%s/pg_resetwal\" --char-signedness %s \"%s\"", + new_cluster.bindir, + new_char_signedness ? "signed" : "unsigned", + new_cluster.pgdata); + check_ok(); + } +} /* * Copy locale and encoding information into the new cluster's template0. diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 53f693c2d4..a2cbf2d6d9 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -245,6 +245,7 @@ typedef struct bool date_is_int; bool float8_pass_by_value; uint32 data_checksum_version; + bool default_char_signedness; } ControlData; /* -- 2.39.3