You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@flink.apache.org by "Ramin Gharib (Jira)" <ji...@apache.org> on 2026/09/27 14:49:00 UTC

[jira] [Created] (FLINK-40825) Support casting primitive types to VARIANT

Ramin Gharib created FLINK-40825:
------------------------------------

             Summary: Support casting primitive types to VARIANT
                 Key: FLINK-40825
                 URL: https://issues.apache.org/jira/browse/FLINK-40825
             Project: Flink
          Issue Type: Sub-task
          Components: Table SQL / API
            Reporter: Ramin Gharib
            Assignee: Ramin Gharib


FLIP-521 lists the types that can be cast to and from VARIANT. FLINK-37925 and FLINK-37926 implemented the direction VARIANT to SQL type. The direction SQL type to VARIANT is still missing: \{{SqlCastFunction}} rejects every cast to VARIANT (see the TODO in \{{canCastFrom}}).

This ticket adds \{{CAST}} and \{{TRY_CAST}} from primitive types to VARIANT. Constructed types (ARRAY, MAP, ROW, STRUCTURED) follow in separate sub-tasks.

h3. Rule

A type can be cast to VARIANT only if a VARIANT kind holds its value without loss. Any other type is rejected at validation time, never at runtime. The cast is explicit only.

||Source type||Stored VARIANT kind||
|BOOLEAN|BOOLEAN|
|TINYINT, SMALLINT, INTEGER, BIGINT|TINYINT, SMALLINT, INT, BIGINT|
|FLOAT, DOUBLE|FLOAT, DOUBLE|
|DECIMAL(p, s)|DECIMAL|
|CHAR, VARCHAR|STRING|
|BINARY, VARBINARY|BYTES|
|DATE, TIME, UUID|DATE, TIME, UUID|
|TIMESTAMP(p), TIMESTAMP_LTZ(p)|TIMESTAMP, TIMESTAMP_LTZ, or the nanosecond kinds when the value has digits below a microsecond|

Rejected: INTERVAL, TIMESTAMP WITH TIME ZONE, RAW, BITMAP, SYMBOL, DESCRIPTOR, MULTISET, and the constructed types for now.

h3. Semantics

{code:sql}
CAST(CAST(1 AS BIGINT) AS VARIANT)            -- 1, stored as BIGINT
CAST(42 AS VARIANT)                           -- 42, stored as INT
CAST('\{"a": 1}' AS VARIANT)                   -- the string '\{"a": 1}', not an object
CAST(CAST(NULL AS INT) AS VARIANT)            -- SQL NULL, not a variant null
CAST(CAST('NaN' AS DOUBLE) AS VARIANT)        -- NaN, stored as DOUBLE
CAST(INTERVAL '2' DAY AS VARIANT)             -- fails at validation
CAST(ARRAY[1, 2] AS VARIANT)                  -- fails at validation, follow-up
{code}

* An integer keeps the width of its SQL type. \{{PARSE_JSON('1')}} picks the smallest kind because JSON text has no width, but a cast keeps the declared type.
* A character string is wrapped as a STRING and never parsed. \{{PARSE_JSON}} remains the way to parse JSON text.
* NaN and infinity are valid VARIANT values, since the binary format stores IEEE numbers. \{{PARSE_JSON}} rejects them only because JSON has no literal for them.
* Every supported type round-trips: \{{CAST(CAST(x AS VARIANT) AS T) = x}}.
* The cast never fails at runtime, so \{{TRY_CAST}} behaves like \{{CAST}}.

h3. Prerequisite change

Casting a VARIANT to FLOAT or DOUBLE rejected every non-finite result as an overflow. A VARIANT holding NaN, for example from the Avro converter, could therefore not be read back. The read now rejects only a finite value that does not fit, such as 1e40 to FLOAT, and keeps a stored NaN or infinity.



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