From caa461373cd14a7cfa41b6a37f0d2c7577c0c935 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthalion6@gmail.com>
Date: Sat, 5 Oct 2024 18:32:04 +0200
Subject: [PATCH v1 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 @@
system versions
+
+ pg_system_libraries
+ linked libraries
+
+
@@ -5120,4 +5125,45 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
+
+ pg_system_libraries
+
+
+ pg_system_libraries
+
+
+
+ The view pg_system_libraries provides description
+ about shared objects PostgreSQL is linked with.
+
+
+
+ pg_system_libraries Columns
+
+
+
+
+ Column Type
+
+
+ Description
+
+
+
+
+
+
+
+ name text
+
+
+ Shared object file path
+
+
+
+
+
+
+
+
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 8ebd0c3..73e8078 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)
@@ -152,3 +157,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 9537f47..01551fd 100644
--- a/src/include/utils/system_version.h
+++ b/src/include/utils/system_version.h
@@ -14,6 +14,7 @@
#include
#define MAX_SYSTEM_VERSIONS 100
+#define MAX_SYSTEM_LIBRARIES 100
typedef enum VersionType
{
@@ -35,8 +36,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);
@@ -44,4 +51,6 @@ const char* core_get_compiler(bool *available);
const char* icu_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