Skip to content

fix: reject a string set compared with a value under a collation that may not compare bytes (#512, port of #507) - #516

Merged
CaffeinatedCoder merged 5 commits into
release/10.xfrom
fix/512-element-side-collation-10.x
Oct 26, 2026
Merged

CaffeinatedCoder merged 5 commits into
release/10.xfrom
fix/512-element-side-collation-10.x

Conversation

@CaffeinatedCoder

Copy link
Copy Markdown
Owner

Closes #512

Port of #513 (#507) to release/10.x, stacked on #515 (both edit Changed answers in 10.4.0 and the changelogs). Review only the last three commits. The fix and seed commits are cherry-picked with -x and applied without conflicts. The docs commit is re-made for 10.x's layout.

Problem

PostgreSQL takes an operator's collation from both sides, and #496 checks only the string set's own. Take a case-insensitive Owner and Members holding {A,b}:

  • Members.Contains(g.Owner) matched for "a".
  • ExecuteUpdate with Remove(g.Owner) stored {b}.

#496's 10.4.0 row says that class is fixed.

Change

As #513:

10.x specifics:

Tests

On release/10.x, EF Core 10.0.0 floor:

  • Full suite green on PostgreSQL 16, including the new collation tests on a runtime and a compiled model.
  • oracles.cs seeds string-set-collation: both seeds caught by StringSetCollationTests.
  • Newest-patch leg (-p:EfFloat=10.0.13 -p:NpgsqlEfFloat=10.0.3): StringSetCollationIntegrationTests with CompiledModelJsonTests 4/4, and StringSetCollationTests 10/10.
  • PostgreSQL 18: StringSetCollationIntegrationTests, 3/3.

🤖 Generated with Claude Code

CaffeinatedCoder and others added 3 commits October 26, 2026 18:16
… may not compare bytes (#507)

PostgreSQL derives an operator's collation from both sides, and #483 only
checks the set's: a value from a case-insensitive column, or collated by
EF.Functions.Collate, made @>, && and array_remove compare
case-insensitively with the set column uncollated, as the remedy leaves
it. Members.Contains(g.Owner) matched {A,b} for "a", and ExecuteUpdate
with Members.Remove(g.Owner) stored {b}, where memory keeps {A,b}.

The guard's walker now derives the collation of a string set operator's
operands as PostgreSQL does (an explicit COLLATE wins; a column's;
a subquery or set-operation column's projection; what a string-typed
function, operator or array takes from its string inputs; a CASE's
results, not its tests) at @>, <@, &&, array_remove, == and the text set
placeholders, and throws for one that may not compare bytes, naming it.
EF.Functions.Collate(value, "C") compares as memory does. The read-optimized
model a query runs on keeps no collation, so the convention that rejects a
collated string set column names every other non-byte collation on its
property (CodoMetis:ValueRanges:Collation), which a compiled model carries.

StringSetCollationIntegrationTests rejects Contains, !Contains, Remove,
Add().Count, ToLower(), EF.Functions.Collate, a subquery's column and
ExecuteUpdate with Remove on a live server and leaves the row unchanged,
runs "C" and a CASE that only tests the column as memory answers, and
holds the rejection on a compiled model; StringSetCollationTests adds a
derived table's and a set operation's column, a concatenation and a CASE
result. Without the walker check every rejection runs and answers.

Found-By: CA
Defect-Class: SQL

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit cb48b63)
…ation check (#507)

Two seeds, both caught: the guard's element check removed, and the
convention leaving a collated column unnamed, which the read-optimized
model would then hide from the guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 4b4f08b)
…e migration and changelog (#512)

The value set entry in efcore.md gains the value's side and the
EF.Functions.Collate(value, "C") remedy; Check string set columns with a
collation, under Changed answers in 10.4.0, gains it with its before and
after table and the GIN index cost of an explicit "C"; the Changed
answers rows of 10.4.0 in the root and EF Core changelogs link #512;
claim E89.

(cherry picked from commit 6e4be22, with the 10.x changelog and migration layout)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CaffeinatedCoder CaffeinatedCoder added this to the 10.4.0 milestone Oct 26, 2026
@CaffeinatedCoder CaffeinatedCoder added bug Something isn't working silent Answers wrongly without throwing — fixes go in the next major, never deferred area/value-sets Value set families and wrapper arities package/efcore Affects CodoMetis.ValueRanges.EFCore.PostgreSQL severity/medium Inconsistency or failure in a narrow scenario stacked Base is another open PR; merge in order, CI does not run until it targets main labels Oct 26, 2026
Base automatically changed from fix/511-yearmonth-upper-bound-10.x to release/10.x October 26, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/value-sets Value set families and wrapper arities bug Something isn't working package/efcore Affects CodoMetis.ValueRanges.EFCore.PostgreSQL severity/medium Inconsistency or failure in a narrow scenario silent Answers wrongly without throwing — fixes go in the next major, never deferred stacked Base is another open PR; merge in order, CI does not run until it targets main

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant