Remove char_tolower() API.
authorJeff Davis <[email protected]>
Wed, 10 Dec 2025 19:55:59 +0000 (11:55 -0800)
committerJeff Davis <[email protected]>
Wed, 10 Dec 2025 19:55:59 +0000 (11:55 -0800)
It's only useful for an ILIKE optimization for the libc provider using
a single-byte encoding and a non-C locale, but it creates significant
internal complexity.

Reviewed-by: Chao Li <[email protected]>
Reviewed-by: Peter Eisentraut <[email protected]>
Discussion: https://postgr.es/m/450ceb6260cad30d7afdf155d991a9caafee7c0d[email protected]

src/backend/utils/adt/like.c
src/backend/utils/adt/like_match.c
src/backend/utils/adt/pg_locale.c
src/backend/utils/adt/pg_locale_libc.c
src/include/utils/pg_locale.h

index 4216ac17f4371f63e3fd379a16ea1941d6e0831f..28980264307804800d546ea84026987c29f78b8e 100644 (file)
@@ -43,8 +43,8 @@ static text *MB_do_like_escape(text *pat, text *esc);
 static int     UTF8_MatchText(const char *t, int tlen, const char *p, int plen,
                                                   pg_locale_t locale);
 
-static int     SB_IMatchText(const char *t, int tlen, const char *p, int plen,
-                                                 pg_locale_t locale);
+static int     C_IMatchText(const char *t, int tlen, const char *p, int plen,
+                                                pg_locale_t locale);
 
 static int     GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation);
 static int     Generic_Text_IC_like(text *str, text *pat, Oid collation);
@@ -84,22 +84,10 @@ wchareq(const char *p1, const char *p2)
  * of getting a single character transformed to the system's wchar_t format.
  * So now, we just downcase the strings using lower() and apply regular LIKE
  * comparison.  This should be revisited when we install better locale support.
- */
-
-/*
- * We do handle case-insensitive matching for single-byte encodings using
+ *
+ * We do handle case-insensitive matching for the C locale using
  * fold-on-the-fly processing, however.
  */
-static char
-SB_lower_char(unsigned char c, pg_locale_t locale)
-{
-       if (locale->ctype_is_c)
-               return pg_ascii_tolower(c);
-       else if (locale->is_default)
-               return pg_tolower(c);
-       else
-               return char_tolower(c, locale);
-}
 
 
 #define NextByte(p, plen)      ((p)++, (plen)--)
@@ -130,10 +118,10 @@ SB_lower_char(unsigned char c, pg_locale_t locale)
 
 #include "like_match.c"
 
-/* setup to compile like_match.c for single byte case insensitive matches */
-#define MATCH_LOWER(t, locale) SB_lower_char((unsigned char) (t), locale)
+/* setup to compile like_match.c for case-insensitive matches in C locale */
+#define MATCH_LOWER
 #define NextChar(p, plen) NextByte((p), (plen))
-#define MatchText SB_IMatchText
+#define MatchText C_IMatchText
 
 #include "like_match.c"
 
@@ -202,22 +190,19 @@ Generic_Text_IC_like(text *str, text *pat, Oid collation)
                                 errmsg("nondeterministic collations are not supported for ILIKE")));
 
        /*
-        * For efficiency reasons, in the single byte case we don't call lower()
-        * on the pattern and text, but instead call SB_lower_char on each
-        * character.  In the multi-byte case we don't have much choice :-(. Also,
-        * ICU does not support single-character case folding, so we go the long
-        * way.
+        * For efficiency reasons, in the C locale we don't call lower() on the
+        * pattern and text, but instead lowercase each character lazily.
+        *
+        * XXX: use casefolding instead?
         */
 
-       if (locale->ctype_is_c ||
-               (char_tolower_enabled(locale) &&
-                pg_database_encoding_max_length() == 1))
+       if (locale->ctype_is_c)
        {
                p = VARDATA_ANY(pat);
                plen = VARSIZE_ANY_EXHDR(pat);
                s = VARDATA_ANY(str);
                slen = VARSIZE_ANY_EXHDR(str);
-               return SB_IMatchText(s, slen, p, plen, locale);
+               return C_IMatchText(s, slen, p, plen, locale);
        }
        else
        {
@@ -229,10 +214,13 @@ Generic_Text_IC_like(text *str, text *pat, Oid collation)
                                                                                                         PointerGetDatum(str)));
                s = VARDATA_ANY(str);
                slen = VARSIZE_ANY_EXHDR(str);
+
                if (GetDatabaseEncoding() == PG_UTF8)
                        return UTF8_MatchText(s, slen, p, plen, 0);
-               else
+               else if (pg_database_encoding_max_length() > 1)
                        return MB_MatchText(s, slen, p, plen, 0);
+               else
+                       return SB_MatchText(s, slen, p, plen, 0);
        }
 }
 
index 892f8a745ea430cfa4dd9d1e4e3b61d213681e82..54846c9541d89701e76ed801949c1fda3be92b57 100644 (file)
  *--------------------
  */
 
+/*
+ * MATCH_LOWER is defined for ILIKE in the C locale as an optimization. Other
+ * locales must casefold the inputs before matching.
+ */
 #ifdef MATCH_LOWER
-#define GETCHAR(t, locale) MATCH_LOWER(t, locale)
+#define GETCHAR(t) pg_ascii_tolower(t)
 #else
-#define GETCHAR(t, locale) (t)
+#define GETCHAR(t) (t)
 #endif
 
 static int
@@ -105,7 +109,7 @@ MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
                                ereport(ERROR,
                                                (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
                                                 errmsg("LIKE pattern must not end with escape character")));
-                       if (GETCHAR(*p, locale) != GETCHAR(*t, locale))
+                       if (GETCHAR(*p) != GETCHAR(*t))
                                return LIKE_FALSE;
                }
                else if (*p == '%')
@@ -167,14 +171,14 @@ MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
                                                         errmsg("LIKE pattern must not end with escape character")));
-                               firstpat = GETCHAR(p[1], locale);
+                               firstpat = GETCHAR(p[1]);
                        }
                        else
-                               firstpat = GETCHAR(*p, locale);
+                               firstpat = GETCHAR(*p);
 
                        while (tlen > 0)
                        {
-                               if (GETCHAR(*t, locale) == firstpat || (locale && !locale->deterministic))
+                               if (GETCHAR(*t) == firstpat || (locale && !locale->deterministic))
                                {
                                        int                     matched = MatchText(t, tlen, p, plen, locale);
 
@@ -342,7 +346,7 @@ MatchText(const char *t, int tlen, const char *p, int plen, pg_locale_t locale)
                                        NextChar(t1, t1len);
                        }
                }
-               else if (GETCHAR(*p, locale) != GETCHAR(*t, locale))
+               else if (GETCHAR(*p) != GETCHAR(*t))
                {
                        /* non-wildcard pattern char fails to match text char */
                        return LIKE_FALSE;
index d73bab97c1577585d6dd3bf105956eceac45e278..b00663b958521331efcd1a7027d2a35405f473ab 100644 (file)
@@ -1629,32 +1629,6 @@ char_is_cased(char ch, pg_locale_t locale)
        return locale->ctype->char_is_cased(ch, locale);
 }
 
-/*
- * char_tolower_enabled()
- *
- * Does the provider support char_tolower()?
- */
-bool
-char_tolower_enabled(pg_locale_t locale)
-{
-       if (locale->ctype == NULL)
-               return true;
-       return (locale->ctype->char_tolower != NULL);
-}
-
-/*
- * char_tolower()
- *
- * Convert char (single-byte encoding) to lowercase.
- */
-char
-char_tolower(unsigned char ch, pg_locale_t locale)
-{
-       if (locale->ctype == NULL)
-               return pg_ascii_tolower(ch);
-       return locale->ctype->char_tolower(ch, locale);
-}
-
 /*
  * Return required encoding ID for the given locale, or -1 if any encoding is
  * valid for the locale.
index b125b5da3a6993853642e3a44fcb78b223297ee9..fa871690e0c31e7a3cb5ce52e7a510d31bf7d720 100644 (file)
@@ -248,13 +248,6 @@ wc_isxdigit_libc_mb(pg_wchar wc, pg_locale_t locale)
 #endif
 }
 
-static char
-char_tolower_libc(unsigned char ch, pg_locale_t locale)
-{
-       Assert(pg_database_encoding_max_length() == 1);
-       return tolower_l(ch, locale->lt);
-}
-
 static bool
 char_is_cased_libc(char ch, pg_locale_t locale)
 {
@@ -339,7 +332,6 @@ static const struct ctype_methods ctype_methods_libc_sb = {
        .wc_isspace = wc_isspace_libc_sb,
        .wc_isxdigit = wc_isxdigit_libc_sb,
        .char_is_cased = char_is_cased_libc,
-       .char_tolower = char_tolower_libc,
        .wc_toupper = toupper_libc_sb,
        .wc_tolower = tolower_libc_sb,
 };
@@ -365,7 +357,6 @@ static const struct ctype_methods ctype_methods_libc_other_mb = {
        .wc_isspace = wc_isspace_libc_sb,
        .wc_isxdigit = wc_isxdigit_libc_sb,
        .char_is_cased = char_is_cased_libc,
-       .char_tolower = char_tolower_libc,
        .wc_toupper = toupper_libc_sb,
        .wc_tolower = tolower_libc_sb,
 };
@@ -387,7 +378,6 @@ static const struct ctype_methods ctype_methods_libc_utf8 = {
        .wc_isspace = wc_isspace_libc_mb,
        .wc_isxdigit = wc_isxdigit_libc_mb,
        .char_is_cased = char_is_cased_libc,
-       .char_tolower = char_tolower_libc,
        .wc_toupper = toupper_libc_mb,
        .wc_tolower = tolower_libc_mb,
 };
index 42e21e7fb8aedc47b86a5c785c62d43d30a6d336..50520e50127bb9c226023b77e5ba6522e315e593 100644 (file)
@@ -127,13 +127,6 @@ struct ctype_methods
 
        /* required */
        bool            (*char_is_cased) (char ch, pg_locale_t locale);
-
-       /*
-        * Optional. If defined, will only be called for single-byte encodings. If
-        * not defined, or if the encoding is multibyte, will fall back to
-        * pg_strlower().
-        */
-       char            (*char_tolower) (unsigned char ch, pg_locale_t locale);
 };
 
 /*
@@ -185,8 +178,6 @@ extern pg_locale_t pg_newlocale_from_collation(Oid collid);
 extern char *get_collation_actual_version(char collprovider, const char *collcollate);
 
 extern bool char_is_cased(char ch, pg_locale_t locale);
-extern bool char_tolower_enabled(pg_locale_t locale);
-extern char char_tolower(unsigned char ch, pg_locale_t locale);
 extern size_t pg_strlower(char *dst, size_t dstsize,
                                                  const char *src, ssize_t srclen,
                                                  pg_locale_t locale);