Skip to content

Quoted range bound with a leading space is refused; PostgreSQL accepts it #45

Closed

Description

@CaffeinatedCoder

A quoted range bound with a leading space is refused, and PostgreSQL accepts it.

DateRange.Parse("[\" 2026-01-01\",2026-02-01)"); // FormatException
SELECT '[" 2026-01-01",2026-02-01)'::daterange; -- [2026-01-01,2026-02-01)

PostgreSQL trims the element before passing it to the element type's input function. The strict ISO grammar here doesn't. It fails loudly, and accepting it only loosens, so it can wait for 9.1.0.

Check which element types PostgreSQL trims for (the numeric ones and the temporal ones may differ) before matching it.

Activity

  1. added this to the 9.1.0 milestone on Oct 17, 2026
  2. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Measured on PostgreSQL 17.10 (postgres:17-alpine, the integration tests' image)

    Every range type here treats whitespace inside a bound the same way. It doesn't matter whether the whitespace is quoted, unquoted or backslash-escaped, or whether it's leading, trailing or both: range_in keeps it all in the bound text, and every element input function strips it from both ends.

    Types: int4range, int8range, numrange, daterange (including -infinity), tsrange, tstzrange, and a custom timerange (subtype = time).

    Whitespace in the bound Leading Trailing Both
    space, tab, LF, CR, VT, FF: quoted " 1", unquoted 1, escaped \ 1 accepted accepted accepted
    U+00A0 no-break space, U+2003 em space refused refused refused
    only whitespace, quoted ([" ",5)) refused (invalid input syntax)

    So no type differs from another, and the numeric and temporal types behave alike. Arrays behave the same way: '{" 1"}'::int4[] is {1} and '{" 2026-01-01"}'::date[] is {2026-01-01}. But '{" ab"}'::text[] keeps the space, because textin doesn't trim.

    Fix: trim the same six ASCII characters (LiteralWhiteSpace) from both ends of a bound's text after unquoting and unescaping, instead of only from its unquoted part. The element grammar is still strict ISO 8601. A bound of only whitespace still throws, and so does a non-ASCII space.

  3. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Oracle check (main at 3ecfa10): Would be caught today (retroactive; no oracle found it at the time) by RangeLiteralGrammarContractTests and LiteralGrammarParityTests, seed quoted-bound-whitespace-kept. The failing rows: RangeLiteralGrammarContractTests (EveryRangeType_ReadsBoundsWithPostgresRangeGrammar, e.g. DateRange [" 2026-01-01","2026-06-30 "): refused, expected [2026-01-01,2026-06-29]) and LiteralGrammarParityTests (BoundWhitespace_ReadsAsPostgresReadsIt and RangeLiterals_ReadAsPostgresReadsThem, daterange [" 2026-01-01",2026-02-01): library refused, PostgreSQL [2026-01-01,2026-01-31]).
    Verified by a run: I reverse-applied #73's src/ diff on 3ecfa10 and ran every class in oracles.json, including the live PostgreSQL ones. These three methods failed, and nothing else did.

  4. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Would be caught today by LiteralCorpusProbeTests (#135). This is retroactive: LiteralGrammarParityTests found it, and #73 fixed it. Row: DateRange whitespace [" 2026-01-01",2026-01-02), library refused (FormatException), PostgreSQL reads [2026-01-01,2026-01-02). The same happens on every temporal range and multirange type, for a trailing space and for [\ …. Verified by applying test/oracles/seeds/quoted-bound-whitespace-kept.patch (the revert of #73's fix) to main + #135 and running the class against postgres:17: 14 of 49 rows fail with 28 lines. That seed now names LiteralCorpusProbeTests too.

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/literalsParse, TryParse and formattingbugSomething isn't workingfound-by/oracleFound by the generated-oracle machinery (claims × API surfaces)package/coreAffects CodoMetis.ValueRangespackage/nodatimeAffects CodoMetis.ValueRanges.NodaTimeseverity/mediumInconsistency or failure in a narrow scenario

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions