Skip to content

Commit 1aab680

Browse files
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
1 parent a8238f8 commit 1aab680

File tree

6 files changed

+105
-2
lines changed

6 files changed

+105
-2
lines changed

doc/src/sgml/ref/pgupgrade.sgml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,59 @@ PostgreSQL documentation
285285
</listitem>
286286
</varlistentry>
287287

288+
<varlistentry>
289+
<term><option>--set-char-signedness=</option><replaceable>option</replaceable></term>
290+
<listitem>
291+
<para>
292+
Manually set the default char signedness of new clusters. Possible values
293+
are <literal>signed</literal> and <literal>unsigned</literal>.
294+
</para>
295+
<para>
296+
In the C language, the default signedness of the <type>char</type> type
297+
(when not explicitly specified) varies across platforms. For example,
298+
<type>char</type> defaults to <type>signed char</type> on x86 CPUs but
299+
to <type>unsigned char</type> on ARM CPUs.
300+
</para>
301+
<para>
302+
Starting from <productname>PostgreSQL</productname> 18, database clusters
303+
maintain their own default char signedness setting, which can be used to
304+
ensure consistent behavior across platforms with different default char
305+
signedness. By default, <application>pg_upgrade</application> preserves
306+
the char signedness setting when upgrading from an existing cluster.
307+
However, when upgrading from <productname>PostgreSQL</productname> 17 or
308+
earlier, <application>pg_upgrade</application> adopts the char signedness
309+
of the platform on which it was built.
310+
</para>
311+
<para>
312+
This option allows you to explicitly set the default char signedness for
313+
the new cluster, overriding any inherited values. There are two specific
314+
scenarios where this option is relevant:
315+
<itemizedlist>
316+
<listitem>
317+
<para>
318+
If you are planning to migrate to a different platform after the upgrade,
319+
you should not use this option. The default behavior is right in this case.
320+
Instead, perform the upgrade on the original platform without this flag,
321+
and then migrate the cluster afterward. This is the recommended and safest
322+
approach.
323+
</para>
324+
</listitem>
325+
<listitem>
326+
<para>
327+
If you have already migrated the cluster to a platform with different
328+
char signedness (for example, from an x86-based system to an ARM-based
329+
system), you should use this option to specify the signedness matching
330+
the original platform's default char signedness. Additionally, it's
331+
essential not to modify any data files between migrating data files and
332+
running <command>pg_upgrade</command>. <command>pg_upgrade</command>
333+
should be the first operation that starts the cluster on the new platform.
334+
</para>
335+
</listitem>
336+
</itemizedlist>
337+
</para>
338+
</listitem>
339+
</varlistentry>
340+
288341
<varlistentry>
289342
<term><option>-?</option></term>
290343
<term><option>--help</option></term>

src/bin/pg_upgrade/check.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,18 @@ check_cluster_versions(void)
838838
GET_MAJOR_VERSION(new_cluster.bin_version))
839839
pg_fatal("New cluster data and binary directories are from different major versions.");
840840

841+
/*
842+
* Since from version 18, newly created database clusters always have
843+
* 'signed' default char-signedness, it makes less sense to use
844+
* --set-char-signedness option for upgrading from version 18 or later.
845+
* Users who want to change the default char signedness of the new
846+
* cluster, they can use pg_resetwal manually before the upgrade.
847+
*/
848+
if (GET_MAJOR_VERSION(old_cluster.major_version) >= 1800 &&
849+
user_opts.char_signedness != -1)
850+
pg_fatal("%s option cannot be used to upgrade from PostgreSQL %s and later.",
851+
"--set-char-signedness", "18");
852+
841853
check_ok();
842854
}
843855

src/bin/pg_upgrade/option.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ parseCommandLine(int argc, char *argv[])
6161
{"copy-file-range", no_argument, NULL, 3},
6262
{"sync-method", required_argument, NULL, 4},
6363
{"no-statistics", no_argument, NULL, 5},
64+
{"set-char-signedness", required_argument, NULL, 6},
6465

6566
{NULL, 0, NULL, 0}
6667
};
@@ -72,6 +73,7 @@ parseCommandLine(int argc, char *argv[])
7273
user_opts.do_sync = true;
7374
user_opts.transfer_mode = TRANSFER_MODE_COPY;
7475
user_opts.do_statistics = true;
76+
user_opts.char_signedness = -1;
7577

7678
os_info.progname = get_progname(argv[0]);
7779

@@ -218,6 +220,14 @@ parseCommandLine(int argc, char *argv[])
218220
user_opts.do_statistics = false;
219221
break;
220222

223+
case 6:
224+
if (pg_strcasecmp(optarg, "signed") == 0)
225+
user_opts.char_signedness = 1;
226+
else if (pg_strcasecmp(optarg, "unsigned") == 0)
227+
user_opts.char_signedness = 0;
228+
else
229+
pg_fatal("invalid argument for option %s", "--set-char-signedness");
230+
break;
221231
default:
222232
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
223233
os_info.progname);
@@ -313,6 +323,8 @@ usage(void)
313323
printf(_(" --copy copy files to new cluster (default)\n"));
314324
printf(_(" --copy-file-range copy files to new cluster with copy_file_range\n"));
315325
printf(_(" --no-statistics do not import statistics from old cluster\n"));
326+
printf(_(" --set-char-signedness=OPTION set new cluster char signedness to \"signed\" or\n"));
327+
printf(_(" \"unsigned\"\n"));
316328
printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
317329
printf(_(" -?, --help show this help, then exit\n"));
318330
printf(_("\n"

src/bin/pg_upgrade/pg_upgrade.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,14 @@ set_new_cluster_char_signedness(void)
399399
{
400400
bool new_char_signedness;
401401

402-
/* Inherit the source database's signedness */
403-
new_char_signedness = old_cluster.controldata.default_char_signedness;
402+
/*
403+
* Use the specified char signedness if specified. Otherwise we inherit
404+
* the source database's signedness.
405+
*/
406+
if (user_opts.char_signedness != -1)
407+
new_char_signedness = (user_opts.char_signedness == 1);
408+
else
409+
new_char_signedness = old_cluster.controldata.default_char_signedness;
404410

405411
/* Change the char signedness of the new cluster, if necessary */
406412
if (new_cluster.controldata.default_char_signedness != new_char_signedness)

src/bin/pg_upgrade/pg_upgrade.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ typedef struct
334334
char *socketdir; /* directory to use for Unix sockets */
335335
char *sync_method;
336336
bool do_statistics; /* carry over statistics from old cluster */
337+
int char_signedness; /* default char signedness: -1 for initial
338+
* value, 1 for "signed" and 0 for
339+
* "unsigned" */
337340
} UserOpts;
338341

339342
typedef struct

src/bin/pg_upgrade/t/005_char_signedness.pl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,23 @@
4040
qr/Default char data signedness:\s+unsigned/,
4141
'updated default char signedness is unsigned in control file');
4242

43+
# Cannot use --set-char-signedness option for upgrading from v18+
44+
command_fails(
45+
[
46+
'pg_upgrade', '--no-sync',
47+
'-d', $old->data_dir,
48+
'-D', $new->data_dir,
49+
'-b', $old->config_data('--bindir'),
50+
'-B', $new->config_data('--bindir'),
51+
'-s', $new->host,
52+
'-p', $old->port,
53+
'-P', $new->port,
54+
'-set-char-signedness', 'signed',
55+
$mode
56+
],
57+
'--set-char-signedness option cannot be used for upgrading from v18 or later'
58+
);
59+
4360
# pg_upgrade should be successful.
4461
command_ok(
4562
[

0 commit comments

Comments
 (0)