From 55d365dd4e1b33e55834b00007b8b580f2db0686 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Wed, 2 Oct 2024 15:08:26 -0700
Subject: [PATCH v5 2/5] pg_resetwal: Add --char-signedness option to change
 the default char signedness.

With the newly added option --char-signedness, pg_resetwal updates the
default char signedness flag in the controlfile. This option is
primarily intended for an upcoming patch that pg_upgrade supports
preserving the default char signedness during upgrades, and is not
meant for manual operation.

Reviewed-by: Noah Misch
Discussion: https://postgr.es/m/CB11ADBC-0C3F-4FE0-A678-666EE80CBB07%40amazon.com
---
 doc/src/sgml/ref/pg_resetwal.sgml  | 19 +++++++++++++++++++
 src/bin/pg_resetwal/pg_resetwal.c  | 25 +++++++++++++++++++++++++
 src/bin/pg_resetwal/t/001_basic.pl |  6 ++++++
 3 files changed, 50 insertions(+)

diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml
index cf9c7e70f27..dd011d246c1 100644
--- a/doc/src/sgml/ref/pg_resetwal.sgml
+++ b/doc/src/sgml/ref/pg_resetwal.sgml
@@ -171,6 +171,25 @@ PostgreSQL documentation
   </para>
 
   <variablelist>
+   <varlistentry>
+    <term><option>--char-signedness=<replaceable class="parameter">option</replaceable></option></term>
+    <listitem>
+     <para>
+      Manually set the default char signedness. Possible values are
+      <literal>signed</literal> and <literal>unsigned</literal>.
+     </para>
+     <para>
+      For a database cluster that <command>pg_upgrade</command> upgraded from
+      a <productname>PostgreSQL</productname> version before 18, the safe
+      value would be the default <type>char</type> signedness of the platform
+      that ran the cluster before that upgrade. For all other
+      clusters, <literal>signed</literal> would be the safe value. However,
+      this option is exclusively for use with <command>pg_upgrade</command>
+      and should not normally be used manually.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><option>-c <replaceable class="parameter">xid</replaceable>,<replaceable class="parameter">xid</replaceable></option></term>
     <term><option>--commit-timestamp-ids=<replaceable class="parameter">xid</replaceable>,<replaceable class="parameter">xid</replaceable></option></term>
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index ed73607a46f..31bc0abff16 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -75,6 +75,7 @@ static TimeLineID minXlogTli = 0;
 static XLogSegNo minXlogSegNo = 0;
 static int	WalSegSz;
 static int	set_wal_segsize;
+static int	set_char_signedness = -1;
 
 static void CheckDataVersion(void);
 static bool read_controlfile(void);
@@ -106,6 +107,7 @@ main(int argc, char *argv[])
 		{"oldest-transaction-id", required_argument, NULL, 'u'},
 		{"next-transaction-id", required_argument, NULL, 'x'},
 		{"wal-segsize", required_argument, NULL, 1},
+		{"char-signedness", required_argument, NULL, 2},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -302,6 +304,23 @@ main(int argc, char *argv[])
 					break;
 				}
 
+			case 2:
+				{
+					errno = 0;
+
+					if (pg_strcasecmp(optarg, "signed") == 0)
+						set_char_signedness = 1;
+					else if (pg_strcasecmp(optarg, "unsigned") == 0)
+						set_char_signedness = 0;
+					else
+					{
+						pg_log_error("invalid argument for option %s", "--char-signedness");
+						pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+						exit(1);
+					}
+					break;
+				}
+
 			default:
 				/* getopt_long already emitted a complaint */
 				pg_log_error_hint("Try \"%s --help\" for more information.", progname);
@@ -456,6 +475,9 @@ main(int argc, char *argv[])
 	if (set_wal_segsize != 0)
 		ControlFile.xlog_seg_size = WalSegSz;
 
+	if (set_char_signedness != -1)
+		ControlFile.default_char_signedness = (set_char_signedness == 1);
+
 	if (minXlogSegNo > newXlogSegNo)
 		newXlogSegNo = minXlogSegNo;
 
@@ -779,6 +801,8 @@ PrintControlValues(bool guessed)
 		   (ControlFile.float8ByVal ? _("by value") : _("by reference")));
 	printf(_("Data page checksum version:           %u\n"),
 		   ControlFile.data_checksum_version);
+	printf(_("Default char data signedness:         %s\n"),
+		   (ControlFile.default_char_signedness ? _("signed") : _("unsigned")));
 }
 
 
@@ -1188,6 +1212,7 @@ usage(void)
 	printf(_("  -O, --multixact-offset=OFFSET    set next multitransaction offset\n"));
 	printf(_("  -u, --oldest-transaction-id=XID  set oldest transaction ID\n"));
 	printf(_("  -x, --next-transaction-id=XID    set next transaction ID\n"));
+	printf(_("      --char-signedness=OPTION     set char signedness to \"signed\"  or \"unsigned\"\n"));
 	printf(_("      --wal-segsize=SIZE           size of WAL segments, in megabytes\n"));
 
 	printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
diff --git a/src/bin/pg_resetwal/t/001_basic.pl b/src/bin/pg_resetwal/t/001_basic.pl
index 323cd483cf3..d6bbbd0ceda 100644
--- a/src/bin/pg_resetwal/t/001_basic.pl
+++ b/src/bin/pg_resetwal/t/001_basic.pl
@@ -173,6 +173,12 @@ command_fails_like(
 	qr/must be greater than/,
 	'fails with -x value too small');
 
+# --char-signedness
+command_fails_like(
+	[ 'pg_resetwal', '--char-signedness', 'foo', $node->data_dir ],
+	qr/error: invalid argument for option --char-signedness/,
+	'fails with incorrect --char-signedness option');
+
 # run with control override options
 
 my $out = (run_command([ 'pg_resetwal', '--dry-run', $node->data_dir ]))[0];
-- 
2.43.5

