On Tue, 2026-01-20 at 12:27 +0700, Александр Кожемякин wrote:
> When executing the following query on branch REL_18_STABLE (first bad
> commit 806555e)
Thank you for the report!
The issue is that the commit in master was dependent on a refactoring
patch, which allowed pg_strfold() to work on any pg_locale_t object,
even if ctype_is_c. Version 18 doesn't have that commit, so it crashed.
It seems to be fine in master, and it was only backported to 18, so the
attached patch is only intended for REL_18_STABLE.
Regards,
Jeff Davis
From 51ee12ca009678a5eac5a4b4e94d0eddb3531c9f Mon Sep 17 00:00:00 2001
From: Jeff Davis <[email protected]>
Date: Wed, 21 Jan 2026 10:26:07 -0800
Subject: [PATCH v1] Fix crash introduced by incorrect backport 806555e300.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit 7f007e4a04 in master depends on 1476028225, but the latter was
not backported. Therefore 806555e300 (the backport of commit
7f007e4a04) incorrectly used pg_strfold() in a locale where
ctype_is_c.
The fix is to simply have the callers check for ctype_is_c.
Because 7f007e4a04 was only backported to version 18, and because the
commit in master is fine, this fix only exists in version 18.
Reported-by: Александр Кожемякин <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
contrib/ltree/crc32.c | 29 ++++++++++++++++++++---------
contrib/ltree/lquery_op.c | 21 +++++++++++++++++++--
2 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/contrib/ltree/crc32.c b/contrib/ltree/crc32.c
index ce1b0f28e21..0aa6e08c61e 100644
--- a/contrib/ltree/crc32.c
+++ b/contrib/ltree/crc32.c
@@ -32,18 +32,29 @@ ltree_crc32_sz(const char *buf, int size)
INIT_TRADITIONAL_CRC32(crc);
while (size > 0)
{
- char foldstr[UNICODE_CASEMAP_BUFSZ];
- int srclen = pg_mblen(p);
- size_t foldlen;
+ if (locale->ctype_is_c)
+ {
+ char c = pg_ascii_tolower(*p);
- /* fold one codepoint at a time */
- foldlen = pg_strfold(foldstr, UNICODE_CASEMAP_BUFSZ, p, srclen,
- locale);
+ COMP_TRADITIONAL_CRC32(crc, &c, 1);
+ size--;
+ p++;
+ }
+ else
+ {
+ char foldstr[UNICODE_CASEMAP_BUFSZ];
+ int srclen = pg_mblen(p);
+ size_t foldlen;
- COMP_TRADITIONAL_CRC32(crc, foldstr, foldlen);
+ /* fold one codepoint at a time */
+ foldlen = pg_strfold(foldstr, UNICODE_CASEMAP_BUFSZ, p, srclen,
+ locale);
- size -= srclen;
- p += srclen;
+ COMP_TRADITIONAL_CRC32(crc, foldstr, foldlen);
+
+ size -= srclen;
+ p += srclen;
+ }
}
FIN_TRADITIONAL_CRC32(crc);
return (unsigned int) crc;
diff --git a/contrib/ltree/lquery_op.c b/contrib/ltree/lquery_op.c
index 9b1de101213..f4a507a27c7 100644
--- a/contrib/ltree/lquery_op.c
+++ b/contrib/ltree/lquery_op.c
@@ -96,15 +96,32 @@ ltree_prefix_eq_ci(const char *a, size_t a_sz, const char *b, size_t b_sz)
static pg_locale_t locale = NULL;
size_t al_sz = a_sz + 1;
size_t al_len;
- char *al = palloc(al_sz);
+ char *al;
size_t bl_sz = b_sz + 1;
size_t bl_len;
- char *bl = palloc(bl_sz);
+ char *bl;
bool res;
if (!locale)
locale = pg_newlocale_from_collation(DEFAULT_COLLATION_OID);
+ if (locale->ctype_is_c)
+ {
+ if (a_sz > b_sz)
+ return false;
+
+ for (int i = 0; i < a_sz; i++)
+ {
+ if (pg_ascii_tolower(a[i]) != pg_ascii_tolower(b[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ al = palloc(al_sz);
+ bl = palloc(bl_sz);
+
/* casefold both a and b */
al_len = pg_strfold(al, al_sz, a, a_sz, locale);
--
2.43.0