From e19ab85f17cc74bfa8df57d249b85a83fd859ac7 Mon Sep 17 00:00:00 2001
From: Nikolay Samokhvalov <nik@postgres.ai>
Date: Wed, 4 Jun 2025 11:37:43 -0700
Subject: [PATCH] [PATCH] Add --system-identifier option to pg_resetwal

This patch adds a new --system-identifier option to pg_resetwal that allows
users to change the database cluster's system identifier. This feature is
useful in recovery scenarios where a restored cluster needs to be made
distinct from the original.

The system identifier change makes the cluster incompatible with existing
backups, standby servers, and replication setups, so the feature includes
appropriate safety checks and user warnings.
---
 doc/src/sgml/ref/pg_resetwal.sgml  | 23 +++++++++++++++++++++++
 src/bin/pg_resetwal/pg_resetwal.c  | 25 +++++++++++++++++++++++++
 src/bin/pg_resetwal/t/001_basic.pl | 29 +++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+)

diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml
index 2c019c2aac6..7ee1c2a08b2 100644
--- a/doc/src/sgml/ref/pg_resetwal.sgml
+++ b/doc/src/sgml/ref/pg_resetwal.sgml
@@ -356,6 +356,29 @@ PostgreSQL documentation
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><option>--system-identifier=<replaceable class="parameter">system_identifier</replaceable></option></term>
+    <listitem>
+     <para>
+      Manually set the database system identifier.
+     </para>
+
+     <para>
+      This option should only be used in recovery scenarios where you need
+      to make a restored cluster distinct from the original, or when cloning
+      a cluster for testing purposes. The value must be a positive 64-bit
+      integer and cannot be zero.
+     </para>
+
+     <warning>
+      <para>
+       Changing the system identifier will break compatibility with existing
+       backups and standby servers. Use this option with extreme caution.
+      </para>
+     </warning>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><option>--char-signedness=<replaceable class="parameter">option</replaceable></option></term>
     <listitem>
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index e876f35f38e..995f4b166b9 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -76,6 +76,7 @@ static XLogSegNo minXlogSegNo = 0;
 static int	WalSegSz;
 static int	set_wal_segsize;
 static int	set_char_signedness = -1;
+static uint64 set_sysid = 0;
 
 static void CheckDataVersion(void);
 static bool read_controlfile(void);
@@ -105,6 +106,7 @@ main(int argc, char *argv[])
 		{"next-oid", required_argument, NULL, 'o'},
 		{"multixact-offset", required_argument, NULL, 'O'},
 		{"oldest-transaction-id", required_argument, NULL, 'u'},
+		{"system-identifier", required_argument, NULL, 3},
 		{"next-transaction-id", required_argument, NULL, 'x'},
 		{"wal-segsize", required_argument, NULL, 1},
 		{"char-signedness", required_argument, NULL, 2},
@@ -321,6 +323,19 @@ main(int argc, char *argv[])
 					break;
 				}
 
+			case 3:
+				errno = 0;
+				set_sysid = strtou64(optarg, &endptr, 0);
+				if (endptr == optarg || *endptr != '\0' || errno != 0)
+				{
+					pg_log_error("invalid argument for option %s", "--system-identifier");
+					pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+					exit(1);
+				}
+				if (set_sysid == 0)
+					pg_fatal("system identifier must not be 0");
+				break;
+
 			default:
 				/* getopt_long already emitted a complaint */
 				pg_log_error_hint("Try \"%s --help\" for more information.", progname);
@@ -478,6 +493,9 @@ main(int argc, char *argv[])
 	if (set_char_signedness != -1)
 		ControlFile.default_char_signedness = (set_char_signedness == 1);
 
+	if (set_sysid != 0)
+		ControlFile.system_identifier = set_sysid;
+
 	if (minXlogSegNo > newXlogSegNo)
 		newXlogSegNo = minXlogSegNo;
 
@@ -875,6 +893,12 @@ PrintNewControlValues(void)
 		printf(_("Bytes per WAL segment:                %u\n"),
 			   ControlFile.xlog_seg_size);
 	}
+
+	if (set_sysid != 0)
+	{
+		printf(_("System identifier:                    " UINT64_FORMAT "\n"),
+			   ControlFile.system_identifier);
+	}
 }
 
 
@@ -1212,6 +1236,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(_("      --system-identifier=SYSID    set system identifier\n"));
 	printf(_("      --char-signedness=OPTION     set char signedness to \"signed\" or \"unsigned\"\n"));
 	printf(_("      --wal-segsize=SIZE           size of WAL segments, in megabytes\n"));
 
diff --git a/src/bin/pg_resetwal/t/001_basic.pl b/src/bin/pg_resetwal/t/001_basic.pl
index d6bbbd0ceda..c740759882c 100644
--- a/src/bin/pg_resetwal/t/001_basic.pl
+++ b/src/bin/pg_resetwal/t/001_basic.pl
@@ -179,6 +179,35 @@ command_fails_like(
 	qr/error: invalid argument for option --char-signedness/,
 	'fails with incorrect --char-signedness option');
 
+# --system-identifier
+command_fails_like(
+	[ 'pg_resetwal', '--system-identifier' => 'foo', $node->data_dir ],
+	qr/error: invalid argument for option --system-identifier/,
+	'fails with incorrect --system-identifier option');
+command_fails_like(
+	[ 'pg_resetwal', '--system-identifier' => '0', $node->data_dir ],
+	qr/system identifier must not be 0/,
+	'fails with zero system identifier');
+
+# Test actual system identifier change with force flag
+$node->stop;
+my $new_sysid = '9876543210987654321';
+command_ok(
+	[ 'pg_resetwal', '-f', '--system-identifier' => $new_sysid, $node->data_dir ],
+	'pg_resetwal --system-identifier with force flag succeeds');
+
+# Verify the change was applied by checking pg_control
+$node->start;
+my $controldata_output = $node->safe_psql('postgres', 
+	"SELECT system_identifier FROM pg_control_system()");
+is($controldata_output, $new_sysid, 'system identifier was changed correctly');
+
+# Test that the server works normally after system identifier change
+is($node->safe_psql("postgres", "SELECT 1;"),
+	1, 'server running and working after system identifier change');
+
+$node->stop;
+
 # run with control override options
 
 my $out = (run_command([ 'pg_resetwal', '--dry-run', $node->data_dir ]))[0];
-- 
2.39.5 (Apple Git-154)

