summaryrefslogtreecommitdiff
path: root/src/bin/initdb
diff options
context:
space:
mode:
authorHeikki Linnakangas2011-09-01 08:08:32 +0000
committerHeikki Linnakangas2011-09-01 08:08:32 +0000
commita88b6e4cfbff9802906dd400ef334ffa49e7f286 (patch)
tree00b5c719b8d22950f933dcc77f317de8bde47013 /src/bin/initdb
parent8ea02570677d2cebe681584fd4c22716f1a1e1a7 (diff)
setlocale() on Windows doesn't work correctly if the locale name contains
dots. I previously worked around this in initdb, mapping the known problematic locale names to aliases that work, but Hiroshi Inoue pointed out that that's not enough because even if you use one of the aliases, like "Chinese_HKG", setlocale(LC_CTYPE, NULL) returns back the long form, ie. "Chinese_Hong Kong S.A.R.". When we try to restore an old locale value by passing that value back to setlocale(), it fails. Note that you are affected by this bug also if you use one of those short-form names manually, so just reverting the hack in initdb won't fix it. To work around that, move the locale name mapping from initdb to a wrapper around setlocale(), so that the mapping is invoked on every setlocale() call. Also, add a few checks for failed setlocale() calls in the backend. These calls shouldn't fail, and if they do there isn't much we can do about it, but at least you'll get a warning. Backpatch to 9.1, where the initdb hack was introduced. The Windows bug affects older versions too if you set locale manually to one of the aliases, but given the lack of complaints from the field, I'm hesitent to backpatch.
Diffstat (limited to 'src/bin/initdb')
-rw-r--r--src/bin/initdb/initdb.c70
1 files changed, 7 insertions, 63 deletions
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index c3173558945..1dbd6f603a3 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -185,7 +185,6 @@ static int locale_date_order(const char *locale);
static bool check_locale_name(const char *locale);
static bool check_locale_encoding(const char *locale, int encoding);
static void setlocales(void);
-static char *localemap(char *locale);
static void usage(const char *progname);
#ifdef WIN32
@@ -2287,61 +2286,6 @@ strreplace(char *str, char *needle, char *replacement)
#endif /* WIN32 */
/*
- * Windows has a problem with locale names that have a dot in the country
- * name. For example:
- *
- * "Chinese (Traditional)_Hong Kong S.A.R..950"
- *
- * For some reason, setlocale() doesn't accept that. Fortunately, Windows'
- * setlocale() accepts various alternative names for such countries, so we
- * map the full country names to accepted aliases.
- *
- * The returned string is always malloc'd - if no mapping is done it is
- * just a malloc'd copy of the original.
- */
-static char *
-localemap(char *locale)
-{
- locale = xstrdup(locale);
-
-#ifdef WIN32
-
- /*
- * Map the full country name to an abbreviation that setlocale() accepts.
- *
- * "HKG" is listed here:
- * http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
- * (Country/Region Strings).
- *
- * "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
- * above list, but seems to work anyway.
- */
- strreplace(locale, "Hong Kong S.A.R.", "HKG");
- strreplace(locale, "U.A.E.", "ARE");
-
- /*
- * The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
- * seem to recognize that. And Macau isn't listed in the table of accepted
- * abbreviations linked above.
- *
- * Fortunately, "ZHM" seems to be accepted as an alias for "Chinese
- * (Traditional)_Macau S.A.R..950", so we use that. Note that it's unlike
- * HKG and ARE, ZHM is an alias for the whole locale name, not just the
- * country part. I'm not sure where that "ZHM" comes from, must be some
- * legacy naming scheme. But hey, it works.
- *
- * Some versions of Windows spell it "Macau", others "Macao".
- */
- strreplace(locale, "Chinese (Traditional)_Macau S.A.R..950", "ZHM");
- strreplace(locale, "Chinese_Macau S.A.R..950", "ZHM");
- strreplace(locale, "Chinese (Traditional)_Macao S.A.R..950", "ZHM");
- strreplace(locale, "Chinese_Macao S.A.R..950", "ZHM");
-#endif /* WIN32 */
-
- return locale;
-}
-
-/*
* set up the locale variables
*
* assumes we have called setlocale(LC_ALL,"")
@@ -2372,25 +2316,25 @@ setlocales(void)
*/
if (strlen(lc_ctype) == 0 || !check_locale_name(lc_ctype))
- lc_ctype = localemap(setlocale(LC_CTYPE, NULL));
+ lc_ctype = xstrdup(setlocale(LC_CTYPE, NULL));
if (strlen(lc_collate) == 0 || !check_locale_name(lc_collate))
- lc_collate = localemap(setlocale(LC_COLLATE, NULL));
+ lc_collate = xstrdup(setlocale(LC_COLLATE, NULL));
if (strlen(lc_numeric) == 0 || !check_locale_name(lc_numeric))
- lc_numeric = localemap(setlocale(LC_NUMERIC, NULL));
+ lc_numeric = xstrdup(setlocale(LC_NUMERIC, NULL));
if (strlen(lc_time) == 0 || !check_locale_name(lc_time))
- lc_time = localemap(setlocale(LC_TIME, NULL));
+ lc_time = xstrdup(setlocale(LC_TIME, NULL));
if (strlen(lc_monetary) == 0 || !check_locale_name(lc_monetary))
- lc_monetary = localemap(setlocale(LC_MONETARY, NULL));
+ lc_monetary = xstrdup(setlocale(LC_MONETARY, NULL));
if (strlen(lc_messages) == 0 || !check_locale_name(lc_messages))
#if defined(LC_MESSAGES) && !defined(WIN32)
{
/* when available get the current locale setting */
- lc_messages = localemap(setlocale(LC_MESSAGES, NULL));
+ lc_messages = xstrdup(setlocale(LC_MESSAGES, NULL));
}
#else
{
/* when not available, get the CTYPE setting */
- lc_messages = localemap(setlocale(LC_CTYPE, NULL));
+ lc_messages = xstrdup(setlocale(LC_CTYPE, NULL));
}
#endif