diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-11-25 22:43:08 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-11-25 22:43:08 +0000 |
commit | e3269cab31613d3e11522e7c8009736f2b3797ec (patch) | |
tree | 2b43bf63fdb380ed4960da40bcf27ff60cbc2cec /src/backend/utils/adt/pg_locale.c | |
parent | 74dc04a034bc32f45738541f88e2d5e9e322cf59 (diff) | |
download | postgresql-e3269cab31613d3e11522e7c8009736f2b3797ec.tar.gz postgresql-e3269cab31613d3e11522e7c8009736f2b3797ec.zip |
Make PGLC_setlocale() static, and document that it can't be used safely
for any other purpose than PGLC_localeconv()'s internal save/restore of
locale settings. Fix cash.c to call PGLC_localeconv() rather than
making a direct call to localeconv() --- the old way, if PGLC_localeconv()
had already cached a locale result, it would be overwritten by the first
cash_in or cash_out operation, leading to wrong-locale results later.
Probably no demonstrable bug today, since we only appear to be looking
at the LC_MONETARY results which should be the same anyway, but definitely
a gotcha waiting to strike.
Diffstat (limited to 'src/backend/utils/adt/pg_locale.c')
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 31e791170fe..5762a084744 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -1,21 +1,18 @@ - /* ----------------------------------------------------------------------- * pg_locale.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.6 2000/08/29 04:41:47 momjian Exp $ + * The PostgreSQL locale utils. * * - * Portions Copyright (c) 1999-2000, PostgreSQL, Inc + * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.7 2000/11/25 22:43:08 tgl Exp $ * - * The PostgreSQL locale utils. + * Portions Copyright (c) 1999-2000, PostgreSQL, Inc * * Karel Zak - Zakkr * * ----------------------------------------------------------------------- */ -#include <stdio.h> - #include "postgres.h" #ifdef USE_LOCALE @@ -28,11 +25,13 @@ static struct lconv *CurrentLocaleConv = NULL; +static void PGLC_setlocale(PG_LocaleCategories * lc); + /*------ - * Return in PG_LocaleCategories current locale setting + * Return in PG_LocaleCategories the current locale settings *------ */ -PG_LocaleCategories * +void PGLC_current(PG_LocaleCategories * lc) { lc->lang = getenv("LANG"); @@ -45,7 +44,6 @@ PGLC_current(PG_LocaleCategories * lc) #ifdef LC_MESSAGES lc->lc_messages = setlocale(LC_MESSAGES, NULL); #endif - return lc; } @@ -55,7 +53,7 @@ PGLC_current(PG_LocaleCategories * lc) * Print a PG_LocaleCategories struct as DEBUG *------ */ -PG_LocaleCategories * +static void PGLC_debug_lc(PG_LocaleCategories * lc) { #ifdef LC_MESSAGES @@ -73,72 +71,86 @@ PGLC_debug_lc(PG_LocaleCategories * lc) , lc->lc_messages #endif ); - - return lc; } #endif /*------ * Set locales via a PG_LocaleCategories struct + * + * NB: it would be very dangerous to set the locale values to any random + * choice of locale, since that could cause indexes to become corrupt, etc. + * Therefore this routine is NOT exported from this module. It should be + * used only to restore previous locale settings during PGLC_localeconv. *------ */ -PG_LocaleCategories * +static void PGLC_setlocale(PG_LocaleCategories * lc) { + if (!setlocale(LC_COLLATE, lc->lc_collate)) + elog(NOTICE, "pg_setlocale(): 'LC_COLLATE=%s' cannot be honored.", + lc->lc_collate); + if (!setlocale(LC_CTYPE, lc->lc_ctype)) - elog(NOTICE, "pg_setlocale(): 'LC_CTYPE=%s' cannot be honored.", lc->lc_ctype); + elog(NOTICE, "pg_setlocale(): 'LC_CTYPE=%s' cannot be honored.", + lc->lc_ctype); if (!setlocale(LC_NUMERIC, lc->lc_numeric)) - elog(NOTICE, "pg_setlocale(): 'LC_NUMERIC=%s' cannot be honored.", lc->lc_numeric); + elog(NOTICE, "pg_setlocale(): 'LC_NUMERIC=%s' cannot be honored.", + lc->lc_numeric); if (!setlocale(LC_TIME, lc->lc_time)) - elog(NOTICE, "pg_setlocale(): 'LC_TIME=%s' cannot be honored.", lc->lc_time); - - if (!setlocale(LC_COLLATE, lc->lc_collate)) - elog(NOTICE, "pg_setlocale(): 'LC_COLLATE=%s' cannot be honored.", lc->lc_collate); + elog(NOTICE, "pg_setlocale(): 'LC_TIME=%s' cannot be honored.", + lc->lc_time); if (!setlocale(LC_MONETARY, lc->lc_monetary)) - elog(NOTICE, "pg_setlocale(): 'LC_MONETARY=%s' cannot be honored.", lc->lc_monetary); + elog(NOTICE, "pg_setlocale(): 'LC_MONETARY=%s' cannot be honored.", + lc->lc_monetary); + #ifdef LC_MESSAGES if (!setlocale(LC_MESSAGES, lc->lc_messages)) - elog(NOTICE, "pg_setlocale(): 'LC_MESSAGE=%s' cannot be honored.", lc->lc_messages); + elog(NOTICE, "pg_setlocale(): 'LC_MESSAGE=%s' cannot be honored.", + lc->lc_messages); #endif - return lc; } /*------ * Return the POSIX lconv struct (contains number/money formatting information) - * with locale information for *all* categories. - * => Returned lconv is *independent* on current locale catogories setting - in - * contrast to standard localeconv(). + * with locale information for all categories. Note that returned lconv + * does not depend on currently active category settings, but on external + * environment variables for locale. + * + * XXX we assume that restoring old category settings via setlocale() will + * not immediately corrupt the static data returned by localeconv(). + * How portable is this? * - * ! libc prepare memory space for lconv itself and all returned strings in - * lconv are *static strings*. + * XXX in any case, there certainly must not be any other calls to + * localeconv() anywhere in the backend, else the values reported here + * will be overwritten with the Postgres-internal locale settings. *------ */ struct lconv * PGLC_localeconv(void) { PG_LocaleCategories lc; - + + /* Did we do it already? */ if (CurrentLocaleConv) return CurrentLocaleConv; /* Save current locale setting to lc */ PGLC_current(&lc); - /* Set all locale category for current lang */ + /* Set all locale categories based on postmaster's environment vars */ setlocale(LC_ALL, ""); - /* Get numeric formatting information */ + /* Get formatting information for the external environment */ CurrentLocaleConv = localeconv(); - /* Set previous original locale */ + /* Restore Postgres' internal locale settings */ PGLC_setlocale(&lc); return CurrentLocaleConv; } - #endif /* USE_LOCALE */ |