Skip to content

Context sweep: every translated member in a filter, a negated filter, an ordering, a grouping key, an aggregate and a projection, over required and nullable operands, against LINQ over the loaded rows #362

Open
6 of 6 issues completed

Description

@CaffeinatedCoder

Problem

The differential sweeps evaluate every operation in a Select projection or in raw SQL, over required columns: ShapeMatrixParityTests, and DifferentialFuzzParityTests through FuzzEngine. Their .Where calls are LINQ over the loaded results. EF Core's own rewrites act elsewhere. It simplifies on declared function nullability in a filter (#349). It compensates comparisons and negations over nullable operands (#355). It leaves NULL placement in ORDER BY to the database (#359), and the aggregates skip NULL inputs (#361). Its materializer throws on a NULL read into a non-nullable type (#355). And a filter and a projection can disagree within SQL (#360).

None of that shows in a projection over a required column. That is why #349, severity/high on every required column, was found by a consumer's probe rather than here. Probing this axis by hand over two days found #349, #350, #355, #360 and #361, and the documentation gap #359.

Change

A sweep with two new axes, on top of the shapes and operand kinds the existing sweeps vary:

  • Query context:
    • a projection;
    • Where(op), and Where(!op) for a Boolean;
    • Where(op == null), Where(op != null) and Where((op ?? fallback) <cmp> v) for a nullable result;
    • OrderBy(op) and OrderByDescending(op), each ThenBy(Id), for a comparable result;
    • a GroupBy(op) key, with counts;
    • an aggregate input, over a group holding NULLs;
    • a filter on a projected value (Select(r => new { V = op }).Where(x => x.V == null)).
  • Operand nullability: a required column; a nullable column holding NULL, in a database of its own as in PredicatesOverANullableColumn; a captured parameter, null and not null; an inlined constant.

The members are discovered, as the probes discover types: every translated range, RangeSet and value set member. Each operation is written once and spliced onto the column (FuzzEngine.Splice). The oracle is LINQ to Objects over the loaded rows. A row whose in-memory call throws is left out, and #350's rule (c) decides which rows those are. A pairwise covering array over member × context × nullability × shape keeps the run time bounded.

Documented differences are expectations, not findings. These are NULL placement in ORDER BY (docs/ranges.md#sort-ranges, #359), CompareTo with a null (#220, #253, #256, #261), and the rows of docs/architecture.md#domain-width-and-the-boundary. The sweep reads them from one place and asserts them, so a documented difference can neither fail the sweep nor hide a new disagreement in the same row.

A static half goes beside it: a test that lists every SqlFunctionExpression the translators emit (name, nullable, argumentsPropagateNullability). It checks each against PostgreSQL's pg_proc.proisstrict, and against a probe for a NULL from non-null inputs. That is the check #349 (lower/upper) and #360 (array_cat) needed. Measured by hand on 2026-10-24, every other range function the translators emit is strict and non-null for non-null input. The range constructor and the aggregates are non-strict and declared that way.

Done when

Activity

  1. added
    testsAdds or changes tests only (oracles, harnesses); no library code
    area/rangesRange unions, variants and the shape engines
    area/range-setRangeSet and multirange algebra
    area/value-setsValue set families and wrapper arities
    package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
    on Oct 24, 2026
  2. CaffeinatedCoder commented on Oct 24, 2026

    @CaffeinatedCoder
    OwnerAuthor

    One seed this sweep should be shown to catch exists now: test/oracles/seeds/bound-declared-null-only-for-a-null-argument.patch (#353 reverted, from #372), caught by ExecutedQueryTests today. The two translator seeds range-predicate-over-a-null-column-is-null.patch and value-set-predicate-over-a-null-column-is-null.patch (from #371) are the other pair. The context sweep should catch all three once it replaces those tests.

  3. CaffeinatedCoder commented on Oct 24, 2026

    @CaffeinatedCoder
    OwnerAuthor

    The composition axes this issue describes are swept by #375–#380 in #383: outer joins, two nullable operands (CASE, COALESCE), quantifiers and compound predicates, repeated and compiled execution, filtered aggregates, and the declared-nullability check (pg_proc and server probes per emitted function, and the filter/projection partition per translated value). Findings: #381 and #382 (new), #360 (reach measured there). The context axis this issue names beyond those (ordering, GroupBy keys, inlined constants across every member) and folding the existing #350/#355/#359 tests into one sweep are not done there; this issue stays open for them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/range-setRangeSet and multirange algebraarea/rangesRange unions, variants and the shape enginesarea/value-setsValue set families and wrapper aritiespackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLpackage/efcore-nodatimeAffects CodoMetis.ValueRanges.EFCore.PostgreSQL.NodaTimetestsAdds or changes tests only (oracles, harnesses); no library code

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions