From 31f7ac9447b087099b9c0196d1087648324c989e Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Thu, 13 Aug 2026 12:15:19 +0200
Subject: [PATCH v4 2/2] Add data_page_checksum_version to
 pg_control_checkpoint

Commit f19c0eccae added the data_checksum_version to the pg_controldata
output, but omitted a corresponding change to the pg_control_checkpoint
SQL function, which reports the same checkpoint information.  The field
is named to match what pg_control_init already reports for consistency.

The integer version reported is an implementation detail which bleeds
through, but it is quite widely used and a more holistic approach to
improving this is left as an excercise for the next major version. The
mapping between states and versions is added to the documentation to
make it easier for users.

Backpatch to v19 where online checksums were introduced.

Author: Ian Barwick <barwick@gmail.com>
Co-authored-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAB8KJ=hb765sE8bKC-6sh=Yp3sCjN8xs474yuBrkwyoTM2pgZA@mail.gmail.com
Backpatch-through: 19
---
 doc/src/sgml/func/func-info.sgml              |  5 +++
 doc/src/sgml/wal.sgml                         | 45 ++++++++++++++++++-
 src/backend/utils/misc/pg_controldata.c       |  9 ++--
 src/include/catalog/pg_proc.dat               |  6 +--
 .../modules/test_checksums/t/001_basic.pl     | 15 +++++++
 5 files changed, 73 insertions(+), 7 deletions(-)

diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml
index 122fc740f1a..e3c05e8b933 100644
--- a/doc/src/sgml/func/func-info.sgml
+++ b/doc/src/sgml/func/func-info.sgml
@@ -3496,6 +3496,11 @@ acl      | {postgres=arwdDxtm/postgres,foo=r/postgres}
        <entry><type>xid</type></entry>
       </row>
 
+      <row>
+       <entry><structfield>data_page_checksum_version</structfield></entry>
+       <entry><type>integer</type></entry>
+      </row>
+
       <row>
        <entry><structfield>checkpoint_time</structfield></entry>
        <entry><type>timestamp with time zone</type></entry>
diff --git a/doc/src/sgml/wal.sgml b/doc/src/sgml/wal.sgml
index 646076f7e39..b7a1686c135 100644
--- a/doc/src/sgml/wal.sgml
+++ b/doc/src/sgml/wal.sgml
@@ -256,9 +256,52 @@
    The current state of checksums in the cluster can be verified by viewing the
    value of the read-only configuration variable <xref
    linkend="guc-data-checksums" /> by issuing the command <command>SHOW
-   data_checksums</command>.
+   data_checksums</command>.  <link linkend="functions-pg-control-init">
+   <literal>pg_control_init</literal></link> and
+   <link linkend="functions-pg-control-checkpoint">
+   <literal>pg_control_checkpoint</literal></link> can also be used for
+   inspecting the data checksums state at cluster initialization and current
+   checkpoint.  Data checksums states are often referred to as data checksums
+   version using an integer representation due to how they were originally
+   implementated.  <xref linkend="data-checksums-mapping" /> contains a mapping
+   between state names and version, which are defined in
+   <filename>src/include/storage/checksum.h</filename>.
   </para>
 
+  <table id="data-checksums-mapping">
+   <title>Data Checksums States and Version Mapping</title>
+   <tgroup cols="2">
+    <thead>
+     <row>
+      <entry>State</entry>
+      <entry>Version</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry>off</entry>
+      <entry>0</entry>
+     </row>
+
+     <row>
+      <entry>on</entry>
+      <entry>1</entry>
+     </row>
+
+     <row>
+      <entry>inprogress-off</entry>
+      <entry>2</entry>
+     </row>
+
+     <row>
+      <entry>inprogress-on</entry>
+      <entry>3</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
   <para>
    When attempting to recover from page corruptions, it may be necessary to
    bypass the checksum protection. To do this, temporarily set the
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index d4feec95b26..ab74d169c96 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -69,8 +69,8 @@ pg_control_system(PG_FUNCTION_ARGS)
 Datum
 pg_control_checkpoint(PG_FUNCTION_ARGS)
 {
-	Datum		values[19];
-	bool		nulls[19];
+	Datum		values[20];
+	bool		nulls[20];
 	TupleDesc	tupdesc;
 	HeapTuple	htup;
 	ControlFileData *ControlFile;
@@ -154,9 +154,12 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 	values[17] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid);
 	nulls[17] = false;
 
-	values[18] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time));
+	values[18] = Int32GetDatum(ControlFile->checkPointCopy.dataChecksumState);
 	nulls[18] = false;
 
+	values[19] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time));
+	nulls[19] = false;
+
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 66c3c9a04cf..1d2a9db3262 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12432,9 +12432,9 @@
   descr => 'pg_controldata checkpoint state information as a function',
   proname => 'pg_control_checkpoint', provolatile => 'v',
   prorettype => 'record', proargtypes => '',
-  proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,timestamptz}',
-  proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
-  proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,logical_decoding,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}',
+  proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,int4,timestamptz}',
+  proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
+  proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,logical_decoding,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,data_page_checksum_version,checkpoint_time}',
   prosrc => 'pg_control_checkpoint' },
 
 { oid => '3443',
diff --git a/src/test/modules/test_checksums/t/001_basic.pl b/src/test/modules/test_checksums/t/001_basic.pl
index 72e0d0df46f..3b944bf334e 100644
--- a/src/test/modules/test_checksums/t/001_basic.pl
+++ b/src/test/modules/test_checksums/t/001_basic.pl
@@ -34,6 +34,16 @@ my $result =
   $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1 ");
 is($result, '9999', 'ensure checksummed pages can be read back');
 
+# Ensure the new state is registered properly in pg_control_checkpoint()
+$result =
+  $node->safe_psql('postgres', 'SELECT data_page_checksum_version FROM pg_control_checkpoint();');
+is($result, '1', 'ensure pg_control_checkpoint reports enabled state');
+# Regardless of the new state, pg_control_init() should still report checksums
+# as off.
+$result =
+  $node->safe_psql('postgres', 'SELECT data_page_checksum_version FROM pg_control_init();');
+is($result, '0', 'ensure pg_control_init reports disabled state');
+
 # Enable data checksums again which should be a no-op so we explicitly don't
 # wait for any state transition as none should happen here.
 enable_data_checksums($node);
@@ -50,6 +60,11 @@ disable_data_checksums($node, wait => 1);
 $result = $node->safe_psql('postgres', "SELECT count(*) FROM t WHERE a > 1");
 is($result, '10000', 'ensure previously checksummed pages can be read back');
 
+# And ensure the disabled state is shown in pg_control_checkpoint()
+$result =
+  $node->safe_psql('postgres', 'SELECT data_page_checksum_version FROM pg_control_checkpoint();');
+is($result, '0', 'ensure pg_control_checkpoint reports disabled state');
+
 # Re-enable checksums and make sure that the underlying data has changed to
 # ensure that checksums will be different.
 $node->safe_psql('postgres', "UPDATE t SET a = a + 1;");
-- 
2.39.3 (Apple Git-146)

