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

Yuepeng Pan closed FLINK-40319.
-------------------------------
    Resolution: Fixed

> Allow CAST from a VARIANT string value to BINARY and VARBINARY
> --------------------------------------------------------------
>
>                 Key: FLINK-40319
>                 URL: https://issues.apache.org/jira/browse/FLINK-40319
>             Project: Flink
>          Issue Type: Improvement
>          Components: API / Core
>            Reporter: Ramin Gharib
>            Assignee: Ramin Gharib
>            Priority: Major
>              Labels: pull-request-available
>             Fix For: 2.4.0, 2.5.0
>
>
> h3. Problem
> {{CAST(v AS BYTES)}} fails for a string variant, whatever the string holds. 
> {{VariantCastUtils#toBytes}} calls {{Variant#getBytes}}, which accepts only 
> the {{BYTES}} kind. For {{PARSE_JSON('"abc"')}} the getter throws a 
> {{VariantTypeException}} with the message {{Expected type BYTES but got 
> STRING}}.
> This is a problem for three reasons:
> * Regular SQL allows {{STRING}} to {{BINARY}}. VARIANT already allows the 
> mirror direction, {{BYTES}} to a character string. Encoding a string to UTF-8 
> always succeeds.
> * JSON has no binary type, so {{PARSE_JSON}} never produces {{BYTES}}. A 
> variant built from JSON can never reach a binary target, such as a 
> {{MAP<STRING, BYTES>}} column.
> * Every other kind fails the same way, with the getter's 
> {{VariantTypeException}}. Most other readers, such as the numeric ones, throw 
> a {{TableRuntimeException}} built by {{VariantCastUtils#unsupportedKind}} 
> instead. Its message names the cast and the target type.
> h3. Proposal
> Change only {{VariantCastUtils#toBytes}}:
> # Accept a stored {{STRING}} value through 
> {{variant.getString().getBytes(StandardCharsets.UTF_8)}}, then pad or 
> truncate it like a stored {{BYTES}} value.
> # Reject every other kind with {{unsupportedKind}}.
> {{Variant}}, {{BinaryVariant}} and {{BinaryVariantUtil}} stay unchanged.
> h3. Observable changes
> ||Expression||Before||After||
> |{{CAST(PARSE_JSON('"abc"') AS 
> BYTES)}}|{{VariantTypeException}}|{{x'616263'}}|
> |{{CAST(PARSE_JSON('"abc"') AS 
> BINARY(2))}}|{{VariantTypeException}}|{{x'6162'}}|
> |{{TRY_CAST(PARSE_JSON('"abc"') AS BYTES)}}|{{NULL}}|{{x'616263'}}|
> |{{CAST(PARSE_JSON('true') AS 
> BYTES)}}|{{VariantTypeException}}|{{TableRuntimeException}} with the 
> {{unsupportedKind}} message|
> The first row flips an existing expectation in {{CastRulesTest}}, which 
> asserts that {{VARIANT_BUILDER.of("foo")}} fails a {{BYTES}} cast. The commit 
> message calls this out. The table of cast targets in 
> {{docs/content/docs/sql/reference/data-types.md}} gets a {{STRING}} to 
> {{BINARY}} and {{VARBINARY}} entry.
> h3. Limits
> A stored {{STRING}} with an invalid UTF-8 payload loses its bytes. 
> {{getString}} replaces malformed input with U+FFFD, so the cast returns {{EF 
> BF BD}} in its place. {{CAST(v AS STRING)}} makes the same substitution 
> today. Such a value can't come from the builders, which take a Java 
> {{String}}, or from {{PARSE_JSON}}, which rejects invalid UTF-8. It can only 
> come from bytes wrapped without validation, such as the binary encoding of 
> the raw format from FLINK-41323. Validating string payloads at ingest, as 
> FLINK-40318 proposes, would close this gap. A test pins the substitution.
> h3. Out of scope
> * A raw-bytes accessor for string values, and UTF-8 validation on the 
> character-string cast. Ingest validation would make both unnecessary.
> * The {{BOOLEAN}} reader and a malformed variant. FLINK-41301 covers them. 
> The {{DATE}} reader already checks the kind since FLINK-41281.
> h3. Tests
> * In {{FromVariantConverterTest}}, a non-ASCII string variant reaches 
> {{BYTES}}, {{VARBINARY(3)}} and {{BINARY(8)}} as its UTF-8 bytes, truncated 
> or padded like a stored {{BYTES}} value. A string payload {{C3 28}} comes out 
> as {{EF BF BD 28}}.
> * In {{FromVariantConverterTest}}, a boolean, an integer and an object 
> variant fail a binary cast with a {{TableRuntimeException}}. 
> {{CastRulesTest}} can't show the exception type, because {{CastExecutor}} 
> wraps any {{Throwable}} in a {{TableRuntimeException}}.
> * In {{CastRulesTest}}, the string case of the {{BYTES}} cast passes.
> * In {{CastFunctionITCase}}, {{CAST}} of a string variant to {{BYTES}} 
> returns its bytes. {{CAST}} of a boolean one fails with the 
> {{unsupportedKind}} message, and {{TRY_CAST}} returns {{NULL}}.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to