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 v2 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
+
+ pg_system_versions
+
+
+ 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.
+
+
+
+ pg_system_versions 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