diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-01-05 00:55:24 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-01-05 00:55:24 +0000 |
commit | d514752dbf15b0a8428e6d8a1dc6cca9b9da5684 (patch) | |
tree | 66b35409b82d60017da511ef476d8f8463429002 | |
parent | 37cdf43eaa58ffc8a361cefc013917ff61c8bb3d (diff) | |
download | postgresql-d514752dbf15b0a8428e6d8a1dc6cca9b9da5684.tar.gz postgresql-d514752dbf15b0a8428e6d8a1dc6cca9b9da5684.zip |
Arrange to set the LC_XXX environment variables to match our locale setup.
Back-patch of previous fix in HEAD for plperl-vs-locale issue.
-rw-r--r-- | src/backend/access/transam/xlog.c | 7 | ||||
-rw-r--r-- | src/backend/main/main.c | 22 | ||||
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 123 | ||||
-rw-r--r-- | src/include/utils/pg_locale.h | 4 |
4 files changed, 139 insertions, 17 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 3d7b55712b6..5a102750750 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.125.2.3 2005/05/31 19:10:57 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.125.2.4 2006/01/05 00:55:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include "storage/spin.h" #include "utils/builtins.h" #include "utils/guc.h" +#include "utils/pg_locale.h" #include "utils/relcache.h" #include "miscadmin.h" @@ -2349,14 +2350,14 @@ ReadControlFile(void) " but the server was compiled with LOCALE_NAME_BUFLEN %d.", ControlFile->localeBuflen, LOCALE_NAME_BUFLEN), errhint("It looks like you need to recompile or initdb."))); - if (setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL) + if (pg_perm_setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL) ereport(FATAL, (errmsg("database files are incompatible with operating system"), errdetail("The database cluster was initialized with LC_COLLATE \"%s\"," " which is not recognized by setlocale().", ControlFile->lc_collate), errhint("It looks like you need to initdb or install locale support."))); - if (setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL) + if (pg_perm_setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL) ereport(FATAL, (errmsg("database files are incompatible with operating system"), errdetail("The database cluster was initialized with LC_CTYPE \"%s\"," diff --git a/src/backend/main/main.c b/src/backend/main/main.c index 6b20dcb5763..33100724d01 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.65 2003/10/18 22:59:08 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.65.2.1 2006/01/05 00:55:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,6 +38,7 @@ #include "bootstrap/bootstrap.h" #include "tcop/tcopprot.h" #include "utils/help_config.h" +#include "utils/pg_locale.h" #include "utils/ps_status.h" @@ -130,19 +131,26 @@ main(int argc, char *argv[]) * set later during GUC option processing, but we set it here to allow * startup error messages to be localized. */ - setlocale(LC_COLLATE, ""); - setlocale(LC_CTYPE, ""); + pg_perm_setlocale(LC_COLLATE, ""); + pg_perm_setlocale(LC_CTYPE, ""); #ifdef LC_MESSAGES - setlocale(LC_MESSAGES, ""); + pg_perm_setlocale(LC_MESSAGES, ""); #endif /* * We keep these set to "C" always, except transiently in pg_locale.c; * see that file for explanations. */ - setlocale(LC_MONETARY, "C"); - setlocale(LC_NUMERIC, "C"); - setlocale(LC_TIME, "C"); + pg_perm_setlocale(LC_MONETARY, "C"); + pg_perm_setlocale(LC_NUMERIC, "C"); + pg_perm_setlocale(LC_TIME, "C"); + + /* + * Now that we have absorbed as much as we wish to from the locale + * environment, remove any LC_ALL setting, so that the environment + * variables installed by pg_perm_setlocale have force. + */ + unsetenv("LC_ALL"); #ifdef ENABLE_NLS bindtextdomain("postgres", LOCALEDIR); diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index eced5a5c42c..3b553a68aee 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -4,7 +4,7 @@ * * Portions Copyright (c) 2002-2003, PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.23 2003/08/04 23:59:38 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.23.4.1 2006/01/05 00:55:24 tgl Exp $ * *----------------------------------------------------------------------- */ @@ -50,13 +50,10 @@ #include <locale.h> +#include "catalog/pg_control.h" #include "utils/pg_locale.h" -/* indicated whether locale information cache is valid */ -static bool CurrentLocaleConvValid = false; - - /* GUC storage area */ char *locale_messages; @@ -64,6 +61,120 @@ char *locale_monetary; char *locale_numeric; char *locale_time; +/* indicates whether locale information cache is valid */ +static bool CurrentLocaleConvValid = false; + +/* Environment variable storage area */ + +#define LC_ENV_BUFSIZE (LOCALE_NAME_BUFLEN + 20) + +static char lc_collate_envbuf[LC_ENV_BUFSIZE]; +static char lc_ctype_envbuf[LC_ENV_BUFSIZE]; +#ifdef LC_MESSAGES +static char lc_messages_envbuf[LC_ENV_BUFSIZE]; +#endif +static char lc_monetary_envbuf[LC_ENV_BUFSIZE]; +static char lc_numeric_envbuf[LC_ENV_BUFSIZE]; +static char lc_time_envbuf[LC_ENV_BUFSIZE]; + + +/* + * pg_perm_setlocale + * + * This is identical to the libc function setlocale(), with the addition + * that if the operation is successful, the corresponding LC_XXX environment + * variable is set to match. By setting the environment variable, we ensure + * that any subsequent use of setlocale(..., "") will preserve the settings + * made through this routine. Of course, LC_ALL must also be unset to fully + * ensure that, but that has to be done elsewhere after all the individual + * LC_XXX variables have been set correctly. (Thank you Perl for making this + * kluge necessary.) + */ +char * +pg_perm_setlocale(int category, const char *locale) +{ + char *result; + const char *envvar; + char *envbuf; + +#ifndef WIN32 + result = setlocale(category, locale); +#else + /* + * On Windows, setlocale(LC_MESSAGES) does not work, so just assume + * that the given value is good and set it in the environment variables. + * We must ignore attempts to set to "", which means "keep using the + * old environment value". + */ +#ifdef LC_MESSAGES + if (category == LC_MESSAGES) + { + result = (char *) locale; + if (locale == NULL || locale[0] == '\0') + return result; + } + else +#endif + result = setlocale(category, locale); +#endif /* WIN32 */ + + if (result == NULL) + return result; /* fall out immediately on failure */ + + switch (category) + { + case LC_COLLATE: + envvar = "LC_COLLATE"; + envbuf = lc_collate_envbuf; + break; + case LC_CTYPE: + envvar = "LC_CTYPE"; + envbuf = lc_ctype_envbuf; + break; +#ifdef LC_MESSAGES + case LC_MESSAGES: + envvar = "LC_MESSAGES"; + envbuf = lc_messages_envbuf; + break; +#endif + case LC_MONETARY: + envvar = "LC_MONETARY"; + envbuf = lc_monetary_envbuf; + break; + case LC_NUMERIC: + envvar = "LC_NUMERIC"; + envbuf = lc_numeric_envbuf; + break; + case LC_TIME: + envvar = "LC_TIME"; + envbuf = lc_time_envbuf; + break; + default: + elog(FATAL, "unrecognized LC category: %d", category); + envvar = NULL; /* keep compiler quiet */ + envbuf = NULL; + break; + } + + snprintf(envbuf, LC_ENV_BUFSIZE-1, "%s=%s", envvar, result); + +#ifndef WIN32 + if (putenv(envbuf)) + return NULL; +#else + /* + * On Windows, we need to modify both the process environment and the + * cached version in msvcrt + */ + if (!SetEnvironmentVariable(envvar, result)) + return NULL; + if (_putenv(envbuf)) + return NULL; +#endif + + return result; +} + /* GUC assign hooks */ @@ -130,7 +241,7 @@ locale_messages_assign(const char *value, bool doit, bool interactive) #ifdef LC_MESSAGES if (doit) { - if (!setlocale(LC_MESSAGES, value)) + if (!pg_perm_setlocale(LC_MESSAGES, value)) return NULL; } else diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h index d47a5c4239c..34e80e0519f 100644 --- a/src/include/utils/pg_locale.h +++ b/src/include/utils/pg_locale.h @@ -2,7 +2,7 @@ * * PostgreSQL locale utilities * - * $Id: pg_locale.h,v 1.15 2003/08/04 23:59:41 tgl Exp $ + * $Id: pg_locale.h,v 1.15.4.1 2006/01/05 00:55:24 tgl Exp $ * * Copyright (c) 2002-2003, PostgreSQL Global Development Group * @@ -28,6 +28,8 @@ extern const char *locale_numeric_assign(const char *value, extern const char *locale_time_assign(const char *value, bool doit, bool interactive); +extern char *pg_perm_setlocale(int category, const char *locale); + extern bool lc_collate_is_c(void); /* |