Skip to content

Commit 6ce4a4e

Browse files
committed
Make sure monetary, numeric, and time locale categories are set to C and
are only activated temporarily to read out formatting information.
1 parent 9c5dacc commit 6ce4a4e

File tree

3 files changed

+136
-39
lines changed

3 files changed

+136
-39
lines changed

doc/src/sgml/runtime.sgml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.122 2002/07/31 17:19:50 tgl Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.123 2002/08/09 22:52:04 petere Exp $
33
-->
44

55
<Chapter Id="runtime">
@@ -1451,8 +1451,9 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
14511451
<term><varname>LC_MONETARY</varname> (<type>string</type>)</term>
14521452
<listitem>
14531453
<para>
1454-
Sets the locale to use for formatting monetary amounts.
1455-
Acceptable values are system-dependent; see <xref
1454+
Sets the locale to use for formatting monetary amounts, for
1455+
example with the <function>to_char()</function> family of
1456+
functions. Acceptable values are system-dependent; see <xref
14561457
linkend="locale"> for more information. If this variable is
14571458
set to the empty string (which is the default) then the value
14581459
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'
14801481
<term><varname>LC_TIME</varname> (<type>string</type>)</term>
14811482
<listitem>
14821483
<para>
1483-
Sets the locale to use for formatting date and time values,
1484-
for example with the <function>to_char()</function> family of
1485-
functions. Acceptable values are system-dependent; see <xref
1484+
Sets the locale to use for formatting date and time values.
1485+
(Currently, this setting does nothing, but it may in the
1486+
future.) Acceptable values are system-dependent; see <xref
14861487
linkend="locale"> for more information. If this variable is
14871488
set to the empty string (which is the default) then the value
14881489
is inherited from the execution environment of the server in a

src/backend/main/main.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.52 2002/06/20 20:29:29 momjian Exp $
16+
* $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.53 2002/08/09 22:52:04 petere Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -134,9 +134,11 @@ main(int argc, char *argv[])
134134
#ifdef LC_MESSAGES
135135
setlocale(LC_MESSAGES, "");
136136
#endif
137-
setlocale(LC_MONETARY, "");
138-
setlocale(LC_NUMERIC, "");
139-
setlocale(LC_TIME, "");
137+
/* We don't use these during startup. See also pg_locale.c about
138+
* why these are set to "C". */
139+
setlocale(LC_MONETARY, "C");
140+
setlocale(LC_NUMERIC, "C");
141+
setlocale(LC_TIME, "C");
140142

141143
#ifdef ENABLE_NLS
142144
bindtextdomain("postgres", LOCALEDIR);

src/backend/utils/adt/pg_locale.c

Lines changed: 123 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,46 @@
22
*
33
* PostgreSQL locale utilities
44
*
5-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.17 2002/05/17 01:19:18 tgl Exp $
5+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.18 2002/08/09 22:52:04 petere Exp $
66
*
77
* Portions Copyright (c) 2002, PostgreSQL Global Development Group
88
*
99
*-----------------------------------------------------------------------
1010
*/
1111

12+
/*
13+
* Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
14+
* are fixed by initdb, stored in pg_control, and cannot be changed.
15+
* Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
16+
* etc. are always in the same fixed locale.
17+
*
18+
* LC_MESSAGES is settable at run time and will take effect
19+
* immediately.
20+
*
21+
* The other categories, LC_MONETARY, LC_NUMERIC, and LC_TIME are also
22+
* settable at run-time. However, we don't actually set those locale
23+
* categories permanently. This would have bizzare effects like no
24+
* longer accepting standard floating-point literals in some locales.
25+
* Instead, we only set the locales briefly when needed, cache the
26+
* required information obtained from localeconv(), and set them back.
27+
* The information is only used by the formatting functions (to_char,
28+
* etc.) and the money type. For the user, this should all be
29+
* transparent. (Actually, LC_TIME doesn't do anything at all right
30+
* now.)
31+
*/
32+
33+
1234
#include "postgres.h"
1335

1436
#include <locale.h>
1537

1638
#include "utils/pg_locale.h"
1739

1840

41+
/* indicated whether locale information cache is valid */
42+
static bool CurrentLocaleConvValid = false;
43+
44+
1945
/* GUC storage area */
2046

2147
char *locale_messages;
@@ -26,41 +52,33 @@ char *locale_time;
2652

2753
/* GUC assign hooks */
2854

55+
/*
56+
* This is common code for several locale categories. This doesn't
57+
* actually set the locale permanently, it only tests if the locale is
58+
* valid. (See explanation at the top of this file.)
59+
*/
2960
static const char *
3061
locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
3162
{
32-
if (doit)
33-
{
34-
if (!setlocale(category, value))
35-
return NULL;
36-
}
37-
else
38-
{
39-
char *save;
63+
char *save;
4064

41-
save = setlocale(category, NULL);
42-
if (!save)
43-
return NULL;
65+
save = setlocale(category, NULL);
66+
if (!save)
67+
return NULL;
4468

45-
if (!setlocale(category, value))
46-
return NULL;
69+
if (!setlocale(category, value))
70+
return NULL;
4771

48-
setlocale(category, save);
49-
}
50-
return value;
51-
}
72+
setlocale(category, save);
73+
74+
/* need to reload cache next time */
75+
if (doit)
76+
CurrentLocaleConvValid = false;
5277

53-
const char *
54-
locale_messages_assign(const char *value, bool doit, bool interactive)
55-
{
56-
/* LC_MESSAGES category does not exist everywhere, but accept it anyway */
57-
#ifdef LC_MESSAGES
58-
return locale_xxx_assign(LC_MESSAGES, value, doit, interactive);
59-
#else
6078
return value;
61-
#endif
6279
}
6380

81+
6482
const char *
6583
locale_monetary_assign(const char *value, bool doit, bool interactive)
6684
{
@@ -80,6 +98,37 @@ locale_time_assign(const char *value, bool doit, bool interactive)
8098
}
8199

82100

101+
/*
102+
* lc_messages takes effect immediately
103+
*/
104+
const char *
105+
locale_messages_assign(const char *value, bool doit, bool interactive)
106+
{
107+
/* LC_MESSAGES category does not exist everywhere, but accept it anyway */
108+
#ifdef LC_MESSAGES
109+
if (doit)
110+
{
111+
if (!setlocale(LC_MESSAGES, value))
112+
return NULL;
113+
}
114+
else
115+
{
116+
char *save;
117+
118+
save = setlocale(LC_MESSAGES, NULL);
119+
if (!save)
120+
return NULL;
121+
122+
if (!setlocale(LC_MESSAGES, value))
123+
return NULL;
124+
125+
setlocale(LC_MESSAGES, save);
126+
}
127+
#endif
128+
return value;
129+
}
130+
131+
83132
/*
84133
* We'd like to cache whether LC_COLLATE is C (or POSIX), so we can
85134
* optimize a few code paths in various places.
@@ -107,23 +156,64 @@ lc_collate_is_c(void)
107156
}
108157

109158

159+
/*
160+
* Frees the malloced content of a struct lconv. (But not the struct
161+
* itself.)
162+
*/
163+
static void
164+
free_struct_lconv(struct lconv *s)
165+
{
166+
if (s == NULL)
167+
return;
168+
169+
if (s->currency_symbol)
170+
free(s->currency_symbol);
171+
if (s->decimal_point)
172+
free(s->decimal_point);
173+
if (s->grouping)
174+
free(s->grouping);
175+
if (s->thousands_sep)
176+
free(s->thousands_sep);
177+
if (s->int_curr_symbol)
178+
free(s->int_curr_symbol);
179+
if (s->mon_decimal_point)
180+
free(s->mon_decimal_point);
181+
if (s->mon_grouping)
182+
free(s->mon_grouping);
183+
if (s->mon_thousands_sep)
184+
free(s->mon_thousands_sep);
185+
if (s->negative_sign)
186+
free(s->negative_sign);
187+
if (s->positive_sign)
188+
free(s->positive_sign);
189+
}
190+
191+
110192
/*
111193
* Return the POSIX lconv struct (contains number/money formatting
112194
* information) with locale information for all categories.
113195
*/
114196
struct lconv *
115197
PGLC_localeconv(void)
116198
{
117-
static bool CurrentLocaleConvValid = false;
118199
static struct lconv CurrentLocaleConv;
119-
120200
struct lconv *extlconv;
201+
char *save_lc_monetary;
202+
char *save_lc_numeric;
121203

122204
/* Did we do it already? */
123205
if (CurrentLocaleConvValid)
124206
return &CurrentLocaleConv;
125207

126-
/* Get formatting information for the external environment */
208+
free_struct_lconv(&CurrentLocaleConv);
209+
210+
save_lc_monetary = setlocale(LC_MONETARY, NULL);
211+
save_lc_numeric = setlocale(LC_NUMERIC, NULL);
212+
213+
setlocale(LC_MONETARY, locale_monetary);
214+
setlocale(LC_NUMERIC, locale_numeric);
215+
216+
/* Get formatting information */
127217
extlconv = localeconv();
128218

129219
/*
@@ -141,6 +231,10 @@ PGLC_localeconv(void)
141231
CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
142232
CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign);
143233
CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
234+
CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;
235+
236+
setlocale(LC_MONETARY, save_lc_monetary);
237+
setlocale(LC_NUMERIC, save_lc_numeric);
144238

145239
CurrentLocaleConvValid = true;
146240
return &CurrentLocaleConv;

0 commit comments

Comments
 (0)