This is an automated email from the ASF dual-hosted git repository.
philo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-gluten.git
The following commit(s) were added to refs/heads/main by this push:
new db86b02612 [GLUTEN-9392][VL] Support casting complex types (#10443)
db86b02612 is described below
commit db86b026127d7f2cca8b9f1b8ade8eca0195faa5
Author: kevinwilfong <[email protected]>
AuthorDate: Sun Aug 17 17:58:25 2025 -0700
[GLUTEN-9392][VL] Support casting complex types (#10443)
---
.../functions/ScalarFunctionsValidateSuite.scala | 231 ++++++++++++++
.../substrait/SubstraitToVeloxPlanValidator.cc | 63 ++--
.../gluten/utils/velox/VeloxTestSettings.scala | 7 -
.../sql/catalyst/expressions/GlutenCastSuite.scala | 59 ----
.../sql/catalyst/expressions/GlutenCastSuite.scala | 59 ----
.../sql/catalyst/expressions/GlutenCastSuite.scala | 59 ----
.../sql/catalyst/expressions/GlutenCastSuite.scala | 59 ----
.../gluten/expressions/GlutenCastSuite.scala | 353 +++++++++++++++++++++
8 files changed, 613 insertions(+), 277 deletions(-)
diff --git
a/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
b/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
index 1d376f5e23..6bef01e96f 100644
---
a/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
+++
b/backends-velox/src/test/scala/org/apache/gluten/functions/ScalarFunctionsValidateSuite.scala
@@ -20,8 +20,10 @@ import org.apache.gluten.config.GlutenConfig
import org.apache.gluten.execution.{BatchScanExecTransformer,
FilterExecTransformer, ProjectExecTransformer}
import org.apache.spark.{SparkConf, SparkException}
+import org.apache.spark.sql.Row
import org.apache.spark.sql.catalyst.optimizer.NullPropagation
import org.apache.spark.sql.execution.ProjectExec
+import org.apache.spark.sql.types._
class ScalarFunctionsValidateSuiteRasOff extends ScalarFunctionsValidateSuite {
override protected def sparkConf: SparkConf = {
@@ -1175,6 +1177,37 @@ abstract class ScalarFunctionsValidateSuite extends
FunctionsValidateSuite {
runQueryAndCompare("select cast(array(timestamp'2024-01-01 12:00:00') AS
array<string>)") {
checkGlutenOperatorMatch[ProjectExecTransformer]
}
+ // Cast Array[String] to Array
+ runQueryAndCompare("select cast(array('123', '-98', 'abc', null) AS
array<tinyint>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(array('123', '-98', 'abc', null) AS
array<smallint>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(array('123', '-98', 'abc', null) AS
array<int>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(array('123', '-98', 'abc', null) AS
array<bigint>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(array('123e-2', '-234.548', 'xyz', null)
AS array<float>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(array('123e-2', '-234.548', 'xyz', null)
AS array<double>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | array('2023-01-01 12:00:00', '2023-01-02
12:00:00', 'def', null)
+ | AS array<timestamp>)
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare(
+ "select cast(array('2024-01-01', '2024-01-02', 'uvw', null) AS
array<date>)") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
// Cast Array as String
withTempView("cast_table") {
withTempPath {
@@ -1207,6 +1240,204 @@ abstract class ScalarFunctionsValidateSuite extends
FunctionsValidateSuite {
runQueryAndCompare("select cast(array(timestamp'2024-01-01 12:00:00') AS
string)") {
checkGlutenOperatorMatch[ProjectExecTransformer]
}
+ // Cast Map
+ withTempView("byte_map_tbl") {
+ withTempPath {
+ path =>
+ Seq[Map[Byte, Byte]](
+ Map(0.toByte -> 1.toByte, 2.toByte -> 3.toByte, 4.toByte ->
0.toByte))
+ .toDF("c1")
+ .write
+ .parquet(path.getCanonicalPath)
+
+
spark.read.parquet(path.getCanonicalPath).createOrReplaceTempView("byte_map_tbl")
+
+ runQueryAndCompare("select cast(c1 as map<tinyint, double>) from
byte_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<double, tinyint>) from
byte_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<tinyint, string>) from
byte_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<string, tinyint>) from
byte_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<tinyint, boolean>) from
byte_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ }
+ }
+
+ withTempView("small_int_map_tbl") {
+ withTempPath {
+ path =>
+ Seq[Map[Short, Short]](
+ Map(
+ 1000.toShort -> 1001.toShort,
+ 1002.toShort -> 1003.toShort,
+ 1004.toShort -> 0.toShort))
+ .toDF("c1")
+ .write
+ .parquet(path.getCanonicalPath)
+
+
spark.read.parquet(path.getCanonicalPath).createOrReplaceTempView("small_int_map_tbl")
+
+ runQueryAndCompare("select cast(c1 as map<smallint, double>) from
small_int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<double, smallint>) from
small_int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<smallint, string>) from
small_int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<string, smallint>) from
small_int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<smallint, boolean>) from
small_int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ }
+ }
+
+ withTempView("int_map_tbl") {
+ withTempPath {
+ path =>
+ Seq[Map[Int, String]](Map(100 -> "101", 102 -> "103", 104 -> "xyz"))
+ .toDF("c1")
+ .write
+ .parquet(path.getCanonicalPath)
+
+
spark.read.parquet(path.getCanonicalPath).createOrReplaceTempView("int_map_tbl")
+
+ runQueryAndCompare("select cast(c1 as map<double, int>) from
int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<string, string>) from
int_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ }
+ }
+
+ withTempView("float_map_tbl") {
+ withTempPath {
+ path =>
+ Seq[Map[Float, String]](Map(1.0f -> "2.0", -3.0f -> "40e-1", 5.0f ->
"xyz"))
+ .toDF("c1")
+ .write
+ .parquet(path.getCanonicalPath)
+
+
spark.read.parquet(path.getCanonicalPath).createOrReplaceTempView("float_map_tbl")
+
+ runQueryAndCompare("select cast(c1 as map<float, float>) from
float_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("select cast(c1 as map<string, string>) from
float_map_tbl") {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ }
+ }
+
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | map(
+ | timestamp '2023-01-01 12:00:00', '2023-01-01
13:00:00',
+ | timestamp '2023-01-02 12:00:00', 'xyz')
+ | as map<string, timestamp>)
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | map(date '2024-01-01', '2024-01-02', date
'2024-02-01', 'xyz')
+ | as map<string, date>)
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ // Cast struct
+ withTempView("struct_tbl") {
+ val structData = Seq(
+ Row(
+ Row(
+ Seq("123", "456.7", "2023-01-01 12:00:00", "2024-01-01"),
+ Map(1.toByte -> 2.toShort, 3.toByte -> 4.toShort),
+ Row(
+ 123.0,
+ 456.1f,
+ 0
+ )
+ )))
+
+ val structSchema = new StructType().add(
+ "c1",
+ new StructType()
+ .add("a", ArrayType(StringType))
+ .add("b", MapType(ByteType, ShortType))
+ .add("c", new StructType().add("x", DoubleType).add("y",
FloatType).add("z", IntegerType))
+ )
+ withTempPath {
+ path =>
+ spark
+ .createDataFrame(spark.sparkContext.parallelize(structData),
structSchema)
+ .write
+ .parquet(path.getCanonicalPath)
+
+
spark.read.parquet(path.getCanonicalPath).createOrReplaceTempView("struct_tbl")
+
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | c1 as
+ | struct<
+ | a: array<bigint>,
+ | b: map<smallint, int>,
+ | c: struct<x: string, y: string,
z:boolean>>)
+ |from struct_tbl
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | c1 as
+ | struct<
+ | a: array<double>,
+ | b: map<int, bigint>,
+ | c: struct<x: int, y: boolean,
z:string>>)
+ |from struct_tbl
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | c1 as
+ | struct<
+ | a: array<timestamp>,
+ | b: map<bigint, boolean>,
+ | c: struct<x: tinyint, y: smallint,
z:double>>)
+ |from struct_tbl
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ runQueryAndCompare("""
+ |select
+ | cast(
+ | c1 as
+ | struct<
+ | a: array<date>,
+ | b: map<string, double>,
+ | c: struct<x: int, y: bigint, z:float>>)
+ |from struct_tbl
+ |""".stripMargin) {
+ checkGlutenOperatorMatch[ProjectExecTransformer]
+ }
+ }
+ }
}
testWithMinSparkVersion("equal_null", "3.4") {
diff --git a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
index 2bc083fd20..1f0a5b3361 100644
--- a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
+++ b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
@@ -235,34 +235,6 @@ bool SubstraitToVeloxPlanValidator::validateScalarFunction(
return true;
}
-bool isSupportedArrayCast(const TypePtr& fromType, const TypePtr& toType) {
- // https://github.com/apache/incubator-gluten/issues/9392
- // is currently WIP to add support for other types.
- if (toType->isVarchar()) {
- return fromType->isDouble() || fromType->isBoolean() ||
fromType->isTimestamp()
- || fromType->isInteger() || fromType->isBigint() || fromType->isDate();
- }
-
- if (toType->isDouble()) {
- if (fromType->isInteger() || fromType->isBigint() ||
fromType->isSmallint() || fromType->isTinyint()) {
- return true;
- }
- }
-
- if (toType->isBoolean()) {
- if (fromType->isDate() || fromType->isShortDecimal()) {
- return false;
- }
-
- if (fromType->isTinyint() || fromType->isSmallint() ||
fromType->isInteger() || fromType->isBigint() ||
- fromType->isReal() || fromType->isDouble()) {
- return true;
- }
- }
-
- return false;
-}
-
bool SubstraitToVeloxPlanValidator::isAllowedCast(const TypePtr& fromType,
const TypePtr& toType) {
// Currently cast is not allowed for various categories, code has a bunch of
rules
// which define the cast categories and if we should offload to velox.
Currently,
@@ -321,19 +293,42 @@ bool SubstraitToVeloxPlanValidator::isAllowedCast(const
TypePtr& fromType, const
return false;
}
+ // For complex types recursively check that their children can be cast.
if (fromType->isArray() && toType->isArray()) {
const auto& toElem = toType->asArray().elementType();
const auto& fromElem = fromType->asArray().elementType();
- if (!isAllowedCast(fromElem, toElem)) {
- return false;
- }
+ return isAllowedCast(fromElem, toElem);
+ }
+
+ if (fromType->isMap() && toType->isMap()) {
+ const auto& fromKey = fromType->asMap().keyType();
+ const auto& fromValue = fromType->asMap().valueType();
+ const auto& toKey = toType->asMap().keyType();
+ const auto& toValue = toType->asMap().valueType();
+
+ return isAllowedCast(fromKey, toKey) && isAllowedCast(fromValue,
toValue);
+ }
+
+ if (fromType->isRow() && toType->isRow()) {
+ const auto& fromChildren = fromType->asRow().children();
+ const auto& toChildren = toType->asRow().children();
- return isSupportedArrayCast(fromElem, toElem);
+ if (fromChildren.size() != toChildren.size()) {
+ return false;
+ }
+
+ for (size_t childIdx = 0; childIdx < fromChildren.size(); ++childIdx) {
+ if (!isAllowedCast(fromChildren[childIdx], toChildren[childIdx])) {
+ return false;
+ }
+ }
+
+ return true;
}
- // Limited support for Complex types.
- if (fromType->isArray() || fromType->isMap() || fromType->isRow()) {
+ // Casting a complex type to/from any other type is not allowed.
+ if (fromType->isArray() || fromType->isMap() || fromType->isRow() ||
toType->isArray() || toType->isMap() || toType->isRow()) {
return false;
}
diff --git
a/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala
b/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala
index 725adb206a..b08d6ed056 100644
---
a/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala
+++
b/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/velox/VeloxTestSettings.scala
@@ -107,13 +107,6 @@ class VeloxTestSettings extends BackendTestSettings {
.exclude("SPARK-35719: cast timestamp with local time zone to timestamp
without timezone")
enableSuite[GlutenTryCastSuite]
- .exclude(
- // array/map/struct not supported yet.
- "cast from invalid string array to numeric array should throw
NumberFormatException",
- "cast from array II",
- "cast from map II",
- "cast from struct II"
- )
// Timezone.
.exclude("SPARK-35711: cast timestamp without time zone to timestamp with
local time zone")
// Timezone.
diff --git
a/gluten-ut/spark32/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
b/gluten-ut/spark32/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
index 05ef3a3686..cd4351e708 100644
---
a/gluten-ut/spark32/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
+++
b/gluten-ut/spark32/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
@@ -67,65 +67,6 @@ class GlutenCastSuite extends CastSuite with
GlutenTestsTrait {
}
}
- test("cast array of integer types to array of double") {
- val intArray = Literal.create(Seq(1, 2, 3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(10000000000L), ArrayType(LongType))
- val smallintArray = Literal.create(Seq(1.toShort, -1.toShort),
ArrayType(ShortType))
- val tinyintArray = Literal.create(Seq(1.toByte, -1.toByte),
ArrayType(ByteType))
-
- checkEvaluation(cast(intArray, ArrayType(DoubleType)), Seq(1.0, 2.0, 3.0))
- checkEvaluation(cast(bigintArray, ArrayType(DoubleType)), Seq(1.0e10))
- checkEvaluation(cast(smallintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- checkEvaluation(cast(tinyintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- }
-
- test("cast array of double to array of integer types") {
- val doubleArray = Literal.create(Seq(1.9, -2.1), ArrayType(DoubleType))
-
- checkEvaluation(cast(doubleArray, ArrayType(IntegerType)), Seq(1, -2))
- checkEvaluation(cast(doubleArray, ArrayType(LongType)), Seq(1L, -2L))
- checkEvaluation(cast(doubleArray, ArrayType(ShortType)), Seq(1.toShort,
-2.toShort))
- checkEvaluation(cast(doubleArray, ArrayType(ByteType)), Seq(1.toByte,
-2.toByte))
- }
-
- test("cast array element from allowed types to string (varchar)") {
- val doubleArray = Literal.create(Seq(1.1, null, 3.3),
ArrayType(DoubleType))
- val boolArray = Literal.create(Seq(true, false), ArrayType(BooleanType))
- val timestampArray = Literal.create(
- Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null),
- ArrayType(TimestampType)
- )
- val integerArray = Literal.create(Seq(1, null, 2), ArrayType(IntegerType))
- val longArray = Literal.create(Seq(1L, null, 2L), ArrayType(LongType))
- val dateArray = Literal.create(
- Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
- ArrayType(DateType)
- )
-
- checkEvaluation(cast(doubleArray, ArrayType(StringType)), Seq("1.1", null,
"3.3"))
- checkEvaluation(cast(boolArray, ArrayType(StringType)), Seq("true",
"false"))
- checkEvaluation(cast(timestampArray, ArrayType(StringType)),
Seq("2023-01-01 12:00:00", null))
- checkEvaluation(cast(integerArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(longArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(dateArray, ArrayType(StringType)), Seq("2024-01-01",
null, "2024-01-03"))
- }
-
- test("cast array of numeric types to array of boolean") {
- val tinyintArray = Literal.create(Seq(0.toByte, 1.toByte, -1.toByte),
ArrayType(ByteType))
- val smallintArray = Literal.create(Seq(0.toShort, 2.toShort, -2.toShort),
ArrayType(ShortType))
- val intArray = Literal.create(Seq(0, 3, -3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(0L, 100L, -100L), ArrayType(LongType))
- val floatArray = Literal.create(Seq(0.0f, 1.5f, -2.3f),
ArrayType(FloatType))
- val doubleArray = Literal.create(Seq(0.0, 2.5, -3.7),
ArrayType(DoubleType))
-
- checkEvaluation(cast(tinyintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(smallintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(intArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(bigintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(floatArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(doubleArray, ArrayType(BooleanType)), Seq(false,
true, true))
- }
-
testGluten("missing cases - from short") {
DataTypeTestUtils.numericTypeWithoutDecimal.foreach {
t =>
diff --git
a/gluten-ut/spark33/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
b/gluten-ut/spark33/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
index 407e3e5ef4..9be180930d 100644
---
a/gluten-ut/spark33/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
+++
b/gluten-ut/spark33/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
@@ -43,65 +43,6 @@ class GlutenCastSuite extends CastSuite with
GlutenTestsTrait {
UDTRegistration.register(classOf[IExampleBaseType].getName,
classOf[ExampleBaseTypeUDT].getName)
UDTRegistration.register(classOf[IExampleSubType].getName,
classOf[ExampleSubTypeUDT].getName)
- test("cast array of integer types to array of double") {
- val intArray = Literal.create(Seq(1, 2, 3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(10000000000L), ArrayType(LongType))
- val smallintArray = Literal.create(Seq(1.toShort, -1.toShort),
ArrayType(ShortType))
- val tinyintArray = Literal.create(Seq(1.toByte, -1.toByte),
ArrayType(ByteType))
-
- checkEvaluation(cast(intArray, ArrayType(DoubleType)), Seq(1.0, 2.0, 3.0))
- checkEvaluation(cast(bigintArray, ArrayType(DoubleType)), Seq(1.0e10))
- checkEvaluation(cast(smallintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- checkEvaluation(cast(tinyintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- }
-
- test("cast array of double to array of integer types") {
- val doubleArray = Literal.create(Seq(1.9, -2.1), ArrayType(DoubleType))
-
- checkEvaluation(cast(doubleArray, ArrayType(IntegerType)), Seq(1, -2))
- checkEvaluation(cast(doubleArray, ArrayType(LongType)), Seq(1L, -2L))
- checkEvaluation(cast(doubleArray, ArrayType(ShortType)), Seq(1.toShort,
-2.toShort))
- checkEvaluation(cast(doubleArray, ArrayType(ByteType)), Seq(1.toByte,
-2.toByte))
- }
-
- test("cast array element from allowed types to string (varchar)") {
- val doubleArray = Literal.create(Seq(1.1, null, 3.3),
ArrayType(DoubleType))
- val boolArray = Literal.create(Seq(true, false), ArrayType(BooleanType))
- val timestampArray = Literal.create(
- Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null),
- ArrayType(TimestampType)
- )
- val integerArray = Literal.create(Seq(1, null, 2), ArrayType(IntegerType))
- val longArray = Literal.create(Seq(1L, null, 2L), ArrayType(LongType))
- val dateArray = Literal.create(
- Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
- ArrayType(DateType)
- )
-
- checkEvaluation(cast(doubleArray, ArrayType(StringType)), Seq("1.1", null,
"3.3"))
- checkEvaluation(cast(boolArray, ArrayType(StringType)), Seq("true",
"false"))
- checkEvaluation(cast(timestampArray, ArrayType(StringType)),
Seq("2023-01-01 12:00:00", null))
- checkEvaluation(cast(integerArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(longArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(dateArray, ArrayType(StringType)), Seq("2024-01-01",
null, "2024-01-03"))
- }
-
- test("cast array of numeric types to array of boolean") {
- val tinyintArray = Literal.create(Seq(0.toByte, 1.toByte, -1.toByte),
ArrayType(ByteType))
- val smallintArray = Literal.create(Seq(0.toShort, 2.toShort, -2.toShort),
ArrayType(ShortType))
- val intArray = Literal.create(Seq(0, 3, -3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(0L, 100L, -100L), ArrayType(LongType))
- val floatArray = Literal.create(Seq(0.0f, 1.5f, -2.3f),
ArrayType(FloatType))
- val doubleArray = Literal.create(Seq(0.0, 2.5, -3.7),
ArrayType(DoubleType))
-
- checkEvaluation(cast(tinyintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(smallintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(intArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(bigintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(floatArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(doubleArray, ArrayType(BooleanType)), Seq(false,
true, true))
- }
-
testGluten("missing cases - from boolean") {
(DataTypeTestUtils.numericTypeWithoutDecimal + BooleanType).foreach {
t =>
diff --git
a/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
b/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
index 493a47c56b..64fa85d37f 100644
---
a/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
+++
b/gluten-ut/spark34/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
@@ -55,65 +55,6 @@ class GlutenCastSuite extends CastWithAnsiOffSuite with
GlutenTestsTrait {
}
}
- test("cast array of integer types to array of double") {
- val intArray = Literal.create(Seq(1, 2, 3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(10000000000L), ArrayType(LongType))
- val smallintArray = Literal.create(Seq(1.toShort, -1.toShort),
ArrayType(ShortType))
- val tinyintArray = Literal.create(Seq(1.toByte, -1.toByte),
ArrayType(ByteType))
-
- checkEvaluation(cast(intArray, ArrayType(DoubleType)), Seq(1.0, 2.0, 3.0))
- checkEvaluation(cast(bigintArray, ArrayType(DoubleType)), Seq(1.0e10))
- checkEvaluation(cast(smallintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- checkEvaluation(cast(tinyintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- }
-
- test("cast array of double to array of integer types") {
- val doubleArray = Literal.create(Seq(1.9, -2.1), ArrayType(DoubleType))
-
- checkEvaluation(cast(doubleArray, ArrayType(IntegerType)), Seq(1, -2))
- checkEvaluation(cast(doubleArray, ArrayType(LongType)), Seq(1L, -2L))
- checkEvaluation(cast(doubleArray, ArrayType(ShortType)), Seq(1.toShort,
-2.toShort))
- checkEvaluation(cast(doubleArray, ArrayType(ByteType)), Seq(1.toByte,
-2.toByte))
- }
-
- test("cast array element from allowed types to string (varchar)") {
- val doubleArray = Literal.create(Seq(1.1, null, 3.3),
ArrayType(DoubleType))
- val boolArray = Literal.create(Seq(true, false), ArrayType(BooleanType))
- val timestampArray = Literal.create(
- Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null),
- ArrayType(TimestampType)
- )
- val integerArray = Literal.create(Seq(1, null, 2), ArrayType(IntegerType))
- val longArray = Literal.create(Seq(1L, null, 2L), ArrayType(LongType))
- val dateArray = Literal.create(
- Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
- ArrayType(DateType)
- )
-
- checkEvaluation(cast(doubleArray, ArrayType(StringType)), Seq("1.1", null,
"3.3"))
- checkEvaluation(cast(boolArray, ArrayType(StringType)), Seq("true",
"false"))
- checkEvaluation(cast(timestampArray, ArrayType(StringType)),
Seq("2023-01-01 12:00:00", null))
- checkEvaluation(cast(integerArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(longArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(dateArray, ArrayType(StringType)), Seq("2024-01-01",
null, "2024-01-03"))
- }
-
- test("cast array of numeric types to array of boolean") {
- val tinyintArray = Literal.create(Seq(0.toByte, 1.toByte, -1.toByte),
ArrayType(ByteType))
- val smallintArray = Literal.create(Seq(0.toShort, 2.toShort, -2.toShort),
ArrayType(ShortType))
- val intArray = Literal.create(Seq(0, 3, -3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(0L, 100L, -100L), ArrayType(LongType))
- val floatArray = Literal.create(Seq(0.0f, 1.5f, -2.3f),
ArrayType(FloatType))
- val doubleArray = Literal.create(Seq(0.0, 2.5, -3.7),
ArrayType(DoubleType))
-
- checkEvaluation(cast(tinyintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(smallintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(intArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(bigintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(floatArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(doubleArray, ArrayType(BooleanType)), Seq(false,
true, true))
- }
-
testGluten("missing cases - from byte") {
DataTypeTestUtils.numericTypeWithoutDecimal.foreach {
t =>
diff --git
a/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
b/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
index 4332f704ef..7cf89937a6 100644
---
a/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
+++
b/gluten-ut/spark35/src/test/scala/org/apache/spark/sql/catalyst/expressions/GlutenCastSuite.scala
@@ -44,65 +44,6 @@ class GlutenCastSuite extends CastWithAnsiOffSuite with
GlutenTestsTrait {
UDTRegistration.register(classOf[IExampleBaseType].getName,
classOf[ExampleBaseTypeUDT].getName)
UDTRegistration.register(classOf[IExampleSubType].getName,
classOf[ExampleSubTypeUDT].getName)
- test("cast array of integer types to array of double") {
- val intArray = Literal.create(Seq(1, 2, 3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(10000000000L), ArrayType(LongType))
- val smallintArray = Literal.create(Seq(1.toShort, -1.toShort),
ArrayType(ShortType))
- val tinyintArray = Literal.create(Seq(1.toByte, -1.toByte),
ArrayType(ByteType))
-
- checkEvaluation(cast(intArray, ArrayType(DoubleType)), Seq(1.0, 2.0, 3.0))
- checkEvaluation(cast(bigintArray, ArrayType(DoubleType)), Seq(1.0e10))
- checkEvaluation(cast(smallintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- checkEvaluation(cast(tinyintArray, ArrayType(DoubleType)), Seq(1.0, -1.0))
- }
-
- test("cast array of double to array of integer types") {
- val doubleArray = Literal.create(Seq(1.9, -2.1), ArrayType(DoubleType))
-
- checkEvaluation(cast(doubleArray, ArrayType(IntegerType)), Seq(1, -2))
- checkEvaluation(cast(doubleArray, ArrayType(LongType)), Seq(1L, -2L))
- checkEvaluation(cast(doubleArray, ArrayType(ShortType)), Seq(1.toShort,
-2.toShort))
- checkEvaluation(cast(doubleArray, ArrayType(ByteType)), Seq(1.toByte,
-2.toByte))
- }
-
- test("cast array element from allowed types to string (varchar)") {
- val doubleArray = Literal.create(Seq(1.1, null, 3.3),
ArrayType(DoubleType))
- val boolArray = Literal.create(Seq(true, false), ArrayType(BooleanType))
- val timestampArray = Literal.create(
- Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null),
- ArrayType(TimestampType)
- )
- val integerArray = Literal.create(Seq(1, null, 2), ArrayType(IntegerType))
- val longArray = Literal.create(Seq(1L, null, 2L), ArrayType(LongType))
- val dateArray = Literal.create(
- Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
- ArrayType(DateType)
- )
-
- checkEvaluation(cast(doubleArray, ArrayType(StringType)), Seq("1.1", null,
"3.3"))
- checkEvaluation(cast(boolArray, ArrayType(StringType)), Seq("true",
"false"))
- checkEvaluation(cast(timestampArray, ArrayType(StringType)),
Seq("2023-01-01 12:00:00", null))
- checkEvaluation(cast(integerArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(longArray, ArrayType(StringType)), Seq("1", null,
"2"))
- checkEvaluation(cast(dateArray, ArrayType(StringType)), Seq("2024-01-01",
null, "2024-01-03"))
- }
-
- test("cast array of numeric types to array of boolean") {
- val tinyintArray = Literal.create(Seq(0.toByte, 1.toByte, -1.toByte),
ArrayType(ByteType))
- val smallintArray = Literal.create(Seq(0.toShort, 2.toShort, -2.toShort),
ArrayType(ShortType))
- val intArray = Literal.create(Seq(0, 3, -3), ArrayType(IntegerType))
- val bigintArray = Literal.create(Seq(0L, 100L, -100L), ArrayType(LongType))
- val floatArray = Literal.create(Seq(0.0f, 1.5f, -2.3f),
ArrayType(FloatType))
- val doubleArray = Literal.create(Seq(0.0, 2.5, -3.7),
ArrayType(DoubleType))
-
- checkEvaluation(cast(tinyintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(smallintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(intArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(bigintArray, ArrayType(BooleanType)), Seq(false,
true, true))
- checkEvaluation(cast(floatArray, ArrayType(BooleanType)), Seq(false, true,
true))
- checkEvaluation(cast(doubleArray, ArrayType(BooleanType)), Seq(false,
true, true))
- }
-
testGluten("missing cases - from boolean") {
(DataTypeTestUtils.numericTypeWithoutDecimal ++ Set(BooleanType)).foreach {
t =>
diff --git
a/gluten-ut/test/src/test/scala/org/apache/gluten/expressions/GlutenCastSuite.scala
b/gluten-ut/test/src/test/scala/org/apache/gluten/expressions/GlutenCastSuite.scala
new file mode 100644
index 0000000000..0094da623b
--- /dev/null
+++
b/gluten-ut/test/src/test/scala/org/apache/gluten/expressions/GlutenCastSuite.scala
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.gluten.expressions
+
+import org.apache.spark.SparkFunSuite
+import org.apache.spark.sql.Row
+import org.apache.spark.sql.catalyst.expressions.{Cast, ExpressionEvalHelper,
Literal}
+import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.types._
+
+import java.sql.{Date, Timestamp}
+
+class GlutenCastSuite extends SparkFunSuite with ExpressionEvalHelper {
+ def checkCast(v: Literal, targetType: DataType, expected: Any): Unit = {
+ withSQLConf(SQLConf.ANSI_ENABLED.key -> "false") {
+ checkEvaluation(Cast(v, targetType), expected)
+ }
+ }
+
+ test("cast array of integer types to array of double") {
+ val intArray = Literal.create(Seq(1, 2, 3), ArrayType(IntegerType))
+ val bigintArray = Literal.create(Seq(10000000000L), ArrayType(LongType))
+ val smallintArray = Literal.create(Seq(1.toShort, -1.toShort),
ArrayType(ShortType))
+ val tinyintArray = Literal.create(Seq(1.toByte, -1.toByte),
ArrayType(ByteType))
+
+ checkCast(intArray, ArrayType(DoubleType), Seq(1.0, 2.0, 3.0))
+ checkCast(bigintArray, ArrayType(DoubleType), Seq(1.0e10))
+ checkCast(smallintArray, ArrayType(DoubleType), Seq(1.0, -1.0))
+ checkCast(tinyintArray, ArrayType(DoubleType), Seq(1.0, -1.0))
+ }
+
+ test("cast array of double to array of integer types") {
+ val doubleArray = Literal.create(Seq(1.9, -2.1), ArrayType(DoubleType))
+
+ checkCast(doubleArray, ArrayType(IntegerType), Seq(1, -2))
+ checkCast(doubleArray, ArrayType(LongType), Seq(1L, -2L))
+ checkCast(doubleArray, ArrayType(ShortType), Seq(1.toShort, -2.toShort))
+ checkCast(doubleArray, ArrayType(ByteType), Seq(1.toByte, -2.toByte))
+ }
+
+ test("cast array element from allowed types to string (varchar)") {
+ val doubleArray = Literal.create(Seq(1.1, null, 3.3),
ArrayType(DoubleType))
+ val boolArray = Literal.create(Seq(true, false), ArrayType(BooleanType))
+ val timestampArray = Literal.create(
+ Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null),
+ ArrayType(TimestampType)
+ )
+ val integerArray = Literal.create(Seq(1, null, 2), ArrayType(IntegerType))
+ val longArray = Literal.create(Seq(1L, null, 2L), ArrayType(LongType))
+ val dateArray = Literal.create(
+ Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
+ ArrayType(DateType)
+ )
+
+ checkCast(doubleArray, ArrayType(StringType), Seq("1.1", null, "3.3"))
+ checkCast(boolArray, ArrayType(StringType), Seq("true", "false"))
+ checkCast(timestampArray, ArrayType(StringType), Seq("2023-01-01
12:00:00", null))
+ checkCast(integerArray, ArrayType(StringType), Seq("1", null, "2"))
+ checkCast(longArray, ArrayType(StringType), Seq("1", null, "2"))
+ checkCast(dateArray, ArrayType(StringType), Seq("2024-01-01", null,
"2024-01-03"))
+ }
+
+ test("cast array of numeric types to array of boolean") {
+ val tinyintArray = Literal.create(Seq(0.toByte, 1.toByte, -1.toByte),
ArrayType(ByteType))
+ val smallintArray = Literal.create(Seq(0.toShort, 2.toShort, -2.toShort),
ArrayType(ShortType))
+ val intArray = Literal.create(Seq(0, 3, -3), ArrayType(IntegerType))
+ val bigintArray = Literal.create(Seq(0L, 100L, -100L), ArrayType(LongType))
+ val floatArray = Literal.create(Seq(0.0f, 1.5f, -2.3f),
ArrayType(FloatType))
+ val doubleArray = Literal.create(Seq(0.0, 2.5, -3.7),
ArrayType(DoubleType))
+
+ checkCast(tinyintArray, ArrayType(BooleanType), Seq(false, true, true))
+ checkCast(smallintArray, ArrayType(BooleanType), Seq(false, true, true))
+ checkCast(intArray, ArrayType(BooleanType), Seq(false, true, true))
+ checkCast(bigintArray, ArrayType(BooleanType), Seq(false, true, true))
+ checkCast(floatArray, ArrayType(BooleanType), Seq(false, true, true))
+ checkCast(doubleArray, ArrayType(BooleanType), Seq(false, true, true))
+ }
+
+ test("cast array of string") {
+ val integerStringArray = Literal.create(Seq("123", "-98", "abc"),
ArrayType(StringType))
+ val floatingPointStringArray =
+ Literal.create(Seq("123e-2", "-234.548", "xyz"), ArrayType(StringType))
+ val timestampStringArray = Literal.create(
+ Seq("2023-01-01 12:00:00", "2023-01-02 12:00:00", "def"),
+ ArrayType(StringType))
+ val dateStringArray =
+ Literal.create(Seq("2024-01-01", "2024-01-02", "uvw"),
ArrayType(StringType))
+
+ checkCast(integerStringArray, ArrayType(ByteType), Seq(123.toByte,
-98.toByte, null))
+ checkCast(integerStringArray, ArrayType(ShortType), Seq(123.toShort,
-98.toShort, null))
+ checkCast(integerStringArray, ArrayType(IntegerType), Seq(123, -98, null))
+ checkCast(integerStringArray, ArrayType(LongType), Seq(123L, -98L, null))
+ checkCast(floatingPointStringArray, ArrayType(DoubleType), Seq(1.23,
-234.548, null))
+ checkCast(floatingPointStringArray, ArrayType(FloatType), Seq(1.23f,
-234.548f, null))
+ checkCast(
+ timestampStringArray,
+ ArrayType(TimestampType),
+ Seq(Timestamp.valueOf("2023-01-01 12:00:00"),
Timestamp.valueOf("2023-01-02 12:00:00"), null))
+ checkCast(
+ dateStringArray,
+ ArrayType(DateType),
+ Seq(Date.valueOf("2024-01-01"), Date.valueOf("2024-01-02"), null))
+ }
+
+ test("cast maps") {
+ val byteMap = Literal.create(
+ Map(0.toByte -> 1.toByte, 2.toByte -> 3.toByte, 4.toByte -> 0.toByte),
+ MapType(ByteType, ByteType))
+ checkCast(
+ byteMap,
+ MapType(ByteType, DoubleType),
+ Map(0.toByte -> 1.0, 2.toByte -> 3.0, 4.toByte -> 0.0))
+ checkCast(
+ byteMap,
+ MapType(DoubleType, ByteType),
+ Map(0.0 -> 1.toByte, 2.0 -> 3.toByte, 4.0 -> 0.toByte))
+ checkCast(
+ byteMap,
+ MapType(ByteType, StringType),
+ Map(0.toByte -> "1", 2.toByte -> "3", 4.toByte -> "0"))
+ checkCast(
+ byteMap,
+ MapType(StringType, ByteType),
+ Map("0" -> 1.toByte, "2" -> 3.toByte, "4" -> 0.toByte))
+ checkCast(
+ byteMap,
+ MapType(ByteType, BooleanType),
+ Map(0.toByte -> true, 2.toByte -> true, 4.toByte -> false))
+
+ val shortMap = Literal.create(
+ Map(1000.toShort -> 1001.toShort, 1002.toShort -> 1003.toShort,
1004.toShort -> 0.toShort),
+ MapType(ShortType, ShortType))
+ checkCast(
+ shortMap,
+ MapType(ShortType, DoubleType),
+ Map(1000.toShort -> 1001.0, 1002.toShort -> 1003.0, 1004.toShort -> 0.0))
+ checkCast(
+ shortMap,
+ MapType(DoubleType, ShortType),
+ Map(1000.0 -> 1001.toShort, 1002.0 -> 1003.toShort, 1004.0 -> 0.toShort))
+ checkCast(
+ shortMap,
+ MapType(ShortType, StringType),
+ Map(1000.toShort -> "1001", 1002.toShort -> "1003", 1004.toShort -> "0"))
+ checkCast(
+ shortMap,
+ MapType(StringType, ShortType),
+ Map("1000" -> 1001.toShort, "1002" -> 1003.toShort, "1004" -> 0.toShort))
+ checkCast(
+ shortMap,
+ MapType(ShortType, BooleanType),
+ Map(1000.toShort -> true, 1002.toShort -> true, 1004.toShort -> false))
+
+ val intMap = Literal.create(
+ Map(100 -> "101", 102 -> "103", 104 -> "xyz"),
+ MapType(IntegerType, StringType))
+ checkCast(
+ intMap,
+ MapType(DoubleType, IntegerType),
+ Map(100.0 -> 101, 102.0 -> 103, 104.0 -> null))
+ checkCast(
+ intMap,
+ MapType(StringType, StringType),
+ Map("100" -> "101", "102" -> "103", "104" -> "xyz"))
+
+ val floatMap = Literal.create(
+ Map(1.0f -> "2.0", -3.0f -> "40e-1", 5.0f -> "xyz"),
+ MapType(FloatType, StringType))
+ checkCast(
+ floatMap,
+ MapType(FloatType, FloatType),
+ Map(1.0f -> 2.0f, -3.0f -> 4.0f, 5.0f -> null))
+ checkCast(
+ floatMap,
+ MapType(StringType, StringType),
+ Map("1.0" -> "2.0", "-3.0" -> "40e-1", "5.0" -> "xyz"))
+
+ val timestampMap = Literal.create(
+ Map(
+ Timestamp.valueOf("2023-01-01 12:00:00") -> "2023-01-01 13:00:00",
+ Timestamp.valueOf("2023-01-02 12:00:00") -> "xyz"),
+ MapType(TimestampType, StringType)
+ )
+ checkCast(
+ timestampMap,
+ MapType(StringType, TimestampType),
+ Map(
+ "2023-01-01 12:00:00" -> Timestamp.valueOf("2023-01-01 13:00:00"),
+ "2023-01-02 12:00:00" -> null))
+
+ val dateMap = Literal.create(
+ Map(Date.valueOf("2024-01-01") -> "2024-01-02",
Date.valueOf("2024-02-01") -> "xyz"),
+ MapType(DateType, StringType))
+ checkCast(
+ dateMap,
+ MapType(StringType, DateType),
+ Map("2024-01-01" -> Date.valueOf("2024-01-02"), "2024-02-01" -> null))
+ }
+
+ test("cast structs") {
+ val struct = Literal.create(
+ Row(
+ Seq("123", "456.7", "2023-01-01 12:00:00", "2024-01-01"),
+ Map(1.toByte -> 2.toShort, 3.toByte -> 4.toShort),
+ Row(
+ 123.0,
+ 456.1f,
+ 0
+ )
+ ),
+ StructType(
+ Seq(
+ StructField("a", ArrayType(StringType)),
+ StructField("b", MapType(ByteType, ShortType)),
+ StructField(
+ "c",
+ StructType(
+ Seq(
+ StructField("x", DoubleType),
+ StructField("y", FloatType),
+ StructField("z", IntegerType)
+ ))
+ )
+ ))
+ )
+
+ checkCast(
+ struct,
+ StructType(
+ Seq(
+ StructField("a", ArrayType(LongType)),
+ StructField("b", MapType(ShortType, IntegerType)),
+ StructField(
+ "c",
+ StructType(
+ Seq(
+ StructField("x", StringType),
+ StructField("y", StringType),
+ StructField("z", BooleanType)
+ ))
+ )
+ )),
+ Row(
+ Seq(123L, 456L, null, null),
+ Map(1.toShort -> 2, 3.toShort -> 4),
+ Row(
+ "123.0",
+ "456.1",
+ false
+ )
+ )
+ )
+
+ checkCast(
+ struct,
+ StructType(
+ Seq(
+ StructField("a", ArrayType(DoubleType)),
+ StructField("b", MapType(IntegerType, LongType)),
+ StructField(
+ "c",
+ StructType(
+ Seq(
+ StructField("x", IntegerType),
+ StructField("y", BooleanType),
+ StructField("z", StringType)
+ ))
+ )
+ )),
+ Row(
+ Seq(123.0, 456.7, null, null),
+ Map(1 -> 2L, 3 -> 4L),
+ Row(
+ 123,
+ true,
+ "0"
+ )
+ )
+ )
+
+ checkCast(
+ struct,
+ StructType(
+ Seq(
+ StructField("a", ArrayType(TimestampType)),
+ StructField("b", MapType(LongType, BooleanType)),
+ StructField(
+ "c",
+ StructType(
+ Seq(
+ StructField("x", ByteType),
+ StructField("y", ShortType),
+ StructField("z", DoubleType)
+ ))
+ )
+ )),
+ Row(
+ Seq(
+ null,
+ null,
+ Timestamp.valueOf("2023-01-01 12:00:00"),
+ Timestamp.valueOf("2024-01-01 00:00:00")),
+ Map(1L -> true, 3L -> true),
+ Row(
+ 123.toByte,
+ 456.toShort,
+ 0.0
+ )
+ )
+ )
+
+ checkCast(
+ struct,
+ StructType(
+ Seq(
+ StructField("a", ArrayType(DateType)),
+ StructField("b", MapType(StringType, DoubleType)),
+ StructField(
+ "c",
+ StructType(
+ Seq(
+ StructField("x", IntegerType),
+ StructField("y", LongType),
+ StructField("z", FloatType)
+ ))
+ )
+ )),
+ Row(
+ Seq(null, null, Date.valueOf("2023-01-01"),
Date.valueOf("2024-01-01")),
+ Map("1" -> 2.0, "3" -> 4.0),
+ Row(
+ 123,
+ 456L,
+ 0.0f
+ )
+ )
+ )
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]