BETWEEN works with literal bounds and fails with a column bound. The failure differs by whether a schema is attached, so both paths are given separately below — an earlier draft showed the schema-less emission under text that read as though it were the general case.
All re-measured at 80f76b1a. Pre-existing; verified against a control clone of the merge-base.
This also corrects an earlier note describing it as "d BETWEEN ts AND ts fails — same column twice": the repetition is irrelevant, and it is not restricted to dates.
Schema-LESS — a client-side throw, before any query is built
Measured through the bridge, which is the production path when no schema is attached:
d BETWEEN ts AND ts2 -> IllegalArgumentException: Unsupported out type for range query: ANY
n BETWEEN lo AND hi -> IllegalArgumentException: Unsupported out type for range query: ANY
d BETWEEN '2025-01-01' AND '2025-12-31'
-> {"range":{"d":{"gte":"2025-01-01","lte":"2025-12-31"}}} ✅
The numeric row is the point: this is not a temporal defect.
The mixed literal/column form, same path
A range query is emitted carrying a Painless expression — and a re-quoted literal — as string bounds:
{"range":{"d":{"gte":"\"2025-01-01\"","lte":"(doc['ts'].size() == 0 ? null : doc['ts'].value)"}}}
Executed against a real index:
400 parse_exception: failed to parse date field ["2025-01-01"] with format
[strict_date_optional_time||epoch_millis]
Schema-CARRYING — a script, and a different failure
Here the same SQL reaches Painless instead. Column bounds emit relational operators:
d BETWEEN ts AND ts2 -> param1 >= param2 && param1 <= param3
n BETWEEN lo AND hi -> param1 >= param2 && param1 <= param3
Correct for numerics (executed: true). On temporals the doc-values are ZonedDateTime objects:
400 class_cast_exception: Cannot apply [>] operation to types
[java.time.ZonedDateTime] and [java.time.ZonedDateTime]
The mixed form takes a third shape again — compareTo against the literal, and against the column:
d BETWEEN '2025-01-01' AND ts
-> param1.compareTo("2025-01-01") >= 0 && param1.compareTo(param2) <= 0
ZonedDateTime.compareTo(String) does not exist.
Relationship to the column-vs-column fix
#373's item 4 fixed this family for binary comparison — a column compared with another column now runs as a script. BETWEEN never reaches that code: schema-less it throws while the range query is being built, and schema-carrying it takes the check path that emits raw >=/<= rather than the temporal isBefore/isAfter dispatch. The control diff confirms that fix moved none of these shapes.
Adjacent
A BETWEEN whose bounds reference an undeclared column was invisible to the computed-column reference walk until #376, because the bounds live in a FromTo, which is not a PainlessScript. That half is fixed; this one is not.
BETWEENworks with literal bounds and fails with a column bound. The failure differs by whether a schema is attached, so both paths are given separately below — an earlier draft showed the schema-less emission under text that read as though it were the general case.All re-measured at
80f76b1a. Pre-existing; verified against a control clone of the merge-base.This also corrects an earlier note describing it as "
d BETWEEN ts AND tsfails — same column twice": the repetition is irrelevant, and it is not restricted to dates.Schema-LESS — a client-side throw, before any query is built
Measured through the bridge, which is the production path when no schema is attached:
The numeric row is the point: this is not a temporal defect.
The mixed literal/column form, same path
A
rangequery is emitted carrying a Painless expression — and a re-quoted literal — as string bounds:{"range":{"d":{"gte":"\"2025-01-01\"","lte":"(doc['ts'].size() == 0 ? null : doc['ts'].value)"}}}Executed against a real index:
Schema-CARRYING — a script, and a different failure
Here the same SQL reaches Painless instead. Column bounds emit relational operators:
Correct for numerics (executed:
true). On temporals the doc-values areZonedDateTimeobjects:The mixed form takes a third shape again —
compareToagainst the literal, and against the column:ZonedDateTime.compareTo(String)does not exist.Relationship to the column-vs-column fix
#373's item 4 fixed this family for binary comparison — a column compared with another column now runs as a script.
BETWEENnever reaches that code: schema-less it throws while the range query is being built, and schema-carrying it takes thecheckpath that emits raw>=/<=rather than the temporalisBefore/isAfterdispatch. The control diff confirms that fix moved none of these shapes.Adjacent
A
BETWEENwhose bounds reference an undeclared column was invisible to the computed-column reference walk until #376, because the bounds live in aFromTo, which is not aPainlessScript. That half is fixed; this one is not.