diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2002-04-03 05:39:33 +0000 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2002-04-03 05:39:33 +0000 |
commit | 867901db9efbdae05270931daeb92042dc285710 (patch) | |
tree | 3a6541fd7908d5ca085d86fae60827efd8a4c847 /src/backend/utils/adt/pg_locale.c | |
parent | 3d7755c8e939ab9e8315fea297ee6aadcd6ad656 (diff) | |
download | postgresql-867901db9efbdae05270931daeb92042dc285710.tar.gz postgresql-867901db9efbdae05270931daeb92042dc285710.zip |
Locale support is on by default. The choice of locale is done in initdb
and/or with GUC variables.
Diffstat (limited to 'src/backend/utils/adt/pg_locale.c')
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 223 |
1 files changed, 93 insertions, 130 deletions
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 2c86ff5bcf1..c5c8d312d3f 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -1,173 +1,144 @@ -/* ----------------------------------------------------------------------- - * pg_locale.c +/*----------------------------------------------------------------------- * - * The PostgreSQL locale utils. + * PostgreSQL locale utilities * + * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.16 2002/04/03 05:39:31 petere Exp $ * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.15 2002/03/06 06:10:14 momjian Exp $ + * Portions Copyright (c) 2002, PostgreSQL Global Development Group * - * Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group - * - * Karel Zak - * - * ----------------------------------------------------------------------- + *----------------------------------------------------------------------- */ #include "postgres.h" - -#ifdef USE_LOCALE - -#include <locale.h> - #include "utils/pg_locale.h" - -/* #define DEBUG_LOCALE_UTILS */ +#include <locale.h> -static bool CurrentLocaleConvValid = false; -static struct lconv CurrentLocaleConv; +/* GUC storage area */ +char * locale_messages; +char * locale_monetary; +char * locale_numeric; +char * locale_time; -static void PGLC_setlocale(PG_LocaleCategories *lc); +/* GUC parse hooks */ -/*------ - * Frees memory used in PG_LocaleCategories -- this memory is - * allocated in PGLC_current(). - *------ - */ -void -PGLC_free_categories(PG_LocaleCategories *lc) +bool locale_messages_check(const char *proposed) { - if (lc->lc_ctype) - pfree(lc->lc_ctype); - if (lc->lc_numeric) - pfree(lc->lc_numeric); - if (lc->lc_time) - pfree(lc->lc_time); - if (lc->lc_collate) - pfree(lc->lc_collate); - if (lc->lc_monetary); - pfree(lc->lc_monetary); #ifdef LC_MESSAGES - if (lc->lc_messages) - pfree(lc->lc_messages); + return chklocale(LC_MESSAGES, proposed); +#else + /* We return true here so LC_MESSAGES can be set in the + configuration file on every system. */ + return true; #endif } -/*------ - * Return in PG_LocaleCategories the current locale settings. - * - * NB: strings are allocated in the current memory context! - *------ - */ -void -PGLC_current(PG_LocaleCategories *lc) +bool locale_monetary_check(const char *proposed) { - lc->lang = getenv("LANG"); + return chklocale(LC_MONETARY, proposed); +} - lc->lc_ctype = pstrdup(setlocale(LC_CTYPE, NULL)); - lc->lc_numeric = pstrdup(setlocale(LC_NUMERIC, NULL)); - lc->lc_time = pstrdup(setlocale(LC_TIME, NULL)); - lc->lc_collate = pstrdup(setlocale(LC_COLLATE, NULL)); - lc->lc_monetary = pstrdup(setlocale(LC_MONETARY, NULL)); -#ifdef LC_MESSAGES - lc->lc_messages = pstrdup(setlocale(LC_MESSAGES, NULL)); -#endif +bool locale_numeric_check(const char *proposed) +{ + return chklocale(LC_NUMERIC, proposed); } +bool locale_time_check(const char *proposed) +{ + return chklocale(LC_TIME, proposed); +} -#ifdef DEBUG_LOCALE_UTILS +/* GUC assign hooks */ -/*------ - * Print a PG_LocaleCategories struct as DEBUG - *------ - */ -static void -PGLC_debug_lc(PG_LocaleCategories *lc) +void locale_messages_assign(const char *value) { #ifdef LC_MESSAGES - elog(LOG, "CURRENT LOCALE ENVIRONMENT:\n\nLANG: \t%s\nLC_CTYPE:\t%s\nLC_NUMERIC:\t%s\nLC_TIME:\t%s\nLC_COLLATE:\t%s\nLC_MONETARY:\t%s\nLC_MESSAGES:\t%s\n", - lc->lang, - lc->lc_ctype, - lc->lc_numeric, - lc->lc_time, - lc->lc_collate, - lc->lc_monetary, - lc->lc_messages); -#else - elog(LOG, "CURRENT LOCALE ENVIRONMENT:\n\nLANG: \t%s\nLC_CTYPE:\t%s\nLC_NUMERIC:\t%s\nLC_TIME:\t%s\nLC_COLLATE:\t%s\nLC_MONETARY:\t%s\n", - lc->lang, - lc->lc_ctype, - lc->lc_numeric, - lc->lc_time, - lc->lc_collate, - lc->lc_monetary); + setlocale(LC_MESSAGES, value); #endif } -#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. - *------ +void locale_monetary_assign(const char *value) +{ + setlocale(LC_MONETARY, value); +} + +void locale_numeric_assign(const char *value) +{ + setlocale(LC_NUMERIC, value); +} + +void locale_time_assign(const char *value) +{ + setlocale(LC_TIME, value); +} + + +/* + * Returns true if the proposed string represents a valid locale of + * the given category. This is probably pretty slow, but it's not + * called in critical places. */ -static void -PGLC_setlocale(PG_LocaleCategories *lc) +bool +chklocale(int category, const char *proposed) { - if (!setlocale(LC_COLLATE, lc->lc_collate)) - elog(WARNING, "pg_setlocale(): 'LC_COLLATE=%s' cannot be honored.", - lc->lc_collate); + char *save; - if (!setlocale(LC_CTYPE, lc->lc_ctype)) - elog(WARNING, "pg_setlocale(): 'LC_CTYPE=%s' cannot be honored.", - lc->lc_ctype); + save = setlocale(category, NULL); + if (!save) + return false; - if (!setlocale(LC_NUMERIC, lc->lc_numeric)) - elog(WARNING, "pg_setlocale(): 'LC_NUMERIC=%s' cannot be honored.", - lc->lc_numeric); + if (!setlocale(category, proposed)) + return false; - if (!setlocale(LC_TIME, lc->lc_time)) - elog(WARNING, "pg_setlocale(): 'LC_TIME=%s' cannot be honored.", - lc->lc_time); + setlocale(category, save); + return true; +} - if (!setlocale(LC_MONETARY, lc->lc_monetary)) - elog(WARNING, "pg_setlocale(): 'LC_MONETARY=%s' cannot be honored.", - lc->lc_monetary); -#ifdef LC_MESSAGES - if (!setlocale(LC_MESSAGES, lc->lc_messages)) - elog(WARNING, "pg_setlocale(): 'LC_MESSAGES=%s' cannot be honored.", - lc->lc_messages); -#endif +/* + * We'd like to cache whether LC_COLLATE is C (or POSIX), so we can + * optimize a few code paths in various places. + */ +bool +lc_collate_is_c(void) +{ + /* Cache result so we only have to compute it once */ + static int result = -1; + char *localeptr; + + if (result >= 0) + return (bool) result; + localeptr = setlocale(LC_COLLATE, NULL); + if (!localeptr) + elog(PANIC, "Invalid LC_COLLATE setting"); + + if (strcmp(localeptr, "C") == 0) + result = true; + else if (strcmp(localeptr, "POSIX") == 0) + result = true; + else + result = false; + return (bool) result; } -/*------ - * Return the POSIX lconv struct (contains number/money formatting information) - * 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. - *------ + + +/* + * Return the POSIX lconv struct (contains number/money formatting + * information) with locale information for all categories. */ struct lconv * PGLC_localeconv(void) { - PG_LocaleCategories lc; struct lconv *extlconv; + static bool CurrentLocaleConvValid = false; + static struct lconv CurrentLocaleConv; /* Did we do it already? */ if (CurrentLocaleConvValid) return &CurrentLocaleConv; - /* Save current locale setting to lc */ - PGLC_current(&lc); - - /* Set all locale categories based on postmaster's environment vars */ - setlocale(LC_ALL, ""); - /* Get formatting information for the external environment */ extlconv = localeconv(); @@ -187,14 +158,6 @@ PGLC_localeconv(void) CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign); CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign); - /* Restore Postgres' internal locale settings */ - PGLC_setlocale(&lc); - - /* Deallocate category settings allocated in PGLC_current() */ - PGLC_free_categories(&lc); - CurrentLocaleConvValid = true; return &CurrentLocaleConv; } - -#endif /* USE_LOCALE */ |