From efae8acde7be2a504dbcccfc43f7994c94753c23 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Sun, 16 Nov 2025 16:01:21 +0100 Subject: [PATCH v4 1/3] Add infrastructure for pg_system_versions view Introduce a unified way of reporting versions (PostgreSQL itself, the compiler, the host system, compile and runtime dependencies, etc.) via a new system view pg_system_versions. This is going to be useful for troubleshooting and should enhance bug reports, replacing manual bug-prone collecting of the same information. The view is backed by a hash table, that contains callbacks returning version string for a particular component. The idea is to allow some flexibility in reporting, making components responsible for how and when the information is exposed. --- doc/src/sgml/system-views.sgml | 65 +++++++++++++++ src/backend/catalog/system_views.sql | 8 ++ src/backend/utils/misc/Makefile | 3 +- src/backend/utils/misc/meson.build | 1 + src/backend/utils/misc/system_version.c | 106 ++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 6 ++ src/include/utils/system_version.h | 38 +++++++++ src/test/regress/expected/rules.out | 8 ++ src/tools/pgindent/typedefs.list | 2 + 9 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 src/backend/utils/misc/system_version.c create mode 100644 src/include/utils/system_version.h diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml index 7971498fe75..cb7b57e0102 100644 --- a/doc/src/sgml/system-views.sgml +++ b/doc/src/sgml/system-views.sgml @@ -246,6 +246,11 @@ wait events + + pg_system_versions + system versions + + @@ -5611,4 +5616,64 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + <structname>pg_system_versions</structname> + + + pg_system_versions + + + + The view pg_system_versions provides description + about versions of various system components, e.g. PostgreSQL itself, + compiler used to build it, dependencies, etc. + + + + <structname>pg_system_versions</structname> Columns + + + + + Column Type + + + Description + + + + + + + + name text + + + Component name + + + + + + version text + + + Component version + + + + + + type text + + + Component type (compile time or Run time) + + + + + +
+
+ diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 059e8778ca7..a00777e4f8b 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1438,3 +1438,11 @@ REVOKE ALL ON pg_aios FROM PUBLIC; GRANT SELECT ON pg_aios TO pg_read_all_stats; REVOKE EXECUTE ON FUNCTION pg_get_aios() FROM PUBLIC; GRANT EXECUTE ON FUNCTION pg_get_aios() TO pg_read_all_stats; + +CREATE VIEW pg_system_versions AS + SELECT + name, version, + CASE type WHEN 0 THEN 'Compile Time' + WHEN 1 THEN 'Run Time' + END AS "type" + FROM pg_get_system_versions(); diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index f142d17178b..0ac5b3c79cd 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -32,7 +32,8 @@ OBJS = \ stack_depth.o \ superuser.o \ timeout.o \ - tzparser.o + tzparser.o \ + system_version.o # This location might depend on the installation directories. Therefore # we can't substitute it into pg_config.h. diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build index 9e389a00d05..5268eaa94c7 100644 --- a/src/backend/utils/misc/meson.build +++ b/src/backend/utils/misc/meson.build @@ -16,6 +16,7 @@ backend_sources += files( 'sampling.c', 'stack_depth.c', 'superuser.c', + 'system_version.c', 'timeout.c', 'tzparser.c', ) diff --git a/src/backend/utils/misc/system_version.c b/src/backend/utils/misc/system_version.c new file mode 100644 index 00000000000..4d15ce58bf9 --- /dev/null +++ b/src/backend/utils/misc/system_version.c @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------ + * + * system_version.c + * Functions for reporting version of system components. + * + * A system component is defined very broadly here, it might be the PostgreSQL + * core itself, the compiler, the host system, any dependency that is used at + * compile time or run time. + * + * Version reporting is implemented via a hash table containing the component's + * name as a key and the callback to fetch the version string. Every component + * can register such a callback during initialization and is responsible for + * exposing its own information. The idea is that storing a callback instead of + * a version string directly allows for more flexibility about how and when the + * information could be reported. + * + * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/misc/system_version.c + * + *------------------------------------------------------------------------ + */ +#include "postgres.h" + +#include + +#include "funcapi.h" +#include "utils/builtins.h" +#include "utils/system_version.h" + +static HTAB *versions = NULL; + +void +add_system_version(const char *name, SystemVersionCB cb, VersionType type) +{ + SystemVersion *hentry; + const char *key; + bool found; + + if (!versions) + { + HASHCTL ctl; + + ctl.keysize = NAMEDATALEN; + ctl.entrysize = sizeof(SystemVersion); + ctl.hcxt = CurrentMemoryContext; + + versions = hash_create("System versions table", + MAX_SYSTEM_VERSIONS, + &ctl, + HASH_ELEM | HASH_STRINGS); + } + + key = pstrdup(name); + hentry = (SystemVersion *) hash_search(versions, key, + HASH_ENTER, &found); + + if (found) + elog(ERROR, "duplicated system version"); + + hentry->callback = cb; + hentry->type = type; +} + +/* + * pg_get_system_versions + * + * List information about system versions. + */ +Datum +pg_get_system_versions(PG_FUNCTION_ARGS) +{ +#define PG_GET_SYS_VERSIONS_COLS 3 + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + HASH_SEQ_STATUS status; + SystemVersion *hentry; + + /* Build tuplestore to hold the result rows */ + InitMaterializedSRF(fcinfo, 0); + + if (!versions) + return (Datum) 0; + + hash_seq_init(&status, versions); + while ((hentry = (SystemVersion *) hash_seq_search(&status)) != NULL) + { + Datum values[PG_GET_SYS_VERSIONS_COLS] = {0}; + bool nulls[PG_GET_SYS_VERSIONS_COLS] = {0}; + bool available = false; + const char *version = hentry->callback(&available); + + if (!available) + continue; + + values[0] = CStringGetTextDatum(hentry->name); + values[1] = CStringGetTextDatum(version); + values[2] = hentry->type; + + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); + } + + return (Datum) 0; +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 5cf9e12fcb9..858e2f9983b 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12604,4 +12604,10 @@ proargnames => '{pid,io_id,io_generation,state,operation,off,length,target,handle_data_len,raw_result,result,target_desc,f_sync,f_localmem,f_buffered}', prosrc => 'pg_get_aios' }, +{ oid => '9432', descr => 'describe system verions', + proname => 'pg_get_system_versions', procost => '10', prorows => '10', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text,text,int8}', + proargmodes => '{o,o,o}', proargnames => '{name,version,type}', + prosrc => 'pg_get_system_versions' }, ] diff --git a/src/include/utils/system_version.h b/src/include/utils/system_version.h new file mode 100644 index 00000000000..18cb673d4ca --- /dev/null +++ b/src/include/utils/system_version.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------- + * system_version.h + * Definitions related to system versions reporting + * + * Copyright (c) 2001-2024, PostgreSQL Global Development Group + * + * src/include/utils/system_version.h + * ---------- + */ + +#ifndef SYSTEM_VERSION_H +#define SYSTEM_VERSION_H + +#define MAX_SYSTEM_VERSIONS 100 + +typedef enum VersionType +{ + CompileTime, + RunTime, +} VersionType; + +/* + * Callback to return version string of a system component. + * The version might be not available, what is indicated via the argument. + */ +typedef const char *(*SystemVersionCB) (bool *available); + +typedef struct SystemVersion +{ + char name[NAMEDATALEN]; /* Unique component name, used as a key + * for versions HTAB */ + VersionType type; + SystemVersionCB callback; /* Callback to fetch the version string */ +} SystemVersion; + +void add_system_version(const char *name, SystemVersionCB cb, VersionType type); + +#endif /* SYSTEM_VERSION_H */ diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 7c52181cbcb..7db23198ff3 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2683,6 +2683,14 @@ pg_stats_ext_exprs| SELECT cn.nspname AS schemaname, JOIN LATERAL ( SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, unnest(sd.stxdexpr) AS a) stat ON ((stat.expr IS NOT NULL))) WHERE (pg_has_role(c.relowner, 'USAGE'::text) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid)))); +pg_system_versions| SELECT name, + version, + CASE type + WHEN 0 THEN 'Compile Time'::text + WHEN 1 THEN 'Run Time'::text + ELSE NULL::text + END AS type + FROM pg_get_system_versions() pg_get_system_versions(name, version, type); pg_tables| SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 23bce72ae64..5ebb83d9899 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2934,6 +2934,7 @@ SysloggerStartupData SystemRowsSamplerData SystemSamplerData SystemTimeSamplerData +SystemVersion TAPtype TAR_MEMBER TBMIterateResult @@ -4215,6 +4216,7 @@ varattrib_1b_e varattrib_4b vbits verifier_context +VersionType walrcv_alter_slot_fn walrcv_check_conninfo_fn walrcv_connect_fn -- 2.49.0