diff options
author | Jeff Davis <jdavis@postgresql.org> | 2025-01-08 14:26:33 -0800 |
---|---|---|
committer | Jeff Davis <jdavis@postgresql.org> | 2025-01-08 14:26:46 -0800 |
commit | a2f17f004d229f69a32cfa80904b95edcbc68f95 (patch) | |
tree | e82bb09d5161ad3d00f3882a8d53650214c4f4b2 /src/backend/utils/adt/pg_locale.c | |
parent | 4f5cef2607c1f8804d4b54250642aaf586745b0e (diff) | |
download | postgresql-a2f17f004d229f69a32cfa80904b95edcbc68f95.tar.gz postgresql-a2f17f004d229f69a32cfa80904b95edcbc68f95.zip |
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
Diffstat (limited to 'src/backend/utils/adt/pg_locale.c')
-rw-r--r-- | src/backend/utils/adt/pg_locale.c | 123 |
1 files changed, 16 insertions, 107 deletions
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index dc8248fb269..875cca6efc8 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -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); } /* |