Repository navigation
test: register #349 and #350 as ExecutedQueryTests candidates - #352
Open
CaffeinatedCoder wants to merge 1 commit into
Open
CaffeinatedCoder wants to merge 1 commit into
CaffeinatedCoder wants to merge 1 commit into
Conversation
Two sweeps in ExecutedQueryTests now end in Candidates.Verdict, compared with LINQ over the rows as loaded. BoundsComparedWithNull runs LowerBound() and UpperBound() against null, HasValue, ?? in a filter and a projection, and a filter on a projected bound over nine shapes in thirteen range columns; all 117 (operation, column) pairs disagree today, one candidate per operation under #349. PredicatesOverANullableColumn runs the twelve predicates of #350 over a nullable DateRange column holding NULL and every shape, one line per row, so only the NULL row is quarantined; one candidate per operation under #350. E70 quotes the bound-null sentence of docs/efcore.md, held by ExecutedQueryTests. With argumentsPropagateNullability: [false] in BoundFunction applied locally, the nine #349 candidates report candidate fixed and nothing else fails; the fix is a separate PR. Closes #351 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 23, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #349
Refs #350
Closes #351
Problem
#349 and #350 were found by a consumer's differential probe (AuditOffice, 2026-10-23), not by an oracle here. Nothing in
ExecutedQueryTestscomparedLowerBound()orUpperBound()withnullinside a query, nothing ran a range predicate over a nullable range column, and no claim quoted thedocs/efcore.mdsentence #349 contradicts. So neither fix would be proven by the suite, and nothing would force the registry entries out when the fixes land. These are candidates, not fixes, which is why the PR refers to #349 and #350 rather than closing them; it closes its own tracking issue, #351.Change
ExecutedQueryTests.BoundsComparedWithNull_SelectTheRowsMemorySelects(LowerBound() and UpperBound() in a query: == null becomes WHERE FALSE and ?? max loses its COALESCE, because lower() and upper() are declared NULL only for a NULL argument #349) seeds nine shapes ([a,b],[a,a],[b,b],(,a],(,b],[a,),[b,),(,), empty) into 13 range columns:Seats,Tickets,Price,Period,LocalTime,InstantTime,NodaPeriod,NodaWallClock,NodaWindow,OpeningHours,Score,LoadandBillingPeriod. Over them it runsLowerBound() == null,LowerBound() != null,LowerBound().HasValue,UpperBound() == null,UpperBound() != null,(UpperBound() ?? max) >= v,(LowerBound() ?? min) <= v,Select(UpperBound() ?? max)andSelect(new { Id, To = UpperBound() }).Where(To == null). Each runs on the server and as LINQ over the rows as loaded. The operation is written once overIRange<T>and spliced onto the column (FuzzEngine.Splice), so the call is the oner.Column.LowerBound()makes. Operands are captured, so they go out as parameters. Each failure line starts with the operation, then the column.ExecutedQueryTests.PredicatesOverANullableColumn_SelectTheRowsMemorySelects(A null range answers some extensions in memory and throws on others, and the answers it gives disagree with PostgreSQL on a NULL column #350) puts a nullableDateRangecolumn, holding NULL and six shapes, in a database of its own, following theRangeOrderParityTestspattern. Over it it runs the twelve predicates of the issue:!IsEmpty(),!IsFinite(),!IsUnboundedEnd(),!UpperBoundInclusive(),!Overlaps(p),Contains(Empty),IsContainedBy(Infinite),Intersect(p) != null,Intersect(p) == Empty,Gap(Empty).IsEmpty(),Union(Infinite).Contains(v)andMerge(Infinite) == x. A row whose in-memory evaluation throws is left out on both sides. Lines are one per row, so each candidate quarantines only the NULL row and the six non-null rows stay judged.test/oracles/candidates.jsongets 21 entries, one per operation, scoped bymethod. Nine belong to LowerBound() and UpperBound() in a query: == null becomes WHERE FALSE and ?? max loses its COALESCE, because lower() and upper() are declared NULL only for a NULL argument #349, family "lower()/upper() declared NULL only for a NULL argument", with rows likeLowerBound() == null on. Twelve belong to A null range answers some extensions in memory and throws on others, and the answers it gives disagree with PostgreSQL on a NULL column #350, family "a null receiver answers in memory where SQL answers NULL", with rows like!IsEmpty() on DateRange? null:.test/oracles/claims.jsongetsE70-bounds-null-for-unbounded-or-empty-in-sql, which quotes "LowerBound()andUpperBound()returnT?. PostgreSQL'slowerandupperreturnNULLfor an unbounded or empty range, and the in-memory methods match that." (docs/efcore.md#read-bounds-merge-ranges-and-aggregate). It is held byExecutedQueryTests.Tests
All runs were local against Docker on SDK
11.0.100-rc.2.26504.105, withExecutedQueryTestsrun as a class.postgres:16-alpineandpostgres:18-alpine): 15/15 pass, with 117SKIPPED [known candidate: …, #349]and 12SKIPPED [known candidate: …, #350]lines.[known candidate: lower()/upper() declared NULL only for a NULL argument], while A null range answers some extensions in memory and throws on others, and the answers it gives disagree with PostgreSQL on a NULL column #350's 12 stay skipped.[known candidate: a null receiver answers in memory where SQL answers NULL], while LowerBound() and UpperBound() in a query: == null becomes WHERE FALSE and ?? max loses its COALESCE, because lower() and upper() are declared NULL only for a NULL argument #349's 117 stay skipped.argumentsPropagateNullability: [false]inBoundFunction,ValueRangesMethodCallTranslator.cs:639): the bound sweep fails with exactly the ninecandidate fixed: remove the entry …lines and no other row. All 117 operation-column pairs now agree, A null range answers some extensions in memory and throws on others, and the answers it gives disagree with PostgreSQL on a NULL column #350's 12 stay skipped, and the other 13 tests pass. The fix was reverted; it belongs in its own PR, which removes the nine LowerBound() and UpperBound() in a query: == null becomes WHERE FALSE and ?? max loses its COALESCE, because lower() and upper() are declared NULL only for a NULL argument #349 entries.dotnet run tools/oracles.cs status: 25 candidates, 0 without an issue, and E70 held.Oracle*TestsplusSeedVerdictTestspass 36/36.Not covered here:
RangeSet'sLowerBound()/UpperBound()go through the same helper (LowerBound() and UpperBound() in a query: == null becomes WHERE FALSE and ?? max loses its COALESCE, because lower() and upper() are declared NULL only for a NULL argument #349 says so), but are not swept.release/10.xport is left for later.🤖 Generated with Claude Code