Repository navigation
10.x: a predicate over a null range, RangeSet or value set is false in memory and in SQL (port of the predicate half of #350, #355 and #356) #357
Description
Problem
#350, #355 and #356 apply to release/10.x (10.1.0) unchanged. RangeExtensions.cs is identical on both lines, and the SQL measured for #355 is identical on EF Core 10.0.0 and on 10.0.13 with Npgsql 10.0.3.
Change (10.2.0)
The predicate half of rule (c) from #350, which only changes answers and so fits a minor under ### Changed answers:
- SQL (A predicate over a NULL range, RangeSet or value set column is NULL in SQL, so its negation drops the row EF Core's own translations keep #355): every Boolean predicate over a range,
RangeSetor value set operand that can be NULL is writtenx IS NOT NULL AND <predicate>. The exception isCompareToagainst 0 or ±1, which keeps A NULL range column now matches CompareTo(null) > 0 in a query; Comparer treats null vs null as equal #261's documentedComparer<T>.Defaultrule; equality stays EF Core's own. The SQL over required columns and non-null parameters stays the same. - Memory, range extensions with a null range on either side. Measured 2026-10-24,
DateRangeagainstEmpty,(,), a finite range, an element,{p}and{}:true→false(changed answers):Contains(Empty),Contains(RangeSet.Empty)andIsContainedBy((,))on a null range.NullReferenceException→false:Contains(T)on a null range. With a non-emptyRangeSetoperand,Overlaps,IsAdjacentToandIsContainedByon a null range. And every predicate whoseRangeSetargument is null (p.Contains(null),p.Overlaps(null),p.IsStrictlyLeftOf(null), …).- Already
false, unchanged:IsEmpty,IsFinite,IsInfinity,IsUnboundedStart,IsUnboundedEnd,LowerBoundInclusiveandUpperBoundInclusive. Also, with a range operand on either side,Overlaps,IsAdjacentTo, the four position operators, andContainsandIsContainedByapart from the two rows above.
RangeSet.From(RangeSet.From accepts a null element: the set holds null, IsEmpty() is false and Contains throws #356, PR fix: a range set refuses a null range instead of storing it #370): throwsArgumentExceptionfor a null element, as the value sets do. SoExceptandUnionon a null range throwArgumentExceptiontoo. Today they build a set holdingnullor throw, andnull.Union((,))returns{(,)}. fix: a range set refuses a null range instead of storing it #370 removes 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'sUnion(Infinite).Contains(v)candidate for that reason, and the port removes it on 10.x.
Left as they are on 10.x, documented in docs/ranges.md and docs/efcore.md as undefined on a null range and throwing from 11.0.0:
Intersect(returnsEmpty);Gap(Empty)(returnsEmpty);Gapwith any other operand already throws;Merge(Empty)(returnsnullthrough a non-nullable return type) andMerge((,))(returns(,));Mergewith any other operand already throws.
Four of #350's twelve candidates therefore stay registered on 10.x: Intersect(p) != null, Intersect(p) == Empty, Gap(Empty).IsEmpty() and Merge(Infinite) == x. Union(Infinite).Contains(v) is fixed by #356, because memory throws for it.
Changelog: one ### Changed answers row per issue in [10.2.0], linking it and its docs/migration.md#changed-answers-in-1020 entry, in all the package changelogs it affects. Needs #331 to open 10.2.0 first.
Done when
On release/10.x, the widened #355 sweep passes on PostgreSQL 16 and 18 with only those four candidates left. The in-memory rows above are pinned by a test that fails with each change reverted. Close by hand after the merge.
Activity
CaffeinatedCoder commentedon Oct 24, 2026
Both
mainsources are ready to port: #370 (merged as ded685a, #356) and #371 (#355 with #350's predicate half, open). Cherry-pickf4f05dd, then #371's commit, with-x. On 10.x, remove the same eight #350 candidates:Union(Infinite).Contains(v)and the seven predicates. Four stay, as onmainuntil #350's 11.0.0 half; on 10.x they stay for good and get documented. Run every seed that patchesRangeExtensions.cs,RangeSet.csor either method-call translator withtools/oracles.cs seedson the branch. Onmain,range-against-set-reads-first-element-for-upper-bound.patchneeded refreshing.CaffeinatedCoder commentedon Oct 24, 2026
Port PR: #373 against
release/10.x, the-xcherry-picks of f4f05dd (#370) and 8bd0048 (#371), with the[10.2.0]changelog rows, the migration subsections under## Changed answers in 10.2.0, and the captured-list pins updated for 10.x'sEmptyCollectionSqlhelper. Locally green on the EF Core floor and 10.0.13, and on PostgreSQL 16 and 18; all fifteen affected seeds are caught on the branch. Candidates 15 → 8.CaffeinatedCoder commentedon Oct 24, 2026
Fixed on
release/10.xby #373, merged as d1180c5: a predicate over a null range, range set or value set isfalsein memory and in SQL, andRangeSet.Fromrefuses a null range withArgumentException.[10.2.0]has the### Changed answersrows, anddocs/migration.mdhas the subsections under## Changed answers in 10.2.0. #350's value-producing half stays 11.0.0-only, documented on 10.x indocs/ranges.md. Ships in 10.2.0 (#358). Closed by hand, sinceClosesacts only onmain.