[ 
https://issues.apache.org/jira/browse/FLINK-40845?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ramin Gharib updated FLINK-40845:
---------------------------------
        Parent:     (was: FLINK-40485)
    Issue Type: Bug  (was: Sub-task)

> VARIANT toString() and result printing still fail on an out-of-range TIME 
> value
> -------------------------------------------------------------------------------
>
>                 Key: FLINK-40845
>                 URL: https://issues.apache.org/jira/browse/FLINK-40845
>             Project: Flink
>          Issue Type: Bug
>          Components: API / Core, Table SQL / Runtime
>            Reporter: Ramin Gharib
>            Assignee: Moritz Manner
>            Priority: Minor
>
> FLINK-40828 made \{{Variant#toString()}} and result printing never fail. A 
> \{{TIME}} node whose value is outside one day still makes both of them throw.
> A \{{TIME}} node stores microseconds since midnight. \{{VariantBuilder}} only 
> writes values in \{{[0, 86_400_000_000)}}, but a variant read from bytes 
> written by another engine can hold any 8-byte value.
> ||TIME value (micros)||\{{Variant#toString()}}||Printing 
> (\{{VariantCastUtils#toPrintString}})||
> |\{{-1}}|throws \{{DateTimeException}}|throws \{{DateTimeException}}|
> |\{{Long.MAX_VALUE}}|throws \{{DateTimeException}}|throws 
> \{{DateTimeException}}|
> |\{{Long.MIN_VALUE}}|\{{"00:00:00"}}|\{{00:00:00.0}}|
> The exception is \{{DateTimeException: Invalid value for NanoOfDay (valid 
> values 0 - 86399999999999): -1000}}. \{{Long.MIN_VALUE}} does not throw, but 
> it renders a wrong value, because \{{micros * 1000}} overflows to \{{0}}.
> h3. Cause
> {\{TIME}} is decoded as \{{LocalTime.ofNanoOfDay(micros * 1000)}} in 
> \{{BinaryVariant#getTime}} and in \{{JsonVariantFormatter#appendNode}}. 
> Nothing checks the range, so a bad value surfaces as a 
> \{{DateTimeException}}. The two lenient paths only catch 
> \{{VariantTypeException}}:
> * \{{JsonVariantFormatter#append}}, which backs \{{BinaryVariant#toString()}}.
> * \{{VariantCastUtils#renderValue}} with \{{printing = true}}, which backs 
> \{{VariantToStringCastRule}} when printing.
> The printing path has a second gap. \{{VariantCastUtils#renderScalar}} throws 
> \{{TableRuntimeException}} from its \{{default}} branch, also when printing. 
> Every current \{{Variant.Type}} has a case, but a type added later fails 
> printing until its case is added.
> h3. Proposed fix
> # Range-check \{{TIME}} where it is decoded, and throw 
> \{{BinaryVariantUtil#malformedVariant()}} for a value outside \{{[0, 
> 86_400_000_000)}}. Both lenient paths then render \{{<INVALID>}}. Strict 
> \{{toJson()}} and \{{CAST}} fail with \{{MALFORMED_VARIANT}} instead of a 
> \{{DateTimeException}}. This also fixes the silent \{{Long.MIN_VALUE}} 
> overflow.
> # When printing, render a type without a case as \{{<UNKNOWN>}} instead of 
> throwing. \{{CAST}} keeps throwing.
> h3. Tests
> * \{{JsonVariantFormatterTest}}: \{{toString()}} of an array holding \{{1}} 
> and a \{{TIME}} of \{{-1}} micros returns \{{[1,"<INVALID>"]}}, and 
> \{{toJson()}} throws \{{MALFORMED_VARIANT}}.
> * \{{VariantCastUtilsTest}}: \{{toPrintString}} of the same array returns 
> \{{[1, <INVALID>]}}.
> * \{{BinaryVariantTest}}: \{{getTime()}} of that node throws 
> \{{MALFORMED_VARIANT}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to