v8-0002-libpq-Allow-developers-to-reimplement-libpq-oauth.patch
application/octet-stream
Filename: v8-0002-libpq-Allow-developers-to-reimplement-libpq-oauth.patch
Type: application/octet-stream
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v8-0002
Subject: libpq: Allow developers to reimplement libpq-oauth
| File | + | − |
|---|---|---|
| src/interfaces/libpq/fe-auth-oauth.c | 41 | 30 |
| src/interfaces/libpq/fe-auth-oauth.h | 1 | 1 |
From 6f886914c836c38e0fedf4fc0dcc3a3be5c7369b Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Fri, 6 Mar 2026 14:18:49 -0800
Subject: [PATCH v8 2/3] libpq: Allow developers to reimplement libpq-oauth
For PG19, since we won't have the ability to officially switch out flow
plugins, relax the flow-loading code to not require the internal init
function. Modules that don't have one will be treated as custom user
flows in error messages.
This will let bleeding-edge developers more easily test out the API and
provide feedback for PG20, by telling the runtime linker to find a
different libpq-oauth. It remains undocumented for end users.
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAOYmi%2BmrGg%2Bn_X2MOLgeWcj3v_M00gR8uz_D7mM8z%3DdX1JYVbg%40mail.gmail.com
---
src/interfaces/libpq/fe-auth-oauth.h | 2 +-
src/interfaces/libpq/fe-auth-oauth.c | 71 ++++++++++++++++------------
2 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/src/interfaces/libpq/fe-auth-oauth.h b/src/interfaces/libpq/fe-auth-oauth.h
index 2b22d23ffde..872f5df551a 100644
--- a/src/interfaces/libpq/fe-auth-oauth.h
+++ b/src/interfaces/libpq/fe-auth-oauth.h
@@ -36,7 +36,7 @@ typedef struct
bool v1;
bool builtin;
- void *builtin_flow;
+ void *flow_module;
} fe_oauth_state;
extern void pqClearOAuthToken(PGconn *conn);
diff --git a/src/interfaces/libpq/fe-auth-oauth.c b/src/interfaces/libpq/fe-auth-oauth.c
index c59b4ce6d30..8dd0392b3d0 100644
--- a/src/interfaces/libpq/fe-auth-oauth.c
+++ b/src/interfaces/libpq/fe-auth-oauth.c
@@ -889,8 +889,8 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re
"libpq-oauth" DLSUFFIX;
#endif
- state->builtin_flow = dlopen(module_name, RTLD_NOW | RTLD_LOCAL);
- if (!state->builtin_flow)
+ state->flow_module = dlopen(module_name, RTLD_NOW | RTLD_LOCAL);
+ if (!state->flow_module)
{
/*
* For end users, this probably isn't an error condition, it just
@@ -905,8 +905,16 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re
return 0;
}
- if ((init = dlsym(state->builtin_flow, "libpq_oauth_init")) == NULL
- || (start_flow = dlsym(state->builtin_flow, "pg_start_oauthbearer")) == NULL)
+ /*
+ * Our libpq-oauth.so provides a special initialization function for libpq
+ * integration. If we don't find this, assume that a custom module is in
+ * use instead.
+ */
+ init = dlsym(state->flow_module, "libpq_oauth_init");
+ if (!init)
+ state->builtin = false; /* adjust our error messages */
+
+ if ((start_flow = dlsym(state->flow_module, "pg_start_oauthbearer")) == NULL)
{
/*
* This is more of an error condition than the one above, but the
@@ -916,8 +924,8 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re
if (oauth_unsafe_debugging_enabled())
fprintf(stderr, "failed dlsym for libpq-oauth: %s\n", dlerror());
- dlclose(state->builtin_flow);
- state->builtin_flow = NULL;
+ dlclose(state->flow_module);
+ state->flow_module = NULL;
request->error = libpq_gettext("could not find entry point for libpq-oauth");
return -1;
@@ -928,39 +936,42 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re
* permanently.
*/
- /*
- * We need to inject necessary function pointers into the module. This
- * only needs to be done once -- even if the pointers are constant,
- * assigning them while another thread is executing the flows feels like
- * tempting fate.
- */
- if ((lockerr = pthread_mutex_lock(&init_mutex)) != 0)
+ if (init)
{
- /* Should not happen... but don't continue if it does. */
- Assert(false);
+ /*
+ * We need to inject necessary function pointers into the module. This
+ * only needs to be done once -- even if the pointers are constant,
+ * assigning them while another thread is executing the flows feels
+ * like tempting fate.
+ */
+ if ((lockerr = pthread_mutex_lock(&init_mutex)) != 0)
+ {
+ /* Should not happen... but don't continue if it does. */
+ Assert(false);
- appendPQExpBuffer(&conn->errorMessage,
- "use_builtin_flow: failed to lock mutex (%d)\n",
- lockerr);
+ appendPQExpBuffer(&conn->errorMessage,
+ "use_builtin_flow: failed to lock mutex (%d)\n",
+ lockerr);
- request->error = ""; /* satisfy report_flow_error() */
- return -1;
- }
+ request->error = ""; /* satisfy report_flow_error() */
+ return -1;
+ }
- if (!initialized)
- {
- init(
+ if (!initialized)
+ {
+ init(
#ifdef ENABLE_NLS
- libpq_gettext
+ libpq_gettext
#else
- NULL
+ NULL
#endif
- );
+ );
- initialized = true;
- }
+ initialized = true;
+ }
- pthread_mutex_unlock(&init_mutex);
+ pthread_mutex_unlock(&init_mutex);
+ }
return (start_flow(conn, request) == 0) ? 1 : -1;
}
--
2.34.1