From fef34945c553de6db5abcd517f7c90fb9199e1b1 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Sat, 25 Jan 2025 20:25:11 +0100 Subject: [PATCH v3 1/4] 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 8e2b0a7927b..fa27f8cf52c 100644 --- a/doc/src/sgml/system-views.sgml +++ b/doc/src/sgml/system-views.sgml @@ -226,6 +226,11 @@ wait events + + pg_system_versions + system versions + + @@ -5068,4 +5073,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 46868bf7e89..0704567bf8c 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1388,3 +1388,11 @@ CREATE VIEW pg_stat_subscription_stats AS CREATE VIEW pg_wait_events AS SELECT * FROM pg_get_wait_events(); + +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 b362ae43771..a1bed7305a8 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..ac7df0527fc --- /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 2aafdbc3e93..563c2bc1437 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12438,4 +12438,10 @@ proargtypes => 'int4', prosrc => 'gist_stratnum_common' }, +{ 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..0321f67214f --- /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 856a8349c50..047441f9ebb 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2617,6 +2617,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 a2644a2e653..ccad37e0e2c 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2823,6 +2823,7 @@ SysloggerStartupData SystemRowsSamplerData SystemSamplerData SystemTimeSamplerData +SystemVersion TAPtype TAR_MEMBER TBMIterateResult @@ -4064,6 +4065,7 @@ varattrib_1b_e varattrib_4b vbits verifier_context +VersionType walrcv_alter_slot_fn walrcv_check_conninfo_fn walrcv_connect_fn base-commit: 87a6690cc69530703b7da7e72769bae2ac5b2e77 -- 2.45.1