Skip to content

RangeIntersectAgg returns empty over a sequence holding a null range, where range_intersect_agg skips the NULL; RangeAgg throws #361

Closed

Description

@CaffeinatedCoder

Problem

docs/ranges.md#aggregate-a-sequence-of-ranges calls RangeAgg() and RangeIntersectAgg() "the in-memory versions of PostgreSQL's range_agg and range_intersect_agg". Those skip NULL inputs, as SQL aggregates do, and so do LINQ's aggregates over nullable values (new int?[] { null, 3, 1 }.Min() is 1). The in-memory RangeAgg and RangeIntersectAgg don't. Measured 2026-10-24 on PostgreSQL 16, with a nullable DateRange column holding NULL, [2026-03-01,2026-03-10], [2026-03-05,2026-03-25] and NULL, in GroupBy(r => 1).Select(g => g.Select(r => r.Maybe!).…):

Aggregate PostgreSQL Memory over the loaded rows
RangeIntersectAgg() [2026-03-05,2026-03-10] empty (silent)
RangeAgg() {[2026-03-01,2026-03-25]} throws InvalidOperationException: Failed to compare two elements in the array.
RangeIntersectAgg() over only NULLs null null

RangeIntersectAgg treats a null range as one that intersects to empty. RangeAgg hands the null to the sort and fails there; with #356's check it would fail with ArgumentNullException instead.

Change

Rule (c) on #350, extended to aggregates: RangeAgg and RangeIntersectAgg skip null ranges, as SQL and LINQ's nullable aggregates do. Over nothing but nulls they return what they return over an empty sequence, which must match SQL's NULL (RangeIntersectAgg returns null today; check RangeAgg). This is in memory only; the SQL is already right.

silent for RangeIntersectAgg; the RangeAgg half turns a throw into a value. A 10.x minor can carry it under ### Changed answers.

Done when

RangeAggregateParityTests runs both aggregates over a nullable column holding NULLs among other shapes, for every family, and compares with memory.

Activity

  1. added this to the 11.0.0 milestone on Oct 24, 2026
  2. added
    bugSomething isn't working
    silentAnswers wrongly without throwing — fixes go in the next major, never deferred
    area/rangesRange unions, variants and the shape engines
    area/range-setRangeSet and multirange algebra
    on Oct 24, 2026
  3. added
    package/coreAffects CodoMetis.ValueRanges
    severity/lowCosmetic, message or documentation-level difference
    breakingChanges an answer or a signature — needs a major
    package/nodatimeAffects CodoMetis.ValueRanges.NodaTime
    on Oct 24, 2026
  4. added 2 commits that reference this issue on Oct 24, 2026
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 enginesbreakingChanges an answer or a signature — needs a majorbugSomething isn't workingpackage/coreAffects CodoMetis.ValueRangespackage/nodatimeAffects CodoMetis.ValueRanges.NodaTimeseverity/lowCosmetic, message or documentation-level differencesilentAnswers wrongly without throwing — fixes go in the next major, never deferred

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions