From d903142d178dd8a9c03d07ee4809ac582b9b7818 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Sat, 5 Oct 2024 18:27:57 +0200 Subject: [PATCH v1 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 | 56 ++++++++++++ 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 | 108 ++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 6 ++ src/include/utils/system_version.h | 40 +++++++++ src/test/regress/expected/rules.out | 8 ++ 8 files changed, 229 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 634a4c0..df0b9d3 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 + + @@ -5064,4 +5069,55 @@ 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 + + + + + +
+
+ diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 7fd5d25..091013d 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1377,3 +1377,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 d9f5978..fcb3be7 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -31,7 +31,8 @@ OBJS = \ sampling.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 6669502..ca2abc5 100644 --- a/src/backend/utils/misc/meson.build +++ b/src/backend/utils/misc/meson.build @@ -15,6 +15,7 @@ backend_sources += files( 'rls.c', 'sampling.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 0000000..4d633fc --- /dev/null +++ b/src/backend/utils/misc/system_version.c @@ -0,0 +1,108 @@ +/*------------------------------------------------------------------------ + * + * 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) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("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 43f608d..59587db 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12316,4 +12316,10 @@ proargtypes => 'int2', prosrc => 'gist_stratnum_identity' }, +{ 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 0000000..a73f046 --- /dev/null +++ b/src/include/utils/system_version.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * 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 + +#include + +#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 a1626f3..b9ad6f5 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2611,6 +2611,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, base-commit: 6aa44060a3c94ee10273bb8a89e98a5bb2fbbacb -- 2.45.1