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

Appearance settings

Commit 95a777c

Browse filesBrowse 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
Copy full SHA for 95a777c

File tree

1 file changed

+72
-13
lines changed
Filter options

1 file changed

+72
-13
lines changed

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

Copy file name to clipboardExpand all lines: src/backend/utils/adt/pg_locale.c
+72-13Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.