From eed61a7cf316ce0bb51e55fddbc3feca3fca8850 Mon Sep 17 00:00:00 2001 From: Nikolay Samokhvalov Date: Sat, 31 Jan 2026 13:12:36 -0800 Subject: [PATCH] Add --system-identifier option to pg_resetwal Add option to manually set the database system identifier. Useful for: - Making restored clusters distinct from originals - Cloning clusters for testing - Recovery attempts on corrupted clusters v3: Address review feedback (Fujii Masao) - use "Database system identifier" label, PRIu64 format, fix test to use pg_controldata. --- doc/src/sgml/ref/pg_resetwal.sgml | 23 +++++++++++++++++++++++ src/bin/pg_resetwal/pg_resetwal.c | 28 ++++++++++++++++++++++++++++ src/bin/pg_resetwal/t/001_basic.pl | 29 +++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml index 41f2b1d..8dc8f6c 100644 --- a/doc/src/sgml/ref/pg_resetwal.sgml +++ b/doc/src/sgml/ref/pg_resetwal.sgml @@ -359,6 +359,29 @@ PostgreSQL documentation + + + + + Manually set the database system identifier. + + + + 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. + + + + + Changing the system identifier will break compatibility with existing + backups and standby servers. Use this option with extreme caution. + + + + + diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index 431b83a..40c4812 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -97,6 +97,9 @@ static int wal_segsize_val; static bool char_signedness_given = false; static bool char_signedness_val; +static bool sysid_given = false; +static uint64 sysid_val; + static TimeLineID minXlogTli = 0; static XLogSegNo minXlogSegNo = 0; @@ -135,6 +138,7 @@ main(int argc, char *argv[]) {"next-transaction-id", required_argument, NULL, 'x'}, {"wal-segsize", required_argument, NULL, 1}, {"char-signedness", required_argument, NULL, 2}, + {"system-identifier", required_argument, NULL, 3}, {NULL, 0, NULL, 0} }; @@ -352,6 +356,20 @@ main(int argc, char *argv[]) break; } + case 3: + errno = 0; + sysid_val = 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 (sysid_val == 0) + pg_fatal("system identifier must not be 0"); + sysid_given = true; + break; + default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -510,6 +528,9 @@ main(int argc, char *argv[]) if (char_signedness_given) ControlFile.default_char_signedness = char_signedness_val; + if (sysid_given) + ControlFile.system_identifier = sysid_val; + if (minXlogSegNo > newXlogSegNo) newXlogSegNo = minXlogSegNo; @@ -894,6 +915,12 @@ PrintNewControlValues(void) printf(_("Bytes per WAL segment: %u\n"), ControlFile.xlog_seg_size); } + + if (sysid_given) + { + printf(_("Database system identifier: %" PRIu64 "\n"), + ControlFile.system_identifier); + } } @@ -1231,6 +1258,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 database 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 d686584..4fe8dbd 100644 --- a/src/bin/pg_resetwal/t/001_basic.pl +++ b/src/bin/pg_resetwal/t/001_basic.pl @@ -194,6 +194,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 = '7654321098765432109'; +command_ok( + [ 'pg_resetwal', '-f', '--system-identifier' => $new_sysid, $node->data_dir ], + 'pg_resetwal --system-identifier with force flag succeeds'); + +# Verify the change using pg_controldata (handles uint64 correctly) +my $controldata_output = run_command([ 'pg_controldata', $node->data_dir ]); +my ($actual_sysid) = $controldata_output->[0] =~ /Database system identifier:\s+(\d+)/; +is($actual_sysid, $new_sysid, 'system identifier was changed correctly'); + +# Test that the server works normally after system identifier change +$node->start; +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.49.0