From 843ef9ec4a19a5c818334d6bee56673827e0feda Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Thu, 19 Feb 2026 12:39:16 -0800
Subject: [PATCH] libpq: Add PQgetThreadLock() to mirror PQregisterThreadLock()

Allow libpq clients to retrieve the current pg_g_threadlock pointer with
PQgetThreadLock(). Single-threaded applications could already do this in
a convoluted way:

    pgthreadlock_t tlock;

    tlock = PQregisterThreadLock(NULL);
    PQregisterThreadLock(tlock);    /* re-register the callback */

    /* use tlock */

But a generic library can't do that without potentially breaking
concurrent libpq connections.

The motivation for doing this now is the libpq-oauth plugin, which
currently relies on direct injection of pg_g_threadlock, and should
ideally not.

Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAOYmi%2BmEU_q9sr1PMmE-4rLwFN%3DOjyndDwFZvpsMU3RNJLrM9g%40mail.gmail.com
---
 doc/src/sgml/libpq.sgml           |  6 +++++-
 src/interfaces/libpq/exports.txt  |  1 +
 src/interfaces/libpq/libpq-fe.h   | 10 ++++++++--
 src/interfaces/libpq/fe-connect.c |  7 +++++++
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index e08d46782cc..57349ef8f84 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -10635,7 +10635,11 @@ int PQisthreadsafe();
    Kerberos calls because Kerberos functions are not thread-safe.  See
    function <function>PQregisterThreadLock</function> in the
    <application>libpq</application> source code for a way to do cooperative
-   locking between <application>libpq</application> and your application.
+   locking between <application>libpq</application> and your application. (Note
+   that it is only safe to call <function>PQregisterThreadLock</function> when
+   there are no open connections.) Clients may retrieve the current locking
+   callback with <function>PQgetThreadLock</function>; if no custom callback
+   has been registered, a default is used.
   </para>
 
   <para>
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index dbbae642d76..1e3d5bd5867 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -210,3 +210,4 @@ PQgetAuthDataHook         207
 PQdefaultAuthDataHook     208
 PQfullProtocolVersion     209
 appendPQExpBufferVA       210
+PQgetThreadLock           211
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 905f2f33ab8..1b46032b6f9 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -63,6 +63,10 @@ extern "C"
 /* Indicates presence of the PQAUTHDATA_PROMPT_OAUTH_DEVICE authdata hook */
 #define LIBPQ_HAS_PROMPT_OAUTH_DEVICE 1
 
+/* Features added in PostgreSQL v19: */
+/* Indicates presence of PQgetThreadLock */
+#define LIBPQ_HAS_GET_THREAD_LOCK 1
+
 /*
  * Option flags for PQcopyResult
  */
@@ -462,12 +466,14 @@ extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
  *	   Used to set callback that prevents concurrent access to
  *	   non-thread safe functions that libpq needs.
  *	   The default implementation uses a libpq internal mutex.
- *	   Only required for multithreaded apps that use kerberos
- *	   both within their app and for postgresql connections.
+ *	   Only required for multithreaded apps that use Kerberos or
+ *	   older (non-threadsafe) versions of Curl both within their
+ *	   app and for postgresql connections.
  */
 typedef void (*pgthreadlock_t) (int acquire);
 
 extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler);
+extern pgthreadlock_t PQgetThreadLock(void);
 
 /* === in fe-trace.c === */
 extern void PQtrace(PGconn *conn, FILE *debug_port);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index b42a0cb4c78..db9b4c8edbf 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8414,3 +8414,10 @@ PQregisterThreadLock(pgthreadlock_t newhandler)
 
 	return prev;
 }
+
+pgthreadlock_t
+PQgetThreadLock(void)
+{
+	Assert(pg_g_threadlock);
+	return pg_g_threadlock;
+}
-- 
2.34.1

