mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Control collation behavior with a method table.
Previously, behavior branched based on the provider. A method table is less error-prone and more flexible. The ctype behavior will be addressed in an upcoming commit. Reviewed-by: Andreas Karlsson Discussion: https://postgr.es/m/2830211e1b6e6a2e26d845780b03e125281ea17b.camel%40j-davis.com
This commit is contained in:
@@ -92,27 +92,12 @@ extern char *get_collation_actual_version_builtin(const char *collcollate);
|
||||
/* pg_locale_icu.c */
|
||||
#ifdef USE_ICU
|
||||
extern UCollator *pg_ucol_open(const char *loc_str);
|
||||
extern int strncoll_icu(const char *arg1, ssize_t len1,
|
||||
const char *arg2, ssize_t len2,
|
||||
pg_locale_t locale);
|
||||
extern size_t strnxfrm_icu(char *dest, size_t destsize,
|
||||
const char *src, ssize_t srclen,
|
||||
pg_locale_t locale);
|
||||
extern size_t strnxfrm_prefix_icu(char *dest, size_t destsize,
|
||||
const char *src, ssize_t srclen,
|
||||
pg_locale_t locale);
|
||||
extern char *get_collation_actual_version_icu(const char *collcollate);
|
||||
#endif
|
||||
extern pg_locale_t create_pg_locale_icu(Oid collid, MemoryContext context);
|
||||
|
||||
/* pg_locale_libc.c */
|
||||
extern pg_locale_t create_pg_locale_libc(Oid collid, MemoryContext context);
|
||||
extern int strncoll_libc(const char *arg1, ssize_t len1,
|
||||
const char *arg2, ssize_t len2,
|
||||
pg_locale_t locale);
|
||||
extern size_t strnxfrm_libc(char *dest, size_t destsize,
|
||||
const char *src, ssize_t srclen,
|
||||
pg_locale_t locale);
|
||||
extern char *get_collation_actual_version_libc(const char *collcollate);
|
||||
|
||||
extern size_t strlower_builtin(char *dst, size_t dstsize, const char *src,
|
||||
@@ -1244,6 +1229,9 @@ create_pg_locale(Oid collid, MemoryContext context)
|
||||
|
||||
result->is_default = false;
|
||||
|
||||
Assert((result->collate_is_c && result->collate == NULL) ||
|
||||
(!result->collate_is_c && result->collate != NULL));
|
||||
|
||||
datum = SysCacheGetAttr(COLLOID, tp, Anum_pg_collation_collversion,
|
||||
&isnull);
|
||||
if (!isnull)
|
||||
@@ -1467,19 +1455,7 @@ pg_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen,
|
||||
int
|
||||
pg_strcoll(const char *arg1, const char *arg2, pg_locale_t locale)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (locale->provider == COLLPROVIDER_LIBC)
|
||||
result = strncoll_libc(arg1, -1, arg2, -1, locale);
|
||||
#ifdef USE_ICU
|
||||
else if (locale->provider == COLLPROVIDER_ICU)
|
||||
result = strncoll_icu(arg1, -1, arg2, -1, locale);
|
||||
#endif
|
||||
else
|
||||
/* shouldn't happen */
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return result;
|
||||
return locale->collate->strncoll(arg1, -1, arg2, -1, locale);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1500,51 +1476,25 @@ int
|
||||
pg_strncoll(const char *arg1, ssize_t len1, const char *arg2, ssize_t len2,
|
||||
pg_locale_t locale)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (locale->provider == COLLPROVIDER_LIBC)
|
||||
result = strncoll_libc(arg1, len1, arg2, len2, locale);
|
||||
#ifdef USE_ICU
|
||||
else if (locale->provider == COLLPROVIDER_ICU)
|
||||
result = strncoll_icu(arg1, len1, arg2, len2, locale);
|
||||
#endif
|
||||
else
|
||||
/* shouldn't happen */
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return result;
|
||||
return locale->collate->strncoll(arg1, len1, arg2, len2, locale);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the collation provider supports pg_strxfrm() and
|
||||
* pg_strnxfrm(); otherwise false.
|
||||
*
|
||||
* Unfortunately, it seems that strxfrm() for non-C collations is broken on
|
||||
* many common platforms; testing of multiple versions of glibc reveals that,
|
||||
* for many locales, strcoll() and strxfrm() do not return consistent
|
||||
* results. While no other libc other than Cygwin has so far been shown to
|
||||
* have a problem, we take the conservative course of action for right now and
|
||||
* disable this categorically. (Users who are certain this isn't a problem on
|
||||
* their system can define TRUST_STRXFRM.)
|
||||
*
|
||||
* No similar problem is known for the ICU provider.
|
||||
*/
|
||||
bool
|
||||
pg_strxfrm_enabled(pg_locale_t locale)
|
||||
{
|
||||
if (locale->provider == COLLPROVIDER_LIBC)
|
||||
#ifdef TRUST_STRXFRM
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
else if (locale->provider == COLLPROVIDER_ICU)
|
||||
return true;
|
||||
else
|
||||
/* shouldn't happen */
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return false; /* keep compiler quiet */
|
||||
/*
|
||||
* locale->collate->strnxfrm is still a required method, even if it may
|
||||
* have the wrong behavior, because the planner uses it for estimates in
|
||||
* some cases.
|
||||
*/
|
||||
return locale->collate->strxfrm_is_safe;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1555,19 +1505,7 @@ pg_strxfrm_enabled(pg_locale_t locale)
|
||||
size_t
|
||||
pg_strxfrm(char *dest, const char *src, size_t destsize, pg_locale_t locale)
|
||||
{
|
||||
size_t result = 0; /* keep compiler quiet */
|
||||
|
||||
if (locale->provider == COLLPROVIDER_LIBC)
|
||||
result = strnxfrm_libc(dest, destsize, src, -1, locale);
|
||||
#ifdef USE_ICU
|
||||
else if (locale->provider == COLLPROVIDER_ICU)
|
||||
result = strnxfrm_icu(dest, destsize, src, -1, locale);
|
||||
#endif
|
||||
else
|
||||
/* shouldn't happen */
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return result;
|
||||
return locale->collate->strnxfrm(dest, destsize, src, -1, locale);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1593,19 +1531,7 @@ size_t
|
||||
pg_strnxfrm(char *dest, size_t destsize, const char *src, ssize_t srclen,
|
||||
pg_locale_t locale)
|
||||
{
|
||||
size_t result = 0; /* keep compiler quiet */
|
||||
|
||||
if (locale->provider == COLLPROVIDER_LIBC)
|
||||
result = strnxfrm_libc(dest, destsize, src, srclen, locale);
|
||||
#ifdef USE_ICU
|
||||
else if (locale->provider == COLLPROVIDER_ICU)
|
||||
result = strnxfrm_icu(dest, destsize, src, srclen, locale);
|
||||
#endif
|
||||
else
|
||||
/* shouldn't happen */
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return result;
|
||||
return locale->collate->strnxfrm(dest, destsize, src, srclen, locale);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1615,15 +1541,7 @@ pg_strnxfrm(char *dest, size_t destsize, const char *src, ssize_t srclen,
|
||||
bool
|
||||
pg_strxfrm_prefix_enabled(pg_locale_t locale)
|
||||
{
|
||||
if (locale->provider == COLLPROVIDER_LIBC)
|
||||
return false;
|
||||
else if (locale->provider == COLLPROVIDER_ICU)
|
||||
return true;
|
||||
else
|
||||
/* shouldn't happen */
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return false; /* keep compiler quiet */
|
||||
return (locale->collate->strnxfrm_prefix != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1635,7 +1553,7 @@ size_t
|
||||
pg_strxfrm_prefix(char *dest, const char *src, size_t destsize,
|
||||
pg_locale_t locale)
|
||||
{
|
||||
return pg_strnxfrm_prefix(dest, destsize, src, -1, locale);
|
||||
return locale->collate->strnxfrm_prefix(dest, destsize, src, -1, locale);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1660,16 +1578,7 @@ size_t
|
||||
pg_strnxfrm_prefix(char *dest, size_t destsize, const char *src,
|
||||
ssize_t srclen, pg_locale_t locale)
|
||||
{
|
||||
size_t result = 0; /* keep compiler quiet */
|
||||
|
||||
#ifdef USE_ICU
|
||||
if (locale->provider == COLLPROVIDER_ICU)
|
||||
result = strnxfrm_prefix_icu(dest, destsize, src, -1, locale);
|
||||
else
|
||||
#endif
|
||||
PGLOCALE_SUPPORT_ERROR(locale->provider);
|
||||
|
||||
return result;
|
||||
return locale->collate->strnxfrm_prefix(dest, destsize, src, srclen, locale);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user