Commit 6ce4a4e3 authored by Peter Eisentraut's avatar Peter Eisentraut

Make sure monetary, numeric, and time locale categories are set to C and

are only activated temporarily to read out formatting information.
parent 9c5dacc5
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.122 2002/07/31 17:19:50 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.123 2002/08/09 22:52:04 petere Exp $
--> -->
<Chapter Id="runtime"> <Chapter Id="runtime">
...@@ -1451,8 +1451,9 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir' ...@@ -1451,8 +1451,9 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
<term><varname>LC_MONETARY</varname> (<type>string</type>)</term> <term><varname>LC_MONETARY</varname> (<type>string</type>)</term>
<listitem> <listitem>
<para> <para>
Sets the locale to use for formatting monetary amounts. Sets the locale to use for formatting monetary amounts, for
Acceptable values are system-dependent; see <xref example with the <function>to_char()</function> family of
functions. Acceptable values are system-dependent; see <xref
linkend="locale"> for more information. If this variable is linkend="locale"> for more information. If this variable is
set to the empty string (which is the default) then the value set to the empty string (which is the default) then the value
is inherited from the execution environment of the server in a is inherited from the execution environment of the server in a
...@@ -1480,9 +1481,9 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir' ...@@ -1480,9 +1481,9 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
<term><varname>LC_TIME</varname> (<type>string</type>)</term> <term><varname>LC_TIME</varname> (<type>string</type>)</term>
<listitem> <listitem>
<para> <para>
Sets the locale to use for formatting date and time values, Sets the locale to use for formatting date and time values.
for example with the <function>to_char()</function> family of (Currently, this setting does nothing, but it may in the
functions. Acceptable values are system-dependent; see <xref future.) Acceptable values are system-dependent; see <xref
linkend="locale"> for more information. If this variable is linkend="locale"> for more information. If this variable is
set to the empty string (which is the default) then the value set to the empty string (which is the default) then the value
is inherited from the execution environment of the server in a is inherited from the execution environment of the server in a
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.52 2002/06/20 20:29:29 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.53 2002/08/09 22:52:04 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -134,9 +134,11 @@ main(int argc, char *argv[]) ...@@ -134,9 +134,11 @@ main(int argc, char *argv[])
#ifdef LC_MESSAGES #ifdef LC_MESSAGES
setlocale(LC_MESSAGES, ""); setlocale(LC_MESSAGES, "");
#endif #endif
setlocale(LC_MONETARY, ""); /* We don't use these during startup. See also pg_locale.c about
setlocale(LC_NUMERIC, ""); * why these are set to "C". */
setlocale(LC_TIME, ""); setlocale(LC_MONETARY, "C");
setlocale(LC_NUMERIC, "C");
setlocale(LC_TIME, "C");
#ifdef ENABLE_NLS #ifdef ENABLE_NLS
bindtextdomain("postgres", LOCALEDIR); bindtextdomain("postgres", LOCALEDIR);
......
...@@ -2,13 +2,35 @@ ...@@ -2,13 +2,35 @@
* *
* PostgreSQL locale utilities * PostgreSQL locale utilities
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.17 2002/05/17 01:19:18 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.18 2002/08/09 22:52:04 petere Exp $
* *
* Portions Copyright (c) 2002, PostgreSQL Global Development Group * Portions Copyright (c) 2002, PostgreSQL Global Development Group
* *
*----------------------------------------------------------------------- *-----------------------------------------------------------------------
*/ */
/*
* Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
* are fixed by initdb, stored in pg_control, and cannot be changed.
* Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
* etc. are always in the same fixed locale.
*
* LC_MESSAGES is settable at run time and will take effect
* immediately.
*
* The other categories, LC_MONETARY, LC_NUMERIC, and LC_TIME are also
* settable at run-time. However, we don't actually set those locale
* categories permanently. This would have bizzare effects like no
* longer accepting standard floating-point literals in some locales.
* Instead, we only set the locales briefly when needed, cache the
* required information obtained from localeconv(), and set them back.
* The information is only used by the formatting functions (to_char,
* etc.) and the money type. For the user, this should all be
* transparent. (Actually, LC_TIME doesn't do anything at all right
* now.)
*/
#include "postgres.h" #include "postgres.h"
#include <locale.h> #include <locale.h>
...@@ -16,6 +38,10 @@ ...@@ -16,6 +38,10 @@
#include "utils/pg_locale.h" #include "utils/pg_locale.h"
/* indicated whether locale information cache is valid */
static bool CurrentLocaleConvValid = false;
/* GUC storage area */ /* GUC storage area */
char *locale_messages; char *locale_messages;
...@@ -26,16 +52,14 @@ char *locale_time; ...@@ -26,16 +52,14 @@ char *locale_time;
/* GUC assign hooks */ /* GUC assign hooks */
/*
* This is common code for several locale categories. This doesn't
* actually set the locale permanently, it only tests if the locale is
* valid. (See explanation at the top of this file.)
*/
static const char * static const char *
locale_xxx_assign(int category, const char *value, bool doit, bool interactive) locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
{ {
if (doit)
{
if (!setlocale(category, value))
return NULL;
}
else
{
char *save; char *save;
save = setlocale(category, NULL); save = setlocale(category, NULL);
...@@ -46,21 +70,15 @@ locale_xxx_assign(int category, const char *value, bool doit, bool interactive) ...@@ -46,21 +70,15 @@ locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
return NULL; return NULL;
setlocale(category, save); setlocale(category, save);
}
return value;
}
const char * /* need to reload cache next time */
locale_messages_assign(const char *value, bool doit, bool interactive) if (doit)
{ CurrentLocaleConvValid = false;
/* LC_MESSAGES category does not exist everywhere, but accept it anyway */
#ifdef LC_MESSAGES
return locale_xxx_assign(LC_MESSAGES, value, doit, interactive);
#else
return value; return value;
#endif
} }
const char * const char *
locale_monetary_assign(const char *value, bool doit, bool interactive) locale_monetary_assign(const char *value, bool doit, bool interactive)
{ {
...@@ -80,6 +98,37 @@ locale_time_assign(const char *value, bool doit, bool interactive) ...@@ -80,6 +98,37 @@ locale_time_assign(const char *value, bool doit, bool interactive)
} }
/*
* lc_messages takes effect immediately
*/
const char *
locale_messages_assign(const char *value, bool doit, bool interactive)
{
/* LC_MESSAGES category does not exist everywhere, but accept it anyway */
#ifdef LC_MESSAGES
if (doit)
{
if (!setlocale(LC_MESSAGES, value))
return NULL;
}
else
{
char *save;
save = setlocale(LC_MESSAGES, NULL);
if (!save)
return NULL;
if (!setlocale(LC_MESSAGES, value))
return NULL;
setlocale(LC_MESSAGES, save);
}
#endif
return value;
}
/* /*
* We'd like to cache whether LC_COLLATE is C (or POSIX), so we can * We'd like to cache whether LC_COLLATE is C (or POSIX), so we can
* optimize a few code paths in various places. * optimize a few code paths in various places.
...@@ -107,6 +156,39 @@ lc_collate_is_c(void) ...@@ -107,6 +156,39 @@ lc_collate_is_c(void)
} }
/*
* Frees the malloced content of a struct lconv. (But not the struct
* itself.)
*/
static void
free_struct_lconv(struct lconv *s)
{
if (s == NULL)
return;
if (s->currency_symbol)
free(s->currency_symbol);
if (s->decimal_point)
free(s->decimal_point);
if (s->grouping)
free(s->grouping);
if (s->thousands_sep)
free(s->thousands_sep);
if (s->int_curr_symbol)
free(s->int_curr_symbol);
if (s->mon_decimal_point)
free(s->mon_decimal_point);
if (s->mon_grouping)
free(s->mon_grouping);
if (s->mon_thousands_sep)
free(s->mon_thousands_sep);
if (s->negative_sign)
free(s->negative_sign);
if (s->positive_sign)
free(s->positive_sign);
}
/* /*
* Return the POSIX lconv struct (contains number/money formatting * Return the POSIX lconv struct (contains number/money formatting
* information) with locale information for all categories. * information) with locale information for all categories.
...@@ -114,16 +196,24 @@ lc_collate_is_c(void) ...@@ -114,16 +196,24 @@ lc_collate_is_c(void)
struct lconv * struct lconv *
PGLC_localeconv(void) PGLC_localeconv(void)
{ {
static bool CurrentLocaleConvValid = false;
static struct lconv CurrentLocaleConv; static struct lconv CurrentLocaleConv;
struct lconv *extlconv; struct lconv *extlconv;
char *save_lc_monetary;
char *save_lc_numeric;
/* Did we do it already? */ /* Did we do it already? */
if (CurrentLocaleConvValid) if (CurrentLocaleConvValid)
return &CurrentLocaleConv; return &CurrentLocaleConv;
/* Get formatting information for the external environment */ free_struct_lconv(&CurrentLocaleConv);
save_lc_monetary = setlocale(LC_MONETARY, NULL);
save_lc_numeric = setlocale(LC_NUMERIC, NULL);
setlocale(LC_MONETARY, locale_monetary);
setlocale(LC_NUMERIC, locale_numeric);
/* Get formatting information */
extlconv = localeconv(); extlconv = localeconv();
/* /*
...@@ -141,6 +231,10 @@ PGLC_localeconv(void) ...@@ -141,6 +231,10 @@ PGLC_localeconv(void)
CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep); CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign); CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign);
CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign); CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;
setlocale(LC_MONETARY, save_lc_monetary);
setlocale(LC_NUMERIC, save_lc_numeric);
CurrentLocaleConvValid = true; CurrentLocaleConvValid = true;
return &CurrentLocaleConv; return &CurrentLocaleConv;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment