* workings can be found in the book "Software Solutions in C" by
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.47 2000/11/25 20:33:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.48 2000/11/25 22:43:08 tgl Exp $
*/
+#include "postgres.h"
+
#include
#include
#include
+#ifdef USE_LOCALE
#include
+#endif
-#include "postgres.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/cash.h"
+#include "utils/pg_locale.h"
+
static const char *num_word(Cash value);
#define LAST_PAREN (TERMINATOR - 1)
#define LAST_DIGIT (LAST_PAREN - 1)
-#ifdef USE_LOCALE
-static struct lconv *lconvert = NULL;
-
-#endif
-
/*
* Cash is a pass-by-ref SQL type, so we must pass and return pointers.
ssymbol,
psymbol,
*nsymbol;
-
#ifdef USE_LOCALE
- if (lconvert == NULL)
- lconvert = localeconv();
+ struct lconv *lconvert = PGLC_localeconv();
+#endif
+#ifdef USE_LOCALE
/*
* frac_digits will be CHAR_MAX in some locales, notably C. However,
* just testing for == CHAR_MAX is risky, because of compilers like
dsymbol,
*nsymbol;
char convention;
-
#ifdef USE_LOCALE
- if (lconvert == NULL)
- lconvert = localeconv();
+ struct lconv *lconvert = PGLC_localeconv();
+#endif
+#ifdef USE_LOCALE
/* see comments about frac_digits in cash_in() */
points = lconvert->frac_digits;
if (points < 0 || points > 10)
-
/* -----------------------------------------------------------------------
* 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
-
#include "postgres.h"
#ifdef USE_LOCALE
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");
#ifdef LC_MESSAGES
lc->lc_messages = setlocale(LC_MESSAGES, NULL);
#endif
- return lc;
}
* Print a PG_LocaleCategories struct as DEBUG
*------
*/
-PG_LocaleCategories *
+static void
PGLC_debug_lc(PG_LocaleCategories * lc)
{
#ifdef LC_MESSAGES
, 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 */
-
/* -----------------------------------------------------------------------
* pg_locale.h
*
- * $Header: /cvsroot/pgsql/src/include/utils/pg_locale.h,v 1.4 2000/04/12 17:16:55 momjian Exp $
+ * The PostgreSQL locale utils.
*
*
- * Portions Copyright (c) 1999-2000, PostgreSQL, Inc
+ * $Id: pg_locale.h,v 1.5 2000/11/25 22:43:07 tgl Exp $
*
- * The PostgreSQL locale utils.
+ * Portions Copyright (c) 1999-2000, PostgreSQL, Inc
*
* Karel Zak - Zakkr
*
} PG_LocaleCategories;
-extern PG_LocaleCategories *PGLC_current(PG_LocaleCategories * lc);
-extern PG_LocaleCategories *PGLC_setlocale(PG_LocaleCategories * lc);
+extern void PGLC_current(PG_LocaleCategories * 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.
*------
*/
extern struct lconv *PGLC_localeconv(void);