diff options
Diffstat (limited to 'src/backend/utils/adt/pg_locale_icu.c')
-rw-r--r-- | src/backend/utils/adt/pg_locale_icu.c | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c index 2a87e25dfb1..73eb430d750 100644 --- a/src/backend/utils/adt/pg_locale_icu.c +++ b/src/backend/utils/adt/pg_locale_icu.c @@ -12,14 +12,20 @@ #include "postgres.h" #ifdef USE_ICU - #include <unicode/ucnv.h> #include <unicode/ustring.h> +#endif +#include "access/htup_details.h" +#include "catalog/pg_database.h" #include "catalog/pg_collation.h" #include "mb/pg_wchar.h" +#include "miscadmin.h" +#include "utils/builtins.h" #include "utils/formatting.h" +#include "utils/memutils.h" #include "utils/pg_locale.h" +#include "utils/syscache.h" /* * Size of stack buffer to use for string transformations, used to avoid heap @@ -29,9 +35,11 @@ */ #define TEXTBUFLEN 1024 +extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context); + +#ifdef USE_ICU + extern UCollator *pg_ucol_open(const char *loc_str); -extern UCollator *make_icu_collator(const char *iculocstr, - const char *icurules); extern int strncoll_icu(const char *arg1, ssize_t len1, const char *arg2, ssize_t len2, pg_locale_t locale); @@ -49,6 +57,8 @@ extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize, */ static UConverter *icu_converter = NULL; +static UCollator *make_icu_collator(const char *iculocstr, + const char *icurules); static int strncoll_icu_no_utf8(const char *arg1, ssize_t len1, const char *arg2, ssize_t len2, pg_locale_t locale); @@ -63,6 +73,85 @@ static int32_t uchar_convert(UConverter *converter, const char *src, int32_t srclen); static void icu_set_collation_attributes(UCollator *collator, const char *loc, UErrorCode *status); +#endif + +pg_locale_t +create_pg_locale_icu(Oid collid, MemoryContext context) +{ +#ifdef USE_ICU + bool deterministic; + const char *iculocstr; + const char *icurules = NULL; + UCollator *collator; + pg_locale_t result; + + if (collid == DEFAULT_COLLATION_OID) + { + HeapTuple tp; + Datum datum; + bool isnull; + + tp = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); + + /* default database collation is always deterministic */ + deterministic = true; + datum = SysCacheGetAttrNotNull(DATABASEOID, tp, + Anum_pg_database_datlocale); + iculocstr = TextDatumGetCString(datum); + datum = SysCacheGetAttr(DATABASEOID, tp, + Anum_pg_database_daticurules, &isnull); + if (!isnull) + icurules = TextDatumGetCString(datum); + + ReleaseSysCache(tp); + } + else + { + Form_pg_collation collform; + HeapTuple tp; + Datum datum; + bool isnull; + + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for collation %u", collid); + collform = (Form_pg_collation) GETSTRUCT(tp); + deterministic = collform->collisdeterministic; + datum = SysCacheGetAttrNotNull(COLLOID, tp, + Anum_pg_collation_colllocale); + iculocstr = TextDatumGetCString(datum); + datum = SysCacheGetAttr(COLLOID, tp, + Anum_pg_collation_collicurules, &isnull); + if (!isnull) + icurules = TextDatumGetCString(datum); + + ReleaseSysCache(tp); + } + + collator = make_icu_collator(iculocstr, icurules); + + result = MemoryContextAllocZero(context, sizeof(struct pg_locale_struct)); + result->info.icu.locale = MemoryContextStrdup(context, iculocstr); + result->info.icu.ucol = collator; + result->provider = COLLPROVIDER_ICU; + result->deterministic = deterministic; + result->collate_is_c = false; + result->ctype_is_c = false; + + return result; +#else + /* could get here if a collation was created by a build with ICU */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ICU is not supported in this build"))); + + return NULL; +#endif +} + +#ifdef USE_ICU /* * Wrapper around ucol_open() to handle API differences for older ICU @@ -160,7 +249,7 @@ pg_ucol_open(const char *loc_str) * * Ensure that no path leaks a UCollator. */ -UCollator * +static UCollator * make_icu_collator(const char *iculocstr, const char *icurules) { if (!icurules) |