]> granicus.if.org Git - postgresql/commitdiff
Always set the six locale category environment variables in main().
authorNoah Misch <noah@leadboat.com>
Thu, 8 Jan 2015 03:34:57 +0000 (22:34 -0500)
committerNoah Misch <noah@leadboat.com>
Thu, 8 Jan 2015 03:35:09 +0000 (22:35 -0500)
Typical server invocations already achieved that.  Invalid locale
settings in the initial postmaster environment interfered, as could
malloc() failure.  Setting "LC_MESSAGES=pt_BR.utf8 LC_ALL=invalid" in
the postmaster environment will now choose C-locale messages, not
Brazilian Portuguese messages.  Most localized programs, including all
PostgreSQL frontend executables, do likewise.  Users are unlikely to
observe changes involving locale categories other than LC_MESSAGES.
CheckMyDatabase() ensures that we successfully set LC_COLLATE and
LC_CTYPE; main() sets the remaining three categories to locale "C",
which almost cannot fail.  Back-patch to 9.0 (all supported versions).

src/backend/main/main.c

index c6fb8c9fbe5ace8419fa3401e2957d58b2b3b7c7..196d4846f7900ac035e0046d2e30a8019e107583 100644 (file)
@@ -50,6 +50,7 @@ const char *progname;
 
 
 static void startup_hacks(const char *progname);
+static void init_locale(int category, const char *locale);
 static void help(const char *progname);
 static void check_root(const char *progname);
 
@@ -122,31 +123,31 @@ main(int argc, char *argv[])
                char       *env_locale;
 
                if ((env_locale = getenv("LC_COLLATE")) != NULL)
-                       pg_perm_setlocale(LC_COLLATE, env_locale);
+                       init_locale(LC_COLLATE, env_locale);
                else
-                       pg_perm_setlocale(LC_COLLATE, "");
+                       init_locale(LC_COLLATE, "");
 
                if ((env_locale = getenv("LC_CTYPE")) != NULL)
-                       pg_perm_setlocale(LC_CTYPE, env_locale);
+                       init_locale(LC_CTYPE, env_locale);
                else
-                       pg_perm_setlocale(LC_CTYPE, "");
+                       init_locale(LC_CTYPE, "");
        }
 #else
-       pg_perm_setlocale(LC_COLLATE, "");
-       pg_perm_setlocale(LC_CTYPE, "");
+       init_locale(LC_COLLATE, "");
+       init_locale(LC_CTYPE, "");
 #endif
 
 #ifdef LC_MESSAGES
-       pg_perm_setlocale(LC_MESSAGES, "");
+       init_locale(LC_MESSAGES, "");
 #endif
 
        /*
         * We keep these set to "C" always, except transiently in pg_locale.c; see
         * that file for explanations.
         */
-       pg_perm_setlocale(LC_MONETARY, "C");
-       pg_perm_setlocale(LC_NUMERIC, "C");
-       pg_perm_setlocale(LC_TIME, "C");
+       init_locale(LC_MONETARY, "C");
+       init_locale(LC_NUMERIC, "C");
+       init_locale(LC_TIME, "C");
 
        /*
         * Now that we have absorbed as much as we wish to from the locale
@@ -299,6 +300,23 @@ startup_hacks(const char *progname)
 }
 
 
+/*
+ * Make the initial permanent setting for a locale category.  If that fails,
+ * perhaps due to LC_foo=invalid in the environment, use locale C.  If even
+ * that fails, perhaps due to out-of-memory, the entire startup fails with it.
+ * When this returns, we are guaranteed to have a setting for the given
+ * category's environment variable.
+ */
+static void
+init_locale(int category, const char *locale)
+{
+       if (pg_perm_setlocale(category, locale) == NULL &&
+               pg_perm_setlocale(category, "C") == NULL)
+               elog(FATAL, "could not adopt C locale");
+}
+
+
+
 /*
  * Help display should match the options accepted by PostmasterMain()
  * and PostgresMain().