Skip to content

Commit 22da731

Browse files
committed
Add C comments for recent to_char('L') fix for Win32.
1 parent 90e04ba commit 22da731

File tree

1 file changed

+55
-23
lines changed

1 file changed

+55
-23
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Portions Copyright (c) 2002-2010, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.54 2010/04/22 01:55:52 itagaki Exp $
7+
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.55 2010/04/24 22:54:56 momjian Exp $
88
*
99
*-----------------------------------------------------------------------
1010
*/
@@ -41,6 +41,10 @@
4141
* DOES NOT WORK RELIABLY: on some platforms the second setlocale() call
4242
* will change the memory save is pointing at. To do this sort of thing
4343
* safely, you *must* pstrdup what setlocale returns the first time.
44+
*
45+
* FYI, The Open Group locale standard is defined here:
46+
*
47+
* http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html
4448
*----------
4549
*/
4650

@@ -424,7 +428,6 @@ PGLC_localeconv(void)
424428
char *grouping;
425429
char *thousands_sep;
426430
int encoding;
427-
428431
#ifdef WIN32
429432
char *save_lc_ctype;
430433
#endif
@@ -435,25 +438,48 @@ PGLC_localeconv(void)
435438

436439
free_struct_lconv(&CurrentLocaleConv);
437440

438-
/* Set user's values of monetary and numeric locales */
441+
/* Save user's values of monetary and numeric locales */
439442
save_lc_monetary = setlocale(LC_MONETARY, NULL);
440443
if (save_lc_monetary)
441444
save_lc_monetary = pstrdup(save_lc_monetary);
445+
442446
save_lc_numeric = setlocale(LC_NUMERIC, NULL);
443447
if (save_lc_numeric)
444448
save_lc_numeric = pstrdup(save_lc_numeric);
445449

446450
#ifdef WIN32
447-
/* set user's value of ctype locale */
451+
/*
452+
* Ideally, monetary and numeric local symbols could be returned in
453+
* any server encoding. Unfortunately, the WIN32 API does not allow
454+
* setlocale() to return values in a codepage/CTYPE that uses more
455+
* than two bytes per character, like UTF-8:
456+
*
457+
* http://msdn.microsoft.com/en-us/library/x99tb11d.aspx
458+
*
459+
* Evidently, LC_CTYPE allows us to control the encoding used
460+
* for strings returned by localeconv(). The Open Group
461+
* standard, mentioned at the top of this C file, doesn't
462+
* explicitly state this.
463+
*
464+
* Therefore, we set LC_CTYPE to match LC_NUMERIC or LC_MONETARY
465+
* (which cannot be UTF8), call localeconv(), and then convert from
466+
* the numeric/monitary LC_CTYPE to the server encoding. One
467+
* example use of this is for the Euro symbol.
468+
*
469+
* Perhaps someday we will use GetLocaleInfoW() which returns values
470+
* in UTF16 and convert from that.
471+
*/
472+
473+
/* save user's value of ctype locale */
448474
save_lc_ctype = setlocale(LC_CTYPE, NULL);
449475
if (save_lc_ctype)
450476
save_lc_ctype = pstrdup(save_lc_ctype);
451-
#endif
452477

453-
/* Get formatting information for numeric */
454-
#ifdef WIN32
478+
/* use numeric to set the ctype */
455479
setlocale(LC_CTYPE, locale_numeric);
456480
#endif
481+
482+
/* Get formatting information for numeric */
457483
setlocale(LC_NUMERIC, locale_numeric);
458484
extlconv = localeconv();
459485
encoding = pg_get_encoding_from_locale(locale_numeric);
@@ -462,10 +488,12 @@ PGLC_localeconv(void)
462488
thousands_sep = db_encoding_strdup(encoding, extlconv->thousands_sep);
463489
grouping = strdup(extlconv->grouping);
464490

465-
/* Get formatting information for monetary */
466491
#ifdef WIN32
492+
/* use monetary to set the ctype */
467493
setlocale(LC_CTYPE, locale_monetary);
468494
#endif
495+
496+
/* Get formatting information for monetary */
469497
setlocale(LC_MONETARY, locale_monetary);
470498
extlconv = localeconv();
471499
encoding = pg_get_encoding_from_locale(locale_monetary);
@@ -500,7 +528,7 @@ PGLC_localeconv(void)
500528
}
501529

502530
#ifdef WIN32
503-
/* try to restore internal ctype settings */
531+
/* Try to restore internal ctype settings */
504532
if (save_lc_ctype)
505533
{
506534
setlocale(LC_CTYPE, save_lc_ctype);
@@ -514,13 +542,15 @@ PGLC_localeconv(void)
514542

515543
#ifdef WIN32
516544
/*
517-
* On win32, strftime() returns the encoding in CP_ACP, which is likely
518-
* different from SERVER_ENCODING. This is especially important in Japanese
519-
* versions of Windows which will use SJIS encoding, which we don't support
520-
* as a server encoding.
545+
* On WIN32, strftime() returns the encoding in CP_ACP (the default
546+
* operating system codpage for that computer), which is likely different
547+
* from SERVER_ENCODING. This is especially important in Japanese versions
548+
* of Windows which will use SJIS encoding, which we don't support as a
549+
* server encoding.
521550
*
522-
* Replace strftime() with a version that gets the string in UTF16 and then
523-
* converts it to the appropriate encoding as necessary.
551+
* So, instead of using strftime(), use wcsftime() to return the value in
552+
* wide characters (internally UTF16) and then convert it to the appropriate
553+
* database encoding.
524554
*
525555
* Note that this only affects the calls to strftime() in this file, which are
526556
* used to get the locale-aware strings. Other parts of the backend use
@@ -537,7 +567,6 @@ strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm
537567

538568
len = wcsftime(wbuf, MAX_L10N_DATA, format, tm);
539569
if (len == 0)
540-
541570
/*
542571
* strftime call failed - return 0 with the contents of dst
543572
* unspecified
@@ -564,7 +593,9 @@ strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm
564593
return len;
565594
}
566595

596+
/* redefine strftime() */
567597
#define strftime(a,b,c,d) strftime_win32(a,b,L##c,d)
598+
568599
#endif /* WIN32 */
569600

570601

@@ -580,7 +611,6 @@ cache_locale_time(void)
580611
char buf[MAX_L10N_DATA];
581612
char *ptr;
582613
int i;
583-
584614
#ifdef WIN32
585615
char *save_lc_ctype;
586616
#endif
@@ -591,20 +621,22 @@ cache_locale_time(void)
591621

592622
elog(DEBUG3, "cache_locale_time() executed; locale: \"%s\"", locale_time);
593623

624+
/* save user's value of time locale */
625+
save_lc_time = setlocale(LC_TIME, NULL);
626+
if (save_lc_time)
627+
save_lc_time = pstrdup(save_lc_time);
628+
594629
#ifdef WIN32
595-
/* set user's value of ctype locale */
630+
/* See the WIN32 comment near the top of PGLC_localeconv() */
631+
/* save user's value of ctype locale */
596632
save_lc_ctype = setlocale(LC_CTYPE, NULL);
597633
if (save_lc_ctype)
598634
save_lc_ctype = pstrdup(save_lc_ctype);
599635

636+
/* use lc_time to set the ctype */
600637
setlocale(LC_CTYPE, locale_time);
601638
#endif
602639

603-
/* set user's value of time locale */
604-
save_lc_time = setlocale(LC_TIME, NULL);
605-
if (save_lc_time)
606-
save_lc_time = pstrdup(save_lc_time);
607-
608640
setlocale(LC_TIME, locale_time);
609641

610642
timenow = time(NULL);

0 commit comments

Comments
 (0)