From bb623fc827b367393e2378846fb12c52a947edfe Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Tue, 11 Aug 2026 12:32:49 +0300 Subject: [PATCH 1/1] Fix pg_strupper/lower/fold() functions work with C locale --- src/backend/utils/adt/pg_locale.c | 68 +++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 78243b2c795..2f8d5fea8f2 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -1273,11 +1273,64 @@ get_collation_actual_version(char collprovider, const char *collcollate) return collversion; } +/* lowercasing/casefolding in C locale */ +static size_t +strlower_c(char *dst, size_t dstsize, const char *src, size_t srclen) +{ + int i; + + for (i = 0; i < srclen && i < dstsize; i++) + dst[i] = pg_ascii_tolower(src[i]); + if (i < dstsize) + dst[i] = '\0'; + return srclen; +} + +/* titlecasing in C locale */ +static size_t +strtitle_c(char *dst, size_t dstsize, const char *src, size_t srclen) +{ + bool wasalnum = false; + int i; + + for (i = 0; i < srclen && i < dstsize; i++) + { + char c = src[i]; + + if (wasalnum) + dst[i] = pg_ascii_tolower(c); + else + dst[i] = pg_ascii_toupper(c); + + wasalnum = ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z')); + } + if (i < dstsize) + dst[i] = '\0'; + return srclen; +} + +/* uppercasing in C locale */ +static size_t +strupper_c(char *dst, size_t dstsize, const char *src, size_t srclen) +{ + int i; + + for (i = 0; i < srclen && i < dstsize; i++) + dst[i] = pg_ascii_toupper(src[i]); + if (i < dstsize) + dst[i] = '\0'; + return srclen; +} + size_t pg_strlower(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale) { - if (locale->provider == COLLPROVIDER_BUILTIN) + if (locale->ctype_is_c) + return strlower_c(dst, dstsize, src, srclen); + else if (locale->provider == COLLPROVIDER_BUILTIN) return strlower_builtin(dst, dstsize, src, srclen, locale); #ifdef USE_ICU else if (locale->provider == COLLPROVIDER_ICU) @@ -1296,7 +1349,9 @@ size_t pg_strtitle(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale) { - if (locale->provider == COLLPROVIDER_BUILTIN) + if (locale->ctype_is_c) + return strtitle_c(dst, dstsize, src, srclen); + else if (locale->provider == COLLPROVIDER_BUILTIN) return strtitle_builtin(dst, dstsize, src, srclen, locale); #ifdef USE_ICU else if (locale->provider == COLLPROVIDER_ICU) @@ -1315,7 +1370,9 @@ size_t pg_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale) { - if (locale->provider == COLLPROVIDER_BUILTIN) + if (locale->ctype_is_c) + return strupper_c(dst, dstsize, src, srclen); + else if (locale->provider == COLLPROVIDER_BUILTIN) return strupper_builtin(dst, dstsize, src, srclen, locale); #ifdef USE_ICU else if (locale->provider == COLLPROVIDER_ICU) @@ -1334,7 +1391,10 @@ size_t pg_strfold(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale) { - if (locale->provider == COLLPROVIDER_BUILTIN) + /* in the C locale, casefolding is the same as lowercasing */ + if (locale->ctype_is_c) + return strlower_c(dst, dstsize, src, srclen); + else if (locale->provider == COLLPROVIDER_BUILTIN) return strfold_builtin(dst, dstsize, src, srclen, locale); #ifdef USE_ICU else if (locale->provider == COLLPROVIDER_ICU) -- 2.47.3