1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-17 17:02:08 +03:00

pg_upgrade: Add --set-char-signedness to set the default char signedness of new cluster.

This change adds a new option --set-char-signedness to pg_upgrade. It
enables user to set arbitrary signedness during pg_upgrade. This helps
cases where user who knew they copied the v17 source cluster from
x86 (signedness=true) to ARM (signedness=false) can pg_upgrade
properly without the prerequisite of acquiring an x86 VM.

Reviewed-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/CB11ADBC-0C3F-4FE0-A678-666EE80CBB07%40amazon.com
This commit is contained in:
Masahiko Sawada
2025-02-21 10:23:39 -08:00
parent a8238f87f9
commit 1aab680591
6 changed files with 105 additions and 2 deletions

View File

@ -285,6 +285,59 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--set-char-signedness=</option><replaceable>option</replaceable></term>
<listitem>
<para>
Manually set the default char signedness of new clusters. Possible values
are <literal>signed</literal> and <literal>unsigned</literal>.
</para>
<para>
In the C language, the default signedness of the <type>char</type> type
(when not explicitly specified) varies across platforms. For example,
<type>char</type> defaults to <type>signed char</type> on x86 CPUs but
to <type>unsigned char</type> on ARM CPUs.
</para>
<para>
Starting from <productname>PostgreSQL</productname> 18, database clusters
maintain their own default char signedness setting, which can be used to
ensure consistent behavior across platforms with different default char
signedness. By default, <application>pg_upgrade</application> preserves
the char signedness setting when upgrading from an existing cluster.
However, when upgrading from <productname>PostgreSQL</productname> 17 or
earlier, <application>pg_upgrade</application> adopts the char signedness
of the platform on which it was built.
</para>
<para>
This option allows you to explicitly set the default char signedness for
the new cluster, overriding any inherited values. There are two specific
scenarios where this option is relevant:
<itemizedlist>
<listitem>
<para>
If you are planning to migrate to a different platform after the upgrade,
you should not use this option. The default behavior is right in this case.
Instead, perform the upgrade on the original platform without this flag,
and then migrate the cluster afterward. This is the recommended and safest
approach.
</para>
</listitem>
<listitem>
<para>
If you have already migrated the cluster to a platform with different
char signedness (for example, from an x86-based system to an ARM-based
system), you should use this option to specify the signedness matching
the original platform's default char signedness. Additionally, it's
essential not to modify any data files between migrating data files and
running <command>pg_upgrade</command>. <command>pg_upgrade</command>
should be the first operation that starts the cluster on the new platform.
</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-?</option></term> <term><option>-?</option></term>
<term><option>--help</option></term> <term><option>--help</option></term>

View File

@ -838,6 +838,18 @@ check_cluster_versions(void)
GET_MAJOR_VERSION(new_cluster.bin_version)) GET_MAJOR_VERSION(new_cluster.bin_version))
pg_fatal("New cluster data and binary directories are from different major versions."); pg_fatal("New cluster data and binary directories are from different major versions.");
/*
* Since from version 18, newly created database clusters always have
* 'signed' default char-signedness, it makes less sense to use
* --set-char-signedness option for upgrading from version 18 or later.
* Users who want to change the default char signedness of the new
* cluster, they can use pg_resetwal manually before the upgrade.
*/
if (GET_MAJOR_VERSION(old_cluster.major_version) >= 1800 &&
user_opts.char_signedness != -1)
pg_fatal("%s option cannot be used to upgrade from PostgreSQL %s and later.",
"--set-char-signedness", "18");
check_ok(); check_ok();
} }

View File

@ -61,6 +61,7 @@ parseCommandLine(int argc, char *argv[])
{"copy-file-range", no_argument, NULL, 3}, {"copy-file-range", no_argument, NULL, 3},
{"sync-method", required_argument, NULL, 4}, {"sync-method", required_argument, NULL, 4},
{"no-statistics", no_argument, NULL, 5}, {"no-statistics", no_argument, NULL, 5},
{"set-char-signedness", required_argument, NULL, 6},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
@ -72,6 +73,7 @@ parseCommandLine(int argc, char *argv[])
user_opts.do_sync = true; user_opts.do_sync = true;
user_opts.transfer_mode = TRANSFER_MODE_COPY; user_opts.transfer_mode = TRANSFER_MODE_COPY;
user_opts.do_statistics = true; user_opts.do_statistics = true;
user_opts.char_signedness = -1;
os_info.progname = get_progname(argv[0]); os_info.progname = get_progname(argv[0]);
@ -218,6 +220,14 @@ parseCommandLine(int argc, char *argv[])
user_opts.do_statistics = false; user_opts.do_statistics = false;
break; break;
case 6:
if (pg_strcasecmp(optarg, "signed") == 0)
user_opts.char_signedness = 1;
else if (pg_strcasecmp(optarg, "unsigned") == 0)
user_opts.char_signedness = 0;
else
pg_fatal("invalid argument for option %s", "--set-char-signedness");
break;
default: default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
os_info.progname); os_info.progname);
@ -313,6 +323,8 @@ usage(void)
printf(_(" --copy copy files to new cluster (default)\n")); printf(_(" --copy copy files to new cluster (default)\n"));
printf(_(" --copy-file-range copy files to new cluster with copy_file_range\n")); printf(_(" --copy-file-range copy files to new cluster with copy_file_range\n"));
printf(_(" --no-statistics do not import statistics from old cluster\n")); printf(_(" --no-statistics do not import statistics from old cluster\n"));
printf(_(" --set-char-signedness=OPTION set new cluster char signedness to \"signed\" or\n"));
printf(_(" \"unsigned\"\n"));
printf(_(" --sync-method=METHOD set method for syncing files to disk\n")); printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
printf(_(" -?, --help show this help, then exit\n")); printf(_(" -?, --help show this help, then exit\n"));
printf(_("\n" printf(_("\n"

View File

@ -399,8 +399,14 @@ set_new_cluster_char_signedness(void)
{ {
bool new_char_signedness; bool new_char_signedness;
/* Inherit the source database's signedness */ /*
new_char_signedness = old_cluster.controldata.default_char_signedness; * Use the specified char signedness if specified. Otherwise we inherit
* the source database's signedness.
*/
if (user_opts.char_signedness != -1)
new_char_signedness = (user_opts.char_signedness == 1);
else
new_char_signedness = old_cluster.controldata.default_char_signedness;
/* Change the char signedness of the new cluster, if necessary */ /* Change the char signedness of the new cluster, if necessary */
if (new_cluster.controldata.default_char_signedness != new_char_signedness) if (new_cluster.controldata.default_char_signedness != new_char_signedness)

View File

@ -334,6 +334,9 @@ typedef struct
char *socketdir; /* directory to use for Unix sockets */ char *socketdir; /* directory to use for Unix sockets */
char *sync_method; char *sync_method;
bool do_statistics; /* carry over statistics from old cluster */ bool do_statistics; /* carry over statistics from old cluster */
int char_signedness; /* default char signedness: -1 for initial
* value, 1 for "signed" and 0 for
* "unsigned" */
} UserOpts; } UserOpts;
typedef struct typedef struct

View File

@ -40,6 +40,23 @@ command_like(
qr/Default char data signedness:\s+unsigned/, qr/Default char data signedness:\s+unsigned/,
'updated default char signedness is unsigned in control file'); 'updated default char signedness is unsigned in control file');
# Cannot use --set-char-signedness option for upgrading from v18+
command_fails(
[
'pg_upgrade', '--no-sync',
'-d', $old->data_dir,
'-D', $new->data_dir,
'-b', $old->config_data('--bindir'),
'-B', $new->config_data('--bindir'),
'-s', $new->host,
'-p', $old->port,
'-P', $new->port,
'-set-char-signedness', 'signed',
$mode
],
'--set-char-signedness option cannot be used for upgrading from v18 or later'
);
# pg_upgrade should be successful. # pg_upgrade should be successful.
command_ok( command_ok(
[ [