=== Applying patches on top of PostgreSQL commit ID 1887d822f1428637c935b9f5e8be4a2a56fb77c7 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Mon Mar 2 16:09:22 UTC 2026 On branch cf/6174 nothing to commit, working tree clean === using 'git am' to apply patch ./v1-0001-Fix-crash-introduced-by-incorrect-backport-806555.patch === Applying: Fix crash introduced by incorrect backport 806555e300. Using index info to reconstruct a base tree... M contrib/ltree/crc32.c M contrib/ltree/lquery_op.c Falling back to patching base and 3-way merge... Auto-merging contrib/ltree/lquery_op.c CONFLICT (content): Merge conflict in contrib/ltree/lquery_op.c Auto-merging contrib/ltree/crc32.c CONFLICT (content): Merge conflict in contrib/ltree/crc32.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Fix crash introduced by incorrect backport 806555e300. When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M contrib/ltree/crc32.c M contrib/ltree/lquery_op.c === using patch(1) to apply patch ./v1-0001-Fix-crash-introduced-by-incorrect-backport-806555.patch === patching file contrib/ltree/crc32.c Hunk #1 FAILED at 32. 1 out of 1 hunk FAILED -- saving rejects to file contrib/ltree/crc32.c.rej patching file contrib/ltree/lquery_op.c Hunk #1 FAILED at 96. 1 out of 1 hunk FAILED -- saving rejects to file contrib/ltree/lquery_op.c.rej Removing contrib/ltree/crc32.c.rej Removing contrib/ltree/lquery_op.c.rej === using 'git apply' to apply patch ./v1-0001-Fix-crash-introduced-by-incorrect-backport-806555.patch === Applied patch to 'contrib/ltree/crc32.c' with conflicts. Applied patch to 'contrib/ltree/lquery_op.c' with conflicts. U contrib/ltree/crc32.c U contrib/ltree/lquery_op.c diff --cc contrib/ltree/crc32.c index d21bed31fdd,0aa6e08c61e..00000000000 --- a/contrib/ltree/crc32.c +++ b/contrib/ltree/crc32.c @@@ -32,18 -32,29 +32,35 @@@ ltree_crc32_sz(const char *buf, int siz INIT_TRADITIONAL_CRC32(crc); while (size > 0) { ++<<<<<<< ours + char foldstr[UNICODE_CASEMAP_BUFSZ]; + int srclen = pg_mblen_range(p, end); + size_t foldlen; ++======= + if (locale->ctype_is_c) + { + char c = pg_ascii_tolower(*p); ++>>>>>>> theirs - /* 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 --cc contrib/ltree/lquery_op.c index e6a1969c3d3,f4a507a27c7..00000000000 --- a/contrib/ltree/lquery_op.c +++ b/contrib/ltree/lquery_op.c @@@ -73,69 -76,81 +73,99 @@@ compare_subnode(ltree_level *t, char *q } /* - * Check if 'a' is a prefix of 'b'. - */ -bool -ltree_prefix_eq(const char *a, size_t a_sz, const char *b, size_t b_sz) -{ - if (a_sz > b_sz) - return false; - else - return (strncmp(a, b, a_sz) == 0); -} - -/* - * Case-insensitive check if 'a' is a prefix of 'b'. + * Check if the label matches the predicate string. If 'prefix' is true, then + * the predicate string is treated as a prefix. If 'ci' is true, then the + * predicate string is case-insensitive (and locale-aware). */ bool -ltree_prefix_eq_ci(const char *a, size_t a_sz, const char *b, size_t b_sz) +ltree_label_match(const char *pred, size_t pred_len, const char *label, + size_t label_len, bool prefix, bool ci) { static pg_locale_t locale = NULL; ++<<<<<<< ours + char *fpred; /* casefolded predicate */ + size_t fpred_len = pred_len; + char *flabel; /* casefolded label */ + size_t flabel_len = label_len; + size_t len; ++======= + size_t al_sz = a_sz + 1; + size_t al_len; + char *al; + size_t bl_sz = b_sz + 1; + size_t bl_len; + char *bl; ++>>>>>>> theirs bool res; - if (!locale) - locale = pg_newlocale_from_collation(DEFAULT_COLLATION_OID); + /* fast path for binary match or binary prefix match */ + if ((pred_len == label_len || (prefix && pred_len < label_len)) && + strncmp(pred, label, pred_len) == 0) + return true; + else if (!ci) + return false; ++<<<<<<< ours + /* + * Slow path for case-insensitive comparison: case fold and then compare. + * This path is necessary even if pred_len > label_len, because the byte + * lengths may change after casefolding. + */ + if (!locale) + locale = pg_database_locale(); ++======= + 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 */ ++>>>>>>> theirs - al_len = pg_strfold(al, al_sz, a, a_sz, locale); - if (al_len + 1 > al_sz) + fpred = palloc(fpred_len + 1); + len = pg_strfold(fpred, fpred_len + 1, pred, pred_len, locale); + if (len > fpred_len) { /* grow buffer if needed and retry */ - al_sz = al_len + 1; - al = repalloc(al, al_sz); - al_len = pg_strfold(al, al_sz, a, a_sz, locale); - Assert(al_len + 1 <= al_sz); + fpred_len = len; + fpred = repalloc(fpred, fpred_len + 1); + len = pg_strfold(fpred, fpred_len + 1, pred, pred_len, locale); } + Assert(len <= fpred_len); + fpred_len = len; - bl_len = pg_strfold(bl, bl_sz, b, b_sz, locale); - if (bl_len + 1 > bl_sz) + flabel = palloc(flabel_len + 1); + len = pg_strfold(flabel, flabel_len + 1, label, label_len, locale); + if (len > flabel_len) { /* grow buffer if needed and retry */ - bl_sz = bl_len + 1; - bl = repalloc(bl, bl_sz); - bl_len = pg_strfold(bl, bl_sz, b, b_sz, locale); - Assert(bl_len + 1 <= bl_sz); + flabel_len = len; + flabel = repalloc(flabel, flabel_len + 1); + len = pg_strfold(flabel, flabel_len + 1, label, label_len, locale); } + Assert(len <= flabel_len); + flabel_len = len; - if (al_len > bl_len) - res = false; + if ((fpred_len == flabel_len || (prefix && fpred_len < flabel_len)) && + strncmp(fpred, flabel, fpred_len) == 0) + res = true; else - res = (strncmp(al, bl, al_len) == 0); + res = false; - pfree(al); - pfree(bl); + pfree(fpred); + pfree(flabel); return res; }