Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita88b6e4

Browse files
committed
setlocale() on Windows doesn't work correctly if the locale name contains
dots. I previously worked around this in initdb, mapping the knownproblematic locale names to aliases that work, but Hiroshi Inoue pointedout that that's not enough because even if you use one of the aliases, like"Chinese_HKG", setlocale(LC_CTYPE, NULL) returns back the long form, ie."Chinese_Hong Kong S.A.R.". When we try to restore an old locale value bypassing that value back to setlocale(), it fails. Note that you are affectedby this bug also if you use one of those short-form names manually, so justreverting the hack in initdb won't fix it.To work around that, move the locale name mapping from initdb to a wrapperaround setlocale(), so that the mapping is invoked on every setlocale() call.Also, add a few checks for failed setlocale() calls in the backend. Thesecalls shouldn't fail, and if they do there isn't much we can do about it,but at least you'll get a warning.Backpatch to 9.1, where the initdb hack was introduced. The Windows bugaffects older versions too if you set locale manually to one of the aliases,but given the lack of complaints from the field, I'm hesitent to backpatch.
1 parent8ea0257 commita88b6e4

File tree

4 files changed

+138
-70
lines changed

4 files changed

+138
-70
lines changed

‎src/backend/utils/adt/pg_locale.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@ check_locale(int category, const char *value)
239239
/* set the locale with setlocale, to see if it accepts it. */
240240
ret= (setlocale(category,value)!=NULL);
241241

242-
setlocale(category,save);/* assume this won't fail */
242+
/* restore old value. */
243+
if (!setlocale(category,save))
244+
elog(WARNING,"failed to restore old locale");
243245
pfree(save);
244246

245247
returnret;
@@ -499,21 +501,24 @@ PGLC_localeconv(void)
499501
/* Try to restore internal settings */
500502
if (save_lc_monetary)
501503
{
502-
setlocale(LC_MONETARY,save_lc_monetary);
504+
if (!setlocale(LC_MONETARY,save_lc_monetary))
505+
elog(WARNING,"failed to restore old locale");
503506
pfree(save_lc_monetary);
504507
}
505508

506509
if (save_lc_numeric)
507510
{
508-
setlocale(LC_NUMERIC,save_lc_numeric);
511+
if (!setlocale(LC_NUMERIC,save_lc_numeric))
512+
elog(WARNING,"failed to restore old locale");
509513
pfree(save_lc_numeric);
510514
}
511515

512516
#ifdefWIN32
513517
/* Try to restore internal ctype settings */
514518
if (save_lc_ctype)
515519
{
516-
setlocale(LC_CTYPE,save_lc_ctype);
520+
if (!setlocale(LC_CTYPE,save_lc_ctype))
521+
elog(WARNING,"failed to restore old locale");
517522
pfree(save_lc_ctype);
518523
}
519524
#endif
@@ -674,15 +679,17 @@ cache_locale_time(void)
674679
/* try to restore internal settings */
675680
if (save_lc_time)
676681
{
677-
setlocale(LC_TIME,save_lc_time);
682+
if (!setlocale(LC_TIME,save_lc_time))
683+
elog(WARNING,"failed to restore old locale");
678684
pfree(save_lc_time);
679685
}
680686

681687
#ifdefWIN32
682688
/* try to restore internal ctype settings */
683689
if (save_lc_ctype)
684690
{
685-
setlocale(LC_CTYPE,save_lc_ctype);
691+
if (!setlocale(LC_CTYPE,save_lc_ctype))
692+
elog(WARNING,"failed to restore old locale");
686693
pfree(save_lc_ctype);
687694
}
688695
#endif

‎src/bin/initdb/initdb.c

Lines changed: 7 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ static intlocale_date_order(const char *locale);
185185
staticboolcheck_locale_name(constchar*locale);
186186
staticboolcheck_locale_encoding(constchar*locale,intencoding);
187187
staticvoidsetlocales(void);
188-
staticchar*localemap(char*locale);
189188
staticvoidusage(constchar*progname);
190189

191190
#ifdefWIN32
@@ -2286,61 +2285,6 @@ strreplace(char *str, char *needle, char *replacement)
22862285
}
22872286
#endif/* WIN32 */
22882287

2289-
/*
2290-
* Windows has a problem with locale names that have a dot in the country
2291-
* name. For example:
2292-
*
2293-
* "Chinese (Traditional)_Hong Kong S.A.R..950"
2294-
*
2295-
* For some reason, setlocale() doesn't accept that. Fortunately, Windows'
2296-
* setlocale() accepts various alternative names for such countries, so we
2297-
* map the full country names to accepted aliases.
2298-
*
2299-
* The returned string is always malloc'd - if no mapping is done it is
2300-
* just a malloc'd copy of the original.
2301-
*/
2302-
staticchar*
2303-
localemap(char*locale)
2304-
{
2305-
locale=xstrdup(locale);
2306-
2307-
#ifdefWIN32
2308-
2309-
/*
2310-
* Map the full country name to an abbreviation that setlocale() accepts.
2311-
*
2312-
* "HKG" is listed here:
2313-
* http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
2314-
* (Country/Region Strings).
2315-
*
2316-
* "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
2317-
* above list, but seems to work anyway.
2318-
*/
2319-
strreplace(locale,"Hong Kong S.A.R.","HKG");
2320-
strreplace(locale,"U.A.E.","ARE");
2321-
2322-
/*
2323-
* The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
2324-
* seem to recognize that. And Macau isn't listed in the table of accepted
2325-
* abbreviations linked above.
2326-
*
2327-
* Fortunately, "ZHM" seems to be accepted as an alias for "Chinese
2328-
* (Traditional)_Macau S.A.R..950", so we use that. Note that it's unlike
2329-
* HKG and ARE, ZHM is an alias for the whole locale name, not just the
2330-
* country part. I'm not sure where that "ZHM" comes from, must be some
2331-
* legacy naming scheme. But hey, it works.
2332-
*
2333-
* Some versions of Windows spell it "Macau", others "Macao".
2334-
*/
2335-
strreplace(locale,"Chinese (Traditional)_Macau S.A.R..950","ZHM");
2336-
strreplace(locale,"Chinese_Macau S.A.R..950","ZHM");
2337-
strreplace(locale,"Chinese (Traditional)_Macao S.A.R..950","ZHM");
2338-
strreplace(locale,"Chinese_Macao S.A.R..950","ZHM");
2339-
#endif/* WIN32 */
2340-
2341-
returnlocale;
2342-
}
2343-
23442288
/*
23452289
* set up the locale variables
23462290
*
@@ -2372,25 +2316,25 @@ setlocales(void)
23722316
*/
23732317

23742318
if (strlen(lc_ctype)==0|| !check_locale_name(lc_ctype))
2375-
lc_ctype=localemap(setlocale(LC_CTYPE,NULL));
2319+
lc_ctype=xstrdup(setlocale(LC_CTYPE,NULL));
23762320
if (strlen(lc_collate)==0|| !check_locale_name(lc_collate))
2377-
lc_collate=localemap(setlocale(LC_COLLATE,NULL));
2321+
lc_collate=xstrdup(setlocale(LC_COLLATE,NULL));
23782322
if (strlen(lc_numeric)==0|| !check_locale_name(lc_numeric))
2379-
lc_numeric=localemap(setlocale(LC_NUMERIC,NULL));
2323+
lc_numeric=xstrdup(setlocale(LC_NUMERIC,NULL));
23802324
if (strlen(lc_time)==0|| !check_locale_name(lc_time))
2381-
lc_time=localemap(setlocale(LC_TIME,NULL));
2325+
lc_time=xstrdup(setlocale(LC_TIME,NULL));
23822326
if (strlen(lc_monetary)==0|| !check_locale_name(lc_monetary))
2383-
lc_monetary=localemap(setlocale(LC_MONETARY,NULL));
2327+
lc_monetary=xstrdup(setlocale(LC_MONETARY,NULL));
23842328
if (strlen(lc_messages)==0|| !check_locale_name(lc_messages))
23852329
#if defined(LC_MESSAGES)&& !defined(WIN32)
23862330
{
23872331
/* when available get the current locale setting */
2388-
lc_messages=localemap(setlocale(LC_MESSAGES,NULL));
2332+
lc_messages=xstrdup(setlocale(LC_MESSAGES,NULL));
23892333
}
23902334
#else
23912335
{
23922336
/* when not available, get the CTYPE setting */
2393-
lc_messages=localemap(setlocale(LC_CTYPE,NULL));
2337+
lc_messages=xstrdup(setlocale(LC_CTYPE,NULL));
23942338
}
23952339
#endif
23962340

‎src/include/port.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,27 @@ __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
226226
#endif
227227
#endif/* USE_REPL_SNPRINTF */
228228

229+
#if defined(WIN32)
229230
/*
230231
* Versions of libintl >= 0.18? try to replace setlocale() with a macro
231232
* to their own versions. Remove the macro, if it exists, because it
232233
* ends up calling the wrong version when the backend and libintl use
233234
* different versions of msvcrt.
234235
*/
235-
#if defined(setlocale)&& defined(WIN32)
236+
#if defined(setlocale)
236237
#undef setlocale
237238
#endif
238239

240+
/*
241+
* Define our own wrapper macro around setlocale() to work around bugs in
242+
* Windows' native setlocale() function.
243+
*/
244+
externchar*pgwin32_setlocale(intcategory,constchar*locale);
245+
246+
#definesetlocale(a,b) pgwin32_setlocale(a,b)
247+
248+
#endif/* WIN32 */
249+
239250
/* Portable prompt handling */
240251
externchar*simple_prompt(constchar*prompt,intmaxlen,boolecho);
241252

‎src/port/chklocale.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,3 +356,109 @@ pg_get_encoding_from_locale(const char *ctype, bool write_message)
356356
}
357357

358358
#endif/* (HAVE_LANGINFO_H && CODESET) || WIN32 */
359+
360+
#ifdefWIN32
361+
/*
362+
* Windows has a problem with locale names that have a dot in the country
363+
* name. For example:
364+
*
365+
* "Chinese (Traditional)_Hong Kong S.A.R..950"
366+
*
367+
* For some reason, setlocale() doesn't accept that. Fortunately, Windows'
368+
* setlocale() accepts various alternative names for such countries, so we
369+
* provide a wrapper setlocale() function that maps the troublemaking locale
370+
* names to accepted aliases.
371+
*/
372+
373+
#undef setlocale
374+
375+
structlocale_map
376+
{
377+
constchar*locale_name_part;/* string in locale name to replace */
378+
constchar*replacement;/* string to replace it with */
379+
};
380+
381+
staticconststructlocale_maplocale_map_list[]= {
382+
383+
/*
384+
* "HKG" is listed here:
385+
* http://msdn.microsoft.com/en-us/library/cdax410z%28v=vs.71%29.aspx
386+
* (Country/Region Strings).
387+
*
388+
* "ARE" is the ISO-3166 three-letter code for U.A.E. It is not on the
389+
* above list, but seems to work anyway.
390+
*/
391+
{"Hong Kong S.A.R.","HKG" },
392+
{"U.A.E.","ARE" },
393+
394+
/*
395+
* The ISO-3166 country code for Macau S.A.R. is MAC, but Windows doesn't
396+
* seem to recognize that. And Macau isn't listed in the table of
397+
* accepted abbreviations linked above. Fortunately, "ZHM" seems to be
398+
* accepted as an alias for "Chinese (Traditional)_Macau S.A.R..950". I'm
399+
* not sure where "ZHM" comes from, must be some legacy naming scheme. But
400+
* hey, it works.
401+
*
402+
* Note that unlike HKG and ARE, ZHM is an alias for the *whole* locale
403+
* name, not just the country part.
404+
*
405+
* Some versions of Windows spell it "Macau", others "Macao".
406+
*/
407+
{"Chinese (Traditional)_Macau S.A.R..950","ZHM" },
408+
{"Chinese_Macau S.A.R..950","ZHM" },
409+
{"Chinese (Traditional)_Macao S.A.R..950","ZHM" },
410+
{"Chinese_Macao S.A.R..950","ZHM" }
411+
};
412+
413+
char*
414+
pgwin32_setlocale(intcategory,constchar*locale)
415+
{
416+
char*result;
417+
char*alias;
418+
inti;
419+
420+
if (locale==NULL)
421+
returnsetlocale(category,locale);
422+
423+
/* Check if the locale name matches any of the problematic ones. */
424+
alias=NULL;
425+
for (i=0;i<lengthof(locale_map_list);i++)
426+
{
427+
constchar*needle=locale_map_list[i].locale_name_part;
428+
constchar*replacement=locale_map_list[i].replacement;
429+
char*match;
430+
431+
match=strstr(locale,needle);
432+
if (match!=NULL)
433+
{
434+
/* Found a match. Replace the matched string. */
435+
intmatchpos=match-locale;
436+
intreplacementlen=strlen(replacement);
437+
char*rest=match+strlen(needle);
438+
intrestlen=strlen(rest);
439+
440+
alias=malloc(matchpos+replacementlen+restlen+1);
441+
if (!alias)
442+
returnNULL;
443+
444+
memcpy(&alias[0],&locale[0],matchpos);
445+
memcpy(&alias[matchpos],replacement,replacementlen);
446+
memcpy(&alias[matchpos+replacementlen],rest,restlen+1);/* includes null terminator */
447+
448+
break;
449+
}
450+
}
451+
452+
/* Call the real setlocale() function */
453+
if (alias)
454+
{
455+
result=setlocale(category,alias);
456+
free(alias);
457+
}
458+
else
459+
result=setlocale(category,locale);
460+
461+
returnresult;
462+
}
463+
464+
#endif/* WIN32 */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp