Skip to content

Commit 95a777c

Browse files
committed
Fix encoding issue when lc_monetary or lc_numeric are different encoding
from lc_ctype, that could happen on Windows. We need to change lc_ctype together with lc_monetary or lc_numeric, and convert strings in lconv from lc_ctype encoding to the database encoding. The bug reported by Mikko, original patch by Hiroshi Inoue, with changes by Bruce and me.
1 parent a6dcd19 commit 95a777c

File tree

1 file changed

+72
-13
lines changed

1 file changed

+72
-13
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 72 additions & 13 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.53 2010/02/27 20:20:44 momjian Exp $
7+
* $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.54 2010/04/22 01:55:52 itagaki Exp $
88
*
99
*-----------------------------------------------------------------------
1010
*/
@@ -387,6 +387,28 @@ free_struct_lconv(struct lconv * s)
387387
}
388388

389389

390+
/*
391+
* Return a strdup'ed string converted from the specified encoding to the
392+
* database encoding.
393+
*/
394+
static char *
395+
db_encoding_strdup(int encoding, const char *str)
396+
{
397+
char *pstr;
398+
char *mstr;
399+
400+
/* convert the string to the database encoding */
401+
pstr = (char *) pg_do_encoding_conversion(
402+
(unsigned char *) str, strlen(str),
403+
encoding, GetDatabaseEncoding());
404+
mstr = strdup(pstr);
405+
if (pstr != str)
406+
pfree(pstr);
407+
408+
return mstr;
409+
}
410+
411+
390412
/*
391413
* Return the POSIX lconv struct (contains number/money formatting
392414
* information) with locale information for all categories.
@@ -398,6 +420,14 @@ PGLC_localeconv(void)
398420
struct lconv *extlconv;
399421
char *save_lc_monetary;
400422
char *save_lc_numeric;
423+
char *decimal_point;
424+
char *grouping;
425+
char *thousands_sep;
426+
int encoding;
427+
428+
#ifdef WIN32
429+
char *save_lc_ctype;
430+
#endif
401431

402432
/* Did we do it already? */
403433
if (CurrentLocaleConvValid)
@@ -413,28 +443,48 @@ PGLC_localeconv(void)
413443
if (save_lc_numeric)
414444
save_lc_numeric = pstrdup(save_lc_numeric);
415445

416-
setlocale(LC_MONETARY, locale_monetary);
446+
#ifdef WIN32
447+
/* set user's value of ctype locale */
448+
save_lc_ctype = setlocale(LC_CTYPE, NULL);
449+
if (save_lc_ctype)
450+
save_lc_ctype = pstrdup(save_lc_ctype);
451+
#endif
452+
453+
/* Get formatting information for numeric */
454+
#ifdef WIN32
455+
setlocale(LC_CTYPE, locale_numeric);
456+
#endif
417457
setlocale(LC_NUMERIC, locale_numeric);
458+
extlconv = localeconv();
459+
encoding = pg_get_encoding_from_locale(locale_numeric);
460+
461+
decimal_point = db_encoding_strdup(encoding, extlconv->decimal_point);
462+
thousands_sep = db_encoding_strdup(encoding, extlconv->thousands_sep);
463+
grouping = strdup(extlconv->grouping);
418464

419-
/* Get formatting information */
465+
/* Get formatting information for monetary */
466+
#ifdef WIN32
467+
setlocale(LC_CTYPE, locale_monetary);
468+
#endif
469+
setlocale(LC_MONETARY, locale_monetary);
420470
extlconv = localeconv();
471+
encoding = pg_get_encoding_from_locale(locale_monetary);
421472

422473
/*
423474
* Must copy all values since restoring internal settings may overwrite
424475
* localeconv()'s results.
425476
*/
426477
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);
478+
CurrentLocaleConv.decimal_point = decimal_point;
479+
CurrentLocaleConv.grouping = grouping;
480+
CurrentLocaleConv.thousands_sep = thousands_sep;
481+
CurrentLocaleConv.int_curr_symbol = db_encoding_strdup(encoding, extlconv->int_curr_symbol);
482+
CurrentLocaleConv.currency_symbol = db_encoding_strdup(encoding, extlconv->currency_symbol);
483+
CurrentLocaleConv.mon_decimal_point = db_encoding_strdup(encoding, extlconv->mon_decimal_point);
433484
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);
437-
CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;
485+
CurrentLocaleConv.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep);
486+
CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign);
487+
CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign);
438488

439489
/* Try to restore internal settings */
440490
if (save_lc_monetary)
@@ -449,6 +499,15 @@ PGLC_localeconv(void)
449499
pfree(save_lc_numeric);
450500
}
451501

502+
#ifdef WIN32
503+
/* try to restore internal ctype settings */
504+
if (save_lc_ctype)
505+
{
506+
setlocale(LC_CTYPE, save_lc_ctype);
507+
pfree(save_lc_ctype);
508+
}
509+
#endif
510+
452511
CurrentLocaleConvValid = true;
453512
return &CurrentLocaleConv;
454513
}

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