*
* PostgreSQL locale utilities
*
- * Portions Copyright (c) 2002-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 2002-2010, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.48 2009/01/27 12:45:09 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.54 2010/04/22 01:55:52 itagaki Exp $
*
*-----------------------------------------------------------------------
*/
/*----------
* Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
- * are fixed by initdb, stored in pg_control, and cannot be changed.
- * Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
- * etc. are always in the same fixed locale.
+ * are fixed at CREATE DATABASE time, stored in pg_database, and cannot
+ * be changed. Thus, the effects of strcoll(), strxfrm(), isupper(),
+ * toupper(), etc. are always in the same fixed locale.
*
* LC_MESSAGES is settable at run time and will take effect
* immediately.
static char lc_time_envbuf[LC_ENV_BUFSIZE];
#if defined(WIN32) && defined(LC_MESSAGES)
-static char *IsoLocaleName(const char *); /* MSVC specific */
+static char *IsoLocaleName(const char *); /* MSVC specific */
#endif
result = IsoLocaleName(locale);
if (result == NULL)
result = (char *) locale;
-#endif /* WIN32 */
+#endif /* WIN32 */
break;
-#endif /* LC_MESSAGES */
+#endif /* LC_MESSAGES */
case LC_MONETARY:
envvar = "LC_MONETARY";
envbuf = lc_monetary_envbuf;
}
+/*
+ * Return a strdup'ed string converted from the specified encoding to the
+ * database encoding.
+ */
+static char *
+db_encoding_strdup(int encoding, const char *str)
+{
+ char *pstr;
+ char *mstr;
+
+ /* convert the string to the database encoding */
+ pstr = (char *) pg_do_encoding_conversion(
+ (unsigned char *) str, strlen(str),
+ encoding, GetDatabaseEncoding());
+ mstr = strdup(pstr);
+ if (pstr != str)
+ pfree(pstr);
+
+ return mstr;
+}
+
+
/*
* Return the POSIX lconv struct (contains number/money formatting
* information) with locale information for all categories.
struct lconv *extlconv;
char *save_lc_monetary;
char *save_lc_numeric;
+ char *decimal_point;
+ char *grouping;
+ char *thousands_sep;
+ int encoding;
+
+#ifdef WIN32
+ char *save_lc_ctype;
+#endif
/* Did we do it already? */
if (CurrentLocaleConvValid)
if (save_lc_numeric)
save_lc_numeric = pstrdup(save_lc_numeric);
- setlocale(LC_MONETARY, locale_monetary);
+#ifdef WIN32
+ /* set user's value of ctype locale */
+ save_lc_ctype = setlocale(LC_CTYPE, NULL);
+ if (save_lc_ctype)
+ save_lc_ctype = pstrdup(save_lc_ctype);
+#endif
+
+ /* Get formatting information for numeric */
+#ifdef WIN32
+ setlocale(LC_CTYPE, locale_numeric);
+#endif
setlocale(LC_NUMERIC, locale_numeric);
+ extlconv = localeconv();
+ encoding = pg_get_encoding_from_locale(locale_numeric);
+
+ decimal_point = db_encoding_strdup(encoding, extlconv->decimal_point);
+ thousands_sep = db_encoding_strdup(encoding, extlconv->thousands_sep);
+ grouping = strdup(extlconv->grouping);
- /* Get formatting information */
+ /* Get formatting information for monetary */
+#ifdef WIN32
+ setlocale(LC_CTYPE, locale_monetary);
+#endif
+ setlocale(LC_MONETARY, locale_monetary);
extlconv = localeconv();
+ encoding = pg_get_encoding_from_locale(locale_monetary);
/*
* Must copy all values since restoring internal settings may overwrite
* localeconv()'s results.
*/
CurrentLocaleConv = *extlconv;
- CurrentLocaleConv.currency_symbol = strdup(extlconv->currency_symbol);
- CurrentLocaleConv.decimal_point = strdup(extlconv->decimal_point);
- CurrentLocaleConv.grouping = strdup(extlconv->grouping);
- CurrentLocaleConv.thousands_sep = strdup(extlconv->thousands_sep);
- CurrentLocaleConv.int_curr_symbol = strdup(extlconv->int_curr_symbol);
- CurrentLocaleConv.mon_decimal_point = strdup(extlconv->mon_decimal_point);
+ CurrentLocaleConv.decimal_point = decimal_point;
+ CurrentLocaleConv.grouping = grouping;
+ CurrentLocaleConv.thousands_sep = thousands_sep;
+ CurrentLocaleConv.int_curr_symbol = db_encoding_strdup(encoding, extlconv->int_curr_symbol);
+ CurrentLocaleConv.currency_symbol = db_encoding_strdup(encoding, extlconv->currency_symbol);
+ CurrentLocaleConv.mon_decimal_point = db_encoding_strdup(encoding, extlconv->mon_decimal_point);
CurrentLocaleConv.mon_grouping = strdup(extlconv->mon_grouping);
- CurrentLocaleConv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
- CurrentLocaleConv.negative_sign = strdup(extlconv->negative_sign);
- CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
- CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;
+ CurrentLocaleConv.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep);
+ CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign);
+ CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign);
/* Try to restore internal settings */
if (save_lc_monetary)
pfree(save_lc_numeric);
}
+#ifdef WIN32
+ /* try to restore internal ctype settings */
+ if (save_lc_ctype)
+ {
+ setlocale(LC_CTYPE, save_lc_ctype);
+ pfree(save_lc_ctype);
+ }
+#endif
+
CurrentLocaleConvValid = true;
return &CurrentLocaleConv;
}
* pg_strftime(), which isn't locale-aware and does not need to be replaced.
*/
static size_t
-strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm *tm)
+strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm * tm)
{
- size_t len;
- wchar_t wbuf[MAX_L10N_DATA];
- int encoding;
+ size_t len;
+ wchar_t wbuf[MAX_L10N_DATA];
+ int encoding;
encoding = GetDatabaseEncoding();
len = wcsftime(wbuf, MAX_L10N_DATA, format, tm);
if (len == 0)
- /* strftime call failed - return 0 with the contents of dst unspecified */
+
+ /*
+ * strftime call failed - return 0 with the contents of dst
+ * unspecified
+ */
return 0;
len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen, NULL, NULL);
if (len == 0)
elog(ERROR,
- "could not convert string to UTF-8:error %lu", GetLastError());
+ "could not convert string to UTF-8:error %lu", GetLastError());
dst[len] = '\0';
if (encoding != PG_UTF8)
{
- char *convstr = pg_do_encoding_conversion(dst, len, PG_UTF8, encoding);
+ char *convstr = pg_do_encoding_conversion(dst, len, PG_UTF8, encoding);
+
if (dst != convstr)
{
strlcpy(dst, convstr, dstlen);
}
#define strftime(a,b,c,d) strftime_win32(a,b,L##c,d)
-
-#endif /* WIN32 */
+#endif /* WIN32 */
/*
void
cache_locale_time(void)
{
- char *save_lc_time;
+ char *save_lc_time;
time_t timenow;
- struct tm *timeinfo;
+ struct tm *timeinfo;
char buf[MAX_L10N_DATA];
char *ptr;
int i;
+
#ifdef WIN32
char *save_lc_ctype;
#endif
* contains the iso formatted locale name.
*/
static
-char *IsoLocaleName(const char *winlocname)
+char *
+IsoLocaleName(const char *winlocname)
{
-#if (_MSC_VER >= 1400) /* VC8.0 or later */
- static char iso_lc_messages[32];
+#if (_MSC_VER >= 1400) /* VC8.0 or later */
+ static char iso_lc_messages[32];
_locale_t loct = NULL;
if (pg_strcasecmp("c", winlocname) == 0 ||
loct = _create_locale(LC_CTYPE, winlocname);
if (loct != NULL)
{
- char isolang[32], isocrty[32];
- LCID lcid;
+ char isolang[32],
+ isocrty[32];
+ LCID lcid;
lcid = loct->locinfo->lc_handle[LC_CTYPE];
if (lcid == 0)
}
return NULL;
#else
- return NULL; /* Not supported on this version of msvc/mingw */
-#endif /* _MSC_VER >= 1400 */
+ return NULL; /* Not supported on this version of msvc/mingw */
+#endif /* _MSC_VER >= 1400 */
}
-#endif /* WIN32 && LC_MESSAGES */
+#endif /* WIN32 && LC_MESSAGES */