aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/pg_locale_libc.c
diff options
context:
space:
mode:
authorJeff Davis <jdavis@postgresql.org>2025-01-08 14:26:33 -0800
committerJeff Davis <jdavis@postgresql.org>2025-01-08 14:26:46 -0800
commita2f17f004d229f69a32cfa80904b95edcbc68f95 (patch)
treee82bb09d5161ad3d00f3882a8d53650214c4f4b2 /src/backend/utils/adt/pg_locale_libc.c
parent4f5cef2607c1f8804d4b54250642aaf586745b0e (diff)
downloadpostgresql-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_libc.c')
-rw-r--r--src/backend/utils/adt/pg_locale_libc.c53
1 files changed, 45 insertions, 8 deletions
diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c
index 81120061b50..8f9a8637897 100644
--- a/src/backend/utils/adt/pg_locale_libc.c
+++ b/src/backend/utils/adt/pg_locale_libc.c
@@ -50,10 +50,10 @@ extern size_t strtitle_libc(char *dst, size_t dstsize, const char *src,
extern size_t strupper_libc(char *dst, size_t dstsize, const char *src,
ssize_t srclen, pg_locale_t locale);
-extern int strncoll_libc(const char *arg1, ssize_t len1,
+static 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,
+static 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);
@@ -86,6 +86,40 @@ static size_t strupper_libc_mb(char *dest, size_t destsize,
const char *src, ssize_t srclen,
pg_locale_t locale);
+static const struct collate_methods collate_methods_libc = {
+ .strncoll = strncoll_libc,
+ .strnxfrm = strnxfrm_libc,
+ .strnxfrm_prefix = NULL,
+
+ /*
+ * 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.)
+ */
+#ifdef TRUST_STRXFRM
+ .strxfrm_is_safe = true,
+#else
+ .strxfrm_is_safe = false,
+#endif
+};
+
+#ifdef WIN32
+static const struct collate_methods collate_methods_libc_win32_utf8 = {
+ .strncoll = strncoll_libc_win32_utf8,
+ .strnxfrm = strnxfrm_libc,
+ .strnxfrm_prefix = NULL,
+#ifdef TRUST_STRXFRM
+ .strxfrm_is_safe = true,
+#else
+ .strxfrm_is_safe = false,
+#endif
+};
+#endif
+
size_t
strlower_libc(char *dst, size_t dstsize, const char *src,
ssize_t srclen, pg_locale_t locale)
@@ -439,6 +473,15 @@ create_pg_locale_libc(Oid collid, MemoryContext context)
result->ctype_is_c = (strcmp(ctype, "C") == 0) ||
(strcmp(ctype, "POSIX") == 0);
result->info.lt = loc;
+ if (!result->collate_is_c)
+ {
+#ifdef WIN32
+ if (GetDatabaseEncoding() == PG_UTF8)
+ result->collate = &collate_methods_libc_win32_utf8;
+ else
+#endif
+ result->collate = &collate_methods_libc;
+ }
return result;
}
@@ -536,12 +579,6 @@ strncoll_libc(const char *arg1, ssize_t len1, const char *arg2, ssize_t len2,
Assert(locale->provider == COLLPROVIDER_LIBC);
-#ifdef WIN32
- /* check for this case before doing the work for nul-termination */
- if (GetDatabaseEncoding() == PG_UTF8)
- return strncoll_libc_win32_utf8(arg1, len1, arg2, len2, locale);
-#endif /* WIN32 */
-
if (bufsize1 + bufsize2 > TEXTBUFLEN)
buf = palloc(bufsize1 + bufsize2);