> On Mon, Oct 07, 2024 at 11:26:41AM GMT, Dmitry Dolgov wrote: > > On Sun, Oct 06, 2024 at 12:01:29PM GMT, Joe Conway wrote: > > I'm not sure why ICU is "Compile Time" rather than "Run Time" when it is not > > statically linked. > > It reports U_UNICODE_VERSION at compile time. It's not necessarily > correct though, I can try to replace it with the runtime version. I > think there was some ICU functionality (something like > u_getUnicodeVersion), which is maybe a better fit. > > > Also, if we are going to include ICU here, shouldn't we > > also include libc version? > > Yeah, why not. One of my goals here is to identify a balanced set of > useful versions to report.
Here is how it would look like, I've added icu and glibc runtime versions into the second patch.
>From d903142d178dd8a9c03d07ee4809ac582b9b7818 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthali...@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 @@ <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> @@ -5064,4 +5069,55 @@ 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> + + </tbody> + </tgroup> + </table> + </sect1> + </chapter> 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 <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) + 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 <link.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 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
>From f3b2ea3dbea5aa8e9197a25d0f38141eb67f0163 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthali...@gmail.com> Date: Sat, 5 Oct 2024 18:30:34 +0200 Subject: [PATCH v2 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 | 9 ++++ src/test/regress/expected/sysviews.out | 8 ++++ src/test/regress/sql/sysviews.sql | 4 ++ 9 files changed, 116 insertions(+) diff --git a/configure b/configure index 53c8a1f..63e6d3e 100755 --- a/configure +++ b/configure @@ -19223,6 +19223,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 6a35b28..d063504 100644 --- a/configure.ac +++ b/configure.ac @@ -2417,6 +2417,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 7150f85..c5dfba6 100644 --- a/meson.build +++ b/meson.build @@ -2756,6 +2756,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 7f5eada..3b45fdc 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -80,6 +80,7 @@ #include "utils/timeout.h" #include "utils/timestamp.h" #include "utils/varlena.h" +#include "utils/system_version.h" /* ---------------- * global variables @@ -197,6 +198,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); /* ---------------------------------------------------------------- @@ -4369,6 +4371,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. @@ -5282,3 +5287,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 4d633fc..8ff8697 100644 --- a/src/backend/utils/misc/system_version.c +++ b/src/backend/utils/misc/system_version.c @@ -67,6 +67,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 3800636..b0a588b 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -621,6 +621,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 a73f046..8508b27 100644 --- 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> #define MAX_SYSTEM_VERSIONS 100 @@ -36,5 +37,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 fad7fc3..0afabc1 100644 --- a/src/test/regress/expected/sysviews.out +++ b/src/test/regress/expected/sysviews.out @@ -222,3 +222,11 @@ select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; t (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 b2a7923..7a5a5f6 100644 --- a/src/test/regress/sql/sysviews.sql +++ b/src/test/regress/sql/sysviews.sql @@ -98,3 +98,7 @@ set timezone_abbreviations = 'Australia'; select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; set timezone_abbreviations = 'India'; select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; + +-- 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 3644bb60a3c24ff0f488321a50f627c83c8a313d Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthali...@gmail.com> Date: Sat, 5 Oct 2024 18:31:36 +0200 Subject: [PATCH v2 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 815b58f..8085a43 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 0f6cec5..2eed882 100644 --- a/src/backend/jit/llvm/llvmjit.c +++ b/src/backend/jit/llvm/llvmjit.c @@ -165,6 +165,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; } @@ -1382,3 +1383,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 3b45fdc..84a2a44 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -5293,4 +5293,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 d9a080c..6b3d453 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 420775b..898848a 100644 --- a/src/include/jit/llvmjit.h +++ b/src/include/jit/llvmjit.h @@ -136,6 +136,8 @@ extern LLVMValueRef slot_compile_deform(struct LLVMJitContext *context, TupleDes extern LLVMTypeRef LLVMGetFunctionReturnType(LLVMValueRef r); extern LLVMTypeRef LLVMGetFunctionType(LLVMValueRef r); +extern const char* llvm_version(bool *available); + #ifdef __cplusplus } /* extern "C" */ #endif -- 2.45.1
>From 2b8d560365012c06c54405bbfb7c69971d7e7dea Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthali...@gmail.com> Date: Sat, 5 Oct 2024 18:32:04 +0200 Subject: [PATCH v2 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 | 81 +++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 6 ++ src/include/utils/system_version.h | 9 +++ src/test/regress/expected/rules.out | 2 + src/test/regress/expected/sysviews.out | 7 +++ src/test/regress/sql/sysviews.sql | 2 + 9 files changed, 157 insertions(+) diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml index df0b9d3..bf397f5 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> @@ -5120,4 +5125,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 091013d..26f087c 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1385,3 +1385,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 84a2a44..80c5372 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4373,6 +4373,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 8ff8697..7eb7138 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) @@ -165,3 +170,79 @@ 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); + + if (found) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("duplicated library"))); + + 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 59587db..f00a562 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12322,4 +12322,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 8508b27..e977d4f 100644 --- a/src/include/utils/system_version.h +++ b/src/include/utils/system_version.h @@ -15,6 +15,7 @@ #include <link.h> #define MAX_SYSTEM_VERSIONS 100 +#define MAX_SYSTEM_LIBRARIES 100 typedef enum VersionType { @@ -36,8 +37,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); @@ -46,4 +53,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 b9ad6f5..3ba2510 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2611,6 +2611,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 0afabc1..c8b14c1 100644 --- a/src/test/regress/expected/sysviews.out +++ b/src/test/regress/expected/sysviews.out @@ -230,3 +230,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 7a5a5f6..1334574 100644 --- a/src/test/regress/sql/sysviews.sql +++ b/src/test/regress/sql/sysviews.sql @@ -102,3 +102,5 @@ select count(distinct utc_offset) >= 24 as ok from pg_timezone_abbrevs; -- 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; -- 2.45.1