From cc6c2044f08f987c44d82683490b8e1a2b7dff9f Mon Sep 17 00:00:00 2001
From: shihao zhong <zhong950419@gmail.com>
Date: Sun, 4 Oct 2026 23:48:37 -0400
Subject: [PATCH v1 1/2] pg_resetwal: Add --cluster-state option

pg_resetwal always marks the cluster as shut down.  This option stores
another state instead.  With any other state the next start goes through
crash recovery, which for example empties unlogged tables.

Discussion: https://postgr.es/m/ar8mhs05SzC4hjmu@paquier.xyz
---
 doc/src/sgml/ref/pg_resetwal.sgml | 22 +++++++++++++++++
 src/bin/pg_resetwal/pg_resetwal.c | 40 ++++++++++++++++++++++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml
index d34aa26413c..7d65393e78f 100644
--- a/doc/src/sgml/ref/pg_resetwal.sgml
+++ b/doc/src/sgml/ref/pg_resetwal.sgml
@@ -384,6 +384,28 @@ PostgreSQL documentation
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><option>--cluster-state=<replaceable class="parameter">state</replaceable></option></term>
+    <listitem>
+     <para>
+      Manually set the database cluster state stored in
+      <filename>pg_control</filename>.  Possible values are
+      <literal>shut-down</literal> (the default),
+      <literal>shut-down-in-recovery</literal>,
+      <literal>shutting-down</literal>,
+      <literal>in-crash-recovery</literal>,
+      <literal>in-archive-recovery</literal> and
+      <literal>in-production</literal>.
+     </para>
+     <para>
+      With any state other than <literal>shut-down</literal>, the server
+      goes through crash recovery at its next start.  There is no WAL to
+      replay after a reset, but the other steps of crash recovery still
+      run.  For example, unlogged tables are emptied.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><option>--wal-segsize=<replaceable class="parameter">wal_segment_size</replaceable></option></term>
     <listitem>
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index 634d966da9e..13044bcdfff 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -97,6 +97,10 @@ static int	wal_segsize_val;
 static bool char_signedness_given = false;
 static bool char_signedness_val;
 
+static bool cluster_state_given = false;
+static DBState cluster_state_val;
+static const char *cluster_state_name;
+
 
 static TimeLineID minXlogTli = 0;
 static XLogSegNo minXlogSegNo = 0;
@@ -135,6 +139,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},
+		{"cluster-state", required_argument, NULL, 3},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -356,6 +361,32 @@ main(int argc, char *argv[])
 					break;
 				}
 
+			case 3:
+				{
+					/* DB_STARTUP is left out, the server rejects it */
+					if (strcmp(optarg, "shut-down") == 0)
+						cluster_state_val = DB_SHUTDOWNED;
+					else if (strcmp(optarg, "shut-down-in-recovery") == 0)
+						cluster_state_val = DB_SHUTDOWNED_IN_RECOVERY;
+					else if (strcmp(optarg, "shutting-down") == 0)
+						cluster_state_val = DB_SHUTDOWNING;
+					else if (strcmp(optarg, "in-crash-recovery") == 0)
+						cluster_state_val = DB_IN_CRASH_RECOVERY;
+					else if (strcmp(optarg, "in-archive-recovery") == 0)
+						cluster_state_val = DB_IN_ARCHIVE_RECOVERY;
+					else if (strcmp(optarg, "in-production") == 0)
+						cluster_state_val = DB_IN_PRODUCTION;
+					else
+					{
+						pg_log_error("invalid argument for option %s", "--cluster-state");
+						pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+						exit(1);
+					}
+					cluster_state_name = optarg;
+					cluster_state_given = true;
+					break;
+				}
+
 			default:
 				/* getopt_long already emitted a complaint */
 				pg_log_error_hint("Try \"%s --help\" for more information.", progname);
@@ -900,6 +931,12 @@ PrintNewControlValues(void)
 		printf(_("Bytes per WAL segment:                %u\n"),
 			   ControlFile.xlog_seg_size);
 	}
+
+	if (cluster_state_given)
+	{
+		printf(_("Database cluster state:               %s\n"),
+			   cluster_state_name);
+	}
 }
 
 
@@ -917,7 +954,7 @@ RewriteControlFile(void)
 							ControlFile.checkPointCopy.redo);
 	ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
 
-	ControlFile.state = DB_SHUTDOWNED;
+	ControlFile.state = cluster_state_given ? cluster_state_val : DB_SHUTDOWNED;
 	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
 	ControlFile.minRecoveryPoint = InvalidXLogRecPtr;
 	ControlFile.minRecoveryPointTLI = 0;
@@ -1250,6 +1287,7 @@ usage(void)
 	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(_("      --cluster-state=STATE        set database cluster state\n"));
 	printf(_("      --wal-segsize=SIZE           size of WAL segments, in megabytes\n"));
 
 	printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
-- 
2.37.1 (Apple Git-137.1)

