77#define PGLOCALE_SUPPORT_ERROR(provider) \
78 elog(ERROR, "unsupported collprovider for %s: %c", __func__, provider)
84#define TEXTBUFLEN 1024
86#define MAX_L10N_DATA 80
94extern UCollator *pg_ucol_open(
const char *loc_str);
95extern char *get_collation_actual_version_icu(
const char *collcollate);
117extern size_t strlower_libc(
char *dst,
size_t dstsize,
const char *src,
119extern size_t strtitle_libc(
char *dst,
size_t dstsize,
const char *src,
121extern size_t strupper_libc(
char *dst,
size_t dstsize,
const char *src,
165#define SH_PREFIX collation_cache
166#define SH_ELEMENT_TYPE collation_cache_entry
167#define SH_KEY_TYPE Oid
169#define SH_HASH_KEY(tb, key) murmurhash32((uint32) key)
170#define SH_EQUAL(tb, a, b) (a == b)
171#define SH_GET_HASH(tb, a) a->hash
172#define SH_SCOPE static inline
188#if defined(WIN32) && defined(LC_MESSAGES)
189static char *IsoLocaleName(
const char *);
223 if (category == LC_MESSAGES)
244 if (category == LC_CTYPE)
249 strlcpy(save_lc_ctype, result,
sizeof(save_lc_ctype));
250 result = save_lc_ctype;
262 envvar =
"LC_COLLATE";
269 envvar =
"LC_MESSAGES";
271 result = IsoLocaleName(
locale);
274 elog(
DEBUG3,
"IsoLocaleName() executed; locale: \"%s\"", result);
279 envvar =
"LC_MONETARY";
282 envvar =
"LC_NUMERIC";
288 elog(
FATAL,
"unrecognized LC category: %d", category);
292 if (
setenv(envvar, result, 1) != 0)
319 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
320 errmsg(
"locale name \"%s\" contains non-ASCII characters",
339 if (
res && canonname)
344 elog(
WARNING,
"failed to restore old locale \"%s\"", save);
348 if (canonname && *canonname && !
pg_is_ascii(*canonname))
351 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
352 errmsg(
"locale name \"%s\" contains non-ASCII characters",
359 return (
res != NULL);
436#if defined(LC_MESSAGES) && !defined(WIN32)
463 free(s->decimal_point);
464 free(s->thousands_sep);
466 free(s->int_curr_symbol);
467 free(s->currency_symbol);
468 free(s->mon_decimal_point);
469 free(s->mon_thousands_sep);
470 free(s->mon_grouping);
471 free(s->positive_sign);
472 free(s->negative_sign);
482 if (s->decimal_point == NULL)
484 if (s->thousands_sep == NULL)
486 if (s->grouping == NULL)
488 if (s->int_curr_symbol == NULL)
490 if (s->currency_symbol == NULL)
492 if (s->mon_decimal_point == NULL)
494 if (s->mon_thousands_sep == NULL)
496 if (s->mon_grouping == NULL)
498 if (s->positive_sign == NULL)
500 if (s->negative_sign == NULL)
525 (
errcode(ERRCODE_OUT_OF_MEMORY),
526 errmsg(
"out of memory")));
543 static struct lconv CurrentLocaleConv;
544 static bool CurrentLocaleConvAllocated =
false;
545 struct lconv *extlconv;
546 struct lconv worklconv;
547 char *save_lc_monetary;
548 char *save_lc_numeric;
555 return &CurrentLocaleConv;
558 if (CurrentLocaleConvAllocated)
561 CurrentLocaleConvAllocated =
false;
576 memset(&worklconv, 0,
sizeof(worklconv));
579 save_lc_monetary =
setlocale(LC_MONETARY, NULL);
580 if (!save_lc_monetary)
582 save_lc_monetary =
pstrdup(save_lc_monetary);
584 save_lc_numeric =
setlocale(LC_NUMERIC, NULL);
585 if (!save_lc_numeric)
587 save_lc_numeric =
pstrdup(save_lc_numeric);
606 save_lc_ctype =
setlocale(LC_CTYPE, NULL);
609 save_lc_ctype =
pstrdup(save_lc_ctype);
619 extlconv = localeconv();
622 worklconv.decimal_point = strdup(extlconv->decimal_point);
623 worklconv.thousands_sep = strdup(extlconv->thousands_sep);
624 worklconv.grouping = strdup(extlconv->grouping);
633 extlconv = localeconv();
636 worklconv.int_curr_symbol = strdup(extlconv->int_curr_symbol);
637 worklconv.currency_symbol = strdup(extlconv->currency_symbol);
638 worklconv.mon_decimal_point = strdup(extlconv->mon_decimal_point);
639 worklconv.mon_thousands_sep = strdup(extlconv->mon_thousands_sep);
640 worklconv.mon_grouping = strdup(extlconv->mon_grouping);
641 worklconv.positive_sign = strdup(extlconv->positive_sign);
642 worklconv.negative_sign = strdup(extlconv->negative_sign);
644 worklconv.int_frac_digits = extlconv->int_frac_digits;
645 worklconv.frac_digits = extlconv->frac_digits;
646 worklconv.p_cs_precedes = extlconv->p_cs_precedes;
647 worklconv.p_sep_by_space = extlconv->p_sep_by_space;
648 worklconv.n_cs_precedes = extlconv->n_cs_precedes;
649 worklconv.n_sep_by_space = extlconv->n_sep_by_space;
650 worklconv.p_sign_posn = extlconv->p_sign_posn;
651 worklconv.n_sign_posn = extlconv->n_sign_posn;
663 elog(
FATAL,
"failed to restore LC_CTYPE to \"%s\"", save_lc_ctype);
665 if (!
setlocale(LC_MONETARY, save_lc_monetary))
666 elog(
FATAL,
"failed to restore LC_MONETARY to \"%s\"", save_lc_monetary);
667 if (!
setlocale(LC_NUMERIC, save_lc_numeric))
668 elog(
FATAL,
"failed to restore LC_NUMERIC to \"%s\"", save_lc_numeric);
680 pfree(save_lc_monetary);
681 pfree(save_lc_numeric);
683 pfree(save_lc_ctype);
689 (
errcode(ERRCODE_OUT_OF_MEMORY),
690 errmsg(
"out of memory")));
729 CurrentLocaleConv = worklconv;
730 CurrentLocaleConvAllocated =
true;
732 return &CurrentLocaleConv;
752strftime_win32(
char *dst,
size_t dstlen,
763 len = MultiByteToWideChar(CP_UTF8, 0,
format, -1,
766 elog(
ERROR,
"could not convert format string from UTF-8: error code %lu",
779 len = WideCharToMultiByte(CP_UTF8, 0, wbuf,
len, dst, dstlen - 1,
782 elog(
ERROR,
"could not convert string to UTF-8: error code %lu",
791#define strftime(a,b,c,d) strftime_win32(a,b,c,d)
829 struct tm timeinfobuf;
830 bool strftimefail =
false;
855 save_lc_time =
pstrdup(save_lc_time);
867 save_lc_ctype =
setlocale(LC_CTYPE, NULL);
870 save_lc_ctype =
pstrdup(save_lc_ctype);
879 timenow = time(NULL);
880 timeinfo = gmtime_r(&timenow, &timeinfobuf);
896 for (
i = 0;
i < 7;
i++)
898 timeinfo->tm_wday =
i;
908 for (
i = 0;
i < 12;
i++)
910 timeinfo->tm_mon =
i;
911 timeinfo->tm_mday = 1;
926 elog(
FATAL,
"failed to restore LC_CTYPE to \"%s\"", save_lc_ctype);
929 elog(
FATAL,
"failed to restore LC_TIME to \"%s\"", save_lc_time);
941 pfree(save_lc_ctype);
968 for (
i = 0;
i < 7;
i++)
979 for (
i = 0;
i < 12;
i++)
993#if defined(WIN32) && defined(LC_MESSAGES)
1046search_locale_enum(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
1048 wchar_t test_locale[LOCALE_NAME_MAX_LENGTH];
1053 argv = (
wchar_t **) lparam;
1054 *argv[2] = (wchar_t) 0;
1056 memset(test_locale, 0,
sizeof(test_locale));
1059 if (GetLocaleInfoEx(pStr, LOCALE_SENGLISHLANGUAGENAME,
1060 test_locale, LOCALE_NAME_MAX_LENGTH))
1067 if (wcsrchr(pStr,
'-') == NULL || wcsrchr(argv[0],
'_') == NULL)
1069 if (_wcsicmp(argv[0], test_locale) == 0)
1071 wcscpy(argv[1], pStr);
1072 *argv[2] = (wchar_t) 1;
1086 wcscat(test_locale, L
"_");
1087 len = wcslen(test_locale);
1088 if (GetLocaleInfoEx(pStr, LOCALE_SENGLISHCOUNTRYNAME,
1090 LOCALE_NAME_MAX_LENGTH -
len))
1092 if (_wcsicmp(argv[0], test_locale) == 0)
1094 wcscpy(argv[1], pStr);
1095 *argv[2] = (wchar_t) 1;
1112get_iso_localename(
const char *winlocname)
1114 wchar_t wc_locale_name[LOCALE_NAME_MAX_LENGTH];
1115 wchar_t buffer[LOCALE_NAME_MAX_LENGTH];
1116 static char iso_lc_messages[LOCALE_NAME_MAX_LENGTH];
1128 period = strchr(winlocname,
'.');
1134 memset(wc_locale_name, 0,
sizeof(wc_locale_name));
1135 memset(buffer, 0,
sizeof(buffer));
1136 MultiByteToWideChar(CP_ACP, 0, winlocname,
len, wc_locale_name,
1137 LOCALE_NAME_MAX_LENGTH);
1143 ret_val = GetLocaleInfoEx(wc_locale_name, LOCALE_SNAME, (LPWSTR) &buffer,
1144 LOCALE_NAME_MAX_LENGTH);
1153 argv[0] = wc_locale_name;
1155 argv[2] = (
wchar_t *) &ret_val;
1156 EnumSystemLocalesEx(search_locale_enum, LOCALE_WINDOWS, (LPARAM) argv,
1166 rc =
wchar2char(iso_lc_messages, buffer,
sizeof(iso_lc_messages), NULL);
1167 if (rc == -1 || rc ==
sizeof(iso_lc_messages))
1177 hyphen = strchr(iso_lc_messages,
'-');
1180 return iso_lc_messages;
1187IsoLocaleName(
const char *winlocname)
1189 static char iso_lc_messages[LOCALE_NAME_MAX_LENGTH];
1194 strcpy(iso_lc_messages,
"C");
1195 return iso_lc_messages;
1198 return get_iso_localename(winlocname);
1220 if (collform->collprovider == COLLPROVIDER_BUILTIN)
1222 else if (collform->collprovider == COLLPROVIDER_ICU)
1224 else if (collform->collprovider == COLLPROVIDER_LIBC)
1239 char *actual_versionstr;
1240 char *collversionstr;
1244 if (collform->collprovider == COLLPROVIDER_LIBC)
1251 if (!actual_versionstr)
1259 (
errmsg(
"collation \"%s\" has no actual version, but a version was recorded",
1260 NameStr(collform->collname))));
1263 if (strcmp(actual_versionstr, collversionstr) != 0)
1265 (
errmsg(
"collation \"%s\" has version mismatch",
1267 errdetail(
"The collation in the database was created using version %s, "
1268 "but the operating system provides version %s.",
1269 collversionstr, actual_versionstr),
1270 errhint(
"Rebuild all objects affected by this collation and run "
1271 "ALTER COLLATION %s REFRESH VERSION, "
1272 "or build PostgreSQL with the right library version.",
1274 NameStr(collform->collname)))));
1300 if (dbform->datlocprovider == COLLPROVIDER_BUILTIN)
1303 else if (dbform->datlocprovider == COLLPROVIDER_ICU)
1306 else if (dbform->datlocprovider == COLLPROVIDER_LIBC)
1333 if (
collid == DEFAULT_COLLATION_OID)
1361 if (cache_entry->
locale == 0)
1369 return cache_entry->
locale;
1379 char *collversion = NULL;
1381 if (collprovider == COLLPROVIDER_BUILTIN)
1384 else if (collprovider == COLLPROVIDER_ICU)
1385 collversion = get_collation_actual_version_icu(collcollate);
1387 else if (collprovider == COLLPROVIDER_LIBC)
1394pg_strlower(
char *dst,
size_t dstsize,
const char *src, ssize_t srclen,
1397 if (
locale->provider == COLLPROVIDER_BUILTIN)
1400 else if (
locale->provider == COLLPROVIDER_ICU)
1403 else if (
locale->provider == COLLPROVIDER_LIBC)
1413pg_strtitle(
char *dst,
size_t dstsize,
const char *src, ssize_t srclen,
1416 if (
locale->provider == COLLPROVIDER_BUILTIN)
1419 else if (
locale->provider == COLLPROVIDER_ICU)
1422 else if (
locale->provider == COLLPROVIDER_LIBC)
1432pg_strupper(
char *dst,
size_t dstsize,
const char *src, ssize_t srclen,
1435 if (
locale->provider == COLLPROVIDER_BUILTIN)
1438 else if (
locale->provider == COLLPROVIDER_ICU)
1441 else if (
locale->provider == COLLPROVIDER_LIBC)
1458 return locale->collate->strncoll(arg1, -1, arg2, -1,
locale);
1476pg_strncoll(
const char *arg1, ssize_t len1,
const char *arg2, ssize_t len2,
1479 return locale->collate->strncoll(arg1, len1, arg2, len2,
locale);
1497 return locale->collate->strxfrm_is_safe;
1544 return (
locale->collate->strnxfrm_prefix != NULL);
1581 return locale->collate->strnxfrm_prefix(
dest, destsize, src, srclen,
locale);
1591 if (strcmp(
locale,
"C") == 0)
1593 else if (strcmp(
locale,
"C.UTF-8") == 0)
1595 else if (strcmp(
locale,
"PG_UNICODE_FAST") == 0)
1600 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
1601 errmsg(
"invalid locale name \"%s\" for builtin provider",
1615 const char *canonical_name = NULL;
1616 int required_encoding;
1618 if (strcmp(
locale,
"C") == 0)
1619 canonical_name =
"C";
1620 else if (strcmp(
locale,
"C.UTF-8") == 0 || strcmp(
locale,
"C.UTF8") == 0)
1621 canonical_name =
"C.UTF-8";
1622 else if (strcmp(
locale,
"PG_UNICODE_FAST") == 0)
1623 canonical_name =
"PG_UNICODE_FAST";
1625 if (!canonical_name)
1627 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
1628 errmsg(
"invalid locale name \"%s\" for builtin provider",
1632 if (required_encoding >= 0 &&
encoding != required_encoding)
1634 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
1635 errmsg(
"encoding \"%s\" does not match locale \"%s\"",
1638 return canonical_name;
1659 const bool strict =
true;
1667 langtag =
palloc(buflen);
1670 status = U_ZERO_ERROR;
1671 uloc_toLanguageTag(loc_str, langtag, buflen, strict, &status);
1674 if ((status == U_BUFFER_OVERFLOW_ERROR ||
1675 status == U_STRING_NOT_TERMINATED_WARNING) &&
1679 langtag =
repalloc(langtag, buflen);
1686 if (U_FAILURE(status))
1692 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1693 errmsg(
"could not convert locale name \"%s\" to language tag: %s",
1694 loc_str, u_errorName(status))));
1701 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1702 errmsg(
"ICU is not supported in this build")));
1714 UCollator *collator;
1716 char lang[ULOC_LANG_CAPACITY];
1729 status = U_ZERO_ERROR;
1730 uloc_getLanguage(loc_str, lang, ULOC_LANG_CAPACITY, &status);
1731 if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
1734 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1735 errmsg(
"could not get language from ICU locale \"%s\": %s",
1736 loc_str, u_errorName(status)),
1737 errhint(
"To disable ICU locale validation, set the parameter \"%s\" to \"%s\".",
1738 "icu_validation_level",
"disabled")));
1743 if (strcmp(lang,
"") == 0 ||
1744 strcmp(lang,
"root") == 0 || strcmp(lang,
"und") == 0)
1748 for (int32_t
i = 0; !found &&
i < uloc_countAvailable();
i++)
1750 const char *otherloc = uloc_getAvailable(
i);
1751 char otherlang[ULOC_LANG_CAPACITY];
1753 status = U_ZERO_ERROR;
1754 uloc_getLanguage(otherloc, otherlang, ULOC_LANG_CAPACITY, &status);
1755 if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING)
1758 if (strcmp(lang, otherlang) == 0)
1764 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1765 errmsg(
"ICU locale \"%s\" has unknown language \"%s\"",
1767 errhint(
"To disable ICU locale validation, set the parameter \"%s\" to \"%s\".",
1768 "icu_validation_level",
"disabled")));
1771 collator = pg_ucol_open(loc_str);
1772 ucol_close(collator);
1776 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1777 errmsg(
"ICU is not supported in this build")));
#define TextDatumGetCString(d)
#define Assert(condition)
#define OidIsValid(objectId)
static void PGresult * res
int errdetail(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define HeapTupleIsValid(tuple)
char * get_namespace_name(Oid nspid)
int GetDatabaseEncoding(void)
char * pg_any_to_server(const char *s, int len, int encoding)
int pg_mbstrlen(const char *mbstr)
void SetMessageEncoding(int encoding)
char * MemoryContextStrdup(MemoryContext context, const char *string)
char * pstrdup(const char *in)
void * repalloc(void *pointer, Size size)
void pfree(void *pointer)
MemoryContext TopMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
FormData_pg_collation * Form_pg_collation
FormData_pg_database * Form_pg_database
static pg_locale_t last_collation_cache_locale
void cache_locale_time(void)
size_t pg_strnxfrm(char *dest, size_t destsize, const char *src, ssize_t srclen, pg_locale_t locale)
bool pg_strxfrm_enabled(pg_locale_t locale)
char * localized_full_months[12+1]
void icu_validate_locale(const char *loc_str)
pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context)
static bool CurrentLCTimeValid
void assign_locale_time(const char *newval, void *extra)
char * get_collation_actual_version(char collprovider, const char *collcollate)
pg_locale_t create_pg_locale_builtin(Oid collid, MemoryContext context)
size_t strupper_icu(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
bool check_locale_time(char **newval, void **extra, GucSource source)
size_t strlower_icu(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
size_t strtitle_libc(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
size_t strupper_libc(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
size_t strtitle_icu(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
pg_locale_t pg_newlocale_from_collation(Oid collid)
int builtin_locale_encoding(const char *locale)
size_t pg_strnxfrm_prefix(char *dest, size_t destsize, const char *src, ssize_t srclen, pg_locale_t locale)
size_t strupper_builtin(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
char * pg_perm_setlocale(int category, const char *locale)
#define PGLOCALE_SUPPORT_ERROR(provider)
static pg_locale_t create_pg_locale(Oid collid, MemoryContext context)
static void cache_single_string(char **dst, const char *src, int encoding)
size_t strlower_builtin(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
char * get_collation_actual_version_libc(const char *collcollate)
size_t pg_strlower(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
bool check_locale_numeric(char **newval, void **extra, GucSource source)
static void db_encoding_convert(int encoding, char **str)
void assign_locale_numeric(const char *newval, void *extra)
bool check_locale_messages(char **newval, void **extra, GucSource source)
size_t strlower_libc(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
char * get_collation_actual_version_builtin(const char *collcollate)
static void free_struct_lconv(struct lconv *s)
static MemoryContext CollationCacheContext
void assign_locale_messages(const char *newval, void *extra)
static bool CurrentLocaleConvValid
struct lconv * PGLC_localeconv(void)
pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context)
size_t pg_strtitle(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
int pg_strcoll(const char *arg1, const char *arg2, pg_locale_t locale)
bool pg_strxfrm_prefix_enabled(pg_locale_t locale)
char * icu_language_tag(const char *loc_str, int elevel)
char * localized_abbrev_months[12+1]
static pg_locale_t default_locale
static collation_cache_hash * CollationCache
int pg_strncoll(const char *arg1, ssize_t len1, const char *arg2, ssize_t len2, pg_locale_t locale)
static bool struct_lconv_is_valid(struct lconv *s)
void init_database_collation(void)
char * localized_full_days[7+1]
size_t strtitle_builtin(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
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)
size_t pg_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
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)
bool check_locale_monetary(char **newval, void **extra, GucSource source)
static Oid last_collation_cache_oid
#define LOCALE_NAME_BUFLEN
size_t wchar2char(char *to, const wchar_t *from, size_t tolen, pg_locale_t locale)
static rewind_source * source
#define pg_encoding_to_char
int pg_strcasecmp(const char *s1, const char *s2)
int pg_get_encoding_from_locale(const char *ctype, bool write_message)
size_t strlcpy(char *dst, const char *src, size_t siz)
static Datum ObjectIdGetDatum(Oid X)
char * quote_qualified_identifier(const char *qualifier, const char *ident)
bool pg_is_ascii(const char *str)
const struct collate_methods * collate
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)