From be63384836855ae5356362793f51f0ffdd554537 Mon Sep 17 00:00:00 2001 From: Bryan Green 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