2
2
*
3
3
* PostgreSQL locale utilities
4
4
*
5
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.19 2002/09/04 20:31:28 momjian Exp $
6
- *
7
5
* Portions Copyright (c) 2002, PostgreSQL Global Development Group
8
6
*
7
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.20 2002/10/18 20:44:02 tgl Exp $
8
+ *
9
9
*-----------------------------------------------------------------------
10
10
*/
11
11
12
- /*
12
+ /*----------
13
13
* Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
14
14
* are fixed by initdb, stored in pg_control, and cannot be changed.
15
15
* Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
20
20
*
21
21
* The other categories, LC_MONETARY, LC_NUMERIC, and LC_TIME are also
22
22
* settable at run-time. However, we don't actually set those locale
23
- * categories permanently. This would have bizzare effects like no
23
+ * categories permanently. This would have bizarre effects like no
24
24
* longer accepting standard floating-point literals in some locales.
25
25
* Instead, we only set the locales briefly when needed, cache the
26
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
27
+ * The cached information is only used by the formatting functions
28
+ * (to_char, etc.) and the money type. For the user, this should all be
29
29
* transparent. (Actually, LC_TIME doesn't do anything at all right
30
30
* now.)
31
+ *
32
+ * !!! NOW HEAR THIS !!!
33
+ *
34
+ * We've been bitten repeatedly by this bug, so let's try to keep it in
35
+ * mind in future: on some platforms, the locale functions return pointers
36
+ * to static data that will be overwritten by any later locale function.
37
+ * Thus, for example, the obvious-looking sequence
38
+ * save = setlocale(category, NULL);
39
+ * if (!setlocale(category, value))
40
+ * fail = true;
41
+ * setlocale(category, save);
42
+ * DOES NOT WORK RELIABLY: on some platforms the second setlocale() call
43
+ * will change the memory save is pointing at. To do this sort of thing
44
+ * safely, you *must* pstrdup what setlocale returns the first time.
45
+ *----------
31
46
*/
32
47
33
48
@@ -64,15 +79,19 @@ locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
64
79
65
80
save = setlocale (category , NULL );
66
81
if (!save )
67
- return NULL ;
82
+ return NULL ; /* won't happen, we hope */
83
+
84
+ /* save may be pointing at a modifiable scratch variable, see above */
85
+ save = pstrdup (save );
68
86
69
87
if (!setlocale (category , value ))
70
- return NULL ;
88
+ value = NULL ; /* set failure return marker */
71
89
72
- setlocale (category , save );
90
+ setlocale (category , save ); /* assume this won't fail */
91
+ pfree (save );
73
92
74
- /* need to reload cache next time */
75
- if (doit )
93
+ /* need to reload cache next time? */
94
+ if (doit && value != NULL )
76
95
CurrentLocaleConvValid = false;
77
96
78
97
return value ;
@@ -99,7 +118,7 @@ locale_time_assign(const char *value, bool doit, bool interactive)
99
118
100
119
101
120
/*
102
- * lc_messages takes effect immediately
121
+ * We allow LC_MESSAGES to actually be set globally.
103
122
*/
104
123
const char *
105
124
locale_messages_assign (const char * value , bool doit , bool interactive )
@@ -116,16 +135,7 @@ locale_messages_assign(const char *value, bool doit, bool interactive)
116
135
}
117
136
else
118
137
{
119
- char * save ;
120
-
121
- save = setlocale (LC_MESSAGES , NULL );
122
- if (!save )
123
- return NULL ;
124
-
125
- if (!setlocale (LC_MESSAGES , value ))
126
- return NULL ;
127
-
128
- setlocale (LC_MESSAGES , save );
138
+ value = locale_xxx_assign (LC_MESSAGES , value , false, interactive );
129
139
}
130
140
#endif
131
141
return value ;
@@ -210,8 +220,13 @@ PGLC_localeconv(void)
210
220
211
221
free_struct_lconv (& CurrentLocaleConv );
212
222
223
+ /* Set user's values of monetary and numeric locales */
213
224
save_lc_monetary = setlocale (LC_MONETARY , NULL );
225
+ if (save_lc_monetary )
226
+ save_lc_monetary = pstrdup (save_lc_monetary );
214
227
save_lc_numeric = setlocale (LC_NUMERIC , NULL );
228
+ if (save_lc_numeric )
229
+ save_lc_numeric = pstrdup (save_lc_numeric );
215
230
216
231
setlocale (LC_MONETARY , locale_monetary );
217
232
setlocale (LC_NUMERIC , locale_numeric );
@@ -221,7 +236,7 @@ PGLC_localeconv(void)
221
236
222
237
/*
223
238
* Must copy all values since restoring internal settings may
224
- * overwrite
239
+ * overwrite localeconv()'s results.
225
240
*/
226
241
CurrentLocaleConv = * extlconv ;
227
242
CurrentLocaleConv .currency_symbol = strdup (extlconv -> currency_symbol );
@@ -236,8 +251,18 @@ PGLC_localeconv(void)
236
251
CurrentLocaleConv .positive_sign = strdup (extlconv -> positive_sign );
237
252
CurrentLocaleConv .n_sign_posn = extlconv -> n_sign_posn ;
238
253
239
- setlocale (LC_MONETARY , save_lc_monetary );
240
- setlocale (LC_NUMERIC , save_lc_numeric );
254
+ /* Try to restore internal settings */
255
+ if (save_lc_monetary )
256
+ {
257
+ setlocale (LC_MONETARY , save_lc_monetary );
258
+ pfree (save_lc_monetary );
259
+ }
260
+
261
+ if (save_lc_numeric )
262
+ {
263
+ setlocale (LC_NUMERIC , save_lc_numeric );
264
+ pfree (save_lc_numeric );
265
+ }
241
266
242
267
CurrentLocaleConvValid = true;
243
268
return & CurrentLocaleConv ;
0 commit comments