This is an automated email from the ASF dual-hosted git repository.
mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 2fafa5254e [CALCITE-7114] Invalid unparse for cast to array type in
Spark
2fafa5254e is described below
commit 2fafa5254e40ddcffbf1fcd9ae56c50954763dac
Author: xuzifu666 <[email protected]>
AuthorDate: Wed Jul 30 14:28:44 2025 +0800
[CALCITE-7114] Invalid unparse for cast to array type in Spark
---
.../calcite/sql/dialect/SparkSqlDialect.java | 13 ++-
.../calcite/sql/dialect/StarRocksSqlDialect.java | 120 +++++++++------------
.../apache/calcite/util/RelToSqlConverterUtil.java | 17 +++
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 22 ++++
4 files changed, 98 insertions(+), 74 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java
b/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java
index eaf5acdc1e..42cd259e51 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java
@@ -37,8 +37,6 @@
import org.apache.calcite.sql.fun.SqlLibraryOperators;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.type.BasicSqlType;
-import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.RelToSqlConverterUtil;
import com.google.common.collect.ImmutableList;
@@ -163,10 +161,19 @@ public SparkSqlDialect(SqlDialect.Context context) {
}
@Override public @Nullable SqlNode getCastSpec(RelDataType type) {
- if (type instanceof BasicSqlType && type.getSqlTypeName() ==
SqlTypeName.VARCHAR) {
+ switch (type.getSqlTypeName()) {
+ case VARCHAR:
return new SqlDataTypeSpec(
new SqlAlienSystemTypeNameSpec("STRING", type.getSqlTypeName(),
SqlParserPos.ZERO), SqlParserPos.ZERO);
+ case ARRAY:
+ return RelToSqlConverterUtil.getCastSpecAngleBracketArrayType(this, type,
+ SqlParserPos.ZERO);
+ case MULTISET:
+ throw new UnsupportedOperationException("Spark dialect does not support
cast to "
+ + type.getSqlTypeName());
+ default:
+ break;
}
return super.getCastSpec(type);
}
diff --git
a/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
b/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
index d7031666fe..07d09b5a24 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/StarRocksSqlDialect.java
@@ -25,7 +25,6 @@
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.SqlAbstractDateTimeLiteral;
import org.apache.calcite.sql.SqlAlienSystemTypeNameSpec;
-import org.apache.calcite.sql.SqlArrayWithAngleBracketsNameSpec;
import org.apache.calcite.sql.SqlBasicTypeNameSpec;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlDataTypeSpec;
@@ -33,13 +32,9 @@
import org.apache.calcite.sql.SqlLiteral;
import org.apache.calcite.sql.SqlMapTypeNameSpec;
import org.apache.calcite.sql.SqlNode;
-import org.apache.calcite.sql.SqlTypeNameSpec;
import org.apache.calcite.sql.SqlWriter;
import org.apache.calcite.sql.fun.SqlFloorFunction;
import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.type.AbstractSqlType;
-import org.apache.calcite.sql.type.ArraySqlType;
-import org.apache.calcite.sql.type.BasicSqlType;
import org.apache.calcite.sql.type.MapSqlType;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.RelToSqlConverterUtil;
@@ -177,72 +172,55 @@ public StarRocksSqlDialect(Context context) {
}
@Override public @Nullable SqlNode getCastSpec(RelDataType type) {
- if (type instanceof BasicSqlType) {
- switch (type.getSqlTypeName()) {
- case INTEGER:
- return new SqlDataTypeSpec(
- new SqlAlienSystemTypeNameSpec(
- "INT",
- type.getSqlTypeName(),
- SqlParserPos.ZERO),
- SqlParserPos.ZERO);
- case REAL:
- return new SqlDataTypeSpec(
- new SqlAlienSystemTypeNameSpec("FLOAT", type.getSqlTypeName(),
- SqlParserPos.ZERO),
- SqlParserPos.ZERO);
- case BIGINT:
- return new SqlDataTypeSpec(
- new SqlBasicTypeNameSpec(SqlTypeName.BIGINT, SqlParserPos.ZERO),
- SqlParserPos.ZERO);
- case TIMESTAMP:
- return new SqlDataTypeSpec(
- new SqlAlienSystemTypeNameSpec(
- "DATETIME",
- type.getSqlTypeName(),
- SqlParserPos.ZERO),
- SqlParserPos.ZERO);
- case VARCHAR:
- return new SqlDataTypeSpec(
- new SqlBasicTypeNameSpec(SqlTypeName.VARCHAR, type.getPrecision(),
SqlParserPos.ZERO),
- SqlParserPos.ZERO);
- default:
- break;
- }
- }
-
- if (type instanceof AbstractSqlType) {
- switch (type.getSqlTypeName()) {
- case MAP:
- MapSqlType mapSqlType = (MapSqlType) type;
- SqlDataTypeSpec keySpec = (SqlDataTypeSpec)
getCastSpec(mapSqlType.getKeyType());
- SqlDataTypeSpec valueSpec =
- (SqlDataTypeSpec) getCastSpec(mapSqlType.getValueType());
- SqlDataTypeSpec nonNullKeySpec =
- requireNonNull(keySpec, "keySpec");
- SqlDataTypeSpec nonNullValueSpec =
- requireNonNull(valueSpec, "valueSpec");
- SqlMapTypeNameSpec sqlMapTypeNameSpec =
- new SqlMapTypeNameSpec(nonNullKeySpec, nonNullValueSpec,
SqlParserPos.ZERO);
- return new SqlDataTypeSpec(sqlMapTypeNameSpec,
- SqlParserPos.ZERO);
- case ARRAY:
- ArraySqlType arraySqlType = (ArraySqlType) type;
- SqlDataTypeSpec arrayValueSpec =
- (SqlDataTypeSpec) getCastSpec(arraySqlType.getComponentType());
- SqlDataTypeSpec nonNullarrayValueSpec =
- requireNonNull(arrayValueSpec, "arrayValueSpec");
- SqlTypeNameSpec typeNameSpec =
- new SqlArrayWithAngleBracketsNameSpec(
- nonNullarrayValueSpec.getTypeNameSpec(),
- arraySqlType.getSqlTypeName(), SqlParserPos.ZERO);
- return new SqlDataTypeSpec(typeNameSpec, SqlParserPos.ZERO);
- case MULTISET:
- throw new UnsupportedOperationException("StarRocks dialect does not
support cast to "
- + type.getSqlTypeName());
- default:
- break;
- }
+ switch (type.getSqlTypeName()) {
+ case INTEGER:
+ return new SqlDataTypeSpec(
+ new SqlAlienSystemTypeNameSpec(
+ "INT",
+ type.getSqlTypeName(),
+ SqlParserPos.ZERO),
+ SqlParserPos.ZERO);
+ case REAL:
+ return new SqlDataTypeSpec(
+ new SqlAlienSystemTypeNameSpec("FLOAT", type.getSqlTypeName(),
+ SqlParserPos.ZERO),
+ SqlParserPos.ZERO);
+ case BIGINT:
+ return new SqlDataTypeSpec(
+ new SqlBasicTypeNameSpec(SqlTypeName.BIGINT, SqlParserPos.ZERO),
+ SqlParserPos.ZERO);
+ case TIMESTAMP:
+ return new SqlDataTypeSpec(
+ new SqlAlienSystemTypeNameSpec(
+ "DATETIME",
+ type.getSqlTypeName(),
+ SqlParserPos.ZERO),
+ SqlParserPos.ZERO);
+ case VARCHAR:
+ return new SqlDataTypeSpec(
+ new SqlBasicTypeNameSpec(SqlTypeName.VARCHAR, type.getPrecision(),
SqlParserPos.ZERO),
+ SqlParserPos.ZERO);
+ case MAP:
+ MapSqlType mapSqlType = (MapSqlType) type;
+ SqlDataTypeSpec keySpec = (SqlDataTypeSpec)
getCastSpec(mapSqlType.getKeyType());
+ SqlDataTypeSpec valueSpec =
+ (SqlDataTypeSpec) getCastSpec(mapSqlType.getValueType());
+ SqlDataTypeSpec nonNullKeySpec =
+ requireNonNull(keySpec, "keySpec");
+ SqlDataTypeSpec nonNullValueSpec =
+ requireNonNull(valueSpec, "valueSpec");
+ SqlMapTypeNameSpec sqlMapTypeNameSpec =
+ new SqlMapTypeNameSpec(nonNullKeySpec, nonNullValueSpec,
SqlParserPos.ZERO);
+ return new SqlDataTypeSpec(sqlMapTypeNameSpec,
+ SqlParserPos.ZERO);
+ case ARRAY:
+ return RelToSqlConverterUtil.getCastSpecAngleBracketArrayType(this, type,
+ SqlParserPos.ZERO);
+ case MULTISET:
+ throw new UnsupportedOperationException("StarRocks dialect does not
support cast to "
+ + type.getSqlTypeName());
+ default:
+ break;
}
return super.getCastSpec(type);
diff --git
a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
index b165448615..ddb37e8dac 100644
--- a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
+++ b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java
@@ -21,6 +21,7 @@
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.SqlArrayWithAngleBracketsNameSpec;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlCharStringLiteral;
import org.apache.calcite.sql.SqlCollectionTypeNameSpec;
@@ -373,6 +374,22 @@ public static SqlDataTypeSpec
getCastSpecClickHouseSqlArrayType(SqlDialect diale
return new SqlDataTypeSpec(sqlArrayTypeNameSpec, SqlParserPos.ZERO);
}
+ /**
+ * Transformation ARRAY type from {@code VARCHAR ARRAY} to {@code
Array<VARCHAR>}.
+ */
+ public static SqlDataTypeSpec getCastSpecAngleBracketArrayType(SqlDialect
dialect,
+ RelDataType type, SqlParserPos pos) {
+ ArraySqlType arraySqlType = (ArraySqlType) type;
+ SqlDataTypeSpec arrayValueSpec =
+ (SqlDataTypeSpec) dialect.getCastSpec(arraySqlType.getComponentType());
+ SqlDataTypeSpec nonNullarrayValueSpec =
+ requireNonNull(arrayValueSpec, "arrayValueSpec");
+ SqlArrayWithAngleBracketsNameSpec sqlArrayTypeNameSpec =
+ new
SqlArrayWithAngleBracketsNameSpec(nonNullarrayValueSpec.getTypeNameSpec(),
+ arraySqlType.getSqlTypeName(), pos);
+ return new SqlDataTypeSpec(sqlArrayTypeNameSpec, SqlParserPos.ZERO);
+ }
+
/**
* ClickHouseSqlMapTypeNameSpec to parse or unparse SQL MAP type to {@code
Map(VARCHAR, VARCHAR)}.
*/
diff --git
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 7283f43870..a0b7c2425d 100644
---
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -2604,6 +2604,27 @@ private SqlDialect nonOrdinalDialect() {
sql(query4).withCalcite().ok(expected4);
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7114">[CALCITE-7114]
+ * Invalid unparse for cast to array type in Spark</a>.
+ */
+ @Test void testCastArraySpark() {
+ final String query = "select cast(array['a','b','c']"
+ + " as varchar array)";
+ final String expectedSpark = "SELECT CAST(ARRAY ('a', 'b', 'c') AS ARRAY<
STRING >)\n"
+ + "FROM (VALUES (0)) `t` (`ZERO`)";
+ sql(query)
+ .withSpark().ok(expectedSpark);
+
+ final String query1 = "select cast(array[array['a'], array['b'],
array['c']]"
+ + " as varchar array array)";
+ final String expectedSpark1 =
+ "SELECT CAST(ARRAY (ARRAY ('a'), ARRAY ('b'), ARRAY ('c')) AS ARRAY<
ARRAY< STRING > >)\n"
+ + "FROM (VALUES (0)) `t` (`ZERO`)";
+ sql(query1)
+ .withSpark().ok(expectedSpark1);
+ }
+
/** Test case for
* <a
href="https://issues.apache.org/jira/browse/CALCITE-7055">[CALCITE-7055]
* Invalid unparse for cast to array type in StarRocks</a>.
@@ -10301,6 +10322,7 @@ private void checkLiteral2(String expression, String
expected) {
.withPhoenix().throws_("Phoenix dialect does not support cast to
MULTISET")
.withStarRocks().throws_("StarRocks dialect does not support cast to
MULTISET")
.withClickHouse().throws_("ClickHouse dialect does not support cast to
MULTISET")
+ .withSpark().throws_("Spark dialect does not support cast to MULTISET")
.withHive().throws_("Hive dialect does not support cast to MULTISET");
String query3 = "SELECT CAST(MAP[1.0,2.0,3.0,4.0] AS MAP<FLOAT, REAL>)
FROM \"employee\"";