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.51 2010/01/02 16:57:54 momjian Exp $
7
+ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.52 2010/02/27 20: 16:17 momjian Exp $
8
8
*
9
9
*-----------------------------------------------------------------------
10
10
*/
@@ -386,6 +386,70 @@ free_struct_lconv(struct lconv * s)
386
386
free (s -> positive_sign );
387
387
}
388
388
389
+ #ifdef WIN32
390
+ static char * db_strdup (const char * item ,const char * str )
391
+ {
392
+ int db_encoding = GetDatabaseEncoding ();
393
+ size_t wchars ,ilen ,wclen ,dstlen ;
394
+ int utflen ,bytes_per_char ;
395
+ wchar_t * wbuf ;
396
+ char * dst ;
397
+
398
+ if (!str [0 ])
399
+ return strdup (str );
400
+ ilen = strlen (str )+ 1 ;
401
+ wclen = ilen * sizeof (wchar_t );
402
+ wbuf = (wchar_t * )palloc (wclen );
403
+
404
+ /* convert multi-byte string to a wide-character string */
405
+ wchars = mbstowcs (wbuf ,str ,ilen );
406
+ if (wchars == (size_t )-1 )
407
+ elog (ERROR ,
408
+ "could not convert string to wide characters: error %lu" ,GetLastError ());
409
+
410
+ /* allocate target string */
411
+ bytes_per_char = pg_encoding_max_length (PG_UTF8 );
412
+ if (pg_encoding_max_length (db_encoding )> bytes_per_char )
413
+ bytes_per_char = pg_encoding_max_length (db_encoding );
414
+ dstlen = wchars * bytes_per_char + 1 ;
415
+ if ((dst = malloc (dstlen ))== NULL )
416
+ elog (ERROR ,"could not allocate a destination buffer" );
417
+
418
+ /* Convert wide string to UTF8 */
419
+ utflen = WideCharToMultiByte (CP_UTF8 ,0 ,wbuf ,wchars ,dst ,dstlen ,NULL ,NULL );
420
+ if (utflen == 0 )
421
+ elog (ERROR ,
422
+ "could not convert string %04x to UTF-8: error %lu" ,wbuf [0 ],GetLastError ());
423
+ pfree (wbuf );
424
+
425
+ dst [utflen ]= '\0' ;
426
+ if (db_encoding != PG_UTF8 )
427
+ {
428
+ PG_TRY ();
429
+ {
430
+ char * convstr = pg_do_encoding_conversion (dst ,utflen ,PG_UTF8 ,db_encoding );
431
+ if (dst != convstr )
432
+ {
433
+ strlcpy (dst ,convstr ,dstlen );
434
+ pfree (convstr );
435
+ }
436
+ }
437
+ PG_CATCH ();
438
+ {
439
+ FlushErrorState ();
440
+ dst [0 ]= '\0' ;
441
+ }
442
+ PG_END_TRY ();
443
+ }
444
+
445
+ return dst ;
446
+ }
447
+ #else
448
+ static char * db_strdup (const char * item ,const char * str )
449
+ {
450
+ return strdup (str );
451
+ }
452
+ #endif /* WIN32 */
389
453
390
454
/*
391
455
* Return the POSIX lconv struct (contains number/money formatting
@@ -398,6 +462,9 @@ PGLC_localeconv(void)
398
462
struct lconv * extlconv ;
399
463
char * save_lc_monetary ;
400
464
char * save_lc_numeric ;
465
+ #ifdef WIN32
466
+ char * save_lc_ctype = NULL ;
467
+ #endif
401
468
402
469
/* Did we do it already? */
403
470
if (CurrentLocaleConvValid )
@@ -413,30 +480,83 @@ PGLC_localeconv(void)
413
480
if (save_lc_numeric )
414
481
save_lc_numeric = pstrdup (save_lc_numeric );
415
482
416
- setlocale (LC_MONETARY ,locale_monetary );
417
- setlocale (LC_NUMERIC ,locale_numeric );
483
+ #ifdef WIN32
484
+ /*
485
+ *WIN32 returns an inaccurately encoded symbol, e.g. Euro,
486
+ *when the LC_CTYPE does not match the numeric or monetary
487
+ *lc types, so we switch to matching LC_CTYPEs as we access them.
488
+ */
489
+
490
+ if ((save_lc_ctype = setlocale (LC_CTYPE ,NULL ))!= NULL )
491
+ {
492
+ /* Save for later restore */
493
+ save_lc_ctype = pstrdup (save_lc_ctype );
494
+
495
+ /* Set LC_CTYPE to match LC_MONETARY? */
496
+ if (pg_strcasecmp (save_lc_ctype ,locale_monetary )!= 0 )
497
+ setlocale (LC_CTYPE ,locale_monetary );
498
+ }
499
+ else
500
+ /* LC_CTYPE not set, unconditionally set it */
501
+ setlocale (LC_CTYPE ,locale_monetary );
418
502
419
- /* Get formatting information */
503
+ /*
504
+ *If LC_NUMERIC and LC_MONETARY match, we can set it now and
505
+ *avoid a second localeconv() call.
506
+ */
507
+ if (pg_strcasecmp (locale_numeric ,locale_monetary )== 0 )
508
+ #else
509
+ setlocale (LC_NUMERIC ,locale_numeric );
510
+ #endif
511
+
512
+ setlocale (LC_MONETARY ,locale_monetary );
513
+ /*
514
+ *Get formatting information for LC_MONETARY, and LC_NUMERIC if they
515
+ *are the same.
516
+ */
420
517
extlconv = localeconv ();
421
518
422
519
/*
423
- * Must copy all values since restoring internal settingsmay overwrite
520
+ * Must copy all values since restoring internal settingsmight overwrite
424
521
* localeconv()'s results.
425
522
*/
426
523
CurrentLocaleConv = * extlconv ;
427
- CurrentLocaleConv .currency_symbol = strdup (extlconv -> currency_symbol );
428
- CurrentLocaleConv .decimal_point = strdup (extlconv -> decimal_point );
429
- CurrentLocaleConv .grouping = strdup (extlconv -> grouping );
430
- CurrentLocaleConv .thousands_sep = strdup (extlconv -> thousands_sep );
431
- CurrentLocaleConv .int_curr_symbol = strdup (extlconv -> int_curr_symbol );
432
- CurrentLocaleConv .mon_decimal_point = strdup (extlconv -> mon_decimal_point );
524
+
525
+ /* The first argument of db_strdup() is only used on WIN32 */
526
+ CurrentLocaleConv .currency_symbol = db_strdup ("currency_symbol" ,extlconv -> currency_symbol );
527
+ CurrentLocaleConv .int_curr_symbol = db_strdup ("int_curr_symbol" ,extlconv -> int_curr_symbol );
528
+ CurrentLocaleConv .mon_decimal_point = db_strdup ("mon_decimal_point" ,extlconv -> mon_decimal_point );
433
529
CurrentLocaleConv .mon_grouping = strdup (extlconv -> mon_grouping );
434
- CurrentLocaleConv .mon_thousands_sep = strdup ( extlconv -> mon_thousands_sep );
435
- CurrentLocaleConv .negative_sign = strdup ( extlconv -> negative_sign );
436
- CurrentLocaleConv .positive_sign = strdup ( extlconv -> positive_sign );
530
+ CurrentLocaleConv .mon_thousands_sep = db_strdup ( "mon_thousands_sep" , extlconv -> mon_thousands_sep );
531
+ CurrentLocaleConv .negative_sign = db_strdup ( "negative_sign" , extlconv -> negative_sign );
532
+ CurrentLocaleConv .positive_sign = db_strdup ( "positive_sign" , extlconv -> positive_sign );
437
533
CurrentLocaleConv .n_sign_posn = extlconv -> n_sign_posn ;
438
534
439
- /* Try to restore internal settings */
535
+ #ifdef WIN32
536
+ /* Do we need to change LC_CTYPE to match LC_NUMERIC? */
537
+ if (pg_strcasecmp (locale_numeric ,locale_monetary )!= 0 )
538
+ {
539
+ setlocale (LC_CTYPE ,locale_numeric );
540
+ setlocale (LC_NUMERIC ,locale_numeric );
541
+ /* Get formatting information for LC_NUMERIC */
542
+ extlconv = localeconv ();
543
+ }
544
+ #endif
545
+
546
+ CurrentLocaleConv .decimal_point = db_strdup ("decimal_point" ,extlconv -> decimal_point );
547
+ CurrentLocaleConv .grouping = strdup (extlconv -> grouping );
548
+ CurrentLocaleConv .thousands_sep = db_strdup ("thousands_sep" ,extlconv -> thousands_sep );
549
+
550
+ /*
551
+ *Restore internal settings
552
+ */
553
+ #ifdef WIN32
554
+ if (save_lc_ctype )
555
+ {
556
+ setlocale (LC_CTYPE ,save_lc_ctype );
557
+ pfree (save_lc_ctype );
558
+ }
559
+ #endif
440
560
if (save_lc_monetary )
441
561
{
442
562
setlocale (LC_MONETARY ,save_lc_monetary );