On Tue, Nov 10, 2020 at 2:22 PM Craig Ringer <craig.rin...@enterprisedb.com> wrote:
> > The main things I'd really like to get in place are a way to get the > version as an ELF data symbol, and a simple way to ID the binary. > > So the minimal change would be to declare: > > const char LIBPQ_VERSION_STR[] = PG_VERSION_STR; > const int LIBPQ_VERSION_NUM = PG_VERSION_NUM; > > then change PQgetVersion() to return LIBPQ_VERSION_NUM and add a > PQgetVersionStr() that returns LIBPQ_VERSION_STR. > > That OK with you? > Proposed minimal patch attached.
From 137fa6f0ee8a13e56025af4adf7707b8ec8e4739 Mon Sep 17 00:00:00 2001 From: Craig Ringer <craig.rin...@2ndquadrant.com> Date: Wed, 11 Nov 2020 11:45:05 +0800 Subject: [PATCH v2] Add PQlibVersionString() to libpq Provide applications with a way to get the full postgres version string associated with the libpq they are dynamically linked against. This might not be the same libpq they were compiled against, so checking PG_VERSION_STR is not the same thing. Expose LIBPQ_VERSION_NUM and LIBPQ_VERSION_STR symbols in the libpq export symbol table for examination in situations like core file analysis where functions cannot be called. Debuggers can't inspect PG_VERSION_NUM etc unless -ggdb3 debuginfo is available, wheras this will will work even with a stripped binary since they're in the export symbol table. Also useful for use in trace tooling (dtrace, systemtap, perf, etc) and for identifying a stray libpq binary found lying around: $ gdb -batch \ -ex 'p (int)LIBPQ_VERSION_NUM' \ -ex 'p (const char*)&LIBPQ_VERSION_STR' \ build/src/interfaces/libpq/libpq.so $1 = 140000 $2 = 0x269c0 <LIBPQ_VERSION_STR> "PostgreSQL 14devel ..." or $ strings build/src/interfaces/libpq/libpq.so | egrep '^PostgreSQL [0-9]' PostgreSQL 14devel ... --- doc/src/sgml/libpq.sgml | 49 ++++++++++++++++++++++++++++++++ src/interfaces/libpq/exports.txt | 3 ++ src/interfaces/libpq/fe-misc.c | 21 +++++++++++++- src/interfaces/libpq/libpq-fe.h | 5 +++- src/interfaces/libpq/libpq-int.h | 8 ++++++ 5 files changed, 84 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 9ce32fb39b..1b7f57c549 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -6248,6 +6248,55 @@ int PQlibVersion(void); on version 9.1 or later. </para> </note> + + <para> + The value returned by <function>PQlibVersion()</function> is also exposed as the + exported symbol <varname>LIBPQ_VERSION_NUM</varname> for use by debuggers and + trace tooling. Applications should not reference this directly; call the function + instead. + </para> + + </listitem> + </varlistentry> + + <varlistentry id="libpq-PQlibVersionString"> + <term> + <function>PQlibVersionString</function> + <indexterm> + <primary>PQlibVersionString</primary> + <seealso>PQserverVersion</seealso> + <seealso>PQlibVersion</seealso> + </indexterm> + </term> + + <listitem> + <para> + Return a string describing the PostgreSQL version that the currently loaded + <productname>libpq</productname> binary was compiled against. +<synopsis> +const char * PQlibVersion(void); +</synopsis> + </para> + + <para> + The return value is a statically allocated string. The caller must not free it. + </para> + + <para> + Applications should prefer to call <function>PQlibVersion()</function> + to determine the major and minor versions. Do not parse this version string + to get the numeric version information. Use <function>PQlibVersionString</function> + when displaying a detailed version in diagnostic output or debug logs where + a more detailed identification of the exact libpq binary may be desirable. + </para> + + <para> + The value returned by <function>PQlibVersionString()</function> is also exposed as the + exported symbol <varname>LIBPQ_VERSION_STR</varname> for use by debuggers and + trace tooling. Applications should not reference this directly; call the function + instead. + </para> + </listitem> </varlistentry> diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index bbc1f90481..76dfdc1d5f 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -179,3 +179,6 @@ PQgetgssctx 176 PQsetSSLKeyPassHook_OpenSSL 177 PQgetSSLKeyPassHook_OpenSSL 178 PQdefaultSSLKeyPassHook_OpenSSL 179 +PQlibVersionString 180 +LIBPQ_VERSION_STR 181 +LIBPQ_VERSION_NUM 182 diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 4ffc7f33fb..c57ef85a4d 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -59,15 +59,34 @@ static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time); static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time); +/* + * Storage for version information. These are deliberately not static, so they + * appear in the symbol table where they can be inspected by debuggers and + * trace tools in contexts where a function call isn't possible. They aren't + * declared as externs in libpq-fe.h because we want programs to use the + * function interfaces instead. + */ +const char LIBPQ_VERSION_STR[] = PG_VERSION_STR; +const int LIBPQ_VERSION_NUM = PG_VERSION_NUM; + /* * PQlibVersion: return the libpq version number */ int PQlibVersion(void) { - return PG_VERSION_NUM; + return LIBPQ_VERSION_NUM; } +/* + * PQlibVersionString: return the postgres version that this libpq + * was compiled against. + */ +const char * +PQlibVersionString(void) +{ + return &LIBPQ_VERSION_STR[0]; +} /* * pqGetc: get 1 character from the connection diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 3b6a9fbce3..9f61cdc1ed 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -594,9 +594,12 @@ extern int lo_export(PGconn *conn, Oid lobjId, const char *filename); /* === in fe-misc.c === */ -/* Get the version of the libpq library in use */ +/* Get the version of the libpq library in use (PG_VERSION_NUM) */ extern int PQlibVersion(void); +/* Get the postgres version string for this libpq build (PG_VERSION_STR) */ +extern const char * PQlibVersionString(void); + /* Determine length of multibyte encoded char at *s */ extern int PQmblen(const char *s, int encoding); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 1de91ae295..e3a970bf11 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -820,4 +820,12 @@ extern char *libpq_ngettext(const char *msgid, const char *msgid_plural, unsigne #define SOCK_ERRNO_SET(e) (errno = (e)) #endif +/* + * Embed libpq version information symbols. Client code should use + * PQlibVersion() and PQlibVersionString() instead. These are here for + * debug/trace tooling and diagnostic purposes. + */ +extern const char LIBPQ_VERSION_STR[]; /* libpq compile-time PG_VERSION_STR */ +extern const int LIBPQ_VERSION_NUM; /* libpq compile-time PG_VERSION_NUM */ + #endif /* LIBPQ_INT_H */ -- 2.26.2