Hi all,
(CCing Heikki as the committer of commit bd8d9c9bdfa)

Commit bd8d9c9bdfa widened MultiXactOffset to uint64, but I found that
pg_upgrade still reads it as a uint32 value when reading the
pg_controldata continents:

else if ((p = strstr(bufin, "Latest checkpoint's NextMultiOffset:")) != NULL)
{
:
    p++;                /* remove ':' char */
    cluster->controldata.chkpnt_nxtmxoff = str2uint(p);

I think it should use strtou64() instead. The attached 0001 patch
fixes it. It introduces str2uint64() as other fields are read by a
similar helper function str2uint().

Also, when checking other similar codes around the new
MultiXactOffset, I found that pg_control_checkpoint() still reports
the value as an xid. I think we should report it as bigint instead.
What do you think? The attached 0002 patch fixes it.

Regards,

-- 
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com
From 4389bc165db2ab33feab21e531bc6a1b7f3a546f Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email protected]>
Date: Wed, 26 Aug 2026 17:44:33 -0700
Subject: [PATCH 2/2] Report next_multi_offset as bigint in
 pg_control_checkpoint().

XXX Bump catalog version.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch-through: 19
---
 doc/src/sgml/func/func-info.sgml        | 2 +-
 src/backend/utils/misc/pg_controldata.c | 2 +-
 src/include/catalog/pg_proc.dat         | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml
index e3c05e8b933..2f03766b67a 100644
--- a/doc/src/sgml/func/func-info.sgml
+++ b/doc/src/sgml/func/func-info.sgml
@@ -3458,7 +3458,7 @@ acl      | {postgres=arwdDxtm/postgres,foo=r/postgres}
 
       <row>
        <entry><structfield>next_multi_offset</structfield></entry>
-       <entry><type>xid</type></entry>
+       <entry><type>bigint</type></entry>
       </row>
 
       <row>
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index ab74d169c96..9014f0953e9 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -130,7 +130,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 	values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMulti);
 	nulls[9] = false;
 
-	values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset);
+	values[10] = Int64GetDatum(ControlFile->checkPointCopy.nextMultiOffset);
 	nulls[10] = false;
 
 	values[11] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f5867349d14..805a579080d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12346,7 +12346,7 @@
   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,int4,timestamptz}',
+  proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,bool,text,oid,xid,int8,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' },
-- 
2.55.0

From 956b715e45e511b48d5d486f63b2f75968d5df90 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email protected]>
Date: Wed, 26 Aug 2026 17:44:02 -0700
Subject: [PATCH 1/2] pg_upgrade: Read nextMultiOffset as a 64-bit value.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch-through: 19
---
 src/bin/pg_upgrade/controldata.c |  2 +-
 src/bin/pg_upgrade/pg_upgrade.h  |  1 +
 src/bin/pg_upgrade/util.c        | 11 +++++++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index fd772ba4f38..8c69329805b 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -352,7 +352,7 @@ get_control_data(ClusterInfo *cluster)
 				pg_fatal("%d: controldata retrieval problem", __LINE__);
 
 			p++;				/* remove ':' char */
-			cluster->controldata.chkpnt_nxtmxoff = str2uint(p);
+			cluster->controldata.chkpnt_nxtmxoff = str2uint64(p);
 			got_mxoff = true;
 		}
 		else if ((p = strstr(bufin, "First log segment after reset:")) != NULL)
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index ccd1ac0d013..92607daace5 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -496,6 +496,7 @@ void		cleanup_output_dirs(void);
 void		prep_status(const char *fmt, ...) pg_attribute_printf(1, 2);
 void		prep_status_progress(const char *fmt, ...) pg_attribute_printf(1, 2);
 unsigned int str2uint(const char *str);
+uint64		str2uint64(const char *str);
 
 
 /* version.c */
diff --git a/src/bin/pg_upgrade/util.c b/src/bin/pg_upgrade/util.c
index 08d6385b512..e7d7ab56445 100644
--- a/src/bin/pg_upgrade/util.c
+++ b/src/bin/pg_upgrade/util.c
@@ -353,3 +353,14 @@ str2uint(const char *str)
 {
 	return strtoul(str, NULL, 10);
 }
+
+/*
+ *	str2uint64()
+ *
+ *	convert string to uint64
+ */
+uint64
+str2uint64(const char *str)
+{
+	return strtou64(str, NULL, 10);
+}
-- 
2.55.0

Reply via email to