Remove lc_ctype_is_c().
authorJeff Davis <[email protected]>
Fri, 6 Sep 2024 20:23:21 +0000 (13:23 -0700)
committerJeff Davis <[email protected]>
Fri, 6 Sep 2024 20:23:21 +0000 (13:23 -0700)
Instead always fetch the locale and look at the ctype_is_c field.

hba.c relies on regexes working for the C locale without needing
catalog access, which worked before due to a special case for
C_COLLATION_OID in lc_ctype_is_c(). Move the special case to
pg_set_regex_collation() now that lc_ctype_is_c() is gone.

Author: Andreas Karlsson
Discussion: https://postgr.es/m/60929555-4709-40a7-b136-bcb44cff5a3c@proxel.se

src/backend/regex/regc_pg_locale.c
src/backend/utils/adt/formatting.c
src/backend/utils/adt/like.c
src/backend/utils/adt/like_support.c
src/backend/utils/adt/pg_locale.c
src/include/catalog/pg_collation.dat
src/include/utils/pg_locale.h

index 35361c46a60ed8103a88870c89ed13e300e5aa2d..8f34948ad37cbce3c0f27254992dced7ed132fed 100644 (file)
@@ -246,9 +246,13 @@ pg_set_regex_collation(Oid collation)
                                 errhint("Use the COLLATE clause to set the collation explicitly.")));
        }
 
-       if (lc_ctype_is_c(collation))
+       if (collation == C_COLLATION_OID)
        {
-               /* C/POSIX collations use this path regardless of database encoding */
+               /*
+                * Some callers expect regexes to work for C_COLLATION_OID before
+                * catalog access is available, so we can't call
+                * pg_newlocale_from_collation().
+                */
                strategy = PG_REGEX_STRATEGY_C;
                collation = C_COLLATION_OID;
        }
@@ -261,7 +265,17 @@ pg_set_regex_collation(Oid collation)
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("nondeterministic collations are not supported for regular expressions")));
 
-               if (locale->provider == COLLPROVIDER_BUILTIN)
+               if (locale->ctype_is_c)
+               {
+                       /*
+                        * C/POSIX collations use this path regardless of database
+                        * encoding
+                        */
+                       strategy = PG_REGEX_STRATEGY_C;
+                       locale = 0;
+                       collation = C_COLLATION_OID;
+               }
+               else if (locale->provider == COLLPROVIDER_BUILTIN)
                {
                        Assert(GetDatabaseEncoding() == PG_UTF8);
                        strategy = PG_REGEX_STRATEGY_BUILTIN;
@@ -274,6 +288,7 @@ pg_set_regex_collation(Oid collation)
 #endif
                else
                {
+                       Assert(locale->provider == COLLPROVIDER_LIBC);
                        if (GetDatabaseEncoding() == PG_UTF8)
                                strategy = PG_REGEX_STRATEGY_LIBC_WIDE;
                        else
index 33a810b008d1b251b132e17135463ba0b1a8fea8..68fa89418ff54dd736b2ff1f2610e14102490c2c 100644 (file)
@@ -1636,6 +1636,7 @@ char *
 str_tolower(const char *buff, size_t nbytes, Oid collid)
 {
        char       *result;
+       pg_locale_t mylocale;
 
        if (!buff)
                return NULL;
@@ -1653,17 +1654,15 @@ str_tolower(const char *buff, size_t nbytes, Oid collid)
                                 errhint("Use the COLLATE clause to set the collation explicitly.")));
        }
 
+       mylocale = pg_newlocale_from_collation(collid);
+
        /* C/POSIX collations use this path regardless of database encoding */
-       if (lc_ctype_is_c(collid))
+       if (mylocale->ctype_is_c)
        {
                result = asc_tolower(buff, nbytes);
        }
        else
        {
-               pg_locale_t mylocale;
-
-               mylocale = pg_newlocale_from_collation(collid);
-
 #ifdef USE_ICU
                if (mylocale->provider == COLLPROVIDER_ICU)
                {
@@ -1774,6 +1773,7 @@ char *
 str_toupper(const char *buff, size_t nbytes, Oid collid)
 {
        char       *result;
+       pg_locale_t mylocale;
 
        if (!buff)
                return NULL;
@@ -1791,17 +1791,15 @@ str_toupper(const char *buff, size_t nbytes, Oid collid)
                                 errhint("Use the COLLATE clause to set the collation explicitly.")));
        }
 
+       mylocale = pg_newlocale_from_collation(collid);
+
        /* C/POSIX collations use this path regardless of database encoding */
-       if (lc_ctype_is_c(collid))
+       if (mylocale->ctype_is_c)
        {
                result = asc_toupper(buff, nbytes);
        }
        else
        {
-               pg_locale_t mylocale;
-
-               mylocale = pg_newlocale_from_collation(collid);
-
 #ifdef USE_ICU
                if (mylocale->provider == COLLPROVIDER_ICU)
                {
@@ -1954,6 +1952,7 @@ str_initcap(const char *buff, size_t nbytes, Oid collid)
 {
        char       *result;
        int                     wasalnum = false;
+       pg_locale_t mylocale;
 
        if (!buff)
                return NULL;
@@ -1971,17 +1970,15 @@ str_initcap(const char *buff, size_t nbytes, Oid collid)
                                 errhint("Use the COLLATE clause to set the collation explicitly.")));
        }
 
+       mylocale = pg_newlocale_from_collation(collid);
+
        /* C/POSIX collations use this path regardless of database encoding */
-       if (lc_ctype_is_c(collid))
+       if (mylocale->ctype_is_c)
        {
                result = asc_initcap(buff, nbytes);
        }
        else
        {
-               pg_locale_t mylocale;
-
-               mylocale = pg_newlocale_from_collation(collid);
-
 #ifdef USE_ICU
                if (mylocale->provider == COLLPROVIDER_ICU)
                {
index 131616fa6b8d2805ea7a1ebf4be7c0cbf0520b7c..f87675d7557460c6ac2e86b1aab40e105823260f 100644 (file)
@@ -147,7 +147,7 @@ SB_lower_char(unsigned char c, pg_locale_t locale, bool locale_is_c)
 static inline int
 GenericMatchText(const char *s, int slen, const char *p, int plen, Oid collation)
 {
-       if (collation && !lc_ctype_is_c(collation))
+       if (collation)
        {
                pg_locale_t locale = pg_newlocale_from_collation(collation);
 
index fb9291441d34430364486bc6ed5c8c47ede2c596..79c4ddc7573f235036d7a5bc5c8b81f7c471eae5 100644 (file)
@@ -100,7 +100,7 @@ static Selectivity regex_selectivity(const char *patt, int pattlen,
                                                                         bool case_insensitive,
                                                                         int fixed_prefix_len);
 static int     pattern_char_isalpha(char c, bool is_multibyte,
-                                                                pg_locale_t locale, bool locale_is_c);
+                                                                pg_locale_t locale);
 static Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc,
                                                                  Oid collation);
 static Datum string_to_datum(const char *str, Oid datatype);
@@ -1000,7 +1000,6 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation,
                                match_pos;
        bool            is_multibyte = (pg_database_encoding_max_length() > 1);
        pg_locale_t locale = 0;
-       bool            locale_is_c = false;
 
        /* the right-hand const is type text or bytea */
        Assert(typeid == BYTEAOID || typeid == TEXTOID);
@@ -1024,11 +1023,7 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation,
                                         errhint("Use the COLLATE clause to set the collation explicitly.")));
                }
 
-               /* If case-insensitive, we need locale info */
-               if (lc_ctype_is_c(collation))
-                       locale_is_c = true;
-               else
-                       locale = pg_newlocale_from_collation(collation);
+               locale = pg_newlocale_from_collation(collation);
        }
 
        if (typeid != BYTEAOID)
@@ -1065,7 +1060,7 @@ like_fixed_prefix(Const *patt_const, bool case_insensitive, Oid collation,
 
                /* Stop if case-varying character (it's sort of a wildcard) */
                if (case_insensitive &&
-                       pattern_char_isalpha(patt[pos], is_multibyte, locale, locale_is_c))
+                       pattern_char_isalpha(patt[pos], is_multibyte, locale))
                        break;
 
                match[match_pos++] = patt[pos];
@@ -1499,16 +1494,16 @@ regex_selectivity(const char *patt, int pattlen, bool case_insensitive,
  */
 static int
 pattern_char_isalpha(char c, bool is_multibyte,
-                                        pg_locale_t locale, bool locale_is_c)
+                                        pg_locale_t locale)
 {
-       if (locale_is_c)
+       if (locale->ctype_is_c)
                return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
        else if (is_multibyte && IS_HIGHBIT_SET(c))
                return true;
-       else if (locale && locale->provider == COLLPROVIDER_ICU)
+       else if (locale->provider == COLLPROVIDER_ICU)
                return IS_HIGHBIT_SET(c) ||
                        (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
-       else if (locale && locale->provider == COLLPROVIDER_LIBC)
+       else if (locale->provider == COLLPROVIDER_LIBC)
                return isalpha_l((unsigned char) c, locale->info.lt);
        else
                return isalpha((unsigned char) c);
index cb9f1b4f78e59c6761ad1fa1a59631b03b685179..a738da5674fe81d283c7e2683b2465a3f2689b2e 100644 (file)
@@ -1266,32 +1266,6 @@ lookup_collation_cache(Oid collation)
        return cache_entry;
 }
 
-/*
- * Detect whether collation's LC_CTYPE property is C
- */
-bool
-lc_ctype_is_c(Oid collation)
-{
-       /*
-        * If we're asked about "collation 0", return false, so that the code will
-        * go into the non-C path and report that the collation is bogus.
-        */
-       if (!OidIsValid(collation))
-               return false;
-
-       /*
-        * If we're asked about the built-in C/POSIX collations, we know that.
-        */
-       if (collation == C_COLLATION_OID ||
-               collation == POSIX_COLLATION_OID)
-               return true;
-
-       /*
-        * Otherwise, we have to consult pg_collation, but we cache that.
-        */
-       return pg_newlocale_from_collation(collation)->ctype_is_c;
-}
-
 /* simple subroutine for reporting errors from newlocale() */
 static void
 report_newlocale_failure(const char *localename)
index f1262012760713191d1af16239ca4ab4aa5255fb..af5c9aa5824f48173ccd321073938a98a5941b82 100644 (file)
@@ -19,8 +19,7 @@
   descr => 'standard C collation',
   collname => 'C', collprovider => 'c', collencoding => '-1',
   collcollate => 'C', collctype => 'C' },
-{ oid => '951', oid_symbol => 'POSIX_COLLATION_OID',
-  descr => 'standard POSIX collation',
+{ oid => '951', descr => 'standard POSIX collation',
   collname => 'POSIX', collprovider => 'c', collencoding => '-1',
   collcollate => 'POSIX', collctype => 'POSIX' },
 { oid => '962', descr => 'sorts by Unicode code point, C character semantics',
index 8ec24437f4d5809548a934f2434ed182baec2af6..ab1c37a44b31b46a7fa4876826b6a86672667c71 100644 (file)
@@ -54,8 +54,6 @@ extern PGDLLIMPORT bool database_ctype_is_c;
 extern bool check_locale(int category, const char *locale, char **canonname);
 extern char *pg_perm_setlocale(int category, const char *locale);
 
-extern bool lc_ctype_is_c(Oid collation);
-
 /*
  * Return the POSIX lconv struct (contains number/money formatting
  * information) with locale information for all categories.