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
2147char * 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+ */
2960static const char *
3061locale_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
6078return value ;
61- #endif
6279}
6380
81+
6482const char *
6583locale_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 */
114196struct lconv *
115197PGLC_localeconv (void )
116198{
117- static bool CurrentLocaleConvValid = false;
118199static struct lconv CurrentLocaleConv ;
119-
120200struct lconv * extlconv ;
201+ char * save_lc_monetary ;
202+ char * save_lc_numeric ;
121203
122204/* Did we do it already? */
123205if (CurrentLocaleConvValid )
124206return & 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 */
127217extlconv = localeconv ();
128218
129219/*
@@ -141,6 +231,10 @@ PGLC_localeconv(void)
141231CurrentLocaleConv .mon_thousands_sep = strdup (extlconv -> mon_thousands_sep );
142232CurrentLocaleConv .negative_sign = strdup (extlconv -> negative_sign );
143233CurrentLocaleConv .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
145239CurrentLocaleConvValid = true;
146240return & CurrentLocaleConv ;