integralLiteralOfType in WindowBoundConverter guards its FP branches with a narrowing round trip — (long) asDouble == value for fp64 and (long) asFloat == value for fp32. A narrowing double→long cast in Java saturates rather than wrapping, so the guard returns true for Long.MAX_VALUE: (double) Long.MAX_VALUE is 2^63 = 9223372036854775808, and casting that back yields Long.MAX_VALUE = 9223372036854775807. The comparison succeeds even though the value changed.
Measured on fb6a54ad: a RANGE BETWEEN <Long.MAX_VALUE> PRECEDING bound over a DOUBLE ordering column converts to Preceding{FP64Literal{9.223372036854776E18}}, an offset one greater than the value in the plan. Every long above 2^53 that is not exactly representable as a double takes the same path, and the fp32 branch has the same shape above 2^24 — rangeOffsetFailingFloatRoundTripThrows covers 2^24+1, just below the magnitude where saturation starts masking the mismatch.
Comparing in the wider direction rejects these instead: BigDecimal.valueOf(asDouble).compareTo(BigDecimal.valueOf(value)) == 0, or a magnitude bound of 2^53 for fp64 and 2^24 for fp32.
This is pre-existing behavior, but #1206 makes the branch throw when it rejects rather than fall through to the literal's own type, so a false accept now silently emits a wrong offset where a true reject would be loud.
integralLiteralOfTypeinWindowBoundConverterguards its FP branches with a narrowing round trip —(long) asDouble == valueforfp64and(long) asFloat == valueforfp32. A narrowingdouble→longcast in Java saturates rather than wrapping, so the guard returns true forLong.MAX_VALUE:(double) Long.MAX_VALUEis 2^63 = 9223372036854775808, and casting that back yieldsLong.MAX_VALUE= 9223372036854775807. The comparison succeeds even though the value changed.Measured on
fb6a54ad: aRANGE BETWEEN <Long.MAX_VALUE> PRECEDINGbound over aDOUBLEordering column converts toPreceding{FP64Literal{9.223372036854776E18}}, an offset one greater than the value in the plan. Everylongabove 2^53 that is not exactly representable as adoubletakes the same path, and thefp32branch has the same shape above 2^24 —rangeOffsetFailingFloatRoundTripThrowscovers 2^24+1, just below the magnitude where saturation starts masking the mismatch.Comparing in the wider direction rejects these instead:
BigDecimal.valueOf(asDouble).compareTo(BigDecimal.valueOf(value)) == 0, or a magnitude bound of 2^53 forfp64and 2^24 forfp32.This is pre-existing behavior, but #1206 makes the branch throw when it rejects rather than fall through to the literal's own type, so a false accept now silently emits a wrong offset where a true reject would be loud.