Skip to content

list.Contains(rangeColumn) fails with 42809 'op ANY/ALL (array) requires array on right side' #71

Closed

Description

@CaffeinatedCoder

A query that tests whether a range column is one of a captured list of ranges fails on the server:

var ranges = new List<Int32Range> { Int32Range.CreateFinite(1, 5) };
db.Reservations.Where(r => ranges.Contains(r.Seats));
SQL:   WHERE r."Seats" = ANY (@ranges)
Error: PostgresException 42809: op ANY/ALL (array) requires array on right side

It fails loudly. A captured List<RangeSet<Int32Range, int>> against a multirange column translates the same way (= ANY (@multis)) and answered correctly in the same probe. So it is the range collection's parameter that isn't bound as an array.

Found while pinning down #46, the same shape over value sets, which failed earlier, in Npgsql, with InvalidCastException. Not yet checked: the other range families, a constant list, an inline collection. Either translate it or refuse it in translation with a message that says what to write instead.

Activity

  1. added this to the 9.1.0 milestone on Oct 17, 2026
  2. added
    bugSomething isn't working
    area/rangesRange unions, variants and the shape engines
    package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
    severity/mediumInconsistency or failure in a narrow scenario
    on Oct 17, 2026
  3. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Repro pinned down (live PostgreSQL 17, Npgsql EF 10.0.0)

    Only a captured collection fails. Constant and inline collections already translated and answered correctly, and so does every multirange collection.

    Column Captured List<T> / T[] Constant list Inline new[] { a, b }
    Int32Range, Int64Range, DecimalRange, DateRange, DateTimeRange, DateTimeOffsetRange = ANY (@List) → 42809 op ANY/ALL (array) requires array on right side IN ('[1,5]'::int4range, 'empty'::int4range), correct IN (@p, @p0), correct
    TimeRange (custom timerange) = ANY (@List) → InvalidCastException: Writing values of 'NpgsqlRange<TimeOnly>[]' is not supported… correct correct
    LocalDateRange, LocalDateTimeRange, InstantRange, YearMonthRange (NodaTime) 42809, as above correct correct
    RangeSet<Int32Range,int>, RangeSet<DateRange,DateOnly> (multirange) = ANY (@List), correct correct correct

    Cause: the collection reaches Npgsql as a plain NpgsqlRange<T>[] with no DataTypeName, and Npgsql infers that CLR type as a multirange. Measured directly with an untyped NpgsqlRange<int>[] parameter: pg_typeof($1) is int4multirange. With DataTypeName = "int4range[]" it is int4range[]. So the right side of = ANY is a multirange, not an array (42809). NpgsqlRange<TimeOnly>[] has no inferred type at all, hence the InvalidCastException. A multirange collection is NpgsqlRange<T>[][], which Npgsql infers as a multirange array, so it works.

    Decision: translate, as in #46

    Typing the single array parameter as int4range[] would need two Npgsql-internal types (NpgsqlArrayTypeMapping, INpgsqlTypeMapping), and still couldn't type the custom timerange. Instead, the query interceptor from #75 also sends a captured collection of ranges one parameter per range: EF Core's MultipleParameters mode, IN (@p1, @p2, …), with VALUES for Any/Count. Each parameter goes through the range's own mapping, which sets its DataTypeName, so this works for timerange too. It is the same SQL the constant and inline forms already produce, and IN is = against each range, which the shape-matrix tests already hold equal to memory. EF.Parameter(list) asks for the untyped single parameter, so it is refused in translation with a message saying to remove it. Multirange collections already work and are left unchanged.

  4. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Scope change from the plan above. The revert proof showed that Any/Count alone over a captured range list did not fail before. They ran through unnest of the multirange-typed parameter and returned answers different from memory without throwing (overlapping ranges merged, empty ones dropped). So #77 switches a range collection only when a Contains reads it, since those queries failed. EF.Parameter is likewise rejected only as the source of Contains. The silent Any/Count defect is #76 (10.0.0).

  5. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Oracle check (main at 3ecfa10): no oracle on main catches this (pending). I reverse-applied #77's src/ diff on 3ecfa10 and ran every class in oracles.json, including the live ones. All of them stayed green. The fix's own regression tests did fail (RangeCollectionContainsTests: 7 of 9, 42809: op ANY/ALL (array) requires array on right side), which shows the revert put the defect back.
    Gap: the same as #46. The EF Core Operand position axis in axes.md has no captured collection value, and DifferentialFuzzParityTests binds operands only as a column, a constant or a parameter. Claim E37 is held only by RangeCollectionContainsTests and RangeCollectionTranslationTests, which are regression tests. The missing pair is captured collection × every range type, outside route B steps 2 and 3.

  6. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Update: would be caught by CapturedCollectionProbeTests (#138, the probe sweep for the gap named above), method Ranges_AnswerAsInMemory. Verified by a run: I reverse-applied #77's src/ diff on the PR branch, and the sweep failed with 1,540 lines, e.g. DateRange over adjacent as List, beside Contains: Contains threw PostgresException: 42809: op ANY/ALL (array) requires array on right side. Labelled found-by/oracle retroactively.

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/rangesRange unions, variants and the shape enginesbugSomething isn't workingfound-by/oracleFound by the generated-oracle machinery (claims × API surfaces)package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLseverity/mediumInconsistency or failure in a narrow scenario

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions