4
4
*
5
5
* Portions Copyright (c) 2002-2010, PostgreSQL Global Development Group
6
6
*
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 $
8
8
*
9
9
*-----------------------------------------------------------------------
10
10
*/
41
41
* DOES NOT WORK RELIABLY: on some platforms the second setlocale() call
42
42
* will change the memory save is pointing at. To do this sort of thing
43
43
* 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
44
48
*----------
45
49
*/
46
50
@@ -424,7 +428,6 @@ PGLC_localeconv(void)
424
428
char * grouping ;
425
429
char * thousands_sep ;
426
430
int encoding ;
427
-
428
431
#ifdef WIN32
429
432
char * save_lc_ctype ;
430
433
#endif
@@ -435,25 +438,48 @@ PGLC_localeconv(void)
435
438
436
439
free_struct_lconv (& CurrentLocaleConv );
437
440
438
- /* Set user's values of monetary and numeric locales */
441
+ /* Save user's values of monetary and numeric locales */
439
442
save_lc_monetary = setlocale (LC_MONETARY , NULL );
440
443
if (save_lc_monetary )
441
444
save_lc_monetary = pstrdup (save_lc_monetary );
445
+
442
446
save_lc_numeric = setlocale (LC_NUMERIC , NULL );
443
447
if (save_lc_numeric )
444
448
save_lc_numeric = pstrdup (save_lc_numeric );
445
449
446
450
#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 */
448
474
save_lc_ctype = setlocale (LC_CTYPE , NULL );
449
475
if (save_lc_ctype )
450
476
save_lc_ctype = pstrdup (save_lc_ctype );
451
- #endif
452
477
453
- /* Get formatting information for numeric */
454
- #ifdef WIN32
478
+ /* use numeric to set the ctype */
455
479
setlocale (LC_CTYPE , locale_numeric );
456
480
#endif
481
+
482
+ /* Get formatting information for numeric */
457
483
setlocale (LC_NUMERIC , locale_numeric );
458
484
extlconv = localeconv ();
459
485
encoding = pg_get_encoding_from_locale (locale_numeric );
@@ -462,10 +488,12 @@ PGLC_localeconv(void)
462
488
thousands_sep = db_encoding_strdup (encoding , extlconv -> thousands_sep );
463
489
grouping = strdup (extlconv -> grouping );
464
490
465
- /* Get formatting information for monetary */
466
491
#ifdef WIN32
492
+ /* use monetary to set the ctype */
467
493
setlocale (LC_CTYPE , locale_monetary );
468
494
#endif
495
+
496
+ /* Get formatting information for monetary */
469
497
setlocale (LC_MONETARY , locale_monetary );
470
498
extlconv = localeconv ();
471
499
encoding = pg_get_encoding_from_locale (locale_monetary );
@@ -500,7 +528,7 @@ PGLC_localeconv(void)
500
528
}
501
529
502
530
#ifdef WIN32
503
- /* try to restore internal ctype settings */
531
+ /* Try to restore internal ctype settings */
504
532
if (save_lc_ctype )
505
533
{
506
534
setlocale (LC_CTYPE , save_lc_ctype );
@@ -514,13 +542,15 @@ PGLC_localeconv(void)
514
542
515
543
#ifdef WIN32
516
544
/*
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.
521
550
*
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.
524
554
*
525
555
* Note that this only affects the calls to strftime() in this file, which are
526
556
* 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
537
567
538
568
len = wcsftime (wbuf , MAX_L10N_DATA , format , tm );
539
569
if (len == 0 )
540
-
541
570
/*
542
571
* strftime call failed - return 0 with the contents of dst
543
572
* unspecified
@@ -564,7 +593,9 @@ strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm
564
593
return len ;
565
594
}
566
595
596
+ /* redefine strftime() */
567
597
#define strftime (a ,b ,c ,d ) strftime_win32(a,b,L##c,d)
598
+
568
599
#endif /* WIN32 */
569
600
570
601
@@ -580,7 +611,6 @@ cache_locale_time(void)
580
611
char buf [MAX_L10N_DATA ];
581
612
char * ptr ;
582
613
int i ;
583
-
584
614
#ifdef WIN32
585
615
char * save_lc_ctype ;
586
616
#endif
@@ -591,20 +621,22 @@ cache_locale_time(void)
591
621
592
622
elog (DEBUG3 , "cache_locale_time() executed; locale: \"%s\"" , locale_time );
593
623
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
+
594
629
#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 */
596
632
save_lc_ctype = setlocale (LC_CTYPE , NULL );
597
633
if (save_lc_ctype )
598
634
save_lc_ctype = pstrdup (save_lc_ctype );
599
635
636
+ /* use lc_time to set the ctype */
600
637
setlocale (LC_CTYPE , locale_time );
601
638
#endif
602
639
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
-
608
640
setlocale (LC_TIME , locale_time );
609
641
610
642
timenow = time (NULL );
0 commit comments