From 9bd779fb711c902b33cfd3a5350e0736d7ceb138 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Mon, 29 Jul 2024 23:58:29 -0700 Subject: [PATCH v6 3/3] selfuncs.c: use pg_strxfrm() instead of strxfrm(). pg_strxfrm() takes a pg_locale_t, so it works properly with other providers and does not rely on setlocale(). Discussion: https://postgr.es/m/cfd9eb85-c52a-4ec9-a90e-a5e4de56e57d@eisentraut.org Reviewed-by: Peter Eisentraut, Andreas Karlsson --- src/backend/utils/adt/pg_locale.c | 23 ++++++++++++++++------- src/backend/utils/adt/selfuncs.c | 9 +++++++-- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index ccd6180a743..17c55c5ab17 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -2164,14 +2164,7 @@ pg_strxfrm_libc(char *dest, const char *src, size_t destsize, pg_locale_t locale) { Assert(locale->provider == COLLPROVIDER_LIBC); - -#ifdef TRUST_STRXFRM return strxfrm_l(dest, src, destsize, locale->info.lt); -#else - /* shouldn't happen */ - PGLOCALE_SUPPORT_ERROR(locale->provider); - return 0; /* keep compiler quiet */ -#endif } static size_t @@ -2380,6 +2373,10 @@ pg_strxfrm_enabled(pg_locale_t locale) * The provided 'src' must be nul-terminated. If 'destsize' is zero, 'dest' * may be NULL. * + * Not all providers support pg_strxfrm() safely. The caller should check + * pg_strxfrm_enabled() first, otherwise this function may return wrong + * results or an error. + * * Returns the number of bytes needed to store the transformed string, * excluding the terminating nul byte. If the value returned is 'destsize' or * greater, the resulting contents of 'dest' are undefined. @@ -2412,6 +2409,10 @@ pg_strxfrm(char *dest, const char *src, size_t destsize, pg_locale_t locale) * 'src' does not need to be nul-terminated. If 'destsize' is zero, 'dest' may * be NULL. * + * Not all providers support pg_strnxfrm() safely. The caller should check + * pg_strxfrm_enabled() first, otherwise this function may return wrong + * results or an error. + * * Returns the number of bytes needed to store the transformed string, * excluding the terminating nul byte. If the value returned is 'destsize' or * greater, the resulting contents of 'dest' are undefined. @@ -2466,6 +2467,10 @@ pg_strxfrm_prefix_enabled(pg_locale_t locale) * * The provided 'src' must be nul-terminated. * + * Not all providers support pg_strxfrm_prefix() safely. The caller should + * check pg_strxfrm_prefix_enabled() first, otherwise this function may return + * wrong results or an error. + * * If destsize is not large enough to hold the resulting byte sequence, stores * only the first destsize bytes in 'dest'. Returns the number of bytes * actually copied to 'dest'. @@ -2495,6 +2500,10 @@ pg_strxfrm_prefix(char *dest, const char *src, size_t destsize, * * The provided 'src' must be nul-terminated. * + * Not all providers support pg_strnxfrm_prefix() safely. The caller should + * check pg_strxfrm_prefix_enabled() first, otherwise this function may return + * wrong results or an error. + * * If destsize is not large enough to hold the resulting byte sequence, stores * only the first destsize bytes in 'dest'. Returns the number of bytes * actually copied to 'dest'. diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 877a62a62ec..673cfd9e703 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -4673,6 +4673,7 @@ convert_string_datum(Datum value, Oid typid, Oid collid, bool *failure) if (!lc_collate_is_c(collid)) { + pg_locale_t mylocale = pg_newlocale_from_collation(collid); char *xfrmstr; size_t xfrmlen; size_t xfrmlen2 PG_USED_FOR_ASSERTS_ONLY; @@ -4685,8 +4686,12 @@ convert_string_datum(Datum value, Oid typid, Oid collid, bool *failure) * bogus data or set an error. This is not really a problem unless it * crashes since it will only give an estimation error and nothing * fatal. + * + * XXX: we do not check pg_strxfrm_enabled(). On some platforms and in + * some cases, libc strxfrm() may return the wrong results, but that + * will only lead to an estimation error. */ - xfrmlen = strxfrm(NULL, val, 0); + xfrmlen = pg_strxfrm(NULL, val, 0, mylocale); #ifdef WIN32 /* @@ -4698,7 +4703,7 @@ convert_string_datum(Datum value, Oid typid, Oid collid, bool *failure) return val; #endif xfrmstr = (char *) palloc(xfrmlen + 1); - xfrmlen2 = strxfrm(xfrmstr, val, xfrmlen + 1); + xfrmlen2 = pg_strxfrm(xfrmstr, val, xfrmlen + 1, mylocale); /* * Some systems (e.g., glibc) can return a smaller value from the -- 2.34.1