Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8ca6147

Browse files
committed
Cope with the likelihood that setlocale and localeconv will return
pointers to data that will be changed by any later call to setlocale. Must copy what they return to be sure we get the right answer. Karel Zak, further tweaks by Tom Lane.
1 parent dc05a99 commit 8ca6147

File tree

2 files changed

+78
-30
lines changed

2 files changed

+78
-30
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
* The PostgreSQL locale utils.
55
*
66
*
7-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.9 2001/03/22 03:59:52 momjian Exp $
7+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.10 2001/09/29 21:16:30 tgl Exp $
88
*
99
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
1010
*
11-
* Karel Zak - Zakkr
11+
* Karel Zak
1212
*
1313
* -----------------------------------------------------------------------
1414
*/
@@ -18,31 +18,60 @@
1818
#ifdef USE_LOCALE
1919

2020
#include <locale.h>
21+
2122
#include "utils/pg_locale.h"
2223

2324
/* #define DEBUG_LOCALE_UTILS */
2425

2526

26-
static struct lconv *CurrentLocaleConv = NULL;
27+
static bool CurrentLocaleConvValid = false;
28+
static struct lconv CurrentLocaleConv;
29+
2730

2831
static void PGLC_setlocale(PG_LocaleCategories * lc);
2932

3033
/*------
31-
* Return in PG_LocaleCategories the current locale settings
34+
* Frees memory used in PG_LocaleCategories -- this memory is
35+
* allocated in PGLC_current().
36+
*------
37+
*/
38+
void
39+
PGLC_free_categories(PG_LocaleCategories * lc)
40+
{
41+
if (lc->lc_ctype)
42+
pfree(lc->lc_ctype);
43+
if (lc->lc_numeric)
44+
pfree(lc->lc_numeric);
45+
if (lc->lc_time)
46+
pfree(lc->lc_time);
47+
if (lc->lc_collate)
48+
pfree(lc->lc_collate);
49+
if (lc->lc_monetary);
50+
pfree(lc->lc_monetary);
51+
#ifdef LC_MESSAGES
52+
if (lc->lc_messages)
53+
pfree(lc->lc_messages);
54+
#endif
55+
}
56+
57+
/*------
58+
* Return in PG_LocaleCategories the current locale settings.
59+
*
60+
* NB: strings are allocated in the current memory context!
3261
*------
3362
*/
3463
void
3564
PGLC_current(PG_LocaleCategories * lc)
3665
{
3766
lc->lang = getenv("LANG");
3867

39-
lc->lc_ctype = setlocale(LC_CTYPE, NULL);
40-
lc->lc_numeric = setlocale(LC_NUMERIC, NULL);
41-
lc->lc_time = setlocale(LC_TIME, NULL);
42-
lc->lc_collate = setlocale(LC_COLLATE, NULL);
43-
lc->lc_monetary = setlocale(LC_MONETARY, NULL);
68+
lc->lc_ctype = pstrdup( setlocale(LC_CTYPE, NULL) );
69+
lc->lc_numeric = pstrdup( setlocale(LC_NUMERIC, NULL) );
70+
lc->lc_time = pstrdup( setlocale(LC_TIME, NULL) );
71+
lc->lc_collate = pstrdup( setlocale(LC_COLLATE, NULL) );
72+
lc->lc_monetary = pstrdup( setlocale(LC_MONETARY, NULL) );
4473
#ifdef LC_MESSAGES
45-
lc->lc_messages = setlocale(LC_MESSAGES, NULL);
74+
lc->lc_messages = pstrdup( setlocale(LC_MESSAGES, NULL) );
4675
#endif
4776
}
4877

@@ -58,19 +87,22 @@ PGLC_debug_lc(PG_LocaleCategories * lc)
5887
{
5988
#ifdef LC_MESSAGES
6089
elog(DEBUG, "CURRENT LOCALE ENVIRONMENT:\n\nLANG: \t%s\nLC_CTYPE:\t%s\nLC_NUMERIC:\t%s\nLC_TIME:\t%s\nLC_COLLATE:\t%s\nLC_MONETARY:\t%s\nLC_MESSAGES:\t%s\n",
90+
lc->lang,
91+
lc->lc_ctype,
92+
lc->lc_numeric,
93+
lc->lc_time,
94+
lc->lc_collate,
95+
lc->lc_monetary,
96+
lc->lc_messages);
6197
#else
6298
elog(DEBUG, "CURRENT LOCALE ENVIRONMENT:\n\nLANG: \t%s\nLC_CTYPE:\t%s\nLC_NUMERIC:\t%s\nLC_TIME:\t%s\nLC_COLLATE:\t%s\nLC_MONETARY:\t%s\n",
63-
#endif
6499
lc->lang,
65100
lc->lc_ctype,
66101
lc->lc_numeric,
67102
lc->lc_time,
68103
lc->lc_collate,
69-
lc->lc_monetary
70-
#ifdef LC_MESSAGES
71-
,lc->lc_messages
104+
lc->lc_monetary);
72105
#endif
73-
);
74106
}
75107

76108
#endif
@@ -109,7 +141,7 @@ PGLC_setlocale(PG_LocaleCategories * lc)
109141

110142
#ifdef LC_MESSAGES
111143
if (!setlocale(LC_MESSAGES, lc->lc_messages))
112-
elog(NOTICE, "pg_setlocale(): 'LC_MESSAGE=%s' cannot be honored.",
144+
elog(NOTICE, "pg_setlocale(): 'LC_MESSAGES=%s' cannot be honored.",
113145
lc->lc_messages);
114146
#endif
115147
}
@@ -119,24 +151,17 @@ PGLC_setlocale(PG_LocaleCategories * lc)
119151
* with locale information for all categories. Note that returned lconv
120152
* does not depend on currently active category settings, but on external
121153
* environment variables for locale.
122-
*
123-
* XXX we assume that restoring old category settings via setlocale() will
124-
* not immediately corrupt the static data returned by localeconv().
125-
* How portable is this?
126-
*
127-
* XXX in any case, there certainly must not be any other calls to
128-
* localeconv() anywhere in the backend, else the values reported here
129-
* will be overwritten with the Postgres-internal locale settings.
130154
*------
131155
*/
132156
struct lconv *
133157
PGLC_localeconv(void)
134158
{
135159
PG_LocaleCategories lc;
160+
struct lconv *extlconv;
136161

137162
/* Did we do it already? */
138-
if (CurrentLocaleConv)
139-
return CurrentLocaleConv;
163+
if (CurrentLocaleConvValid)
164+
return &CurrentLocaleConv;
140165

141166
/* Save current locale setting to lc */
142167
PGLC_current(&lc);
@@ -145,12 +170,29 @@ PGLC_localeconv(void)
145170
setlocale(LC_ALL, "");
146171

147172
/* Get formatting information for the external environment */
148-
CurrentLocaleConv = localeconv();
173+
extlconv = localeconv();
174+
175+
/* Must copy all values since restoring internal settings may overwrite */
176+
CurrentLocaleConv = *extlconv;
177+
CurrentLocaleConv.currency_symbol = strdup(extlconv->currency_symbol);
178+
CurrentLocaleConv.decimal_point = strdup(extlconv->decimal_point);
179+
CurrentLocaleConv.grouping = strdup(extlconv->grouping);
180+
CurrentLocaleConv.thousands_sep = strdup(extlconv->thousands_sep);
181+
CurrentLocaleConv.int_curr_symbol = strdup(extlconv->int_curr_symbol);
182+
CurrentLocaleConv.mon_decimal_point = strdup(extlconv->mon_decimal_point);
183+
CurrentLocaleConv.mon_grouping = strdup(extlconv->mon_grouping);
184+
CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
185+
CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign);
186+
CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
149187

150188
/* Restore Postgres' internal locale settings */
151189
PGLC_setlocale(&lc);
152190

153-
return CurrentLocaleConv;
191+
/* Deallocate category settings allocated in PGLC_current() */
192+
PGLC_free_categories(&lc);
193+
194+
CurrentLocaleConvValid = true;
195+
return &CurrentLocaleConv;
154196
}
155197

156198
#endif /* USE_LOCALE */

src/include/utils/pg_locale.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* The PostgreSQL locale utils.
55
*
66
*
7-
* $Id: pg_locale.h,v 1.7 2001/03/22 04:01:14 momjian Exp $
7+
* $Id: pg_locale.h,v 1.8 2001/09/29 21:16:30 tgl Exp $
88
*
99
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
1010
*
@@ -33,8 +33,14 @@ typedef struct PG_LocaleCategories
3333
*lc_messages;
3434
} PG_LocaleCategories;
3535

36-
36+
/*
37+
* Save locale category settings into PG memory
38+
*/
3739
extern void PGLC_current(PG_LocaleCategories * lc);
40+
/*
41+
* Free memory allocated in PGLC_current()
42+
*/
43+
extern void PGLC_free_categories(PG_LocaleCategories * lc);
3844

3945
/*------
4046
* Return the POSIX lconv struct (contains number/money formatting information)

0 commit comments

Comments
 (0)