Use thread-safe nl_langinfo_l(), not nl_langinfo().
authorThomas Munro <tmunro@postgresql.org>
Tue, 13 Aug 2024 10:27:16 +0000 (22:27 +1200)
committerThomas Munro <tmunro@postgresql.org>
Tue, 13 Aug 2024 10:34:53 +0000 (22:34 +1200)
This gets rid of some setlocale() calls.  The remaining call to
setlocale() in pg_get_encoding_from_locale() is a query of the name
of the current locale when none was provided (in a multi-threaded future
that would need more work).

All known non-Windows targets have nl_langinfo_l(), from POSIX 2008, and
for Windows we already do something thread-safe.

Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Discussion: https://postgr.es/m/CA%2BhUKGJqVe0%2BPv9dvC9dSums_PXxGo9SWcxYAMBguWJUGbWz-A%40mail.gmail.com

src/port/chklocale.c

index a0cc52c38df77b38192c062c4a775fb09f53e3da..14d0e2c55794bfcff6daac04bf4ef58cae358f4a 100644 (file)
@@ -306,63 +306,34 @@ pg_get_encoding_from_locale(const char *ctype, bool write_message)
    char       *sys;
    int         i;
 
-   /* Get the CODESET property, and also LC_CTYPE if not passed in */
-   if (ctype)
-   {
-       char       *save;
-       char       *name;
-
-       /* If locale is C or POSIX, we can allow all encodings */
-       if (pg_strcasecmp(ctype, "C") == 0 ||
-           pg_strcasecmp(ctype, "POSIX") == 0)
-           return PG_SQL_ASCII;
-
-       save = setlocale(LC_CTYPE, NULL);
-       if (!save)
-           return -1;          /* setlocale() broken? */
-       /* must copy result, or it might change after setlocale */
-       save = strdup(save);
-       if (!save)
-           return -1;          /* out of memory; unlikely */
-
-       name = setlocale(LC_CTYPE, ctype);
-       if (!name)
-       {
-           free(save);
-           return -1;          /* bogus ctype passed in? */
-       }
-
 #ifndef WIN32
-       sys = nl_langinfo(CODESET);
-       if (sys)
-           sys = strdup(sys);
-#else
-       sys = win32_langinfo(name);
+   locale_t    loc;
 #endif
 
-       setlocale(LC_CTYPE, save);
-       free(save);
-   }
-   else
-   {
-       /* much easier... */
+   /* Get the CODESET property, and also LC_CTYPE if not passed in */
+   if (!ctype)
        ctype = setlocale(LC_CTYPE, NULL);
-       if (!ctype)
-           return -1;          /* setlocale() broken? */
 
-       /* If locale is C or POSIX, we can allow all encodings */
-       if (pg_strcasecmp(ctype, "C") == 0 ||
-           pg_strcasecmp(ctype, "POSIX") == 0)
-           return PG_SQL_ASCII;
+
+   /* If locale is C or POSIX, we can allow all encodings */
+   if (pg_strcasecmp(ctype, "C") == 0 ||
+       pg_strcasecmp(ctype, "POSIX") == 0)
+       return PG_SQL_ASCII;
+
 
 #ifndef WIN32
-       sys = nl_langinfo(CODESET);
-       if (sys)
-           sys = strdup(sys);
+   loc = newlocale(LC_CTYPE_MASK, ctype, (locale_t) 0);
+   if (loc == (locale_t) 0)
+       return -1;              /* bogus ctype passed in? */
+
+   sys = nl_langinfo_l(CODESET, loc);
+   if (sys)
+       sys = strdup(sys);
+
+   freelocale(loc);
 #else
-       sys = win32_langinfo(ctype);
+   sys = win32_langinfo(ctype);
 #endif
-   }
 
    if (!sys)
        return -1;              /* out of memory; unlikely */