v1-0001-Avoid-gettext-0.20-performance-bug-on-Windows.patch

text/plain

Filename: v1-0001-Avoid-gettext-0.20-performance-bug-on-Windows.patch
Type: text/plain
Part: 0
Message: [PATCH] Fix severe performance regression with gettext 0.20+ on Windows
From be63384836855ae5356362793f51f0ffdd554537 Mon Sep 17 00:00:00 2001
From: Bryan Green <dbryan.green@gmail.com>
Date: Tue, 9 Dec 2025 18:21:45 -0600
Subject: [PATCH v1] Avoid gettext 0.20+ performance bug on Windows.

gettext 0.20.1+ expects Windows locale format ("English_United States")
not POSIX format ("en_US"), and has a cache bug where failed lookups
cause repeated enumeration of all ~259 system locales on every gettext()
call.  This makes exception-heavy workloads 5-6x slower.

PostgreSQL has always converted to POSIX format via IsoLocaleName()
before setting LC_MESSAGES, which triggers this bug.  Setting lc_messages
to 'C' or 'POSIX' triggers it too, since these aren't Windows names.

Fix by using Windows format for gettext 0.20.1+, which handles it
correctly.  Retain POSIX format for 0.19.8 and earlier.  Detect version
via LIBINTL_VERSION macro.

Improves 1M exception test from ~180s to ~40s.
---
 src/backend/utils/adt/pg_locale.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index b26257c0a8..eb8025438a 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -230,10 +230,19 @@ pg_perm_setlocale(int category, const char *locale)
 		case LC_MESSAGES:
 			envvar = "LC_MESSAGES";
 #ifdef WIN32
+#if defined(LIBINTL_VERSION) && (LIBINTL_VERSION >= 0x001401)
+			if (locale == NULL || locale[0] == '\0' ||
+				strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0)
+				result = setlocale(LC_CTYPE, NULL);
+			else
+				result = (char *) locale;
+#else
+			/* Convert to ISO locale name */
 			result = IsoLocaleName(locale);
 			if (result == NULL)
 				result = (char *) locale;
-			elog(DEBUG3, "IsoLocaleName() executed; locale: \"%s\"", result);
+#endif
+		elog(DEBUG3,"LC_MESSAGES locale: \"%s\"", result);
 #endif							/* WIN32 */
 			break;
 #endif							/* LC_MESSAGES */
-- 
2.52.0.windows.1