diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-03-25 21:47:22 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-03-25 21:47:22 -0400 |
commit | c7cea267de3ca05b29a57b9d113b95ef3793c8d8 (patch) | |
tree | 87c2c9b6c660a843287e0ac8ac0567d31c5ab2ed /src/backend/utils/adt/pg_locale.c | |
parent | 8279eb4191c7ab9920c72ec8eec5df0e7b8c7530 (diff) | |
download | postgresql-c7cea267de3ca05b29a57b9d113b95ef3793c8d8.tar.gz postgresql-c7cea267de3ca05b29a57b9d113b95ef3793c8d8.zip |
Replace empty locale name with implied value in CREATE DATABASE and initdb.
setlocale() accepts locale name "" as meaning "the locale specified by the
process's environment variables". Historically we've accepted that for
Postgres' locale settings, too. However, it's fairly unsafe to store an
empty string in a new database's pg_database.datcollate or datctype fields,
because then the interpretation could vary across postmaster restarts,
possibly resulting in index corruption and other unpleasantness.
Instead, we should expand "" to whatever it means at the moment of calling
CREATE DATABASE, which we can do by saving the value returned by
setlocale().
For consistency, make initdb set up the initial lc_xxx parameter values the
same way. initdb was already doing the right thing for empty locale names,
but it did not replace non-empty names with setlocale results. On a
platform where setlocale chooses to canonicalize the spellings of locale
names, this would result in annoying inconsistency. (It seems that popular
implementations of setlocale don't do such canonicalization, which is a
pity, but the POSIX spec certainly allows it to be done.) The same risk
of inconsistency leads me to not venture back-patching this, although it
could certainly be seen as a longstanding bug.
Per report from Jeff Davis, though this is not his proposed patch.
Diffstat (limited to 'src/backend/utils/adt/pg_locale.c')
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 9f112e8c5cb..0920c13cd9f 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -222,29 +222,43 @@ pg_perm_setlocale(int category, const char *locale) /* * Is the locale name valid for the locale category? + * + * If successful, and canonname isn't NULL, a palloc'd copy of the locale's + * canonical name is stored there. This is especially useful for figuring out + * what locale name "" means (ie, the server environment value). (Actually, + * it seems that on most implementations that's the only thing it's good for; + * we could wish that setlocale gave back a canonically spelled version of + * the locale name, but typically it doesn't.) */ bool -check_locale(int category, const char *value) +check_locale(int category, const char *locale, char **canonname) { char *save; - bool ret; + char *res; + + if (canonname) + *canonname = NULL; /* in case of failure */ save = setlocale(category, NULL); if (!save) return false; /* won't happen, we hope */ - /* save may be pointing at a modifiable scratch variable, see above */ + /* save may be pointing at a modifiable scratch variable, see above. */ save = pstrdup(save); /* set the locale with setlocale, to see if it accepts it. */ - ret = (setlocale(category, value) != NULL); + res = setlocale(category, locale); + + /* save canonical name if requested. */ + if (res && canonname) + *canonname = pstrdup(res); /* restore old value. */ if (!setlocale(category, save)) - elog(WARNING, "failed to restore old locale"); + elog(WARNING, "failed to restore old locale \"%s\"", save); pfree(save); - return ret; + return (res != NULL); } @@ -262,7 +276,7 @@ check_locale(int category, const char *value) bool check_locale_monetary(char **newval, void **extra, GucSource source) { - return check_locale(LC_MONETARY, *newval); + return check_locale(LC_MONETARY, *newval, NULL); } void @@ -274,7 +288,7 @@ assign_locale_monetary(const char *newval, void *extra) bool check_locale_numeric(char **newval, void **extra, GucSource source) { - return check_locale(LC_NUMERIC, *newval); + return check_locale(LC_NUMERIC, *newval, NULL); } void @@ -286,7 +300,7 @@ assign_locale_numeric(const char *newval, void *extra) bool check_locale_time(char **newval, void **extra, GucSource source) { - return check_locale(LC_TIME, *newval); + return check_locale(LC_TIME, *newval, NULL); } void @@ -322,7 +336,7 @@ check_locale_messages(char **newval, void **extra, GucSource source) * On Windows, we can't even check the value, so accept blindly */ #if defined(LC_MESSAGES) && !defined(WIN32) - return check_locale(LC_MESSAGES, *newval); + return check_locale(LC_MESSAGES, *newval, NULL); #else return true; #endif |