The attached patches propose new interfaces for exposing more configuration
and versioning information from libpq at runtime. They are to be used by
applications to obtain finer grained information about libpq's
configuration (SSL, GSSAPI, etc), to identify libpq binaries, and for
applications that use libpq to report diagnostic information


Patch 0001 adds PQlibInfo(), which returns an array of key/value
description items reporting on configuration like the full version string,
SSL support, gssapi support, thread safety, default port and default unix
socket path. This is for application use and application diagnostics. It
also adds PQlibInfoPrint() which dumps PQlibInfo() keys/values to stdout.
See the commit message in patch 0001 for details.


Patch 0002 exposes LIBPQ_VERSION_STR, LIBPQ_VERSION_NUM and
LIBPQ_CONFIGURE_ARGS symbols in the dynamic symbol table. These can be
accessed by a debugger even when the library cannot be loaded or executed,
and unlike macros are available even in a stripped executable. So they can
be used to identify a libpq binary found in the wild. Their storage is
shared with PQlibInfo()'s static data, so they only cost three symbol table
entries.

$ cp ./build/src/interfaces/libpq/libpq.so libpq.so.stripped
$ strip libpq.so.stripped
$ gdb -batch -ex 'p (int)LIBPQ_VERSION_NUM' -ex 'p (const char
*)LIBPQ_VERSION_STR' -ex 'p (const char *)LIBPQ_CONFIGURE_ARGS'
./libpq.so.stripped
$1 = 140000
$2 = 0x285f0 "PostgreSQL 14devel on x86_64-pc-linux-gnu, ...."
$3 = 0x28660 " '--cache-file=config.cache-'
'--prefix=/home/craig/pg/master' '--enable-debug' '--enable-cassert'
'--enable-tap-tests' '--enable-dtrace' 'CC=/usr/lib64/ccache/gcc'
'CFLAGS=-Og -ggdb3' ..."



Patch 0003 allows libpq.so to be executed directly from the command line to
print its version, configure arguments etc exactly as PQlibInfoPrint()
would output them. This is only enabled on x64 linux for now but can be
extended to other targets quite simply.

$  ./build/src/interfaces/libpq/libpq.so
VERSION_NUM: 140000
VERSION: PostgreSQL 14devel on x86_64-pc-linux-gnu, compiled by gcc (GCC)
10.2.1 20200723 (Red Hat 10.2.1-1), 64-bit
CONFIGURE_ARGS:  '--cache-file=config.cache-'
'--prefix=/home/craig/pg/master' '--enable-debug' '--enable-cassert'
'--enable-tap-tests' '--enable-dtrace' 'CC=/usr/lib64/ccache/gcc'
'CFLAGS=-Og -ggdb3' 'CPPFLAGS=' 'CPP=/usr/lib64/ccache/gcc -E'
USE_SSL: 0
ENABLE_GSS: 0
ENABLE_THREAD_SAFETY: 1
HAVE_UNIX_SOCKETS: 1
DEFAULT_PGSOCKET_DIR: /tmp
DEF_PGPORT: 5432
From a4741725a9596b25a9b7308b6a47e85b889d4557 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.rin...@2ndquadrant.com>
Date: Mon, 26 Oct 2020 20:43:24 +0800
Subject: [PATCH v1 2/3] Add libpq version information to dynamic symbol table

Add three new data symbols LIBPQ_VERSION_STR, LIBPQ_VERSION_NUM and
LIBPQ_CONFIGURE_ARGS to libpq's symbol table. These make it much easier to
identify a given libpq without debuginfo, even if it cannot be executed (e.g.
due to dependency problems or mismatched platforms).

    $ strip libpq.so
    $ gdb -batch -ex 'p (int)LIBPQ_VERSION_NUM' \
                 -ex 'p (const char *)LIBPQ_VERSION_STR' \
                 -ex 'p (const char *)LIBPQ_CONFIGURE_ARGS' \
                 ./libpq.so.stripped
    $1 = 140000
    $2 = 0x285f0 "PostgreSQL 14devel on x86_64 ...."
    $3 = 0x28660 " '--enable-debug' '--enable-cassert' ...."
---
 src/interfaces/libpq/exports.txt     |  3 +++
 src/interfaces/libpq/libpq-version.c | 32 +++++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index 1d8600f0d8..64fb62c802 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -181,3 +181,6 @@ PQgetSSLKeyPassHook_OpenSSL         178
 PQdefaultSSLKeyPassHook_OpenSSL     179
 PQlibInfo                           180
 PQlibInfoPrint                      181
+LIBPQ_VERSION_STR                   182
+LIBPQ_VERSION_NUM                   183
+LIBPQ_CONFIGURE_ARGS                184
diff --git a/src/interfaces/libpq/libpq-version.c b/src/interfaces/libpq/libpq-version.c
index 51a5c608c8..bab0263848 100644
--- a/src/interfaces/libpq/libpq-version.c
+++ b/src/interfaces/libpq/libpq-version.c
@@ -47,21 +47,47 @@
 
 #define libinfo_boolstr(x) (x) == 1 ? gettext_noop("1") : gettext_noop("0")
 
+/*
+ * Store postgres version information in const symbols in the read-only data
+ * section of the libpq binary so they are exposed in the export symbol table,
+ * not just as macros.
+ *
+ * This way the exact version of a given libpq.so / libpq.dll can be determined
+ * even if it was built without macros in debuginfo or if is stripped, and
+ * without necessarily being able to execute the binary (e.g. due to linker
+ * issues).
+ *
+ * We need to store these for PGlibInfoEntries anyway, this just makes them
+ * individually addressable for the use of trace/diagnostic tools and
+ * debuggers.
+ *
+ * The linker will put these in read-only data segments so they won't use extra
+ * dynamic memory at runtime.
+ *
+ * You should prefer to use the normal methods of getting version info in your
+ * applications - PQlibVersion(), PG_VERSION_NUM, the server_version_num GUC,
+ * etc.
+ */
+
+const char * const LIBPQ_VERSION_STR = PG_VERSION_STR;
+const int LIBPQ_VERSION_NUM = PG_VERSION_NUM;
+const char * const LIBPQ_CONFIGURE_ARGS = CONFIGURE_ARGS;
+
 static const PGlibInfoEntry PGlibInfoEntries[] = {
 	{
 		PGRES_LIBINFO_VERSION_NUM,
 		gettext_noop("VERSION_NUM"),
-		CppAsString2(PG_VERSION_NUM), 1, PG_VERSION_NUM
+		CppAsString2(PG_VERSION_NUM), 1, LIBPQ_VERSION_NUM
 	},
 	{
 		PGRES_LIBINFO_VERSION_STR,
 		gettext_noop("VERSION"),
-		PG_VERSION_STR, 0, 0
+		LIBPQ_VERSION_STR, 0, 0
 	},
 	{
 		PGRES_LIBINFO_CONFIGURE_ARGS,
 		gettext_noop("CONFIGURE_ARGS"),
-		CONFIGURE_ARGS, 0, 0
+		LIBPQ_CONFIGURE_ARGS, 0, 0
 	},
 	{
 		PGRES_LIBINFO_USE_SSL,
-- 
2.26.2

From d0eb44fc066d9125dbb097d76975be8278722586 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.rin...@2ndquadrant.com>
Date: Mon, 26 Oct 2020 16:39:50 +0800
Subject: [PATCH v1 3/3] On x64 linux, run PQlibInfoPrint() when libpq.so is
 executed

Allow libpq.so to be directly executed. When run, it emits the same version and
configuration information as PQlibInfoPrint().

This approach should work on any or all ELF platforms with dynamic linker
support, but the toolchain support for producing a -shared library that
has an interpreter set in its headers is presently a bit limited.
---
 doc/src/sgml/libpq.sgml              |  7 +++++++
 src/interfaces/libpq/Makefile        |  5 +++++
 src/interfaces/libpq/libpq-version.c | 28 ++++++++++++++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index f0e2255d18..77e0e66ebc 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -6436,6 +6436,13 @@ void PQlibInfoPrint(void);
       returned by <xref linkend="libpq-PQlibInfo"/> to the application's
       default stdio output stream (stdout).
      </para>
+     <para>
+      On Linux the same output may be obtained by executing <filename>libpq.so</filename>
+      directly, e.g.
+      <programlisting>
+        $ /usr/pgsql-11/lib/libpq.so
+      </programlisting>
+     </para>
      <note>
       <para>
        This function appeared in <productname>PostgreSQL</productname> version 14.
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 8a9a6f4c09..330e00bfc9 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -90,6 +90,11 @@ SHLIB_PREREQS = submake-libpgport
 
 SHLIB_EXPORTS = exports.txt
 
+# Support ./libpq.so execution of the built library; see libpq-version.c
+ifeq ($(host_tuple),x86_64-pc-linux-gnu)
+SHLIB_LINK += -Wl,--entry=libpq_exec_main
+endif
+
 PKG_CONFIG_REQUIRES_PRIVATE = libssl libcrypto
 
 all: all-lib
diff --git a/src/interfaces/libpq/libpq-version.c b/src/interfaces/libpq/libpq-version.c
index bab0263848..a24496360d 100644
--- a/src/interfaces/libpq/libpq-version.c
+++ b/src/interfaces/libpq/libpq-version.c
@@ -148,3 +148,31 @@ PQlibInfoPrint(void)
 		ientry ++;
 	}
 }
+
+/*
+ * If gcc and ld or clang and ld.lld would offer a --dynamic-linker=default
+ * or similar to force the .interp section to be emitted when building with
+ * -shared, we wouldn't need this. As it is, limit support for running
+ * libpq as an executable to x64 linux.
+ */
+#if defined(__GNUC__) && defined(__linux__) && defined(__x86_64__)
+const char interp_section[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
+
+/*
+ * Report library version and configuration by dumping PGlibInfoEntries to
+ * stdout when libpq is invoked as ./libpq.so. Do not call this when loading
+ * libpq as a shared library. Use PQlibInfo() instead.
+ *
+ * This won't work on Windows. You can abuse it with rundll32 if you must, but
+ * that's deprecated and should not be relied upon.
+ */
+extern void
+libpq_exec_main(void);
+
+void
+libpq_exec_main(void)
+{
+	PQlibInfoPrint();
+	exit(0);
+}
+#endif
-- 
2.26.2

From 7be4425d5f9c89f3fdd7946370efe3a20ec0d2a6 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.rin...@2ndquadrant.com>
Date: Mon, 26 Oct 2020 12:53:16 +0800
Subject: [PATCH v1 1/3] Add PQlibInfo() to get runtime configuration of
 current libpq

The new PQlibInfo() function allows applications linked to libpq to determine
whether the current libpq is built with SSL/TLS, GSSAPI, thread safety etc at
runtime. This lets applications check that the libpq the dynamic linker picked
actually matches the libpq they were compiled against. It also provides a way
for applications to include more useful libpq diagnostic and descriptive
information in their own diagnostic output commands.

Applications can also use PQlibInfo() to obtain finer-grained intput into
runtime decisions about whether to use certain libpq features. It is already
possible for applications to use lazy dynamic linking (RTLD_LAZY) or runtime
dynamic linking (dlopen) and use the return value from PQlibVersion() to decide
whether to attempt to use certain API functions. The addition of PQlibInfo()
extends this capability to potentially allow applications to access
compile-time optional library features. The application can test for the
availablity of the optional libpq APIs, so there's no requirement for libpq to
be able to expose sensible stubs when the functionality isn't configured or
available.

For covenient diagnostic use the new function PQlibInfoPrint() prints all
keys and values from PQlibInfo() to stdout.
---
 doc/src/sgml/libpq.sgml              | 195 ++++++++++++++++++++++++++-
 src/interfaces/libpq/Makefile        |   1 +
 src/interfaces/libpq/exports.txt     |   2 +
 src/interfaces/libpq/libpq-fe.h      |   6 +-
 src/interfaces/libpq/libpq-version.c | 124 +++++++++++++++++
 src/interfaces/libpq/libpq-version.h |  46 +++++++
 6 files changed, 372 insertions(+), 2 deletions(-)
 create mode 100644 src/interfaces/libpq/libpq-version.c
 create mode 100644 src/interfaces/libpq/libpq-version.h

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index de60281fcb..f0e2255d18 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -6251,6 +6251,199 @@ int PQlibVersion(void);
     </listitem>
    </varlistentry>
 
+   <varlistentry id="libpq-PQlibInfo">
+    <term><function>PQlibInfo</function><indexterm
+    ><primary>PQlibInfo</primary><seealso>PQlibVersion</seealso></indexterm></term>
+
+    <listitem>
+     <para>
+      Return an array of <structname>PGlibInfoEntry</structname> describing the
+      version and configuration of the currently loaded <filename>libpq</filename>.
+<synopsis>
+/* libpq-version.h */
+const PGlibInfoEntry * PQlibInfo(void);
+</synopsis>
+     </para>
+
+     <para>
+      The result of <function>PQlibInfo()</function> provides details about
+      the <filename>libpq</filename> that the application is actually linked
+      to at runtime. It exposes finer-grained information than is available
+      from <function>PQlibVersion()</function>.
+     </para>
+
+     <para>
+      Applications must include <filename>libpq-version.h</filename> to use
+      <function>PQlibInfo()</function>.
+     </para>
+
+     <para>
+      The return value is a pointer to a statically allocated array of
+      <structname>PGlibInfoEntry</structname>:
+      <variablelist id="libpq-struct-PGlibInfoEntry" xreflabel="struct PGlibInfoEntry">
+        <title><structname>PGlibInfoEntry</structname></title>
+        <varlistentry>
+          <term><type>enum PGlibInfoEntryKey</type> <structfield>key</structfield></term>
+          <listitem>
+            <para>
+              <xref linkend="libpq-enum-PGlibInfoEntryKey"/> identifying the entry, or
+              <literal>PGRES_LIBINFO_END_OF_LIST</literal> (0) for the end-of-array
+              sentinel value. The application should ignore entries with unrecognised
+              values for this field.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><type>const char *</type> <structfield>key_name</structfield></term>
+          <listitem>
+            <para>String representation of <structfield>key</structfield></para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><type>const char *</type> <structfield>value_str</structfield></term>
+          <listitem>
+            <para>Printable string describing key's value. Should never be 0.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><type>bool</type> <structfield>has_intvalue</structfield></term>
+          <listitem>
+            <para>1 if the <structfield>value_int</structfield> is valid, otherwise 0.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><type>int</type> <structfield>value_str</structfield></term>
+          <listitem>
+            <para>Integer describing key's value, if <structfield>value_int</structfield> is true.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+      The array is terminated by an entry with <structfield>key</structfield> <literal>==</literal>
+      <literal>PGRES_LIBINFO_END_OF_LIST</literal> (0). The caller
+      <emphasis>must not</emphasis> attempt to free or modify the return value.
+     </para>
+
+     <para>
+      Entries include but are not limited to:
+      <variablelist id="libpq-enum-PGlibInfoEntryKey" xreflabel="enum PGlibInfoEntryKey">
+        <title><type>PGlibInfoEntryKey</type></title>
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_END_OF_LIST</literal></term>
+         <listitem><para>List terminator. Do not read past this point. Always has value 0.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_END_OF_LIST</literal></term>
+         <listitem><para>List terminator. Do not read past this point. Always has value 0.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_VERSION_NUM</literal></term>
+         <listitem><para>Same as <function>PQlibVersion()</function></para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_VERSION_STR</literal></term>
+         <listitem><para>
+           Version string for the PostgreSQL this libpq came from, in exactly
+           the same format as the <literal>PG_VERSION_STR</literal> macro or
+           <xref linkend="guc-server-version-num"/> server variable. This
+           value is the version of the actually loaded libpq, not
+           the the application was compiled against or the version of
+           the postgres server being connected to.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_CONFIGURE_ARGS</literal></term>
+         <listitem><para>
+           Arguments passed to the <literal>configure</literal>
+           utility when the PostgreSQL this libpq came from was compiled.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_USE_SSL</literal></term>
+         <listitem><para>
+           1 if this libpq was compiled with SSL/TLS support, otherwise 0.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_ENABLE_GSS</literal></term>
+         <listitem><para>
+           1 if this libpq was compiled with GSSAPI (Kerberos) support, otherwise 0.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_ENABLE_THREAD_SAFETY</literal></term>
+         <listitem><para>
+           1 if this libpq was compiled with thread safety enabled, otherwise 0,
+           like <xref linkend="libpq-PQisthreadsafe"/>.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_HAVE_UNIX_SOCKETS</literal></term>
+         <listitem><para>
+           1 if this libpq was compiled with unix socket support, otherwise 0.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_DEFAULT_PGSOCKET_DIR</literal></term>
+         <listitem><para>
+           The default unix socket directory this libpq will use when no
+           <literal>host</literal> is provided in a connection string.
+         </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>PGRES_LIBINFO_DEF_PGPORT</literal></term>
+         <listitem><para>
+           The default TCP or unix socket port that libpq will use if no
+           <literal>port</literal> is provided in a connection string.
+         </para></listitem>
+        </varlistentry>
+
+      </variablelist>
+     </para>
+
+     <note>
+      <para>
+       This function appeared in <productname>PostgreSQL</productname> version 14.
+      </para>
+     </note>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="libpq-PQlibInfoPrint">
+    <term><function>PQlibInfoPrint</function><indexterm
+    ><primary>PQlibInfoPrint</primary><seealso>PQlibInfo</seealso></indexterm></term>
+    <listitem>
+     <para>
+      Writes libpq version and configuration information to stdout.
+<synopsis>
+/* libpq-version.h */
+void PQlibInfoPrint(void);
+</synopsis>
+     </para>
+     <para>
+      This function prints the <structfield>key_str</structfield> and
+      <structfield>value_str</structfield> of each
+      <xref linkend="libpq-struct-PGlibInfoEntry"/>
+      returned by <xref linkend="libpq-PQlibInfo"/> to the application's
+      default stdio output stream (stdout).
+     </para>
+     <note>
+      <para>
+       This function appeared in <productname>PostgreSQL</productname> version 14.
+      </para>
+     </note>
+    </listitem>
+   </varlistentry>
+
   </variablelist>
 
  </sect1>
@@ -7998,7 +8191,7 @@ void PQinitSSL(int do_ssl);
   </para>
 
   <variablelist>
-   <varlistentry id="libpq-PQisthreadsafe">
+   <varlistentry id="libpq-PQisthreadsafe" xreflabel="PQisthreadsafe()">
     <term><function>PQisthreadsafe</function><indexterm><primary>PQisthreadsafe</primary></indexterm></term>
 
     <listitem>
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 4ac5f4b340..8a9a6f4c09 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -42,6 +42,7 @@ OBJS = \
 	fe-secure.o \
 	legacy-pqsignal.o \
 	libpq-events.o \
+	libpq-version.o \
 	pqexpbuffer.o \
 	fe-auth.o
 
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index bbc1f90481..1d8600f0d8 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -179,3 +179,5 @@ PQgetgssctx               176
 PQsetSSLKeyPassHook_OpenSSL         177
 PQgetSSLKeyPassHook_OpenSSL         178
 PQdefaultSSLKeyPassHook_OpenSSL     179
+PQlibInfo                           180
+PQlibInfoPrint                      181
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 3b6a9fbce3..d9594cfa9b 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -594,7 +594,11 @@ 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).
+ *
+ * See libpq-version.h for more detailed library information.
+ */
 extern int	PQlibVersion(void);
 
 /* Determine length of multibyte encoded char at *s */
diff --git a/src/interfaces/libpq/libpq-version.c b/src/interfaces/libpq/libpq-version.c
new file mode 100644
index 0000000000..51a5c608c8
--- /dev/null
+++ b/src/interfaces/libpq/libpq-version.c
@@ -0,0 +1,124 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-version.c
+ *	  Functions to report libpq version, configuration and options
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/interfaces/libpq/fe-version.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <stdio.h>
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+#include "libpq-version.h"
+
+/* Adapt defined(foo) to is_foo boolean-truth */
+#ifdef USE_SSL
+#define is_use_ssl 1
+#else
+#define is_use_ssl 0
+#endif
+#ifdef ENABLE_GSS
+#define is_enable_gss 1
+#else
+#define is_enable_gss 0
+#endif
+#ifdef ENABLE_THREAD_SAFETY
+#define is_enable_thread_safety 1
+#else
+#define is_enable_thread_safety 0
+#endif
+#ifdef HAVE_UNIX_SOCKETS
+#define is_have_unix_sockets 1
+#else
+#define is_have_unix_sockets 0
+#ifndef DEFAULT_PGSOCKET_DIR
+#define DEFAULT_PGSOCKET_DIR gettext_noop("")
+#endif
+#endif
+
+#define libinfo_boolstr(x) (x) == 1 ? gettext_noop("1") : gettext_noop("0")
+
+static const PGlibInfoEntry PGlibInfoEntries[] = {
+	{
+		PGRES_LIBINFO_VERSION_NUM,
+		gettext_noop("VERSION_NUM"),
+		CppAsString2(PG_VERSION_NUM), 1, PG_VERSION_NUM
+	},
+	{
+		PGRES_LIBINFO_VERSION_STR,
+		gettext_noop("VERSION"),
+		PG_VERSION_STR, 0, 0
+	},
+	{
+		PGRES_LIBINFO_CONFIGURE_ARGS,
+		gettext_noop("CONFIGURE_ARGS"),
+		CONFIGURE_ARGS, 0, 0
+	},
+	{
+		PGRES_LIBINFO_USE_SSL,
+		gettext_noop("USE_SSL"),
+		libinfo_boolstr(is_use_ssl), 1, is_use_ssl
+	},
+	{
+		PGRES_LIBINFO_ENABLE_GSS,
+		gettext_noop("ENABLE_GSS"),
+		libinfo_boolstr(is_enable_gss), 1, is_enable_gss
+	},
+	{
+		PGRES_LIBINFO_ENABLE_THREAD_SAFETY,
+		gettext_noop("ENABLE_THREAD_SAFETY"),
+		libinfo_boolstr(is_enable_thread_safety),
+		1, is_enable_thread_safety
+	},
+	{
+		PGRES_LIBINFO_HAVE_UNIX_SOCKETS,
+		gettext_noop("HAVE_UNIX_SOCKETS"),
+		libinfo_boolstr(is_have_unix_sockets),
+		1, is_have_unix_sockets
+	},
+	{
+		PGRES_LIBINFO_DEFAULT_PGSOCKET_DIR,
+		gettext_noop("DEFAULT_PGSOCKET_DIR"),
+		DEFAULT_PGSOCKET_DIR, 0, 0
+	},
+	{
+		PGRES_LIBINFO_DEF_PGPORT,
+		gettext_noop("DEF_PGPORT"),
+		DEF_PGPORT_STR, 1, DEF_PGPORT
+	},
+	/* Sentry value, must always be at end of list */
+	{ PGRES_LIBINFO_END_OF_LIST, NULL, 0, 0 }
+};
+
+/* Get key/value library configuration info for apps */
+const PGlibInfoEntry *
+PQlibInfo(void)
+{
+	return &PGlibInfoEntries[0];
+}
+
+/*
+ * Dump PGlibInfoEntries to stdout. This deliberately does not take a FILE*
+ * because it is not guaranteed to be safe to pass a FILE* across shared
+ * library boundaries on Windows or anywhere else that libpq might be linked to
+ * a different C runtime than the executable that loaded it .
+ */
+void
+PQlibInfoPrint(void)
+{
+	const PGlibInfoEntry * ientry = PQlibInfo();
+	while (ientry->key != PGRES_LIBINFO_END_OF_LIST)
+	{
+		fprintf(stdout, "%s: %s\n", ientry->key_name, ientry->value_str);
+		ientry ++;
+	}
+}
diff --git a/src/interfaces/libpq/libpq-version.h b/src/interfaces/libpq/libpq-version.h
new file mode 100644
index 0000000000..d38af8fa9a
--- /dev/null
+++ b/src/interfaces/libpq/libpq-version.h
@@ -0,0 +1,46 @@
+/*-------------------------------------------------------------------------
+ *
+ * libpq-version.h
+ *	  This file provides an interface to inspect the version and capabilities
+ *	  of the currently linked-to libpq at runtime.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/interfaces/libpq/libpq-version.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+/* See the main documentation for info on these keys */
+typedef enum PGlibInfoEntryKey
+{
+	PGRES_LIBINFO_END_OF_LIST = 0,
+	PGRES_LIBINFO_VERSION_NUM,
+	PGRES_LIBINFO_VERSION_STR,
+	PGRES_LIBINFO_CONFIGURE_ARGS,
+	PGRES_LIBINFO_USE_SSL,
+	PGRES_LIBINFO_ENABLE_GSS,
+	PGRES_LIBINFO_ENABLE_THREAD_SAFETY,
+	PGRES_LIBINFO_HAVE_UNIX_SOCKETS,
+	PGRES_LIBINFO_DEFAULT_PGSOCKET_DIR,
+	PGRES_LIBINFO_DEF_PGPORT
+} PGlibInfoEntryKey;
+
+/* One entry from PQlibInfo() */
+typedef struct PGlibInfoEntry
+{
+	enum PGlibInfoEntryKey key;
+	const char * key_name;
+	const char * value_str;
+	bool has_int_value;
+	int value_int;
+} PGlibInfoEntry;
+
+/* Return statically allocated array of PQlibInfo terminated by null sentinel */
+extern const PGlibInfoEntry * PQlibInfo(void);
+
+/* Dump PQlibInfo output to stdout */
+extern void PQlibInfoPrint(void);
-- 
2.26.2

Reply via email to