[FLINK-37926][table] Support casting from VARIANT to ARRAY - #29073
Conversation
230c201 to
64be049
Compare
f3432e9 to
c068f50
Compare
| } | ||
| result$0 = new org.apache.flink.table.data.GenericArrayData(objArray$3); | ||
|
|
||
| A JSON null element leaves the slot null (SQL NULL); a NOT NULL element type emits a throw instead. |
There was a problem hiding this comment.
For ARRAY<VARIANT> this drops a value: the identity cast keeps a variant null at top level, but here it becomes SQL NULL.
I think by skipping the isNull when the elementType is VARIANT casts could keep null elements as variant null instead.
This would also match Spark, Trino and Snowflake in this regard.
There was a problem hiding this comment.
Excellent catch @mateczagany! I have addressed your feedback and the codegen should be able to handle this now. I have added a test:
CAST VARIANT -> ARRAY<VARIANT>
[1, null, 3]
It is green now.
| return allowExplicit | ||
| && supportsCasting(sourceType, ((ArrayType) targetType).getElementType(), true); |
There was a problem hiding this comment.
why this?
| return allowExplicit | |
| && supportsCasting(sourceType, ((ArrayType) targetType).getElementType(), true); | |
| return supportsCasting(sourceType, ((ArrayType) targetType).getElementType(), true); |
There was a problem hiding this comment.
We should keep the allowExplicit so the user must write CAST(v AS ARRAY<...>) the cast to an ARRAY from a variant is explicit.
| ARRAY(INT()).notNull()) | ||
| // a JSON null element fails a NOT NULL element type | ||
| .testTableApiRuntimeError( | ||
| call("PARSE_JSON", "[1, null, 3]").cast(ARRAY(INT().notNull())), |
There was a problem hiding this comment.
is there no "Table API" way of parsing JSON? Can we avoid call()?
There was a problem hiding this comment.
there's no dedicated Table API parseJson() — PARSE_JSON exists only as BuiltInFunctionDefinitions.PARSE_JSON, invoked via call(). So call() can't be avoided
There was a problem hiding this comment.
Created a ticket for this:
https://issues.apache.org/jira/browse/FLINK-40545
…RAY<VARIANT> A variant array element casts to a VARIANT target by the identity cast, so a JSON null element is a valid variant null and is kept as-is rather than downgraded to SQL NULL, matching the top-level VARIANT cast and Spark, Trino and Snowflake. The null guard is skipped for a VARIANT element type. Also reuse a shared VariantBuilder across the cast test fixtures.
fd62734 to
9e3a72c
Compare
What is the purpose of the change
Let
CASTandTRY_CASTconvert aVARIANTinto anARRAY<T>. This is the first of three stacked PRs for FLINK-37926 (VARIANT to constructed types); the follow-ups addROW/STRUCTUREDandMAP<STRING, V>and build on this branch. It extends FLINK-37925 (VARIANT to scalar types, already merged): a constructed cast is that same scalar cast applied to every element, plus a shape check at each level, so no new leaf semantics are introduced.A variant array casts to
ARRAY<T>by casting each element toTwith the full VARIANT-to-Trule, recursively. The recursion bottoms out at the scalar cast, which keeps one mental model for the whole type and one deliberate strictness: a stored value keeps its kind, so a stored string is never parsed into a number.CAST(PARSE_JSON('["1","2"]') AS ARRAY<INT>)therefore fails; read it asARRAY<STRING>and convert with a regular cast instead.Brief change log
VariantToArrayCastRule: shape-check the variant is an array, then cast each element to the target element type, recursively reusing the existing VARIANT cast rules (including theVARIANT-to-VARIANTidentity, soARRAY<VARIANT>shreds exactly one level).nullelement maps to SQLNULLfor a nullable element type and fails the cast for aNOT NULLone; an empty array casts to an emptyARRAY<T>; a top-level JSONnullcasts to SQLNULLfor a nullable target before the shape check.CASTfails on any bad element andTRY_CASTreturnsNULLfor the whole array (all-or-nothing), matching nestedARRAYcasts today.AbstractVariantToConstructedCastRulebase (JSON-null passthrough andcanFail), reused by the follow-up ROW and MAP PRs.VARIANTtoARRAY<T>is castable iffVARIANTtoTis, so an element type with no variant counterpart (e.g.INTERVAL) is rejected at plan time.Verifying this change
This change added tests and can be verified as follows:
LogicalTypeCastsTest:VARIANTtoARRAYcastability, including nesting,ARRAY<VARIANT>, and an unsupported leaf.CastRuleProviderTest#testResolveVariantToArray: rule resolution and recursive resolvability.CastRulesTest: codegen behavior forARRAY<INT>(nullable andNOT NULL),ARRAY<STRING>,ARRAY<DOUBLE>, nestedARRAY<ARRAY<INT>>,ARRAY<VARIANT>, empty and null-element arrays, a heterogeneous array, and shape mismatches.CastFunctionITCase: end-to-endCAST/TRY_CASToverPARSE_JSON, covering the same shapes, the strict-leaf failures, and validation errors.Does this pull request potentially affect one of the following parts:
@Public(Evolving): noDocumentation
data-types.md, EN and zh) and JavaDocsWas generative AI tooling used to co-author this PR?
Generated-by: Opus 4.8