71 #include <unicode/ucnv.h>
72 #include <unicode/ustring.h>
76 #include <gnu/libc-version.h>
84 #define PGLOCALE_SUPPORT_ERROR(provider) \
85 elog(ERROR, "unsupported collprovider for %s: %c", __func__, provider)
91 #define TEXTBUFLEN 1024
93 #define MAX_L10N_DATA 80
137 #if defined(WIN32) && defined(LC_MESSAGES)
138 static char *IsoLocaleName(
const char *);
147 static UConverter *icu_converter = NULL;
149 static UCollator *pg_ucol_open(
const char *loc_str);
150 static void init_icu_converter(
void);
151 static size_t uchar_length(UConverter *converter,
152 const char *
str, int32_t
len);
153 static int32_t uchar_convert(UConverter *converter,
154 UChar *
dest, int32_t destlen,
155 const char *src, int32_t srclen);
156 static void icu_set_collation_attributes(UCollator *collator,
const char *loc,
164 #ifndef HAVE_MBSTOWCS_L
169 return _mbstowcs_l(
dest, src, n, loc);
172 locale_t save_locale = uselocale(loc);
174 result = mbstowcs(
dest, src, n);
175 uselocale(save_locale);
180 #ifndef HAVE_WCSTOMBS_L
185 return _wcstombs_l(
dest, src, n, loc);
188 locale_t save_locale = uselocale(loc);
190 result = wcstombs(
dest, src, n);
191 uselocale(save_locale);
228 if (category == LC_MESSAGES)
249 if (category == LC_CTYPE)
254 strlcpy(save_lc_ctype, result,
sizeof(save_lc_ctype));
255 result = save_lc_ctype;
267 envvar =
"LC_COLLATE";
274 envvar =
"LC_MESSAGES";
276 result = IsoLocaleName(
locale);
279 elog(
DEBUG3,
"IsoLocaleName() executed; locale: \"%s\"", result);
284 envvar =
"LC_MONETARY";
287 envvar =
"LC_NUMERIC";
293 elog(
FATAL,
"unrecognized LC category: %d", category);
297 if (
setenv(envvar, result, 1) != 0)
334 if (
res && canonname)
339 elog(
WARNING,
"failed to restore old locale \"%s\"", save);
342 return (
res != NULL);
419 #if defined(LC_MESSAGES) && !defined(WIN32)
446 free(s->decimal_point);
447 free(s->thousands_sep);
449 free(s->int_curr_symbol);
450 free(s->currency_symbol);
451 free(s->mon_decimal_point);
452 free(s->mon_thousands_sep);
453 free(s->mon_grouping);
454 free(s->positive_sign);
455 free(s->negative_sign);
465 if (s->decimal_point == NULL)
467 if (s->thousands_sep == NULL)
469 if (s->grouping == NULL)
471 if (s->int_curr_symbol == NULL)
473 if (s->currency_symbol == NULL)
475 if (s->mon_decimal_point == NULL)
477 if (s->mon_thousands_sep == NULL)
479 if (s->mon_grouping == NULL)
481 if (s->positive_sign == NULL)
483 if (s->negative_sign == NULL)
508 (
errcode(ERRCODE_OUT_OF_MEMORY),
509 errmsg(
"out of memory")));
526 static struct lconv CurrentLocaleConv;
527 static bool CurrentLocaleConvAllocated =
false;
528 struct lconv *extlconv;
529 struct lconv worklconv;
530 char *save_lc_monetary;
531 char *save_lc_numeric;
538 return &CurrentLocaleConv;
541 if (CurrentLocaleConvAllocated)
544 CurrentLocaleConvAllocated =
false;
559 memset(&worklconv, 0,
sizeof(worklconv));
562 save_lc_monetary =
setlocale(LC_MONETARY, NULL);
563 if (!save_lc_monetary)
565 save_lc_monetary =
pstrdup(save_lc_monetary);
567 save_lc_numeric =
setlocale(LC_NUMERIC, NULL);
568 if (!save_lc_numeric)
570 save_lc_numeric =
pstrdup(save_lc_numeric);
589 save_lc_ctype =
setlocale(LC_CTYPE, NULL);
592 save_lc_ctype =
pstrdup(save_lc_ctype);
602 extlconv = localeconv();
605 worklconv.decimal_point = strdup(extlconv->decimal_point);
606 worklconv.thousands_sep = strdup(extlconv->thousands_sep);
607 worklconv.grouping = strdup(extlconv->grouping);
616 extlconv = localeconv();
619 worklconv.int_curr_symbol = strdup(extlconv->int_curr_symbol);
620 worklconv.currency_symbol = strdup(extlconv->currency_symbol);
621 worklconv.mon_decimal_point = strdup(extlconv->mon_decimal_point);
622 worklconv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
623 worklconv.mon_grouping = strdup(extlconv->mon_grouping);
624 worklconv.positive_sign = strdup(extlconv->positive_sign);
625 worklconv.negative_sign = strdup(extlconv->negative_sign);
627 worklconv.int_frac_digits = extlconv->int_frac_digits;
628 worklconv.frac_digits = extlconv->frac_digits;
629 worklconv.p_cs_precedes = extlconv->p_cs_precedes;
630 worklconv.p_sep_by_space = extlconv->p_sep_by_space;
631 worklconv.n_cs_precedes = extlconv->n_cs_precedes;
632 worklconv.n_sep_by_space = extlconv->n_sep_by_space;
633 worklconv.p_sign_posn = extlconv->p_sign_posn;
634 worklconv.n_sign_posn = extlconv->n_sign_posn;
646 elog(
FATAL,
"failed to restore LC_CTYPE to \"%s\"", save_lc_ctype);
648 if (!
setlocale(LC_MONETARY, save_lc_monetary))
649 elog(
FATAL,
"failed to restore LC_MONETARY to \"%s\"", save_lc_monetary);
650 if (!
setlocale(LC_NUMERIC, save_lc_numeric))
651 elog(
FATAL,
"failed to restore LC_NUMERIC to \"%s\"", save_lc_numeric);
663 pfree(save_lc_monetary);
664 pfree(save_lc_numeric);
666 pfree(save_lc_ctype);
672 (
errcode(ERRCODE_OUT_OF_MEMORY),
673 errmsg(
"out of memory")));
712 CurrentLocaleConv = worklconv;
713 CurrentLocaleConvAllocated =
true;
715 return &CurrentLocaleConv;
735 strftime_win32(
char *dst,
size_t dstlen,
746 len = MultiByteToWideChar(CP_UTF8, 0,
format, -1,
749 elog(
ERROR,
"could not convert format string from UTF-8: error code %lu",
762 len = WideCharToMultiByte(CP_UTF8, 0, wbuf,
len, dst, dstlen - 1,
765 elog(
ERROR,
"could not convert string to UTF-8: error code %lu",
774 #define strftime(a,b,c,d) strftime_win32(a,b,c,d)
812 bool strftimefail =
false;
837 save_lc_time =
pstrdup(save_lc_time);
849 save_lc_ctype =
setlocale(LC_CTYPE, NULL);
852 save_lc_ctype =
pstrdup(save_lc_ctype);
861 timenow = time(NULL);
862 timeinfo = localtime(&timenow);
878 for (
i = 0;
i < 7;
i++)
880 timeinfo->tm_wday =
i;
890 for (
i = 0;
i < 12;
i++)
892 timeinfo->tm_mon =
i;
893 timeinfo->tm_mday = 1;
908 elog(
FATAL,
"failed to restore LC_CTYPE to \"%s\"", save_lc_ctype);
911 elog(
FATAL,
"failed to restore LC_TIME to \"%s\"", save_lc_time);
923 pfree(save_lc_ctype);
950 for (
i = 0;
i < 7;
i++)
961 for (
i = 0;
i < 12;
i++)
975 #if defined(WIN32) && defined(LC_MESSAGES)
1022 #if defined(_MSC_VER)
1036 static BOOL CALLBACK
1037 search_locale_enum(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
1039 wchar_t test_locale[LOCALE_NAME_MAX_LENGTH];
1044 argv = (
wchar_t **) lparam;
1045 *argv[2] = (wchar_t) 0;
1047 memset(test_locale, 0,
sizeof(test_locale));
1050 if (GetLocaleInfoEx(pStr, LOCALE_SENGLISHLANGUAGENAME,
1051 test_locale, LOCALE_NAME_MAX_LENGTH))
1058 if (wcsrchr(pStr,
'-') == NULL || wcsrchr(argv[0],
'_') == NULL)
1060 if (_wcsicmp(argv[0], test_locale) == 0)
1062 wcscpy(argv[1], pStr);
1063 *argv[2] = (wchar_t) 1;
1077 wcscat(test_locale, L
"_");
1078 len = wcslen(test_locale);
1079 if (GetLocaleInfoEx(pStr, LOCALE_SENGLISHCOUNTRYNAME,
1081 LOCALE_NAME_MAX_LENGTH -
len))
1083 if (_wcsicmp(argv[0], test_locale) == 0)
1085 wcscpy(argv[1], pStr);
1086 *argv[2] = (wchar_t) 1;
1103 get_iso_localename(
const char *winlocname)
1105 wchar_t wc_locale_name[LOCALE_NAME_MAX_LENGTH];
1106 wchar_t buffer[LOCALE_NAME_MAX_LENGTH];
1107 static char iso_lc_messages[LOCALE_NAME_MAX_LENGTH];
1119 period = strchr(winlocname,
'.');
1125 memset(wc_locale_name, 0,
sizeof(wc_locale_name));
1126 memset(buffer, 0,
sizeof(buffer));
1127 MultiByteToWideChar(CP_ACP, 0, winlocname,
len, wc_locale_name,
1128 LOCALE_NAME_MAX_LENGTH);
1134 ret_val = GetLocaleInfoEx(wc_locale_name, LOCALE_SNAME, (LPWSTR) &buffer,
1135 LOCALE_NAME_MAX_LENGTH);
1144 argv[0] = wc_locale_name;
1146 argv[2] = (
wchar_t *) &ret_val;
1147 EnumSystemLocalesEx(search_locale_enum, LOCALE_WINDOWS, (LPARAM) argv,
1157 rc =
wchar2char(iso_lc_messages, buffer,
sizeof(iso_lc_messages), NULL);
1158 if (rc == -1 || rc ==
sizeof(iso_lc_messages))
1168 hyphen = strchr(iso_lc_messages,
'-');
1171 return iso_lc_messages;
1178 IsoLocaleName(
const char *winlocname)
1180 static char iso_lc_messages[LOCALE_NAME_MAX_LENGTH];
1185 strcpy(iso_lc_messages,
"C");
1186 return iso_lc_messages;
1189 return get_iso_localename(winlocname);
1195 IsoLocaleName(
const char *winlocname)
1236 Assert(collation != DEFAULT_COLLATION_OID);
1243 ctl.keysize =
sizeof(
Oid);
1268 elog(
ERROR,
"cache lookup failed for collation %u", collation);
1271 if (collform->collprovider == COLLPROVIDER_BUILTIN)
1274 const char *colllocale;
1280 cache_entry->
ctype_is_c = (strcmp(colllocale,
"C") == 0);
1282 else if (collform->collprovider == COLLPROVIDER_LIBC)
1285 const char *collcollate;
1286 const char *collctype;
1293 cache_entry->
collate_is_c = ((strcmp(collcollate,
"C") == 0) ||
1294 (strcmp(collcollate,
"POSIX") == 0));
1295 cache_entry->
ctype_is_c = ((strcmp(collctype,
"C") == 0) ||
1296 (strcmp(collctype,
"POSIX") == 0));
1330 if (collation == DEFAULT_COLLATION_OID)
1332 static int result = -1;
1333 const char *localeptr;
1336 return (
bool) result;
1341 return (
bool) result;
1346 return (
bool) result;
1352 elog(
ERROR,
"invalid LC_CTYPE setting");
1355 elog(
ERROR,
"unexpected collation provider '%c'",
1358 if (strcmp(localeptr,
"C") == 0)
1360 else if (strcmp(localeptr,
"POSIX") == 0)
1364 return (
bool) result;
1370 if (collation == C_COLLATION_OID ||
1371 collation == POSIX_COLLATION_OID)
1397 if (collation == DEFAULT_COLLATION_OID)
1399 static int result = -1;
1400 const char *localeptr;
1403 return (
bool) result;
1412 return (
bool) result;
1418 elog(
ERROR,
"invalid LC_CTYPE setting");
1421 elog(
ERROR,
"unexpected collation provider '%c'",
1424 if (strcmp(localeptr,
"C") == 0)
1426 else if (strcmp(localeptr,
"POSIX") == 0)
1430 return (
bool) result;
1436 if (collation == C_COLLATION_OID ||
1437 collation == POSIX_COLLATION_OID)
1450 const char *icurules,
1454 UCollator *collator;
1456 collator = pg_ucol_open(iculocstr);
1464 const UChar *default_rules;
1470 default_rules = ucol_getRules(collator, &length);
1471 icu_to_uchar(&my_rules, icurules, strlen(icurules));
1473 agg_rules =
palloc_array(UChar, u_strlen(default_rules) + u_strlen(my_rules) + 1);
1474 u_strcpy(agg_rules, default_rules);
1475 u_strcat(agg_rules, my_rules);
1477 ucol_close(collator);
1479 status = U_ZERO_ERROR;
1480 collator = ucol_openRules(agg_rules, u_strlen(agg_rules),
1481 UCOL_DEFAULT, UCOL_DEFAULT_STRENGTH, NULL, &status);
1482 if (U_FAILURE(status))
1484 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1485 errmsg(
"could not open collator for locale \"%s\" with rules \"%s\": %s",
1486 iculocstr, icurules, u_errorName(status))));
1491 resultp->
info.icu.ucol = collator;
1495 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1496 errmsg(
"ICU is not supported in this build")));
1523 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1524 errmsg(
"could not create locale \"%s\": %m",
1526 (save_errno == ENOENT ?
1527 errdetail(
"The operating system could not find any locale data for the locale name \"%s\".",
1538 return locale->deterministic;
1559 if (
collid == DEFAULT_COLLATION_OID)
1569 if (cache_entry->
locale == 0)
1585 memset(&result, 0,
sizeof(result));
1586 result.
provider = collform->collprovider;
1589 if (collform->collprovider == COLLPROVIDER_BUILTIN)
1601 else if (collform->collprovider == COLLPROVIDER_LIBC)
1603 const char *collcollate;
1612 if (strcmp(collcollate, collctype) == 0)
1617 loc = newlocale(LC_COLLATE_MASK | LC_CTYPE_MASK, collcollate,
1620 loc = _create_locale(LC_ALL, collcollate);
1632 loc1 = newlocale(LC_COLLATE_MASK, collcollate, NULL);
1636 loc = newlocale(LC_CTYPE_MASK, collctype, loc1);
1647 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1648 errmsg(
"collations with different collate and ctype values are not supported on this platform")));
1654 else if (collform->collprovider == COLLPROVIDER_ICU)
1656 const char *iculocstr;
1657 const char *icurules;
1662 datum =
SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collicurules, &isnull);
1675 char *actual_versionstr;
1676 char *collversionstr;
1680 if (collform->collprovider == COLLPROVIDER_LIBC)
1687 if (!actual_versionstr)
1695 (
errmsg(
"collation \"%s\" has no actual version, but a version was recorded",
1696 NameStr(collform->collname))));
1699 if (strcmp(actual_versionstr, collversionstr) != 0)
1701 (
errmsg(
"collation \"%s\" has version mismatch",
1703 errdetail(
"The collation in the database was created using version %s, "
1704 "but the operating system provides version %s.",
1705 collversionstr, actual_versionstr),
1706 errhint(
"Rebuild all objects affected by this collation and run "
1707 "ALTER COLLATION %s REFRESH VERSION, "
1708 "or build PostgreSQL with the right library version.",
1710 NameStr(collform->collname)))));
1719 cache_entry->
locale = resultp;
1722 return cache_entry->
locale;
1732 char *collversion = NULL;
1741 if (collprovider == COLLPROVIDER_BUILTIN)
1743 if (strcmp(collcollate,
"C") == 0)
1745 else if (strcmp(collcollate,
"C.UTF-8") == 0)
1749 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
1750 errmsg(
"invalid locale name \"%s\" for builtin provider",
1755 if (collprovider == COLLPROVIDER_ICU)
1757 UCollator *collator;
1758 UVersionInfo versioninfo;
1759 char buf[U_MAX_VERSION_STRING_LENGTH];
1761 collator = pg_ucol_open(collcollate);
1763 ucol_getVersion(collator, versioninfo);
1764 ucol_close(collator);
1766 u_versionToString(versioninfo,
buf);
1771 if (collprovider == COLLPROVIDER_LIBC &&
1776 #if defined(__GLIBC__)
1778 collversion =
pstrdup(gnu_get_libc_version());
1779 #elif defined(LC_VERSION_MASK)
1783 loc = newlocale(LC_COLLATE, collcollate, NULL);
1787 pstrdup(querylocale(LC_COLLATE_MASK | LC_VERSION_MASK, loc));
1792 (
errmsg(
"could not load locale \"%s\"", collcollate)));
1793 #elif defined(WIN32)
1799 NLSVERSIONINFOEX version = {
sizeof(NLSVERSIONINFOEX)};
1800 WCHAR wide_collcollate[LOCALE_NAME_MAX_LENGTH];
1802 MultiByteToWideChar(CP_ACP, 0, collcollate, -1, wide_collcollate,
1803 LOCALE_NAME_MAX_LENGTH);
1804 if (!GetNLSVersionEx(COMPARE_STRING, wide_collcollate, &version))
1813 if (GetLastError() == ERROR_INVALID_PARAMETER)
1817 (
errmsg(
"could not get collation version for locale \"%s\": error code %lu",
1821 collversion =
psprintf(
"%lu.%lu,%lu.%lu",
1822 (version.dwNLSVersion >> 8) & 0xFFFF,
1823 version.dwNLSVersion & 0xFF,
1824 (version.dwDefinedVersion >> 8) & 0xFFFF,
1825 version.dwDefinedVersion & 0xFF);
1840 pg_strncoll_libc_win32_utf8(
const char *arg1,
size_t len1,
const char *arg2,
1847 int a1len = len1 * 2 + 2;
1848 int a2len = len2 * 2 + 2;
1869 r = MultiByteToWideChar(CP_UTF8, 0, arg1, len1,
1870 (LPWSTR) a1p, a1len / 2);
1873 (
errmsg(
"could not convert string to UTF-16: error code %lu",
1876 ((LPWSTR) a1p)[r] = 0;
1882 r = MultiByteToWideChar(CP_UTF8, 0, arg2, len2,
1883 (LPWSTR) a2p, a2len / 2);
1886 (
errmsg(
"could not convert string to UTF-16: error code %lu",
1889 ((LPWSTR) a2p)[r] = 0;
1895 result = wcscoll((LPWSTR) a1p, (LPWSTR) a2p);
1896 if (result == 2147483647)
1898 (
errmsg(
"could not compare Unicode strings: %m")));
1925 size_t len1 = strlen(arg1);
1926 size_t len2 = strlen(arg2);
1928 result = pg_strncoll_libc_win32_utf8(arg1, len1, arg2, len2,
locale);
1935 result = strcoll(arg1, arg2);
1951 size_t bufsize1 = len1 + 1;
1952 size_t bufsize2 = len2 + 1;
1962 return pg_strncoll_libc_win32_utf8(arg1, len1, arg2, len2,
locale);
1969 arg2n =
buf + bufsize1;
1972 memcpy(arg1n, arg1, len1);
1974 memcpy(arg2n, arg2, len2);
1998 pg_strncoll_icu_no_utf8(
const char *arg1, int32_t len1,
2012 #ifdef HAVE_UCOL_STRCOLLUTF8
2016 init_icu_converter();
2018 ulen1 = uchar_length(icu_converter, arg1, len1);
2019 ulen2 = uchar_length(icu_converter, arg2, len2);
2021 bufsize1 = (ulen1 + 1) *
sizeof(UChar);
2022 bufsize2 = (ulen2 + 1) *
sizeof(UChar);
2027 uchar1 = (UChar *)
buf;
2028 uchar2 = (UChar *) (
buf + bufsize1);
2030 ulen1 = uchar_convert(icu_converter, uchar1, ulen1 + 1, arg1, len1);
2031 ulen2 = uchar_convert(icu_converter, uchar2, ulen2 + 1, arg2, len2);
2033 result = ucol_strcoll(
locale->info.icu.ucol,
2053 pg_strncoll_icu(
const char *arg1, int32_t len1,
const char *arg2, int32_t len2,
2060 #ifdef HAVE_UCOL_STRCOLLUTF8
2065 status = U_ZERO_ERROR;
2066 result = ucol_strcollUTF8(
locale->info.icu.ucol,
2070 if (U_FAILURE(status))
2072 (
errmsg(
"collation failed: %s", u_errorName(status))));
2077 result = pg_strncoll_icu_no_utf8(arg1, len1, arg2, len2,
locale);
2106 else if (
locale->provider == COLLPROVIDER_ICU)
2107 result = pg_strncoll_icu(arg1, -1, arg2, -1,
locale);
2134 pg_strncoll(
const char *arg1,
size_t len1,
const char *arg2,
size_t len2,
2142 else if (
locale->provider == COLLPROVIDER_ICU)
2143 result = pg_strncoll_icu(arg1, len1, arg2, len2,
locale);
2159 #ifdef TRUST_STRXFRM
2163 return strxfrm(
dest, src, destsize);
2186 memcpy(
buf, src, srclen);
2195 Assert(result >= destsize ||
dest[result] ==
'\0');
2204 pg_strnxfrm_icu(
char *
dest,
const char *src, int32_t srclen, int32_t destsize,
2216 init_icu_converter();
2218 ulen = uchar_length(icu_converter, src, srclen);
2220 uchar_bsize = (ulen + 1) *
sizeof(UChar);
2225 uchar = (UChar *)
buf;
2227 ulen = uchar_convert(icu_converter, uchar, ulen + 1, src, srclen);
2229 result_bsize = ucol_getSortKey(
locale->info.icu.ucol,
2231 (uint8_t *)
dest, destsize);
2237 Assert(result_bsize > 0);
2244 Assert(result_bsize >= destsize ||
dest[result_bsize] ==
'\0');
2246 return result_bsize;
2251 pg_strnxfrm_prefix_icu_no_utf8(
char *
dest,
const char *src, int32_t srclen,
2260 UChar *uchar = NULL;
2267 init_icu_converter();
2269 ulen = uchar_length(icu_converter, src, srclen);
2271 uchar_bsize = (ulen + 1) *
sizeof(UChar);
2276 uchar = (UChar *)
buf;
2278 ulen = uchar_convert(icu_converter, uchar, ulen + 1, src, srclen);
2280 uiter_setString(&iter, uchar, ulen);
2282 status = U_ZERO_ERROR;
2283 result_bsize = ucol_nextSortKeyPart(
locale->info.icu.ucol,
2289 if (U_FAILURE(status))
2291 (
errmsg(
"sort key generation failed: %s",
2292 u_errorName(status))));
2294 return result_bsize;
2299 pg_strnxfrm_prefix_icu(
char *
dest,
const char *src, int32_t srclen,
2312 uiter_setUTF8(&iter, src, srclen);
2314 status = U_ZERO_ERROR;
2315 result = ucol_nextSortKeyPart(
locale->info.icu.ucol,
2321 if (U_FAILURE(status))
2323 (
errmsg(
"sort key generation failed: %s",
2324 u_errorName(status))));
2327 result = pg_strnxfrm_prefix_icu_no_utf8(
dest, src, srclen, destsize,
2353 #ifdef TRUST_STRXFRM
2358 else if (
locale->provider == COLLPROVIDER_ICU)
2389 else if (
locale->provider == COLLPROVIDER_ICU)
2390 result = pg_strnxfrm_icu(
dest, src, -1, destsize,
locale);
2426 else if (
locale->provider == COLLPROVIDER_ICU)
2427 result = pg_strnxfrm_icu(
dest, src, srclen, destsize,
locale);
2445 else if (
locale->provider == COLLPROVIDER_ICU)
2476 else if (
locale->provider == COLLPROVIDER_ICU)
2477 result = pg_strnxfrm_prefix_icu(
dest, src, -1, destsize,
locale);
2511 else if (
locale->provider == COLLPROVIDER_ICU)
2512 result = pg_strnxfrm_prefix_icu(
dest, src, -1, destsize,
locale);
2527 if (strcmp(
locale,
"C") == 0)
2529 if (strcmp(
locale,
"C.UTF-8") == 0)
2533 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
2534 errmsg(
"invalid locale name \"%s\" for builtin provider",
2548 const char *canonical_name = NULL;
2549 int required_encoding;
2551 if (strcmp(
locale,
"C") == 0)
2552 canonical_name =
"C";
2553 else if (strcmp(
locale,
"C.UTF-8") == 0 || strcmp(
locale,
"C.UTF8") == 0)
2554 canonical_name =
"C.UTF-8";
2556 if (!canonical_name)
2558 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
2559 errmsg(
"invalid locale name \"%s\" for builtin provider",
2563 if (required_encoding >= 0 &&
encoding != required_encoding)
2565 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
2566 errmsg(
"encoding \"%s\" does not match locale \"%s\"",
2569 return canonical_name;
2580 pg_ucol_open(
const char *loc_str)
2582 UCollator *collator;
2584 const char *orig_str = loc_str;
2585 char *fixed_str = NULL;
2596 if (loc_str == NULL)
2597 elog(
ERROR,
"opening default collator is not supported");
2604 if (U_ICU_VERSION_MAJOR_NUM < 55)
2606 char lang[ULOC_LANG_CAPACITY];
2608 status = U_ZERO_ERROR;
2609 uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
2610 if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
2613 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2614 errmsg(
"could not get language from locale \"%s\": %s",
2615 loc_str, u_errorName(status))));
2618 if (strcmp(lang,
"und") == 0)
2620 const char *remainder = loc_str + strlen(
"und");
2622 fixed_str =
palloc(strlen(
"root") + strlen(remainder) + 1);
2623 strcpy(fixed_str,
"root");
2624 strcat(fixed_str, remainder);
2626 loc_str = fixed_str;
2630 status = U_ZERO_ERROR;
2631 collator = ucol_open(loc_str, &status);
2632 if (U_FAILURE(status))
2635 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2636 errmsg(
"could not open collator for locale \"%s\": %s",
2637 orig_str, u_errorName(status))));
2639 if (U_ICU_VERSION_MAJOR_NUM < 54)
2641 status = U_ZERO_ERROR;
2642 icu_set_collation_attributes(collator, loc_str, &status);
2648 if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
2650 ucol_close(collator);
2652 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2653 errmsg(
"could not open collator for locale \"%s\": %s",
2654 orig_str, u_errorName(status))));
2658 if (fixed_str != NULL)
2665 init_icu_converter(
void)
2667 const char *icu_encoding_name;
2675 if (!icu_encoding_name)
2677 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2678 errmsg(
"encoding \"%s\" not supported by ICU",
2681 status = U_ZERO_ERROR;
2682 conv = ucnv_open(icu_encoding_name, &status);
2683 if (U_FAILURE(status))
2685 (
errmsg(
"could not open ICU converter for encoding \"%s\": %s",
2686 icu_encoding_name, u_errorName(status))));
2688 icu_converter = conv;
2695 uchar_length(UConverter *converter,
const char *
str, int32_t
len)
2697 UErrorCode status = U_ZERO_ERROR;
2700 ulen = ucnv_toUChars(converter, NULL, 0,
str,
len, &status);
2701 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
2703 (
errmsg(
"%s failed: %s",
"ucnv_toUChars", u_errorName(status))));
2712 uchar_convert(UConverter *converter, UChar *
dest, int32_t destlen,
2713 const char *src, int32_t srclen)
2715 UErrorCode status = U_ZERO_ERROR;
2718 status = U_ZERO_ERROR;
2719 ulen = ucnv_toUChars(converter,
dest, destlen, src, srclen, &status);
2720 if (U_FAILURE(status))
2722 (
errmsg(
"%s failed: %s",
"ucnv_toUChars", u_errorName(status))));
2739 icu_to_uchar(UChar **buff_uchar,
const char *buff,
size_t nbytes)
2743 init_icu_converter();
2745 len_uchar = uchar_length(icu_converter, buff, nbytes);
2747 *buff_uchar =
palloc((len_uchar + 1) *
sizeof(**buff_uchar));
2748 len_uchar = uchar_convert(icu_converter,
2749 *buff_uchar, len_uchar + 1, buff, nbytes);
2766 icu_from_uchar(
char **result,
const UChar *buff_uchar, int32_t len_uchar)
2771 init_icu_converter();
2773 status = U_ZERO_ERROR;
2774 len_result = ucnv_fromUChars(icu_converter, NULL, 0,
2775 buff_uchar, len_uchar, &status);
2776 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
2778 (
errmsg(
"%s failed: %s",
"ucnv_fromUChars",
2779 u_errorName(status))));
2781 *result =
palloc(len_result + 1);
2783 status = U_ZERO_ERROR;
2784 len_result = ucnv_fromUChars(icu_converter, *result, len_result + 1,
2785 buff_uchar, len_uchar, &status);
2786 if (U_FAILURE(status) ||
2787 status == U_STRING_NOT_TERMINATED_WARNING)
2789 (
errmsg(
"%s failed: %s",
"ucnv_fromUChars",
2790 u_errorName(status))));
2809 icu_set_collation_attributes(UCollator *collator, const
char *loc,
2813 char *icu_locale_id;
2825 *status = U_ZERO_ERROR;
2826 len = uloc_canonicalize(loc, NULL, 0, status);
2828 *status = U_ZERO_ERROR;
2829 len = uloc_canonicalize(loc, icu_locale_id,
len + 1, status);
2830 if (U_FAILURE(*status) || *status == U_STRING_NOT_TERMINATED_WARNING)
2833 lower_str =
asc_tolower(icu_locale_id, strlen(icu_locale_id));
2835 pfree(icu_locale_id);
2837 str = strchr(lower_str,
'@');
2844 char *
e = strchr(
token,
'=');
2850 UColAttribute uattr;
2851 UColAttributeValue uvalue;
2853 *status = U_ZERO_ERROR;
2862 if (strcmp(
name,
"colstrength") == 0)
2863 uattr = UCOL_STRENGTH;
2864 else if (strcmp(
name,
"colbackwards") == 0)
2865 uattr = UCOL_FRENCH_COLLATION;
2866 else if (strcmp(
name,
"colcaselevel") == 0)
2867 uattr = UCOL_CASE_LEVEL;
2868 else if (strcmp(
name,
"colcasefirst") == 0)
2869 uattr = UCOL_CASE_FIRST;
2870 else if (strcmp(
name,
"colalternate") == 0)
2871 uattr = UCOL_ALTERNATE_HANDLING;
2872 else if (strcmp(
name,
"colnormalization") == 0)
2873 uattr = UCOL_NORMALIZATION_MODE;
2874 else if (strcmp(
name,
"colnumeric") == 0)
2875 uattr = UCOL_NUMERIC_COLLATION;
2880 if (strcmp(
value,
"primary") == 0)
2881 uvalue = UCOL_PRIMARY;
2882 else if (strcmp(
value,
"secondary") == 0)
2883 uvalue = UCOL_SECONDARY;
2884 else if (strcmp(
value,
"tertiary") == 0)
2885 uvalue = UCOL_TERTIARY;
2886 else if (strcmp(
value,
"quaternary") == 0)
2887 uvalue = UCOL_QUATERNARY;
2888 else if (strcmp(
value,
"identical") == 0)
2889 uvalue = UCOL_IDENTICAL;
2890 else if (strcmp(
value,
"no") == 0)
2892 else if (strcmp(
value,
"yes") == 0)
2894 else if (strcmp(
value,
"shifted") == 0)
2895 uvalue = UCOL_SHIFTED;
2896 else if (strcmp(
value,
"non-ignorable") == 0)
2897 uvalue = UCOL_NON_IGNORABLE;
2898 else if (strcmp(
value,
"lower") == 0)
2899 uvalue = UCOL_LOWER_FIRST;
2900 else if (strcmp(
value,
"upper") == 0)
2901 uvalue = UCOL_UPPER_FIRST;
2904 *status = U_ILLEGAL_ARGUMENT_ERROR;
2908 ucol_setAttribute(collator, uattr, uvalue, status);
2932 const bool strict =
true;
2940 langtag =
palloc(buflen);
2943 status = U_ZERO_ERROR;
2944 uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
2947 if ((status == U_BUFFER_OVERFLOW_ERROR ||
2948 status == U_STRING_NOT_TERMINATED_WARNING) &&
2952 langtag =
repalloc(langtag, buflen);
2959 if (U_FAILURE(status))
2965 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2966 errmsg(
"could not convert locale name \"%s\" to language tag: %s",
2967 loc_str, u_errorName(status))));
2974 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2975 errmsg(
"ICU is not supported in this build")));
2987 UCollator *collator;
2989 char lang[ULOC_LANG_CAPACITY];
3002 status = U_ZERO_ERROR;
3003 uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
3004 if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
3007 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3008 errmsg(
"could not get language from ICU locale \"%s\": %s",
3009 loc_str, u_errorName(status)),
3010 errhint(
"To disable ICU locale validation, set the parameter \"%s\" to \"%s\".",
3011 "icu_validation_level",
"disabled")));
3016 if (strcmp(lang,
"") == 0 ||
3017 strcmp(lang,
"root") == 0 || strcmp(lang,
"und") == 0)
3021 for (int32_t
i = 0; !found &&
i < uloc_countAvailable();
i++)
3023 const char *otherloc = uloc_getAvailable(
i);
3024 char otherlang[ULOC_LANG_CAPACITY];
3026 status = U_ZERO_ERROR;
3027 uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status);
3028 if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
3031 if (strcmp(lang, otherlang) == 0)
3037 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3038 errmsg(
"ICU locale \"%s\" has unknown language \"%s\"",
3040 errhint(
"To disable ICU locale validation, set the parameter \"%s\" to \"%s\".",
3041 "icu_validation_level",
"disabled")));
3044 collator = pg_ucol_open(loc_str);
3045 ucol_close(collator);
3049 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3050 errmsg(
"ICU is not supported in this build")));
3085 result = WideCharToMultiByte(CP_UTF8, 0, from, -1, to, tolen,
3102 result = wcstombs(to, from, tolen);
3123 char2wchar(
wchar_t *to,
size_t tolen,
const char *from,
size_t fromlen,
3142 result = MultiByteToWideChar(CP_UTF8, 0, from, fromlen, to, tolen - 1);
3164 result = mbstowcs(to,
str, tolen);
3188 (
errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
3189 errmsg(
"invalid multibyte character for locale"),
3190 errhint(
"The server's LC_CTYPE locale is probably incompatible with the database encoding.")));
#define TextDatumGetCString(d)
#define pg_attribute_unused()
#define Assert(condition)
#define OidIsValid(objectId)
static void PGresult * res
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
const char * get_encoding_name_for_icu(int encoding)
#define palloc_array(type, count)
#define HeapTupleIsValid(tuple)
char * get_namespace_name(Oid nspid)
char * pg_any_to_server(const char *s, int len, int encoding)
int GetDatabaseEncoding(void)
int pg_mbstrlen(const char *mbstr)
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
void SetMessageEncoding(int encoding)
char * pnstrdup(const char *in, Size len)
char * pstrdup(const char *in)
void pfree(void *pointer)
MemoryContext TopMemoryContext
void * repalloc(void *pointer, Size size)
void * MemoryContextAlloc(MemoryContext context, Size size)
char * MemoryContextStrdup(MemoryContext context, const char *string)
FormData_pg_collation * Form_pg_collation
size_t pg_strnxfrm(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
static size_t pg_strxfrm_libc(char *dest, const char *src, size_t destsize, pg_locale_t locale)
void cache_locale_time(void)
bool pg_strxfrm_enabled(pg_locale_t locale)
char * localized_full_months[12+1]
size_t wchar2char(char *to, const wchar_t *from, size_t tolen, pg_locale_t locale)
struct lconv * PGLC_localeconv(void)
int pg_strncoll(const char *arg1, size_t len1, const char *arg2, size_t len2, pg_locale_t locale)
void make_icu_collator(const char *iculocstr, const char *icurules, struct pg_locale_struct *resultp)
bool lc_collate_is_c(Oid collation)
struct pg_locale_struct default_locale
void icu_validate_locale(const char *loc_str)
static bool CurrentLCTimeValid
void assign_locale_time(const char *newval, void *extra)
bool check_locale_time(char **newval, void **extra, GucSource source)
pg_locale_t pg_newlocale_from_collation(Oid collid)
int builtin_locale_encoding(const char *locale)
#define PGLOCALE_SUPPORT_ERROR(provider)
static void cache_single_string(char **dst, const char *src, int encoding)
bool lc_ctype_is_c(Oid collation)
bool check_locale_numeric(char **newval, void **extra, GucSource source)
bool pg_locale_deterministic(pg_locale_t locale)
static void db_encoding_convert(int encoding, char **str)
static size_t wcstombs_l(char *dest, const wchar_t *src, size_t n, locale_t loc)
void assign_locale_numeric(const char *newval, void *extra)
bool check_locale_messages(char **newval, void **extra, GucSource source)
char * get_collation_actual_version(char collprovider, const char *collcollate)
static void free_struct_lconv(struct lconv *s)
char * pg_perm_setlocale(int category, const char *locale)
void assign_locale_messages(const char *newval, void *extra)
static bool CurrentLocaleConvValid
char * icu_language_tag(const char *loc_str, int elevel)
int pg_strcoll(const char *arg1, const char *arg2, pg_locale_t locale)
static int pg_strcoll_libc(const char *arg1, const char *arg2, pg_locale_t locale)
static HTAB * collation_cache
bool pg_strxfrm_prefix_enabled(pg_locale_t locale)
static void report_newlocale_failure(const char *localename)
char * localized_abbrev_months[12+1]
static int pg_strncoll_libc(const char *arg1, size_t len1, const char *arg2, size_t len2, pg_locale_t locale)
size_t pg_strnxfrm_prefix(char *dest, size_t destsize, const char *src, size_t srclen, pg_locale_t locale)
static bool struct_lconv_is_valid(struct lconv *s)
char * localized_full_days[7+1]
size_t pg_strxfrm(char *dest, const char *src, size_t destsize, pg_locale_t locale)
const char * builtin_validate_locale(int encoding, const char *locale)
static collation_cache_entry * lookup_collation_cache(Oid collation, bool set_flags)
void assign_locale_monetary(const char *newval, void *extra)
bool check_locale(int category, const char *locale, char **canonname)
char * localized_abbrev_days[7+1]
size_t pg_strxfrm_prefix(char *dest, const char *src, size_t destsize, pg_locale_t locale)
size_t char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen, pg_locale_t locale)
bool check_locale_monetary(char **newval, void **extra, GucSource source)
static size_t mbstowcs_l(wchar_t *dest, const char *src, size_t n, locale_t loc)
static size_t pg_strnxfrm_libc(char *dest, const char *src, size_t srclen, size_t destsize, pg_locale_t locale)
#define LOCALE_NAME_BUFLEN
static rewind_source * source
#define pg_encoding_to_char
int pg_strcasecmp(const char *s1, const char *s2)
char * strsep(char **stringp, const char *delim)
int pg_get_encoding_from_locale(const char *ctype, bool write_message)
size_t strlcpy(char *dst, const char *src, size_t siz)
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
static Datum ObjectIdGetDatum(Oid X)
char * psprintf(const char *fmt,...)
char * quote_qualified_identifier(const char *qualifier, const char *ident)
struct pg_locale_struct::@151::@152 builtin
union pg_locale_struct::@151 info
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)