Skip to content

Quoted value set element with surrounding whitespace is refused for temporal sets; PostgreSQL accepts it #70

Closed

Description

@CaffeinatedCoder

A temporal value set throws on a quoted element with leading or trailing whitespace, but PostgreSQL accepts it. This is the value-set version of #45.

DateSet.Parse("{\" 2026-01-01\"}", null); // FormatException
TimeSet.Parse("{\" 09:00\"}", null);      // FormatException
Int32Set.Parse("{\" 1\"}", null);         // {1}, because int.Parse trims
SELECT '{" 2026-01-01"}'::date[]; -- {2026-01-01}
SELECT '{" 09:00"}'::time[];      -- {09:00:00}
SELECT '{" ab"}'::text[];         -- {" ab"}: textin keeps it

array_in hands a quoted element to the element input function with its whitespace intact. date_in, time_in, timestamp_in, timestamptz_in, int4in and numeric_in strip ASCII whitespace from both ends (measured on PostgreSQL 17, see #45). textin keeps it. So trimming can't happen in SetFormat for every family: StringSet and the string wrapper arities have to keep the space. It belongs to the families whose PostgreSQL input function trims.

Before matching it, measure uuid_in and the NodaTime families' store types (date, timestamp, timestamptz, time, and YearMonthSet's date). It fails loudly and only accepts more, so it fits a minor release.

Found while fixing #45.

Activity

  1. added this to the 9.1.0 milestone on Oct 17, 2026
  2. added
    bugSomething isn't working
    area/value-setsValue set families and wrapper arities
    package/nodatimeAffects CodoMetis.ValueRanges.NodaTime
    area/literalsParse, TryParse and formatting
    package/coreAffects CodoMetis.ValueRanges
    severity/lowCosmetic, message or documentation-level difference
    on Oct 17, 2026
  3. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Measured on PostgreSQL 17.10 (postgres:17-alpine)

    For each element type, I tried six ASCII whitespace characters (space, tab, LF, CR, VT, FF) plus U+00A0 and U+2003. The forms were:

    • quoted, at the start, the end, or both: {" x"}
    • backslash-escaped, at the start or the end: {\ x}
    • bare: { x}
    • quoted, whitespace only: {" "}

    array_in itself drops whitespace around a bare element. It passes quoted and escaped whitespace to the element input function.

    Element type (library family) Quoted or escaped ASCII whitespace U+00A0 / U+2003 Whitespace only
    int2, int4, int8, numeric stripped rejected rejected
    date (also infinity), timestamp, timestamptz, time stripped rejected rejected
    uuid rejected (bare is fine, array_in drops it) rejected rejected
    text kept ({" ab"}) kept kept ({" "})

    What the library does today

    • Already the same as PostgreSQL: Int16Set, Int32Set, Int64Set and DecimalSet (the BCL number parsers trim exactly these six characters), and StringSet, which keeps everything.
    • This issue: DateSet, DateTimeSet, DateTimeOffsetSet, TimeSet, LocalDateSet, LocalDateTimeSet, InstantSet, LocalTimeSet and YearMonthSet (stored as date[]) throw on quoted or escaped ASCII whitespace. PostgreSQL strips it.
    • The opposite problem, filed separately for 10.0.0: GuidSet accepts quoted and escaped whitespace, and a no-break space even bare. Guid.Parse trims all Unicode whitespace, but uuid_in rejects it. Fixing that rejects input that parses today.

    Fix for this issue: each temporal family's element parser (ParseValue, which Parse, TryParse, JSON, the TypeConverter and the wrapper arities all use) trims these six characters, and only them. Nothing changes for StringSet or the string wrapper arities.

  4. 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 SetElementWhiteSpaceContractTests and LiteralGrammarParityTests, seed temporal-set-element-whitespace-kept. The failing rows: SetElementWhiteSpaceContractTests (EverySetType_ReadsElementWhitespaceAsItsInputFunctionDoes, 1,080 lines, e.g. DateSet: Parse rejected {" 2024-06-15 "}, expected {2024-06-15}, through Parse, TryParse, TypeConverter and JSON) and LiteralGrammarParityTests (ElementWhitespace_ReadsAsPostgresReadsIt, 324 lines, date[] DateSet {" 2026-01-01"}: library refused, PostgreSQL {2026-01-01}).
    Verified by a run: I reverse-applied #81's src/ diff on 3ecfa10 and ran every registered oracle. These two methods failed, and nothing else did.

  5. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Would be caught today by LiteralCorpusProbeTests (#135). This is retroactive: LiteralGrammarParityTests found it, and #81 fixed it. Row: DateSet whitespace {" 2026-01-01"}, library refused (FormatException), PostgreSQL reads {2026-01-01}. The same happens on every temporal set family and its wrapper arity (BCL and NodaTime), for a trailing space and for {\ …}. Verified by applying test/oracles/seeds/temporal-set-element-whitespace-kept.patch (the revert of #81's fix) to main + #135 and running the class against postgres:17: 16 of 49 rows fail with 48 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 formattingarea/value-setsValue set families and wrapper aritiesbugSomething isn't workingfound-by/oracleFound by the generated-oracle machinery (claims × API surfaces)package/coreAffects CodoMetis.ValueRangespackage/nodatimeAffects CodoMetis.ValueRanges.NodaTimeseverity/lowCosmetic, message or documentation-level difference

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions