1 /*-----------------------------------------------------------------------
3 * PostgreSQL locale utilities
5 * Portions Copyright (c) 2002-2009, PostgreSQL Global Development Group
9 *-----------------------------------------------------------------------
13 * Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
14 * are fixed at CREATE DATABASE time, stored in pg_database, and cannot
15 * be changed. Thus, the effects of strcoll(), strxfrm(), isupper(),
16 * toupper(), etc. are always in the same fixed locale.
18 * LC_MESSAGES is settable at run time and will take effect
21 * The other categories, LC_MONETARY, LC_NUMERIC, and LC_TIME are also
22 * settable at run-time. However, we don't actually set those locale
23 * categories permanently. This would have bizarre effects like no
24 * longer accepting standard floating-point literals in some locales.
25 * Instead, we only set the locales briefly when needed, cache the
26 * required information obtained from localeconv(), and set them back.
27 * The cached information is only used by the formatting functions
28 * (to_char, etc.) and the money type. For the user, this should all be
31 * !!! NOW HEAR THIS !!!
33 * We've been bitten repeatedly by this bug, so let's try to keep it in
34 * mind in future: on some platforms, the locale functions return pointers
35 * to static data that will be overwritten by any later locale function.
36 * Thus, for example, the obvious-looking sequence
37 * save = setlocale(category, NULL);
38 * if (!setlocale(category, value))
40 * setlocale(category, save);
41 * DOES NOT WORK RELIABLY: on some platforms the second setlocale() call
42 * will change the memory save is pointing at. To do this sort of thing
43 * safely, you *must* pstrdup what setlocale returns the first time.
53 #include "catalog/pg_control.h"
54 #include "mb/pg_wchar.h"
55 #include "utils/memutils.h"
56 #include "utils/pg_locale.h"
62 #define MAX_L10N_DATA 80
66 char *locale_messages
;
67 char *locale_monetary
;
71 /* lc_time localization cache */
72 char *localized_abbrev_days
[7];
73 char *localized_full_days
[7];
74 char *localized_abbrev_months
[12];
75 char *localized_full_months
[12];
77 /* indicates whether locale information cache is valid */
78 static bool CurrentLocaleConvValid
= false;
79 static bool CurrentLCTimeValid
= false;
81 /* Environment variable storage area */
83 #define LC_ENV_BUFSIZE (NAMEDATALEN + 20)
85 static char lc_collate_envbuf
[LC_ENV_BUFSIZE
];
86 static char lc_ctype_envbuf
[LC_ENV_BUFSIZE
];
89 static char lc_messages_envbuf
[LC_ENV_BUFSIZE
];
91 static char lc_monetary_envbuf
[LC_ENV_BUFSIZE
];
92 static char lc_numeric_envbuf
[LC_ENV_BUFSIZE
];
93 static char lc_time_envbuf
[LC_ENV_BUFSIZE
];
95 #if defined(WIN32) && defined(LC_MESSAGES)
96 static char *IsoLocaleName(const char *); /* MSVC specific */
103 * This is identical to the libc function setlocale(), with the addition
104 * that if the operation is successful, the corresponding LC_XXX environment
105 * variable is set to match. By setting the environment variable, we ensure
106 * that any subsequent use of setlocale(..., "") will preserve the settings
107 * made through this routine. Of course, LC_ALL must also be unset to fully
108 * ensure that, but that has to be done elsewhere after all the individual
109 * LC_XXX variables have been set correctly. (Thank you Perl for making this
113 pg_perm_setlocale(int category
, const char *locale
)
120 result
= setlocale(category
, locale
);
124 * On Windows, setlocale(LC_MESSAGES) does not work, so just assume that
125 * the given value is good and set it in the environment variables. We
126 * must ignore attempts to set to "", which means "keep using the old
127 * environment value".
130 if (category
== LC_MESSAGES
)
132 result
= (char *) locale
;
133 if (locale
== NULL
|| locale
[0] == '\0')
138 result
= setlocale(category
, locale
);
142 return result
; /* fall out immediately on failure */
147 envvar
= "LC_COLLATE";
148 envbuf
= lc_collate_envbuf
;
152 envbuf
= lc_ctype_envbuf
;
156 envvar
= "LC_MESSAGES";
157 envbuf
= lc_messages_envbuf
;
159 result
= IsoLocaleName(locale
);
161 result
= (char *) locale
;
164 #endif /* LC_MESSAGES */
166 envvar
= "LC_MONETARY";
167 envbuf
= lc_monetary_envbuf
;
170 envvar
= "LC_NUMERIC";
171 envbuf
= lc_numeric_envbuf
;
175 envbuf
= lc_time_envbuf
;
178 elog(FATAL
, "unrecognized LC category: %d", category
);
179 envvar
= NULL
; /* keep compiler quiet */
184 snprintf(envbuf
, LC_ENV_BUFSIZE
- 1, "%s=%s", envvar
, result
);
194 * Is the locale name valid for the locale category?
197 check_locale(int category
, const char *value
)
202 save
= setlocale(category
, NULL
);
204 return false; /* won't happen, we hope */
206 /* save may be pointing at a modifiable scratch variable, see above */
207 save
= pstrdup(save
);
209 /* set the locale with setlocale, to see if it accepts it. */
210 ret
= (setlocale(category
, value
) != NULL
);
212 setlocale(category
, save
); /* assume this won't fail */
218 /* GUC assign hooks */
221 * This is common code for several locale categories. This doesn't
222 * actually set the locale permanently, it only tests if the locale is
223 * valid. (See explanation at the top of this file.)
225 * Note: we accept value = "" as selecting the postmaster's environment
226 * value, whatever it was (so long as the environment setting is legal).
227 * This will have been locked down by an earlier call to pg_perm_setlocale.
230 locale_xxx_assign(int category
, const char *value
, bool doit
, GucSource source
)
232 if (!check_locale(category
, value
))
233 value
= NULL
; /* set failure return marker */
235 /* need to reload cache next time? */
236 if (doit
&& value
!= NULL
)
238 CurrentLocaleConvValid
= false;
239 CurrentLCTimeValid
= false;
247 locale_monetary_assign(const char *value
, bool doit
, GucSource source
)
249 return locale_xxx_assign(LC_MONETARY
, value
, doit
, source
);
253 locale_numeric_assign(const char *value
, bool doit
, GucSource source
)
255 return locale_xxx_assign(LC_NUMERIC
, value
, doit
, source
);
259 locale_time_assign(const char *value
, bool doit
, GucSource source
)
261 return locale_xxx_assign(LC_TIME
, value
, doit
, source
);
266 * We allow LC_MESSAGES to actually be set globally.
268 * Note: we normally disallow value = "" because it wouldn't have consistent
269 * semantics (it'd effectively just use the previous value). However, this
270 * is the value passed for PGC_S_DEFAULT, so don't complain in that case,
271 * not even if the attempted setting fails due to invalid environment value.
272 * The idea there is just to accept the environment setting *if possible*
273 * during startup, until we can read the proper value from postgresql.conf.
276 locale_messages_assign(const char *value
, bool doit
, GucSource source
)
278 if (*value
== '\0' && source
!= PGC_S_DEFAULT
)
282 * LC_MESSAGES category does not exist everywhere, but accept it anyway
284 * On Windows, we can't even check the value, so the non-doit case is a
290 if (!pg_perm_setlocale(LC_MESSAGES
, value
))
291 if (source
!= PGC_S_DEFAULT
)
296 value
= locale_xxx_assign(LC_MESSAGES
, value
, false, source
);
298 #endif /* LC_MESSAGES */
304 * We'd like to cache whether LC_COLLATE is C (or POSIX), so we can
305 * optimize a few code paths in various places.
308 lc_collate_is_c(void)
310 /* Cache result so we only have to compute it once */
311 static int result
= -1;
315 return (bool) result
;
316 localeptr
= setlocale(LC_COLLATE
, NULL
);
318 elog(ERROR
, "invalid LC_COLLATE setting");
320 if (strcmp(localeptr
, "C") == 0)
322 else if (strcmp(localeptr
, "POSIX") == 0)
326 return (bool) result
;
331 * We'd like to cache whether LC_CTYPE is C (or POSIX), so we can
332 * optimize a few code paths in various places.
337 /* Cache result so we only have to compute it once */
338 static int result
= -1;
342 return (bool) result
;
343 localeptr
= setlocale(LC_CTYPE
, NULL
);
345 elog(ERROR
, "invalid LC_CTYPE setting");
347 if (strcmp(localeptr
, "C") == 0)
349 else if (strcmp(localeptr
, "POSIX") == 0)
353 return (bool) result
;
358 * Frees the malloced content of a struct lconv. (But not the struct
362 free_struct_lconv(struct lconv
* s
)
367 if (s
->currency_symbol
)
368 free(s
->currency_symbol
);
369 if (s
->decimal_point
)
370 free(s
->decimal_point
);
373 if (s
->thousands_sep
)
374 free(s
->thousands_sep
);
375 if (s
->int_curr_symbol
)
376 free(s
->int_curr_symbol
);
377 if (s
->mon_decimal_point
)
378 free(s
->mon_decimal_point
);
380 free(s
->mon_grouping
);
381 if (s
->mon_thousands_sep
)
382 free(s
->mon_thousands_sep
);
383 if (s
->negative_sign
)
384 free(s
->negative_sign
);
385 if (s
->positive_sign
)
386 free(s
->positive_sign
);
391 * Return the POSIX lconv struct (contains number/money formatting
392 * information) with locale information for all categories.
395 PGLC_localeconv(void)
397 static struct lconv CurrentLocaleConv
;
398 struct lconv
*extlconv
;
399 char *save_lc_monetary
;
400 char *save_lc_numeric
;
402 /* Did we do it already? */
403 if (CurrentLocaleConvValid
)
404 return &CurrentLocaleConv
;
406 free_struct_lconv(&CurrentLocaleConv
);
408 /* Set user's values of monetary and numeric locales */
409 save_lc_monetary
= setlocale(LC_MONETARY
, NULL
);
410 if (save_lc_monetary
)
411 save_lc_monetary
= pstrdup(save_lc_monetary
);
412 save_lc_numeric
= setlocale(LC_NUMERIC
, NULL
);
414 save_lc_numeric
= pstrdup(save_lc_numeric
);
416 setlocale(LC_MONETARY
, locale_monetary
);
417 setlocale(LC_NUMERIC
, locale_numeric
);
419 /* Get formatting information */
420 extlconv
= localeconv();
423 * Must copy all values since restoring internal settings may overwrite
424 * localeconv()'s results.
426 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
);
433 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
;
439 /* Try to restore internal settings */
440 if (save_lc_monetary
)
442 setlocale(LC_MONETARY
, save_lc_monetary
);
443 pfree(save_lc_monetary
);
448 setlocale(LC_NUMERIC
, save_lc_numeric
);
449 pfree(save_lc_numeric
);
452 CurrentLocaleConvValid
= true;
453 return &CurrentLocaleConv
;
458 * On win32, strftime() returns the encoding in CP_ACP, which is likely
459 * different from SERVER_ENCODING. This is especially important in Japanese
460 * versions of Windows which will use SJIS encoding, which we don't support
461 * as a server encoding.
463 * Replace strftime() with a version that gets the string in UTF16 and then
464 * converts it to the appropriate encoding as necessary.
466 * Note that this only affects the calls to strftime() in this file, which are
467 * used to get the locale-aware strings. Other parts of the backend use
468 * pg_strftime(), which isn't locale-aware and does not need to be replaced.
471 strftime_win32(char *dst
, size_t dstlen
, const wchar_t *format
, const struct tm
* tm
)
474 wchar_t wbuf
[MAX_L10N_DATA
];
477 encoding
= GetDatabaseEncoding();
479 len
= wcsftime(wbuf
, MAX_L10N_DATA
, format
, tm
);
483 * strftime call failed - return 0 with the contents of dst
488 len
= WideCharToMultiByte(CP_UTF8
, 0, wbuf
, len
, dst
, dstlen
, NULL
, NULL
);
491 "could not convert string to UTF-8:error %lu", GetLastError());
494 if (encoding
!= PG_UTF8
)
496 char *convstr
= pg_do_encoding_conversion(dst
, len
, PG_UTF8
, encoding
);
500 strlcpy(dst
, convstr
, dstlen
);
508 #define strftime(a,b,c,d) strftime_win32(a,b,L##c,d)
513 * Update the lc_time localization cache variables if needed.
516 cache_locale_time(void)
521 char buf
[MAX_L10N_DATA
];
529 /* did we do this already? */
530 if (CurrentLCTimeValid
)
533 elog(DEBUG3
, "cache_locale_time() executed; locale: \"%s\"", locale_time
);
536 /* set user's value of ctype locale */
537 save_lc_ctype
= setlocale(LC_CTYPE
, NULL
);
539 save_lc_ctype
= pstrdup(save_lc_ctype
);
541 setlocale(LC_CTYPE
, locale_time
);
544 /* set user's value of time locale */
545 save_lc_time
= setlocale(LC_TIME
, NULL
);
547 save_lc_time
= pstrdup(save_lc_time
);
549 setlocale(LC_TIME
, locale_time
);
551 timenow
= time(NULL
);
552 timeinfo
= localtime(&timenow
);
555 for (i
= 0; i
< 7; i
++)
557 timeinfo
->tm_wday
= i
;
558 strftime(buf
, MAX_L10N_DATA
, "%a", timeinfo
);
559 ptr
= MemoryContextStrdup(TopMemoryContext
, buf
);
560 if (localized_abbrev_days
[i
])
561 pfree(localized_abbrev_days
[i
]);
562 localized_abbrev_days
[i
] = ptr
;
564 strftime(buf
, MAX_L10N_DATA
, "%A", timeinfo
);
565 ptr
= MemoryContextStrdup(TopMemoryContext
, buf
);
566 if (localized_full_days
[i
])
567 pfree(localized_full_days
[i
]);
568 localized_full_days
[i
] = ptr
;
571 /* localized months */
572 for (i
= 0; i
< 12; i
++)
574 timeinfo
->tm_mon
= i
;
575 timeinfo
->tm_mday
= 1; /* make sure we don't have invalid date */
576 strftime(buf
, MAX_L10N_DATA
, "%b", timeinfo
);
577 ptr
= MemoryContextStrdup(TopMemoryContext
, buf
);
578 if (localized_abbrev_months
[i
])
579 pfree(localized_abbrev_months
[i
]);
580 localized_abbrev_months
[i
] = ptr
;
582 strftime(buf
, MAX_L10N_DATA
, "%B", timeinfo
);
583 ptr
= MemoryContextStrdup(TopMemoryContext
, buf
);
584 if (localized_full_months
[i
])
585 pfree(localized_full_months
[i
]);
586 localized_full_months
[i
] = ptr
;
589 /* try to restore internal settings */
592 setlocale(LC_TIME
, save_lc_time
);
597 /* try to restore internal ctype settings */
600 setlocale(LC_CTYPE
, save_lc_ctype
);
601 pfree(save_lc_ctype
);
605 CurrentLCTimeValid
= true;
609 #if defined(WIN32) && defined(LC_MESSAGES)
611 * Convert Windows locale name to the ISO formatted one
614 * This function returns NULL if conversion is impossible,
615 * otherwise returns the pointer to a static area which
616 * contains the iso formatted locale name.
620 IsoLocaleName(const char *winlocname
)
622 #if (_MSC_VER >= 1400) /* VC8.0 or later */
623 static char iso_lc_messages
[32];
624 _locale_t loct
= NULL
;
626 if (pg_strcasecmp("c", winlocname
) == 0 ||
627 pg_strcasecmp("posix", winlocname
) == 0)
629 strcpy(iso_lc_messages
, "C");
630 return iso_lc_messages
;
633 loct
= _create_locale(LC_CTYPE
, winlocname
);
640 lcid
= loct
->locinfo
->lc_handle
[LC_CTYPE
];
642 lcid
= MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), SORT_DEFAULT
);
645 if (!GetLocaleInfoA(lcid
, LOCALE_SISO639LANGNAME
, isolang
, sizeof(isolang
)))
647 if (!GetLocaleInfoA(lcid
, LOCALE_SISO3166CTRYNAME
, isocrty
, sizeof(isocrty
)))
649 snprintf(iso_lc_messages
, sizeof(iso_lc_messages
) - 1, "%s_%s", isolang
, isocrty
);
650 return iso_lc_messages
;
654 return NULL
; /* Not supported on this version of msvc/mingw */
655 #endif /* _MSC_VER >= 1400 */
658 #endif /* WIN32 && LC_MESSAGES */