Skip to content

Commit ab51bba

Browse files
committed
Arrange to set the LC_XXX environment variables to match our locale
setup. This protects against undesired changes in locale behavior if someone carelessly does setlocale(LC_ALL, "") (and we know who you are, perl guys).
1 parent b6c881c commit ab51bba

File tree

4 files changed

+146
-51
lines changed

4 files changed

+146
-51
lines changed

src/backend/access/transam/xlog.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.223 2005/11/22 18:17:07 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.224 2005/12/28 23:22:50 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -45,6 +45,7 @@
4545
#include "utils/builtins.h"
4646
#include "utils/guc.h"
4747
#include "utils/nabstime.h"
48+
#include "utils/pg_locale.h"
4849
#include "utils/relcache.h"
4950

5051

@@ -3619,14 +3620,14 @@ ReadControlFile(void)
36193620
" but the server was compiled with LOCALE_NAME_BUFLEN %d.",
36203621
ControlFile->localeBuflen, LOCALE_NAME_BUFLEN),
36213622
errhint("It looks like you need to recompile or initdb.")));
3622-
if (setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
3623+
if (pg_perm_setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
36233624
ereport(FATAL,
36243625
(errmsg("database files are incompatible with operating system"),
36253626
errdetail("The database cluster was initialized with LC_COLLATE \"%s\","
36263627
" which is not recognized by setlocale().",
36273628
ControlFile->lc_collate),
36283629
errhint("It looks like you need to initdb or install locale support.")));
3629-
if (setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
3630+
if (pg_perm_setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
36303631
ereport(FATAL,
36313632
(errmsg("database files are incompatible with operating system"),
36323633
errdetail("The database cluster was initialized with LC_CTYPE \"%s\","

src/backend/main/main.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.97 2005/11/22 18:17:11 momjian Exp $
16+
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.98 2005/12/28 23:22:51 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
2020
#include "postgres.h"
2121

22-
#include <errno.h>
2322
#include <pwd.h>
2423
#include <unistd.h>
2524

@@ -40,6 +39,7 @@
4039
#include "postmaster/postmaster.h"
4140
#include "tcop/tcopprot.h"
4241
#include "utils/help_config.h"
42+
#include "utils/pg_locale.h"
4343
#include "utils/ps_status.h"
4444
#ifdef WIN32
4545
#include "libpq/pqsignal.h"
@@ -162,30 +162,37 @@ main(int argc, char *argv[])
162162
*/
163163

164164
if ((env_locale = getenv("LC_COLLATE")) != NULL)
165-
setlocale(LC_COLLATE, env_locale);
165+
pg_perm_setlocale(LC_COLLATE, env_locale);
166166
else
167-
setlocale(LC_COLLATE, "");
167+
pg_perm_setlocale(LC_COLLATE, "");
168168

169169
if ((env_locale = getenv("LC_CTYPE")) != NULL)
170-
setlocale(LC_CTYPE, env_locale);
170+
pg_perm_setlocale(LC_CTYPE, env_locale);
171171
else
172-
setlocale(LC_CTYPE, "");
172+
pg_perm_setlocale(LC_CTYPE, "");
173173
#else
174-
setlocale(LC_COLLATE, "");
175-
setlocale(LC_CTYPE, "");
174+
pg_perm_setlocale(LC_COLLATE, "");
175+
pg_perm_setlocale(LC_CTYPE, "");
176176
#endif
177177

178178
#ifdef LC_MESSAGES
179-
setlocale(LC_MESSAGES, "");
179+
pg_perm_setlocale(LC_MESSAGES, "");
180180
#endif
181181

182182
/*
183183
* We keep these set to "C" always, except transiently in pg_locale.c; see
184184
* that file for explanations.
185185
*/
186-
setlocale(LC_MONETARY, "C");
187-
setlocale(LC_NUMERIC, "C");
188-
setlocale(LC_TIME, "C");
186+
pg_perm_setlocale(LC_MONETARY, "C");
187+
pg_perm_setlocale(LC_NUMERIC, "C");
188+
pg_perm_setlocale(LC_TIME, "C");
189+
190+
/*
191+
* Now that we have absorbed as much as we wish to from the locale
192+
* environment, remove any LC_ALL setting, so that the environment
193+
* variables installed by pg_perm_setlocale have force.
194+
*/
195+
unsetenv("LC_ALL");
189196

190197
/*
191198
* Skip permission checks if we're just trying to do --help or --version;

src/backend/utils/adt/pg_locale.c

Lines changed: 120 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Portions Copyright (c) 2002-2005, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.32 2005/10/15 02:49:29 momjian Exp $
7+
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.33 2005/12/28 23:22:51 tgl Exp $
88
*
99
*-----------------------------------------------------------------------
1010
*/
@@ -50,20 +50,129 @@
5050

5151
#include <locale.h>
5252

53+
#include "catalog/pg_control.h"
5354
#include "utils/pg_locale.h"
5455

5556

56-
/* indicated whether locale information cache is valid */
57-
static bool CurrentLocaleConvValid = false;
58-
59-
6057
/* GUC storage area */
6158

6259
char *locale_messages;
6360
char *locale_monetary;
6461
char *locale_numeric;
6562
char *locale_time;
6663

64+
/* indicates whether locale information cache is valid */
65+
static bool CurrentLocaleConvValid = false;
66+
67+
/* Environment variable storage area */
68+
69+
#define LC_ENV_BUFSIZE (LOCALE_NAME_BUFLEN + 20)
70+
71+
static char lc_collate_envbuf[LC_ENV_BUFSIZE];
72+
static char lc_ctype_envbuf[LC_ENV_BUFSIZE];
73+
#ifdef LC_MESSAGES
74+
static char lc_messages_envbuf[LC_ENV_BUFSIZE];
75+
#endif
76+
static char lc_monetary_envbuf[LC_ENV_BUFSIZE];
77+
static char lc_numeric_envbuf[LC_ENV_BUFSIZE];
78+
static char lc_time_envbuf[LC_ENV_BUFSIZE];
79+
80+
81+
/*
82+
* pg_perm_setlocale
83+
*
84+
* This is identical to the libc function setlocale(), with the addition
85+
* that if the operation is successful, the corresponding LC_XXX environment
86+
* variable is set to match. By setting the environment variable, we ensure
87+
* that any subsequent use of setlocale(..., "") will preserve the settings
88+
* made through this routine. Of course, LC_ALL must also be unset to fully
89+
* ensure that, but that has to be done elsewhere after all the individual
90+
* LC_XXX variables have been set correctly. (Thank you Perl for making this
91+
* kluge necessary.)
92+
*/
93+
char *
94+
pg_perm_setlocale(int category, const char *locale)
95+
{
96+
char *result;
97+
const char *envvar;
98+
char *envbuf;
99+
100+
#ifndef WIN32
101+
result = setlocale(category, locale);
102+
#else
103+
/*
104+
* On Windows, setlocale(LC_MESSAGES) does not work, so just assume
105+
* that the given value is good and set it in the environment variables.
106+
* We must ignore attempts to set to "", which means "keep using the
107+
* old environment value".
108+
*/
109+
if (category != LC_MESSAGES)
110+
result = setlocale(category, locale);
111+
else
112+
{
113+
result = (char *) locale;
114+
if (locale == NULL || locale[0] == '\0')
115+
return result;
116+
}
117+
#endif
118+
119+
if (result == NULL)
120+
return result; /* fall out immediately on failure */
121+
122+
switch (category)
123+
{
124+
case LC_COLLATE:
125+
envvar = "LC_COLLATE";
126+
envbuf = lc_collate_envbuf;
127+
break;
128+
case LC_CTYPE:
129+
envvar = "LC_CTYPE";
130+
envbuf = lc_ctype_envbuf;
131+
break;
132+
#ifdef LC_MESSAGES
133+
case LC_MESSAGES:
134+
envvar = "LC_MESSAGES";
135+
envbuf = lc_messages_envbuf;
136+
break;
137+
#endif
138+
case LC_MONETARY:
139+
envvar = "LC_MONETARY";
140+
envbuf = lc_monetary_envbuf;
141+
break;
142+
case LC_NUMERIC:
143+
envvar = "LC_NUMERIC";
144+
envbuf = lc_numeric_envbuf;
145+
break;
146+
case LC_TIME:
147+
envvar = "LC_TIME";
148+
envbuf = lc_time_envbuf;
149+
break;
150+
default:
151+
elog(FATAL, "unrecognized LC category: %d", category);
152+
envvar = NULL; /* keep compiler quiet */
153+
envbuf = NULL;
154+
break;
155+
}
156+
157+
snprintf(envbuf, LC_ENV_BUFSIZE-1, "%s=%s", envvar, result);
158+
159+
#ifndef WIN32
160+
if (putenv(envbuf))
161+
return NULL;
162+
#else
163+
/*
164+
* On Windows, we need to modify both the process environment and the
165+
* cached version in msvcrt
166+
*/
167+
if (!SetEnvironmentVariable(envvar, result))
168+
return NULL;
169+
if (_putenv(envbuf))
170+
return NULL;
171+
#endif
172+
173+
return result;
174+
}
175+
67176

68177
/* GUC assign hooks */
69178

@@ -123,48 +232,24 @@ locale_time_assign(const char *value, bool doit, GucSource source)
123232
const char *
124233
locale_messages_assign(const char *value, bool doit, GucSource source)
125234
{
126-
#ifndef WIN32
127-
128235
/*
129236
* LC_MESSAGES category does not exist everywhere, but accept it anyway
237+
*
238+
* On Windows, we can't even check the value, so the non-doit case
239+
* is a no-op
130240
*/
131241
#ifdef LC_MESSAGES
132242
if (doit)
133243
{
134-
if (!setlocale(LC_MESSAGES, value))
244+
if (!pg_perm_setlocale(LC_MESSAGES, value))
135245
return NULL;
136246
}
247+
#ifndef WIN32
137248
else
138249
value = locale_xxx_assign(LC_MESSAGES, value, false, source);
250+
#endif /* WIN32 */
139251
#endif /* LC_MESSAGES */
140252
return value;
141-
#else /* WIN32 */
142-
143-
/*
144-
* Win32 does not have working setlocale() for LC_MESSAGES. We can only
145-
* use environment variables to change it (per gettext FAQ). This means
146-
* we can't actually check the supplied value, so always assume it's good.
147-
* Also, ignore attempts to set to "", which really means "keep using the
148-
* old value". (Actually it means "use the environment value", but we are
149-
* too lazy to try to implement that exactly.)
150-
*/
151-
if (doit && value[0])
152-
{
153-
/*
154-
* We need to modify both the process environment and the cached
155-
* version in msvcrt
156-
*/
157-
static char env[128];
158-
159-
if (!SetEnvironmentVariable("LC_MESSAGES", value))
160-
return NULL;
161-
162-
snprintf(env, sizeof(env) - 1, "LC_MESSAGES=%s", value);
163-
if (_putenv(env))
164-
return NULL;
165-
}
166-
return value;
167-
#endif /* WIN32 */
168253
}
169254

170255

src/include/utils/pg_locale.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* PostgreSQL locale utilities
44
*
5-
* $PostgreSQL: pgsql/src/include/utils/pg_locale.h,v 1.20 2005/03/16 00:02:49 momjian Exp $
5+
* $PostgreSQL: pgsql/src/include/utils/pg_locale.h,v 1.21 2005/12/28 23:22:51 tgl Exp $
66
*
77
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
88
*
@@ -31,6 +31,8 @@ extern const char *locale_numeric_assign(const char *value,
3131
extern const char *locale_time_assign(const char *value,
3232
bool doit, GucSource source);
3333

34+
extern char *pg_perm_setlocale(int category, const char *locale);
35+
3436
extern bool lc_collate_is_c(void);
3537
extern bool lc_ctype_is_c(void);
3638

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy