2026年8月10日(月) 22:30 Fujii Masao <[email protected]>: > > On Mon, Aug 10, 2026 at 9:39 PM Ian Lawrence Barwick <[email protected]> > wrote: > > The function "get_checksum_state_string()" which performs the conversion is > > in > > src/backend/access/rmgrdesc/xlogdesc.c, which AFAIR can't be linked from > > frontend utilities, so we'd either have to move that somewhere else (maybe > > src/common/controldata_utils.c?) or duplicate it. > > Agreed. I think moving it to common is better than duplicating the mapping. > > src/common/controldata_utils.c seems like a reasonable place, since > this state is stored in the control/checkpoint data and both pg_controldata > and pg_control_checkpoint() already use controldata_utils.
TBH it feels a little odd there because it's not really specific to the controldata output functions, but it has to go somewhere, I guess. Updated patch with that and changes per your other suggestions attached. Regards Ian Barwick
From 285bb2a7b6515cbc95519025ea49d9706afc9718 Mon Sep 17 00:00:00 2001 From: Ian Barwick <[email protected]> Date: Mon, 10 Aug 2026 23:16:21 +0900 Subject: [PATCH v3] Add data_checksum_state 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. Have both the function and pg_controldata emit the textual checksum state rather than the internal enum value. Backpatch to v19 where online checksums were introduced. Author: Ian Barwick <[email protected]> Discussion: https://postgr.es/m/CAB8KJ=hb765sE8bKC-6sh=yp3scjn8xs474yubrkwyotm2p...@mail.gmail.com Backpatch-through: 19 --- doc/src/sgml/func/func-info.sgml | 5 +++++ src/backend/access/rmgrdesc/xlogdesc.c | 20 +------------------ src/backend/utils/misc/pg_controldata.c | 9 ++++++--- src/bin/pg_controldata/pg_controldata.c | 4 ++-- src/common/controldata_utils.c | 19 ++++++++++++++++++ src/include/access/xlog.h | 1 - src/include/catalog/pg_proc.dat | 6 +++--- src/include/common/controldata_utils.h | 1 + .../modules/test_checksums/t/001_basic.pl | 10 ++++++++++ 9 files changed, 47 insertions(+), 28 deletions(-) diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml index 122fc740f1a..48bc84978ec 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_checksum_state</structfield></entry> + <entry><type>text</type></entry> + </row> + <row> <entry><structfield>checkpoint_time</structfield></entry> <entry><type>timestamp with time zone</type></entry> diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 2468a7d2578..2c70f1f9498 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -18,6 +18,7 @@ #include "access/xlog.h" #include "access/xlog_internal.h" #include "catalog/pg_control.h" +#include "common/controldata_utils.h" #include "storage/checksum.h" #include "utils/guc.h" #include "utils/timestamp.h" @@ -55,25 +56,6 @@ get_wal_level_string(int wal_level) return wal_level_str; } -const char * -get_checksum_state_string(uint32 state) -{ - switch (state) - { - case PG_DATA_CHECKSUM_VERSION: - return "on"; - case PG_DATA_CHECKSUM_INPROGRESS_OFF: - return "inprogress-off"; - case PG_DATA_CHECKSUM_INPROGRESS_ON: - return "inprogress-on"; - case PG_DATA_CHECKSUM_OFF: - return "off"; - } - - Assert(false); - return "?"; -} - void xlog2_desc(StringInfo buf, XLogReaderState *record) { diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index d229ae35209..5a31bb5ae2a 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] = CStringGetTextDatum(get_checksum_state_string(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/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c index 6fc87ed114d..875a7f9153c 100644 --- a/src/bin/pg_controldata/pg_controldata.c +++ b/src/bin/pg_controldata/pg_controldata.c @@ -289,8 +289,8 @@ main(int argc, char *argv[]) ControlFile->checkPointCopy.oldestCommitTsXid); printf(_("Latest checkpoint's newestCommitTsXid:%u\n"), ControlFile->checkPointCopy.newestCommitTsXid); - printf(_("Latest checkpoint's data_checksum_version:%u\n"), - ControlFile->checkPointCopy.dataChecksumState); + printf(_("Latest checkpoint's data_checksum_state:%s\n"), + get_checksum_state_string(ControlFile->checkPointCopy.dataChecksumState)); printf(_("Time of latest checkpoint: %s\n"), ckpttime_str); printf(_("Fake LSN counter for unlogged rels: %X/%08X\n"), diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c index 0e8e03c566c..2de61124962 100644 --- a/src/common/controldata_utils.c +++ b/src/common/controldata_utils.c @@ -282,3 +282,22 @@ update_controlfile(const char *DataDir, #endif } } + +const char * +get_checksum_state_string(uint32 state) +{ + switch (state) + { + case PG_DATA_CHECKSUM_VERSION: + return "on"; + case PG_DATA_CHECKSUM_INPROGRESS_OFF: + return "inprogress-off"; + case PG_DATA_CHECKSUM_INPROGRESS_ON: + return "inprogress-on"; + case PG_DATA_CHECKSUM_OFF: + return "off"; + } + + Assert(false); + return "?"; +} diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 4dd98624204..2f90d656f05 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -256,7 +256,6 @@ extern void SetDataChecksumsOnInProgress(void); extern void SetDataChecksumsOn(void); extern void SetDataChecksumsOff(void); extern const char *show_data_checksums(void); -extern const char *get_checksum_state_string(uint32 state); extern void InitLocalDataChecksumState(void); extern void SetLocalDataChecksumState(uint32 data_checksum_version); extern bool GetDefaultCharSignedness(void); diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index f8a021987b5..49d2c15e8aa 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12371,9 +12371,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,text,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_checksum_state,checkpoint_time}', prosrc => 'pg_control_checkpoint' }, { oid => '3443', diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h index 6dd0999f805..132b10f51c6 100644 --- a/src/include/common/controldata_utils.h +++ b/src/include/common/controldata_utils.h @@ -17,5 +17,6 @@ extern ControlFileData *get_controlfile_by_exact_path(const char *ControlFilePat bool *crc_ok_p); extern void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync); +extern const char *get_checksum_state_string(uint32 state); #endif /* COMMON_CONTROLDATA_UTILS_H */ diff --git a/src/test/modules/test_checksums/t/001_basic.pl b/src/test/modules/test_checksums/t/001_basic.pl index 72e0d0df46f..5511391639e 100644 --- a/src/test/modules/test_checksums/t/001_basic.pl +++ b/src/test/modules/test_checksums/t/001_basic.pl @@ -34,6 +34,11 @@ 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_checksum_state FROM pg_control_checkpoint();'); +is($result, 'on', 'ensure pg_control_checkpoint reports on 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 +55,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_checksum_state FROM pg_control_checkpoint();'); +is($result, 'off', 'ensure pg_control_checkpoint reports off 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.52.0
