v3-0001-Add-pg_stat_kind_info-view.patch
text/plain
Filename: v3-0001-Add-pg_stat_kind_info-view.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v3-0001
Subject: Add pg_stat_kind_info view
| File | + | − |
|---|---|---|
| doc/src/sgml/monitoring.sgml | 142 | 0 |
| src/backend/catalog/system_views.sql | 12 | 0 |
| src/backend/utils/activity/Makefile | 1 | 0 |
| src/backend/utils/activity/meson.build | 1 | 0 |
| src/backend/utils/activity/pgstat_kind.c | 85 | 0 |
| src/include/catalog/pg_proc.dat | 10 | 0 |
| src/test/modules/test_custom_stats/t/001_custom_stats.pl | 13 | 1 |
| src/test/regress/expected/rules.out | 9 | 0 |
| src/test/regress/expected/stats.out | 23 | 0 |
| src/test/regress/expected/sysviews.out | 7 | 0 |
| src/test/regress/sql/stats.sql | 7 | 0 |
| src/test/regress/sql/sysviews.sql | 3 | 0 |
From 32b0910efdeeefb75ab3aa74100f446302a68a2e Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Wed, 1 Jul 2026 15:56:11 +0900
Subject: [PATCH v3] Add pg_stat_kind_info view
Blah..
---
src/include/catalog/pg_proc.dat | 10 ++
src/backend/catalog/system_views.sql | 12 ++
src/backend/utils/activity/Makefile | 1 +
src/backend/utils/activity/meson.build | 1 +
src/backend/utils/activity/pgstat_kind.c | 85 +++++++++++
.../test_custom_stats/t/001_custom_stats.pl | 14 +-
src/test/regress/expected/rules.out | 9 ++
src/test/regress/expected/stats.out | 23 +++
src/test/regress/expected/sysviews.out | 7 +
src/test/regress/sql/stats.sql | 7 +
src/test/regress/sql/sysviews.sql | 3 +
doc/src/sgml/monitoring.sgml | 142 ++++++++++++++++++
12 files changed, 313 insertions(+), 1 deletion(-)
create mode 100644 src/backend/utils/activity/pgstat_kind.c
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 73bb7fbb4304..9571f033aa85 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6078,6 +6078,16 @@
proargnames => '{backend_pid,backend_type,object,context,reads,read_bytes,read_time,writes,write_bytes,write_time,writebacks,writeback_time,extends,extend_bytes,extend_time,hits,evictions,reuses,fsyncs,fsync_time,stats_reset}',
prosrc => 'pg_stat_get_backend_io' },
+{ oid => '8683',
+ descr => 'statistics: information about loaded 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,int8}',
+ proargmodes => '{o,o,o,o,o,o,o,o}',
+ proargnames => '{id,name,builtin,fixed_amount,accessed_across_databases,write_to_file,entry_size,entry_count}',
+ prosrc => 'pg_stat_get_kind_info' },
+
{ oid => '1136', descr => 'statistics: information about WAL activity',
proname => 'pg_stat_get_wal', proisstrict => 'f', provolatile => 's',
proparallel => 'r', prorettype => 'record', proargtypes => '',
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 8f129baec906..6a9d94d78f34 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1282,6 +1282,18 @@ SELECT
b.stats_reset
FROM pg_stat_get_io() b;
+CREATE VIEW pg_stat_kind_info AS
+ SELECT
+ k.id,
+ k.name,
+ k.builtin,
+ k.fixed_amount,
+ k.accessed_across_databases,
+ k.write_to_file,
+ k.entry_size,
+ k.entry_count
+ FROM pg_stat_get_kind_info() k;
+
CREATE VIEW pg_stat_wal AS
SELECT
w.wal_records,
diff --git a/src/backend/utils/activity/Makefile b/src/backend/utils/activity/Makefile
index ca3ef89bf599..5fed953c28a7 100644
--- a/src/backend/utils/activity/Makefile
+++ b/src/backend/utils/activity/Makefile
@@ -26,6 +26,7 @@ OBJS = \
pgstat_database.o \
pgstat_function.o \
pgstat_io.o \
+ pgstat_kind.o \
pgstat_lock.o \
pgstat_relation.o \
pgstat_replslot.o \
diff --git a/src/backend/utils/activity/meson.build b/src/backend/utils/activity/meson.build
index 1aa7ece52908..470b5dac402b 100644
--- a/src/backend/utils/activity/meson.build
+++ b/src/backend/utils/activity/meson.build
@@ -11,6 +11,7 @@ backend_sources += files(
'pgstat_database.c',
'pgstat_function.c',
'pgstat_io.c',
+ 'pgstat_kind.c',
'pgstat_lock.c',
'pgstat_relation.c',
'pgstat_replslot.c',
diff --git a/src/backend/utils/activity/pgstat_kind.c b/src/backend/utils/activity/pgstat_kind.c
new file mode 100644
index 000000000000..bc43553170b5
--- /dev/null
+++ b/src/backend/utils/activity/pgstat_kind.c
@@ -0,0 +1,85 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgstat_kind.c
+ * Functions related to statistics kinds.
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/utils/activity/pgstat_kind.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "funcapi.h"
+#include "utils/builtins.h"
+#include "utils/fmgrprotos.h"
+#include "utils/pgstat_internal.h"
+#include "utils/pgstat_kind.h"
+#include "utils/tuplestore.h"
+
+
+/*
+ * pg_stat_get_kind_info
+ *
+ * Get information about the statistics kinds loaded into the system.
+ */
+Datum
+pg_stat_get_kind_info(PG_FUNCTION_ARGS)
+{
+#define PG_STAT_KIND_INFO_COLS 8
+ ReturnSetInfo *rsinfo;
+
+ InitMaterializedSRF(fcinfo, 0);
+ rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+
+ for (int kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
+ {
+ Datum values[PG_STAT_KIND_INFO_COLS] = {0};
+ bool nulls[PG_STAT_KIND_INFO_COLS] = {0};
+ const PgStat_KindInfo *info;
+
+ info = pgstat_get_kind_info(kind);
+ if (info == NULL)
+ continue;
+
+ values[0] = Int32GetDatum(kind);
+ values[1] = CStringGetTextDatum(info->name);
+
+ values[2] = BoolGetDatum(pgstat_is_kind_builtin(kind));
+ values[3] = BoolGetDatum(info->fixed_amount);
+ values[4] = BoolGetDatum(info->accessed_across_databases);
+ values[5] = BoolGetDatum(info->write_to_file);
+
+ /*
+ * Built-in fixed-amount kinds store their single entry in
+ * PgStat_ShmemControl, so shared_size is unused and left zero in
+ * their PgStat_KindInfo. Reporting it would be misleading, so report
+ * NULL instead. Custom fixed-amount kinds declare shared_size to
+ * size their slot in custom_data[].
+ */
+ if (info->fixed_amount && pgstat_is_kind_builtin(kind))
+ nulls[6] = true;
+ else
+ values[6] = Int64GetDatum(info->shared_size);
+
+ /*
+ * When track_entry_count is disabled, use NULL. Fixed-sized stats
+ * kinds report NULL here.
+ */
+ if (info->track_entry_count)
+ values[7] = Int64GetDatum(pgstat_get_entry_count(kind));
+ else
+ nulls[7] = true;
+
+
+ tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+ }
+
+ return (Datum) 0;
+#undef PG_STAT_KIND_INFO_COLS
+}
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 9e6a7a385775..f1774ba6f925 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
@@ -27,6 +27,18 @@ $node->start;
$node->safe_psql('postgres', q(CREATE EXTENSION test_custom_var_stats));
$node->safe_psql('postgres', q(CREATE EXTENSION test_custom_fixed_stats));
+# Verify custom stats kinds appear in pg_stat_kind_info.
+my $result = $node->safe_psql(
+ 'postgres',
+ q(SELECT id, name, builtin, fixed_amount, accessed_across_databases,
+ 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|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.
$node->safe_psql('postgres',
q(select test_custom_stats_var_create('entry1', 'Test entry 1')));
@@ -63,7 +75,7 @@ $node->safe_psql('postgres', q(select test_custom_stats_fixed_update()));
$node->safe_psql('postgres', q(select test_custom_stats_fixed_update()));
# Test data reports.
-my $result = $node->safe_psql('postgres',
+$result = $node->safe_psql('postgres',
q(select * from test_custom_stats_var_report('entry1')));
is( $result,
"entry1|2|Test entry 1",
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index a65a5bf0c4fb..4ed7b31528f9 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1967,6 +1967,15 @@ pg_stat_io| SELECT backend_type,
fsync_time,
stats_reset
FROM pg_stat_get_io() b(backend_type, object, context, reads, read_bytes, read_time, writes, write_bytes, write_time, writebacks, writeback_time, extends, extend_bytes, extend_time, hits, evictions, reuses, fsyncs, fsync_time, stats_reset);
+pg_stat_kind_info| SELECT id,
+ name,
+ builtin,
+ fixed_amount,
+ accessed_across_databases,
+ write_to_file,
+ entry_size,
+ entry_count
+ FROM pg_stat_get_kind_info() k(id, name, builtin, fixed_amount, accessed_across_databases, write_to_file, entry_size, entry_count);
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 fa550676f835..932613a6e767 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -113,6 +113,29 @@ walwriter|wal|init
walwriter|wal|normal
(95 rows)
\a
+-- List of loaded statistics kinds.
+SELECT name, id, fixed_amount,
+ accessed_across_databases AS across_db, write_to_file
+ FROM pg_stat_kind_info
+ WHERE builtin
+ ORDER BY name COLLATE "C";
+ name | id | fixed_amount | across_db | write_to_file
+--------------+----+--------------+-----------+---------------
+ archiver | 7 | t | f | t
+ backend | 6 | f | t | f
+ bgwriter | 8 | t | f | t
+ checkpointer | 9 | t | f | t
+ database | 1 | f | t | t
+ function | 3 | f | f | t
+ io | 10 | t | f | t
+ lock | 11 | t | f | t
+ relation | 2 | f | f | t
+ replslot | 4 | f | t | t
+ slru | 12 | t | f | t
+ subscription | 5 | f | t | t
+ wal | 13 | t | f | t
+(13 rows)
+
-- ensure that both seqscan and indexscan plans are allowed
SET enable_seqscan TO on;
SET enable_indexscan TO on;
diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out
index 132b56a5864c..ac9e033c2ae1 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -129,6 +129,13 @@ select count(*) > 0 as ok from pg_stat_slru;
t
(1 row)
+-- There should be at least one statistics kind loaded
+select count(*) > 0 as ok from pg_stat_kind_info;
+ ok
+----
+ t
+(1 row)
+
-- There must be only one record
select count(*) = 1 as ok from pg_stat_wal;
ok
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index f5683302a75c..2c47c4b69b50 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -14,6 +14,13 @@ SELECT backend_type, object, context FROM pg_stat_io
ORDER BY backend_type COLLATE "C", object COLLATE "C", context COLLATE "C";
\a
+-- List of loaded statistics kinds.
+SELECT name, id, fixed_amount,
+ accessed_across_databases AS across_db, write_to_file
+ FROM pg_stat_kind_info
+ WHERE builtin
+ ORDER BY name COLLATE "C";
+
-- ensure that both seqscan and indexscan plans are allowed
SET enable_seqscan TO on;
SET enable_indexscan TO on;
diff --git a/src/test/regress/sql/sysviews.sql b/src/test/regress/sql/sysviews.sql
index 507e400ad4af..193bf84dad86 100644
--- a/src/test/regress/sql/sysviews.sql
+++ b/src/test/regress/sql/sysviews.sql
@@ -70,6 +70,9 @@ select count(*) >= 0 as ok from pg_prepared_xacts;
-- There will surely be at least one SLRU cache
select count(*) > 0 as ok from pg_stat_slru;
+-- There should be at least one statistics kind loaded
+select count(*) > 0 as ok from pg_stat_kind_info;
+
-- There must be only one record
select count(*) = 1 as ok from pg_stat_wal;
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 2ec2bdd000bc..d77bb30bc588 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -509,6 +509,16 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
</entry>
</row>
+ <row>
+ <entry><structname>pg_stat_kind_info</structname><indexterm><primary>pg_stat_kind_info</primary></indexterm></entry>
+ <entry>
+ One row for each loaded statistics kind, showing information about
+ each kind.
+ See <link linkend="monitoring-pg-stat-kind-info-view">
+ <structname>pg_stat_kind_info</structname></link> for details.
+ </entry>
+ </row>
+
<row>
<entry><structname>pg_stat_lock</structname><indexterm><primary>pg_stat_lock</primary></indexterm></entry>
<entry>
@@ -3303,6 +3313,138 @@ description | Waiting for a newly initialized WAL file to reach durable storage
</sect2>
+ <sect2 id="monitoring-pg-stat-kind-info-view">
+ <title><structname>pg_stat_kind_info</structname></title>
+
+ <indexterm>
+ <primary>pg_stat_kind_info</primary>
+ </indexterm>
+
+ <para>
+ The <structname>pg_stat_kind_info</structname> view contains one row for each
+ loaded statistics kind, including both built-in and custom kinds.
+ </para>
+
+ <table id="pg-stat-kind-info-view" xreflabel="pg_stat_kind_info">
+ <title><structname>pg_stat_kind_info</structname> View</title>
+ <tgroup cols="1">
+ <thead>
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ Column Type
+ </para>
+ <para>
+ Description
+ </para>
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>id</structfield> <type>integer</type>
+ </para>
+ <para>
+ Numeric identifier of the statistics kind.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>name</structfield> <type>text</type>
+ </para>
+ <para>
+ Name of the statistics kind.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>builtin</structfield> <type>boolean</type>
+ </para>
+ <para>
+ True if this is a built-in statistics kind, false if it was registered
+ by an extension.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>fixed_amount</structfield> <type>boolean</type>
+ </para>
+ <para>
+ True if this kind tracks a fixed amount of data (a single, statically
+ allocated entry), false if it tracks a variable number of entries
+ keyed by object identifier.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>accessed_across_databases</structfield> <type>boolean</type>
+ </para>
+ <para>
+ True if entries of this kind are accessed across databases (cluster-wide
+ statistics), false if they are scoped to a single database.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>write_to_file</structfield> <type>boolean</type>
+ </para>
+ <para>
+ True if entries of this kind are persisted to the statistics file at
+ shutdown and reloaded on startup, false if they are kept only in
+ shared memory.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>entry_size</structfield> <type>bigint</type>
+ </para>
+ <para>
+ Size in bytes of a shared memory entry for this statistics kind.
+ <literal>NULL</literal> for built-in fixed-amount kinds, whose
+ single entry lives in a statically-allocated slot rather than a
+ sized shared memory entry.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry role="catalog_table_entry">
+ <para role="column_definition">
+ <structfield>entry_count</structfield> <type>bigint</type>
+ </para>
+ <para>
+ Number of tracked entries for this kind. For variable-numbered kinds,
+ this is the number of objects currently tracked.
+ <literal>NULL</literal> for fixed-sized statistics kinds, or if the
+ kind does not track entry counts.
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect2>
+
<sect2 id="monitoring-pg-stat-lock-view">
<title><structname>pg_stat_lock</structname></title>
--
2.54.0