From 536eb8b08a2feb65966930b9bab1894a5fcbefc2 Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Thu, 13 Nov 2025 15:18:23 -0800
Subject: [PATCH v2 3/4] libpq: Align oauth_json_set_error() with other NLS
 patterns

Now that the prior commits have fixed missing OAuth translations, pull
the bespoke usage of libpq_gettext() for OAUTHBEARER parsing into
oauth_json_set_error() itself, and make that a gettext trigger as well,
to better match what the other sites are doing. Add an _internal()
variant to handle the existing untranslated case.

Suggested-by: Daniel Gustafsson <daniel@yesql.se>
Discussion: https://postgr.es/m/0EEBCAA8-A5AC-4E3B-BABA-0BA7A08C361B%40yesql.se
Backpatch-through: ?
---
 src/interfaces/libpq/fe-auth-oauth.c | 31 +++++++++++++++++-----------
 src/interfaces/libpq/nls.mk          |  2 ++
 2 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/interfaces/libpq/fe-auth-oauth.c b/src/interfaces/libpq/fe-auth-oauth.c
index d146c5f567c..fb63a3249d6 100644
--- a/src/interfaces/libpq/fe-auth-oauth.c
+++ b/src/interfaces/libpq/fe-auth-oauth.c
@@ -183,7 +183,14 @@ struct json_ctx
 #define oauth_json_has_error(ctx) \
 	(PQExpBufferDataBroken((ctx)->errbuf) || (ctx)->errmsg)
 
-#define oauth_json_set_error(ctx, ...) \
+#define oauth_json_set_error(ctx, fmt, ...) \
+	do { \
+		appendPQExpBuffer(&(ctx)->errbuf, libpq_gettext(fmt), ##__VA_ARGS__); \
+		(ctx)->errmsg = (ctx)->errbuf.data; \
+	} while (0)
+
+/* An untranslated version of oauth_json_set_error(). */
+#define oauth_json_set_error_internal(ctx, ...) \
 	do { \
 		appendPQExpBuffer(&(ctx)->errbuf, __VA_ARGS__); \
 		(ctx)->errmsg = (ctx)->errbuf.data; \
@@ -199,13 +206,13 @@ oauth_json_object_start(void *state)
 		Assert(ctx->nested == 1);
 
 		oauth_json_set_error(ctx,
-							 libpq_gettext("field \"%s\" must be a string"),
+							 "field \"%s\" must be a string",
 							 ctx->target_field_name);
 	}
 
 	++ctx->nested;
 	if (ctx->nested > MAX_SASL_NESTING_LEVEL)
-		oauth_json_set_error(ctx, libpq_gettext("JSON is too deeply nested"));
+		oauth_json_set_error(ctx, "JSON is too deeply nested");
 
 	return oauth_json_has_error(ctx) ? JSON_SEM_ACTION_FAILED : JSON_SUCCESS;
 }
@@ -254,20 +261,20 @@ oauth_json_array_start(void *state)
 
 	if (!ctx->nested)
 	{
-		ctx->errmsg = libpq_gettext("top-level element must be an object");
+		oauth_json_set_error(ctx, "top-level element must be an object");
 	}
 	else if (ctx->target_field)
 	{
 		Assert(ctx->nested == 1);
 
 		oauth_json_set_error(ctx,
-							 libpq_gettext("field \"%s\" must be a string"),
+							 "field \"%s\" must be a string",
 							 ctx->target_field_name);
 	}
 
 	++ctx->nested;
 	if (ctx->nested > MAX_SASL_NESTING_LEVEL)
-		oauth_json_set_error(ctx, libpq_gettext("JSON is too deeply nested"));
+		oauth_json_set_error(ctx, "JSON is too deeply nested");
 
 	return oauth_json_has_error(ctx) ? JSON_SEM_ACTION_FAILED : JSON_SUCCESS;
 }
@@ -288,7 +295,7 @@ oauth_json_scalar(void *state, char *token, JsonTokenType type)
 
 	if (!ctx->nested)
 	{
-		ctx->errmsg = libpq_gettext("top-level element must be an object");
+		oauth_json_set_error(ctx, "top-level element must be an object");
 		return JSON_SEM_ACTION_FAILED;
 	}
 
@@ -301,9 +308,9 @@ oauth_json_scalar(void *state, char *token, JsonTokenType type)
 			 * Assert and don't continue any further for production builds.
 			 */
 			Assert(false);
-			oauth_json_set_error(ctx,
-								 "internal error: target scalar found at nesting level %d during OAUTHBEARER parsing",
-								 ctx->nested);
+			oauth_json_set_error_internal(ctx,
+										  "internal error: target scalar found at nesting level %d during OAUTHBEARER parsing",
+										  ctx->nested);
 			return JSON_SEM_ACTION_FAILED;
 		}
 
@@ -314,7 +321,7 @@ oauth_json_scalar(void *state, char *token, JsonTokenType type)
 		if (*ctx->target_field)
 		{
 			oauth_json_set_error(ctx,
-								 libpq_gettext("field \"%s\" is duplicated"),
+								 "field \"%s\" is duplicated",
 								 ctx->target_field_name);
 			return JSON_SEM_ACTION_FAILED;
 		}
@@ -323,7 +330,7 @@ oauth_json_scalar(void *state, char *token, JsonTokenType type)
 		if (type != JSON_TOKEN_STRING)
 		{
 			oauth_json_set_error(ctx,
-								 libpq_gettext("field \"%s\" must be a string"),
+								 "field \"%s\" must be a string",
 								 ctx->target_field_name);
 			return JSON_SEM_ACTION_FAILED;
 		}
diff --git a/src/interfaces/libpq/nls.mk b/src/interfaces/libpq/nls.mk
index 111e4849ed5..3fa87a0aaac 100644
--- a/src/interfaces/libpq/nls.mk
+++ b/src/interfaces/libpq/nls.mk
@@ -22,6 +22,7 @@ GETTEXT_TRIGGERS = actx_error:2 \
                    libpq_append_error:2 \
                    libpq_gettext \
                    libpq_ngettext:1,2 \
+                   oauth_json_set_error:2 \
                    oauth_parse_set_error:2 \
                    pqInternalNotice:2
 GETTEXT_FLAGS    = actx_error:2:c-format \
@@ -30,5 +31,6 @@ GETTEXT_FLAGS    = actx_error:2:c-format \
                    libpq_gettext:1:pass-c-format \
                    libpq_ngettext:1:pass-c-format \
                    libpq_ngettext:2:pass-c-format \
+                   oauth_json_set_error:2:c-format \
                    oauth_parse_set_error:2:c-format \
                    pqInternalNotice:2:c-format
-- 
2.34.1

