> On Thu, Jan 02, 2025 at 10:36:48AM GMT, jian he wrote:
> hi.
> https://cirrus-ci.com/github/postgresql-cfbot/postgresql/cf%2F5318
> shows lots of failures, but it doesn't seem to tell you about doc build 
> failure.

Thanks for checking this out. Here is the updated version with applied
changes. The tests were failing due to injection_points library
apparently linking something twice, triggering a duplication error I
didn't expect. Since apparently it can happen, I'm just overwriting
duplicates.

> --- a/src/include/utils/system_version.h
> +++ b/src/include/utils/system_version.h
> @@ -11,6 +11,7 @@
>  #ifndef SYSTEM_VERSION_H
>  #define SYSTEM_VERSION_H
>
> +#include <gnu/libc-version.h>
>  #include <link.h>
>
> "gnu/libc-version.h" does not exist in the clang compiler?
> will "link.h" everywhere?

This one I don't follow, what do you mean by "link.h" everywhere? I
think those two are coming from glibc and compiler independent. But it
indeed makes sense to wrap them into __GLIBC__.

> Currently, only a few rows are displayed for pg_system_versions. If I have
> linked a dependency, I should be able to retrieve its version—for example, I
> should be able to determine the version of zstd (i have linked the
> zstd dependency).

Maybe I'm missing something, but that's the plan -- pg_system_versions
contains only some selected components, that have to be registered
manually before showing up there. This of course means that it's hard to
get all the linked libraries, but opens a possibility to show any kind
of objects, not only what is linked. The actual list of versions is open
for discussion of course, but showing everything is not feasible I
think. For things like zstd pg_system_libraries is a better fit.
>From fef34945c553de6db5abcd517f7c90fb9199e1b1 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthali...@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 @@
       <entry>wait events</entry>
      </row>
 
+     <row>
+      <entry><link 
linkend="view-pg-system-versions"><structname>pg_system_versions</structname></link></entry>
+      <entry>system versions</entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
@@ -5068,4 +5073,64 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
   </table>
  </sect1>
 
+ <sect1 id="view-pg-system-versions">
+  <title><structname>pg_system_versions</structname></title>
+
+  <indexterm zone="view-pg-system-version">
+   <primary>pg_system_versions</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_system_versions</structname> provides description
+   about versions of various system components, e.g. PostgreSQL itself,
+   compiler used to build it, dependencies, etc.
+  </para>
+
+  <table>
+   <title><structname>pg_system_versions</structname> Columns</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>name</structfield> <type>text</type>
+      </para>
+      <para>
+       Component name
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>version</structfield> <type>text</type>
+      </para>
+      <para>
+       Component version
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>type</structfield> <type>text</type>
+      </para>
+      <para>
+       Component type (compile time or Run time)
+      </para></entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+ </sect1>
+
 </chapter>
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 <unicode/uchar.h>
+
+#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

>From 33e5e4b2245f3ba909321a6edcf20f042b17453a Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthali...@gmail.com>
Date: Sat, 25 Jan 2025 20:31:55 +0100
Subject: [PATCH v3 2/4] Add core versions to pg_system_versions

Populate pg_system_versions with a set of core versions: host system
architecture, ICU version, glibc version, PostgreSQL itself and compiler
which was used to build everything. Register the core versions at the
backend startup.

    select * from pg_system_versions;
       name   |   version    |     type
    ----------+--------------+--------------
     Arch     | x86_64-linux | Compile Time
     ICU      | 15.1         | Run Time
     Core     | 18devel      | Compile Time
     Compiler | gcc-14.0.1   | Compile Time
     Glibc    | 2.40         | Run Time
---
 configure                               | 12 +++++
 configure.ac                            |  4 ++
 meson.build                             |  4 ++
 src/backend/tcop/postgres.c             | 12 +++++
 src/backend/utils/misc/system_version.c | 59 +++++++++++++++++++++++++
 src/include/pg_config.h.in              |  4 ++
 src/include/utils/system_version.h      | 12 +++++
 src/test/regress/expected/sysviews.out  |  8 ++++
 src/test/regress/sql/sysviews.sql       |  4 ++
 9 files changed, 119 insertions(+)

diff --git a/configure b/configure
index ceeef9b0915..e68cb447f20 100755
--- a/configure
+++ b/configure
@@ -18715,6 +18715,18 @@ else
 fi
 
 
+cat >>confdefs.h <<_ACEOF
+#define PG_CC_STR "$cc_string"
+_ACEOF
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define PG_ARCH_STR "$host"
+_ACEOF
+
+
+
 cat >>confdefs.h <<_ACEOF
 #define PG_VERSION_STR "PostgreSQL $PG_VERSION on $host, compiled by 
$cc_string, `expr $ac_cv_sizeof_void_p \* 8`-bit"
 _ACEOF
diff --git a/configure.ac b/configure.ac
index d713360f340..07d1ca0cf9c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2352,6 +2352,10 @@ else
   cc_string=$CC
 fi
 
+AC_DEFINE_UNQUOTED(PG_CC_STR, ["$cc_string"], [C compiler version])
+
+AC_DEFINE_UNQUOTED(PG_ARCH_STR, ["$host"], [Platform])
+
 AC_DEFINE_UNQUOTED(PG_VERSION_STR,
                    ["PostgreSQL $PG_VERSION on $host, compiled by $cc_string, 
`expr $ac_cv_sizeof_void_p \* 8`-bit"],
                    [A string containing the version number, platform, and C 
compiler])
diff --git a/meson.build b/meson.build
index 8e128f4982a..2eafd645399 100644
--- a/meson.build
+++ b/meson.build
@@ -2718,6 +2718,10 @@ 
cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
 cdata.set_quoted('DLSUFFIX', dlsuffix)
 
+cdata.set_quoted('PG_CC_STR', '@0@-@1@'.format(cc.get_id(), cc.version()))
+
+cdata.set_quoted('PG_ARCH_STR', '@0@-@1@'.format(
+  host_machine.cpu_family(), host_system))
 
 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
 cdata.set_quoted('PG_VERSION_STR',
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 5655348a2e2..15edc827d62 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -79,6 +79,7 @@
 #include "utils/timeout.h"
 #include "utils/timestamp.h"
 #include "utils/varlena.h"
+#include "utils/system_version.h"
 
 /* ----------------
  *             global variables
@@ -184,6 +185,7 @@ static void drop_unnamed_stmt(void);
 static void log_disconnections(int code, Datum arg);
 static void enable_statement_timeout(void);
 static void disable_statement_timeout(void);
+static void register_system_versions(void);
 
 
 /* ----------------------------------------------------------------
@@ -4267,6 +4269,9 @@ PostgresMain(const char *dbname, const char *username)
         */
        BeginReportingGUCOptions();
 
+       /* Prepare information for reporting versions and libraries. */
+       register_system_versions();
+
        /*
         * Also set up handler to log session end; we have to wait till now to 
be
         * sure Log_disconnections has its final value.
@@ -5153,3 +5158,10 @@ disable_statement_timeout(void)
        if (get_timeout_active(STATEMENT_TIMEOUT))
                disable_timeout(STATEMENT_TIMEOUT, false);
 }
+
+static void
+register_system_versions()
+{
+       /* Set up reporting of core versions. */
+       register_core_versions();
+}
diff --git a/src/backend/utils/misc/system_version.c 
b/src/backend/utils/misc/system_version.c
index ac7df0527fc..d217c7e8cdb 100644
--- a/src/backend/utils/misc/system_version.c
+++ b/src/backend/utils/misc/system_version.c
@@ -65,6 +65,65 @@ add_system_version(const char* name, SystemVersionCB cb, 
VersionType type)
        hentry->type = type;
 }
 
+/*
+ * Register versions that describe core components and do not correspond to any
+ * individual component.
+ */
+void
+register_core_versions()
+{
+       add_system_version("Core", core_get_version, CompileTime);
+       add_system_version("Arch", core_get_arch, CompileTime);
+       add_system_version("Compiler", core_get_compiler, CompileTime);
+       add_system_version("ICU", icu_get_version, RunTime);
+       add_system_version("Glibc", glibc_get_version, RunTime);
+}
+
+const char*
+core_get_version(bool *available)
+{
+       *available = true;
+       return (const char*) psprintf("%s", PG_VERSION);
+}
+
+const char*
+core_get_arch(bool *available)
+{
+       *available = true;
+       return (const char*) psprintf("%s", PG_ARCH_STR);
+}
+
+const char*
+core_get_compiler(bool *available)
+{
+       *available = true;
+       return (const char*) psprintf("%s", PG_CC_STR);
+}
+
+const char*
+icu_get_version(bool *available)
+{
+#ifdef USE_ICU
+       UVersionInfo UCDVersion;
+       char* version = palloc0(U_MAX_VERSION_STRING_LENGTH);
+
+       *available = true;
+       u_getUnicodeVersion(UCDVersion);
+       u_versionToString(UCDVersion, version);
+       return (const char*) version;
+#else
+       *available = false;
+       return (const char*) "";
+#endif
+}
+
+const char*
+glibc_get_version(bool *available)
+{
+       *available = true;
+       return (const char*) gnu_get_libc_version();
+}
+
 /*
  * pg_get_system_versions
  *
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 07b2f798abd..1489ef7eeb1 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -591,6 +591,10 @@
 /* PostgreSQL version as a number */
 #undef PG_VERSION_NUM
 
+#undef PG_CC_STR
+
+#undef PG_ARCH_STR
+
 /* A string containing the version number, platform, and C compiler */
 #undef PG_VERSION_STR
 
diff --git a/src/include/utils/system_version.h 
b/src/include/utils/system_version.h
index 0321f67214f..28ebfb30807 100644
--- a/src/include/utils/system_version.h
+++ b/src/include/utils/system_version.h
@@ -11,6 +11,10 @@
 #ifndef SYSTEM_VERSION_H
 #define SYSTEM_VERSION_H
 
+#ifdef __GLIBC__
+#include <gnu/libc-version.h>
+#endif
+
 #define MAX_SYSTEM_VERSIONS 100
 
 typedef enum VersionType
@@ -34,5 +38,13 @@ typedef struct SystemVersion
 } SystemVersion;
 
 void add_system_version(const char* name, SystemVersionCB cb, VersionType 
type);
+extern void register_core_versions(void);
+
+const char* core_get_version(bool *available);
+const char* core_get_arch(bool *available);
+const char* core_get_compiler(bool *available);
+
+const char* icu_get_version(bool *available);
+const char* glibc_get_version(bool *available);
 
 #endif                                                 /* SYSTEM_VERSION_H */
diff --git a/src/test/regress/expected/sysviews.out 
b/src/test/regress/expected/sysviews.out
index 352abc0bd42..e9af9a72df6 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -231,3 +231,11 @@ select * from pg_timezone_abbrevs where abbrev = 'LMT';
  LMT    | @ 7 hours 52 mins 58 secs ago | f
 (1 row)
 
+-- At least 4 core versions should be present, architecture, ICU, core and
+-- compiler
+select count(*) >= 4 as ok FROM pg_system_versions;
+ ok 
+----
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/sysviews.sql 
b/src/test/regress/sql/sysviews.sql
index 66179f026b3..4ac0dacbb3e 100644
--- a/src/test/regress/sql/sysviews.sql
+++ b/src/test/regress/sql/sysviews.sql
@@ -101,3 +101,7 @@ select count(distinct utc_offset) >= 24 as ok from 
pg_timezone_abbrevs;
 -- One specific case we can check without much fear of breakage
 -- is the historical local-mean-time value used for America/Los_Angeles.
 select * from pg_timezone_abbrevs where abbrev = 'LMT';
+
+-- At least 4 core versions should be present, architecture, ICU, core and
+-- compiler
+select count(*) >= 4 as ok FROM pg_system_versions;
-- 
2.45.1

>From b3fd638e176a817eb110bcee419292d1303a12d9 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthali...@gmail.com>
Date: Sat, 5 Oct 2024 18:31:36 +0200
Subject: [PATCH v3 3/4] Add JIT provider version to pg_system_versions

Populate pg_system_versions with the JIT provider version. To actually
fetch the version, extend the JIT provider callbacks with the
get_version method. For LLVM provider llvm_version will be used, which
utilizes C-API LLVMGetVersion, available since LLVM 16.

The JIT provider will be initialized, when a first expression will be
compiled. For reporting purposes it's too late, thus register the
version at the backend startup, right after the core versions.
---
 src/backend/jit/jit.c          | 19 +++++++++++++++++++
 src/backend/jit/llvm/llvmjit.c | 17 +++++++++++++++++
 src/backend/tcop/postgres.c    |  7 +++++++
 src/include/jit/jit.h          | 11 +++++++++++
 src/include/jit/llvmjit.h      |  2 ++
 5 files changed, 56 insertions(+)

diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
index d2ccef9de85..cd6505f0db0 100644
--- a/src/backend/jit/jit.c
+++ b/src/backend/jit/jit.c
@@ -188,3 +188,22 @@ InstrJitAgg(JitInstrumentation *dst, JitInstrumentation 
*add)
        INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
        INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
 }
+
+/*
+ * Return JIT provider's version string for troubleshooting purposes.
+ */
+const char *
+jit_get_version(bool *available)
+{
+       if (provider_init())
+               return provider.get_version(available);
+
+       *available = false;
+       return "";
+}
+
+void
+jit_register_version(void)
+{
+       add_system_version("LLVM", jit_get_version, RunTime);
+}
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 614926720fb..ef8058e4af3 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -150,6 +150,7 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
        cb->reset_after_error = llvm_reset_after_error;
        cb->release_context = llvm_release_context;
        cb->compile_expr = llvm_compile_expr;
+       cb->get_version = llvm_version;
 }
 
 
@@ -1275,3 +1276,19 @@ ResOwnerReleaseJitContext(Datum res)
        context->resowner = NULL;
        jit_release_context(&context->base);
 }
+
+const char *
+llvm_version(bool *available)
+{
+#if LLVM_VERSION_MAJOR > 15
+       unsigned int major, minor, patch;
+
+       LLVMGetVersion(&major, &minor, &patch);
+
+       *available = true;
+       return (const char*) psprintf("%d.%d.%d", major, minor, patch);
+#else
+       *available = false;
+       return "";
+#endif
+}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 15edc827d62..3d815bfa1d2 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -5164,4 +5164,11 @@ register_system_versions()
 {
        /* Set up reporting of core versions. */
        register_core_versions();
+
+       /*
+        * Set up reporting for JIT provider version. JIT provider 
initialization
+        * happens when the first expression is getting compiled, which is too
+        * late. Thus register the callback here instead.
+        */
+       jit_register_version();
 }
diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h
index 33cb36c5d2e..37776530acd 100644
--- a/src/include/jit/jit.h
+++ b/src/include/jit/jit.h
@@ -13,6 +13,7 @@
 
 #include "executor/instrument.h"
 #include "utils/resowner.h"
+#include "utils/system_version.h"
 
 
 /* Flags determining what kind of JIT operations to perform */
@@ -70,12 +71,14 @@ typedef void (*JitProviderResetAfterErrorCB) (void);
 typedef void (*JitProviderReleaseContextCB) (JitContext *context);
 struct ExprState;
 typedef bool (*JitProviderCompileExprCB) (struct ExprState *state);
+typedef const char* (*JitProviderVersion) (bool *available);
 
 struct JitProviderCallbacks
 {
        JitProviderResetAfterErrorCB reset_after_error;
        JitProviderReleaseContextCB release_context;
        JitProviderCompileExprCB compile_expr;
+       JitProviderVersion get_version;
 };
 
 
@@ -102,5 +105,13 @@ extern void jit_release_context(JitContext *context);
 extern bool jit_compile_expr(struct ExprState *state);
 extern void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add);
 
+/*
+ * Get the provider's version string. The flag indicating availability is
+ * passed as an argument, and will be set accordingly if it's not possible to
+ * get the version.
+ */
+extern const char *jit_get_version(bool *available);
+
+extern void jit_register_version(void);
 
 #endif                                                 /* JIT_H */
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
index 5038cf33e3f..7e3810f5965 100644
--- a/src/include/jit/llvmjit.h
+++ b/src/include/jit/llvmjit.h
@@ -144,6 +144,8 @@ extern LLVMTypeRef LLVMGetFunctionType(LLVMValueRef r);
 extern LLVMOrcObjectLayerRef 
LLVMOrcCreateRTDyldObjectLinkingLayerWithSafeSectionMemoryManager(LLVMOrcExecutionSessionRef
 ES);
 #endif
 
+extern const char* llvm_version(bool *available);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-- 
2.45.1

>From 3c4d3b0b2f29dd65c4a01128f56babe552986800 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthali...@gmail.com>
Date: Sat, 25 Jan 2025 20:32:59 +0100
Subject: [PATCH v3 4/4] Add pg_system_libraries view

Introduce a way to report shared objects linked with PostgreSQL. Such
information is useful for troubleshooting, and could enhance bug reports. The
reporting is done via pg_system_libraries view, which contains a file path to
the shared object. It's implemented via standard C library dl_iterate_phdr,
which should be portable enough.

    select * from pg_system_libraries;
                name
    -----------------------------
     /lib64/libkrb5.so.3
     /lib64/libz.so.1
     linux-vdso.so.1
     /lib64/libxml2.so.2
    [...]
---
 doc/src/sgml/system-views.sgml          | 46 +++++++++++++++
 src/backend/catalog/system_views.sql    |  3 +
 src/backend/tcop/postgres.c             |  1 +
 src/backend/utils/misc/system_version.c | 76 +++++++++++++++++++++++++
 src/include/catalog/pg_proc.dat         |  6 ++
 src/include/utils/system_version.h      | 10 ++++
 src/test/regress/expected/rules.out     |  2 +
 src/test/regress/expected/sysviews.out  |  7 +++
 src/test/regress/sql/sysviews.sql       |  2 +
 src/tools/pgindent/typedefs.list        |  1 +
 10 files changed, 154 insertions(+)

diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml
index fa27f8cf52c..e86b1f61bbc 100644
--- a/doc/src/sgml/system-views.sgml
+++ b/doc/src/sgml/system-views.sgml
@@ -231,6 +231,11 @@
       <entry>system versions</entry>
      </row>
 
+     <row>
+      <entry><link 
linkend="view-pg-system-libraries"><structname>pg_system_libraries</structname></link></entry>
+      <entry>linked libraries</entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
@@ -5133,4 +5138,45 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
   </table>
  </sect1>
 
+ <sect1 id="view-pg-system-libraries">
+  <title><structname>pg_system_libraries</structname></title>
+
+  <indexterm zone="view-pg-system-libraries">
+   <primary>pg_system_libraries</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_system_libraries</structname> provides description
+   about shared objects PostgreSQL is linked with.
+  </para>
+
+  <table>
+   <title><structname>pg_system_libraries</structname> Columns</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>name</structfield> <type>text</type>
+      </para>
+      <para>
+       Shared object file path
+      </para></entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+ </sect1>
+
 </chapter>
diff --git a/src/backend/catalog/system_views.sql 
b/src/backend/catalog/system_views.sql
index 0704567bf8c..46b8711be7e 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1396,3 +1396,6 @@ CREATE VIEW pg_system_versions AS
                   WHEN 1 THEN 'Run Time'
                   END AS "type"
     FROM pg_get_system_versions();
+
+CREATE VIEW pg_system_libraries AS
+    SELECT * FROM pg_get_system_libraries() as f(name text);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 3d815bfa1d2..602d0a51f2a 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4271,6 +4271,7 @@ PostgresMain(const char *dbname, const char *username)
 
        /* Prepare information for reporting versions and libraries. */
        register_system_versions();
+       register_libraries();
 
        /*
         * Also set up handler to log session end; we have to wait till now to 
be
diff --git a/src/backend/utils/misc/system_version.c 
b/src/backend/utils/misc/system_version.c
index d217c7e8cdb..0851da966f2 100644
--- a/src/backend/utils/misc/system_version.c
+++ b/src/backend/utils/misc/system_version.c
@@ -14,6 +14,10 @@
  * a version string directly allows for more flexibility about how and when the
  * information could be reported.
  *
+ * Libraries reporting is implemented similarly via a hash table containing
+ * only the library file path. This information is populated directly during
+ * the initialization.
+ *
  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -32,6 +36,7 @@
 #include "utils/system_version.h"
 
 static HTAB       *versions = NULL;
+static HTAB       *libraries = NULL;
 
 void
 add_system_version(const char* name, SystemVersionCB cb, VersionType type)
@@ -163,3 +168,74 @@ pg_get_system_versions(PG_FUNCTION_ARGS)
 
        return (Datum) 0;
 }
+
+/*
+ * Walk through list of shared objects and populate the libraries hash table.
+ */
+void
+register_libraries()
+{
+       HASHCTL         ctl;
+
+       ctl.keysize = NAMEDATALEN;
+       ctl.entrysize = sizeof(SystemLibrary);
+       ctl.hcxt = CurrentMemoryContext;
+
+       libraries = hash_create("Libraries table",
+                                                                  
MAX_SYSTEM_LIBRARIES,
+                                                                  &ctl,
+                                                                  HASH_ELEM | 
HASH_STRINGS);
+
+       dl_iterate_phdr(add_library, NULL);
+}
+
+int add_library(struct dl_phdr_info *info, size_t size, void *data)
+{
+       const char              *key;
+       bool                    found;
+
+       if (strcmp(info->dlpi_name, "") == 0)
+       {
+               /* The first visited object is the main program with the empty 
name,
+                * which is not so interesting. */
+               return 0;
+       }
+
+       key = pstrdup(info->dlpi_name);
+       hash_search(libraries, key, HASH_ENTER, &found);
+
+       return 0;
+}
+
+/*
+ * pg_get_libraries
+ *
+ * List information about shared objects.
+ */
+Datum
+pg_get_system_libraries(PG_FUNCTION_ARGS)
+{
+#define PG_GET_SYS_LIBRARIES_COLS 1
+       ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+       HASH_SEQ_STATUS status;
+       SystemLibrary *hentry;
+
+       /* Build tuplestore to hold the result rows */
+       InitMaterializedSRF(fcinfo, 0);
+
+       if (!versions)
+               return (Datum) 0;
+
+       hash_seq_init(&status, libraries);
+       while ((hentry = (SystemLibrary *) hash_seq_search(&status)) != NULL)
+       {
+               Datum           values[PG_GET_SYS_LIBRARIES_COLS] = {0};
+               bool            nulls[PG_GET_SYS_LIBRARIES_COLS] = {0};
+
+               values[0] = CStringGetTextDatum(hentry->filepath);
+
+               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 563c2bc1437..3584be8bf77 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12444,4 +12444,10 @@
   proargtypes => '', proallargtypes => '{text,text,int8}',
   proargmodes => '{o,o,o}', proargnames => '{name,version,type}',
   prosrc => 'pg_get_system_versions' },
+{ oid => '9433', descr => 'describe system libraries',
+  proname => 'pg_get_system_libraries', procost => '10', prorows => '30',
+  proretset => 't', provolatile => 'v', prorettype => 'record',
+  proargtypes => '', proallargtypes => '{text}',
+  proargmodes => '{o}', proargnames => '{name}',
+  prosrc => 'pg_get_system_libraries' },
 ]
diff --git a/src/include/utils/system_version.h 
b/src/include/utils/system_version.h
index 28ebfb30807..4c65e7288b2 100644
--- a/src/include/utils/system_version.h
+++ b/src/include/utils/system_version.h
@@ -13,9 +13,11 @@
 
 #ifdef __GLIBC__
 #include <gnu/libc-version.h>
+#include <link.h>
 #endif
 
 #define MAX_SYSTEM_VERSIONS 100
+#define MAX_SYSTEM_LIBRARIES 100
 
 typedef enum VersionType
 {
@@ -37,8 +39,14 @@ typedef struct SystemVersion
        SystemVersionCB callback;                       /* Callback to fetch 
the version string */
 } SystemVersion;
 
+typedef struct SystemLibrary
+{
+       char                    filepath[NAMEDATALEN];
+} SystemLibrary;
+
 void add_system_version(const char* name, SystemVersionCB cb, VersionType 
type);
 extern void register_core_versions(void);
+extern void register_libraries(void);
 
 const char* core_get_version(bool *available);
 const char* core_get_arch(bool *available);
@@ -47,4 +55,6 @@ const char* core_get_compiler(bool *available);
 const char* icu_get_version(bool *available);
 const char* glibc_get_version(bool *available);
 
+int add_library(struct dl_phdr_info *info, size_t size, void *data);
+
 #endif                                                 /* SYSTEM_VERSION_H */
diff --git a/src/test/regress/expected/rules.out 
b/src/test/regress/expected/rules.out
index 047441f9ebb..3949bebab3f 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2617,6 +2617,8 @@ 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_libraries| SELECT name
+   FROM pg_get_system_libraries() f(name text);
 pg_system_versions| SELECT name,
     version,
         CASE type
diff --git a/src/test/regress/expected/sysviews.out 
b/src/test/regress/expected/sysviews.out
index e9af9a72df6..af5b0c2ba5c 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -239,3 +239,10 @@ select count(*) >= 4 as ok FROM pg_system_versions;
  t
 (1 row)
 
+-- There is always some number of shared objects
+select count(*) > 0 as ok FROM pg_system_libraries;
+ ok 
+----
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/sysviews.sql 
b/src/test/regress/sql/sysviews.sql
index 4ac0dacbb3e..30000c3f770 100644
--- a/src/test/regress/sql/sysviews.sql
+++ b/src/test/regress/sql/sysviews.sql
@@ -105,3 +105,5 @@ select * from pg_timezone_abbrevs where abbrev = 'LMT';
 -- At least 4 core versions should be present, architecture, ICU, core and
 -- compiler
 select count(*) >= 4 as ok FROM pg_system_versions;
+-- There is always some number of shared objects
+select count(*) > 0 as ok FROM pg_system_libraries;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index ccad37e0e2c..ae12644286a 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2820,6 +2820,7 @@ SysFKRelationship
 SysScanDesc
 SyscacheCallbackFunction
 SysloggerStartupData
+SystemLibrary
 SystemRowsSamplerData
 SystemSamplerData
 SystemTimeSamplerData
-- 
2.45.1

Reply via email to