Ramin Gharib created FLINK-41279:
------------------------------------

             Summary: Support the PostgreSQL-style :: cast operator
                 Key: FLINK-41279
                 URL: https://issues.apache.org/jira/browse/FLINK-41279
             Project: Flink
          Issue Type: New Feature
          Components: Table SQL / API
            Reporter: Ramin Gharib
            Assignee: Ramin Gharib


Flink SQL only supports {{CAST(x AS type)}}. PostgreSQL, DuckDB and Snowflake 
also accept the shorter infix form {{x::type}}, and Calcite supports it in its 
Babel parser. These statements fail to parse in Flink today:

{code:sql}
SELECT '42'::INT + 1;           -- CAST('42' AS INT) + 1
SELECT payload::VARIANT FROM t; -- CAST(payload AS VARIANT)
SELECT m['k']::INT FROM t;      -- CAST(m['k'] AS INT)
SELECT s::INT::STRING FROM t;   -- CAST(CAST(s AS INT) AS STRING)
{code}

h3. Proposal

Treat {{::}} as pure syntax for {{CAST}}. The parser turns {{x::type}} into a 
plain {{CAST(x AS type)}} call, so validation, planning, code generation and 
compiled plans stay unchanged.

* Add the {{::}} token and an {{InfixCast}} production through the existing 
{{binaryOperatorsTokens}} and {{extraBinaryExpressions}} hooks in 
{{Parser.tdd}} and {{parserImpls.ftl}}. {{Parser.jj}} stays untouched.
* The production emits a Flink-side binary operator whose {{createCall}} 
returns a {{CAST}} call. It keeps Calcite's precedence for {{::}}: tighter than 
arithmetic, looser than {{[]}} and {{.}}.
* The type after {{::}} goes through Flink's {{DataType()}} production, so 
types like {{ARRAY<INT>}}, {{ROW<...>}} and {{VARIANT}} work.

h3. Why not reuse Calcite's SqlLibraryOperators.INFIX_CAST

Calcite's operator stays in the validated tree and unparses as {{a :: INT}}. 
That text ends up in persisted catalog state, such as view expanded queries, 
computed columns and materialized table definition queries, and older Flink 
versions can't parse it. The unparse format also belongs to Calcite: 
CALCITE-7475 changed it in Calcite 1.42. Desugaring in the parser keeps all 
stored text as {{CAST(a AS INT)}} and leaves no new operator for later Calcite 
upgrades to track.

h3. Out of scope

* Table API. {{BaseExpressions#cast}} already covers it.
* A {{TRY_CAST}} counterpart. PostgreSQL has none.
* Postfix access directly after the type, like {{x::ARRAY<INT>[1]}}, which 
Calcite Babel added in CALCITE-7475.




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

Reply via email to