1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-14 08:21:07 +03:00

Locale support is on by default. The choice of locale is done in initdb

and/or with GUC variables.
This commit is contained in:
Peter Eisentraut
2002-04-03 05:39:33 +00:00
parent 3d7755c8e9
commit 867901db9e
19 changed files with 554 additions and 479 deletions

View File

@ -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 "utils/pg_locale.h"
#include <locale.h>
#include "utils/pg_locale.h"
/* #define DEBUG_LOCALE_UTILS */
/* GUC storage area */
char * locale_messages;
char * locale_monetary;
char * locale_numeric;
char * locale_time;
static bool CurrentLocaleConvValid = false;
static struct lconv CurrentLocaleConv;
/* GUC parse hooks */
static void PGLC_setlocale(PG_LocaleCategories *lc);
/*------
* Frees memory used in PG_LocaleCategories -- this memory is
* allocated in PGLC_current().
*------
*/
void
PGLC_free_categories(PG_LocaleCategories *lc)
{
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);
#endif
}
/*------
* Return in PG_LocaleCategories the current locale settings.
*
* NB: strings are allocated in the current memory context!
*------
*/
void
PGLC_current(PG_LocaleCategories *lc)
{
lc->lang = getenv("LANG");
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
}
#ifdef DEBUG_LOCALE_UTILS
/*------
* Print a PG_LocaleCategories struct as DEBUG
*------
*/
static void
PGLC_debug_lc(PG_LocaleCategories *lc)
bool locale_messages_check(const char *proposed)
{
#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);
return chklocale(LC_MESSAGES, proposed);
#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);
/* We return true here so LC_MESSAGES can be set in the
configuration file on every system. */
return true;
#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.
*------
*/
static void
PGLC_setlocale(PG_LocaleCategories *lc)
bool locale_monetary_check(const char *proposed)
{
if (!setlocale(LC_COLLATE, lc->lc_collate))
elog(WARNING, "pg_setlocale(): 'LC_COLLATE=%s' cannot be honored.",
lc->lc_collate);
return chklocale(LC_MONETARY, proposed);
}
if (!setlocale(LC_CTYPE, lc->lc_ctype))
elog(WARNING, "pg_setlocale(): 'LC_CTYPE=%s' cannot be honored.",
lc->lc_ctype);
bool locale_numeric_check(const char *proposed)
{
return chklocale(LC_NUMERIC, proposed);
}
if (!setlocale(LC_NUMERIC, lc->lc_numeric))
elog(WARNING, "pg_setlocale(): 'LC_NUMERIC=%s' cannot be honored.",
lc->lc_numeric);
bool locale_time_check(const char *proposed)
{
return chklocale(LC_TIME, proposed);
}
if (!setlocale(LC_TIME, lc->lc_time))
elog(WARNING, "pg_setlocale(): 'LC_TIME=%s' cannot be honored.",
lc->lc_time);
if (!setlocale(LC_MONETARY, lc->lc_monetary))
elog(WARNING, "pg_setlocale(): 'LC_MONETARY=%s' cannot be honored.",
lc->lc_monetary);
/* GUC assign hooks */
void locale_messages_assign(const char *value)
{
#ifdef LC_MESSAGES
if (!setlocale(LC_MESSAGES, lc->lc_messages))
elog(WARNING, "pg_setlocale(): 'LC_MESSAGES=%s' cannot be honored.",
lc->lc_messages);
setlocale(LC_MESSAGES, value);
#endif
}
/*------
* 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.
*------
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.
*/
bool
chklocale(int category, const char *proposed)
{
char *save;
save = setlocale(category, NULL);
if (!save)
return false;
if (!setlocale(category, proposed))
return false;
setlocale(category, save);
return true;
}
/*
* 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.
*/
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 */