From 97f87ae42e339d5d30d30c35f80ee9d7db75dca6 Mon Sep 17 00:00:00 2001
From: Tristan Partin <tristan@partin.io>
Date: Mon, 6 Jul 2026 22:30:12 +0000
Subject: [PATCH v1] Add entry_size column to pg_stat_kind_info

pg_stat_kind_info lacked a way to inspect the size of the statistics
data payload for each registered kind. The column represents
PgStat_KindInfo::shared_data_len, which is the size of the serializable
statistics data payload, excluding shared memory wrapper overhead such
as locking structures and hash table bookkeeping.

Signed-off-by: Tristan Partin <tristan@partin.io>
---
 doc/src/sgml/monitoring.sgml                  | 13 +++++++
 src/backend/catalog/system_views.sql          |  3 +-
 src/backend/utils/activity/pgstat_kind.c      |  4 ++-
 src/include/catalog/pg_proc.dat               |  6 ++--
 .../test_custom_stats/t/001_custom_stats.pl   |  8 ++---
 src/test/regress/expected/rules.out           |  5 +--
 src/test/regress/expected/stats.out           | 34 +++++++++----------
 src/test/regress/sql/stats.sql                |  4 +--
 8 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 12b9ee20d4a..76b43d0b38c 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -3426,6 +3426,19 @@ description | Waiting for a newly initialized WAL file to reach durable storage
        </para>
       </entry>
      </row>
+
+     <row>
+      <entry role="catalog_table_entry">
+       <para role="column_definition">
+        <structfield>entry_size</structfield> <type>bigint</type>
+       </para>
+       <para>
+        Size of the statistics data for each entry of this kind in bytes. This
+        reflects the serializable statistics payload only, and does not include
+        any shared memory overhead.
+       </para>
+      </entry>
+     </row>
     </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 6c1c5545cb5..a1196be6e54 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1290,7 +1290,8 @@ CREATE VIEW pg_stat_kind_info AS
         k.fixed_amount,
         k.accessed_across_databases,
         k.write_to_file,
-        k.entry_count
+        k.entry_count,
+        k.entry_size
     FROM pg_stat_get_kind_info() k;
 
 CREATE VIEW pg_stat_wal AS
diff --git a/src/backend/utils/activity/pgstat_kind.c b/src/backend/utils/activity/pgstat_kind.c
index 6c53b7e49bf..e9e636b34aa 100644
--- a/src/backend/utils/activity/pgstat_kind.c
+++ b/src/backend/utils/activity/pgstat_kind.c
@@ -31,7 +31,7 @@
 Datum
 pg_stat_get_kind_info(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_KIND_INFO_COLS	7
+#define PG_STAT_KIND_INFO_COLS	8
 	ReturnSetInfo *rsinfo;
 
 	InitMaterializedSRF(fcinfo, 0);
@@ -64,6 +64,8 @@ pg_stat_get_kind_info(PG_FUNCTION_ARGS)
 		else
 			nulls[6] = true;
 
+		values[7] = Int64GetDatum((int64) pgstat_get_entry_len(kind));
+
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3cb84359adf..89d13d01184 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6081,9 +6081,9 @@
 { oid => '8683', descr => 'statistics: information about statistics kinds',
   proname => 'pg_stat_get_kind_info', prorows => '20', proretset => 't',
   provolatile => 'v', proparallel => 'r', prorettype => 'record',
-  proargtypes => '', proallargtypes => '{int4,text,bool,bool,bool,bool,int8}',
-  proargmodes => '{o,o,o,o,o,o,o}',
-  proargnames => '{id,name,builtin,fixed_amount,accessed_across_databases,write_to_file,entry_count}',
+  proargtypes => '', proallargtypes => '{int4,text,bool,bool,bool,bool,int8,int8}',
+  proargmodes => '{o,o,o,o,o,o,o,o}',
+  proargnames => '{id,name,builtin,fixed_amount,accessed_across_databases,write_to_file,entry_count,entry_size}',
   prosrc => 'pg_stat_get_kind_info' },
 
 { oid => '1136', descr => 'statistics: information about WAL activity',
diff --git a/src/test/modules/test_custom_stats/t/001_custom_stats.pl b/src/test/modules/test_custom_stats/t/001_custom_stats.pl
index 69f2284229e..ee291f4ac13 100644
--- a/src/test/modules/test_custom_stats/t/001_custom_stats.pl
+++ b/src/test/modules/test_custom_stats/t/001_custom_stats.pl
@@ -31,12 +31,12 @@
 my $result = $node->safe_psql(
 	'postgres',
 	q(SELECT id, name, builtin, fixed_amount, accessed_across_databases,
-	         write_to_file
+	         write_to_file, entry_size > 0
 	    FROM pg_stat_kind_info
 	    WHERE name LIKE 'test_custom%' ORDER BY id));
-is( $result,
-	qq{25|test_custom_var_stats|f|f|t|t
-26|test_custom_fixed_stats|f|t|f|t},
+is($result,
+	qq{25|test_custom_var_stats|f|f|t|t|t
+26|test_custom_fixed_stats|f|t|f|t|t},
 	"custom stats kinds visible in pg_stat_kind_info");
 
 # Create entries for variable-sized stats.
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 39905c2de14..f623b06910a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1973,8 +1973,9 @@ pg_stat_kind_info| SELECT id,
     fixed_amount,
     accessed_across_databases,
     write_to_file,
-    entry_count
-   FROM pg_stat_get_kind_info() k(id, name, builtin, fixed_amount, accessed_across_databases, write_to_file, entry_count);
+    entry_count,
+    entry_size
+   FROM pg_stat_get_kind_info() k(id, name, builtin, fixed_amount, accessed_across_databases, write_to_file, entry_count, entry_size);
 pg_stat_lock| SELECT locktype,
     waits,
     wait_time,
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 03cbc1cdef5..c8479c0faf7 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -114,26 +114,26 @@ walwriter|wal|normal
 (95 rows)
 \a
 -- List of registered statistics kinds.
-SELECT id, name, fixed_amount,
-    accessed_across_databases AS across_db, write_to_file
+SELECT id, name, fixed_amount, accessed_across_databases AS across_db,
+       write_to_file, entry_size > 0 AS has_entry_size
   FROM pg_stat_kind_info
   WHERE builtin
   ORDER BY id;
- id |     name     | fixed_amount | across_db | write_to_file 
-----+--------------+--------------+-----------+---------------
-  1 | database     | f            | t         | t
-  2 | relation     | f            | f         | t
-  3 | function     | f            | f         | t
-  4 | replslot     | f            | t         | t
-  5 | subscription | f            | t         | t
-  6 | backend      | f            | t         | f
-  7 | archiver     | t            | f         | t
-  8 | bgwriter     | t            | f         | t
-  9 | checkpointer | t            | f         | t
- 10 | io           | t            | f         | t
- 11 | lock         | t            | f         | t
- 12 | slru         | t            | f         | t
- 13 | wal          | t            | f         | t
+ id |     name     | fixed_amount | across_db | write_to_file | has_entry_size 
+----+--------------+--------------+-----------+---------------+----------------
+  1 | database     | f            | t         | t             | t
+  2 | relation     | f            | f         | t             | t
+  3 | function     | f            | f         | t             | t
+  4 | replslot     | f            | t         | t             | t
+  5 | subscription | f            | t         | t             | t
+  6 | backend      | f            | t         | f             | t
+  7 | archiver     | t            | f         | t             | t
+  8 | bgwriter     | t            | f         | t             | t
+  9 | checkpointer | t            | f         | t             | t
+ 10 | io           | t            | f         | t             | t
+ 11 | lock         | t            | f         | t             | t
+ 12 | slru         | t            | f         | t             | t
+ 13 | wal          | t            | f         | t             | t
 (13 rows)
 
 -- ensure that both seqscan and indexscan plans are allowed
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 4c265d1245c..554e6068aa5 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -15,8 +15,8 @@ SELECT backend_type, object, context FROM pg_stat_io
 \a
 
 -- List of registered statistics kinds.
-SELECT id, name, fixed_amount,
-    accessed_across_databases AS across_db, write_to_file
+SELECT id, name, fixed_amount, accessed_across_databases AS across_db,
+       write_to_file, entry_size > 0 AS has_entry_size
   FROM pg_stat_kind_info
   WHERE builtin
   ORDER BY id;
-- 
Tristan Partin
https://tristan.partin.io

