From 8b4a2177c0cac7aba0b86579188a6267b693e785 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Thu, 13 Aug 2026 12:15:19 +0200
Subject: [PATCH v5 2/3] 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>
Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@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     | 18 ++++++++
 5 files changed, 76 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..ec62d17fbcc 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 checksum state at cluster initialization and current
+   checkpoint.  Data checksum states are often referred to as data checksum
+   versions using an integer representation due to how they were originally
+   implemented.  <xref linkend="data-checksums-mapping" /> contains a mapping
+   between state names and versions, 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 7477f00947d..5a16b6fb9e4 100644
--- a/src/test/modules/test_checksums/t/001_basic.pl
+++ b/src/test/modules/test_checksums/t/001_basic.pl
@@ -43,6 +43,18 @@ enable_data_checksums($node, wait => 'on');
 $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 on.
+$result =
+  $node->safe_psql('postgres',
+	'SELECT data_page_checksum_version FROM pg_control_init();');
+is($result, '1', 'ensure pg_control_init reports enabled 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);
@@ -59,6 +71,12 @@ 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)

