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 699c2f7a9f [GLUTEN-9392][VL] Support casting array element to varchar 
(#9394)
699c2f7a9f is described below

commit 699c2f7a9fe5173a7a10d025168ed1a23a2f36f6
Author: Arnav Balyan <[email protected]>
AuthorDate: Mon Apr 28 21:06:44 2025 +0530

    [GLUTEN-9392][VL] Support casting array element to varchar (#9394)
---
 .../substrait/SubstraitToVeloxPlanValidator.cc     | 27 ++++++++++
 .../utils/clickhouse/ClickHouseTestSettings.scala  |  5 ++
 .../sql/catalyst/expressions/GlutenCastSuite.scala | 63 ++++++++++++++++++++++
 .../utils/clickhouse/ClickHouseTestSettings.scala  |  5 ++
 .../sql/catalyst/expressions/GlutenCastSuite.scala | 63 ++++++++++++++++++++++
 .../utils/clickhouse/ClickHouseTestSettings.scala  |  5 ++
 .../sql/catalyst/expressions/GlutenCastSuite.scala | 63 ++++++++++++++++++++++
 .../utils/clickhouse/ClickHouseTestSettings.scala  |  5 ++
 .../sql/catalyst/expressions/GlutenCastSuite.scala | 63 ++++++++++++++++++++++
 9 files changed, 299 insertions(+)

diff --git a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc 
b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
index 15b6949c78..a91c96f039 100644
--- a/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
+++ b/cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc
@@ -232,6 +232,22 @@ bool SubstraitToVeloxPlanValidator::validateScalarFunction(
   return true;
 }
 
+bool isSupportedArrayCast(const TypePtr& fromType, const TypePtr& toType) {
+  static const std::unordered_set<TypeKind> kAllowedArrayElementKinds = {
+      TypeKind::DOUBLE,
+      TypeKind::BOOLEAN,
+      TypeKind::TIMESTAMP,
+  };
+
+  // https://github.com/apache/incubator-gluten/issues/9392
+  // is currently WIP to add support for other types.
+  if (toType->isVarchar()) {
+    return kAllowedArrayElementKinds.count(fromType->kind()) > 0;
+  }
+
+  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,
@@ -275,6 +291,17 @@ bool SubstraitToVeloxPlanValidator::isAllowedCast(const 
TypePtr& fromType, const
     return false;
   }
 
+  if (fromType->isArray() && toType->isArray()) {
+    const auto& toElem = toType->asArray().elementType();
+    const auto& fromElem = fromType->asArray().elementType();
+
+    if (!isAllowedCast(fromElem, toElem)) {
+      return false;
+    }
+
+    return isSupportedArrayCast(fromElem, toElem);
+  }
+
   // Limited support for Complex types.
   if (fromType->isArray() || fromType->isMap() || fromType->isRow()) {
     return false;
diff --git 
a/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
 
b/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
index cdd2509680..ba21c3d6f4 100644
--- 
a/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
+++ 
b/gluten-ut/spark32/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
@@ -609,6 +609,11 @@ class ClickHouseTestSettings extends BackendTestSettings {
     .exclude("SPARK-34727: cast from float II")
     .exclude("SPARK-35720: cast invalid string input to timestamp without time 
zone")
     .exclude("Cast should output null for invalid strings when ANSI is not 
enabled.")
+    .exclude("cast array element from integer to string")
+    .exclude("cast array element from double to string")
+    .exclude("cast array element from bool to string")
+    .exclude("cast array element from date to string")
+    .exclude("cast array from timestamp to string")
   enableSuite[GlutenCastSuiteWithAnsiModeOn]
     .exclude("null cast")
     .exclude("cast string to date")
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 31446aba08..235c761062 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
@@ -43,6 +43,69 @@ 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 element from integer to string") {
+    val inputWithNull = Literal.create(Seq(1, null, 3), ArrayType(IntegerType))
+    val expectedWithNull = Seq("1", null, "3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Int], ArrayType(IntegerType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+
+    val inputNegative = Literal.create(Seq(-1, 0, 999999), 
ArrayType(IntegerType))
+    val expectedNegative = Seq("-1", "0", "999999")
+    checkEvaluation(cast(inputNegative, ArrayType(StringType)), 
expectedNegative)
+  }
+
+  test("cast array element from double to string") {
+    val inputWithNull = Literal.create(Seq(1.1, null, 3.3), 
ArrayType(DoubleType))
+    val expectedWithNull = Seq("1.1", null, "3.3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputScientific = Literal.create(Seq(1.23e4, -5.67e-3), 
ArrayType(DoubleType))
+    val expectedScientific = Seq("12300.0", "-0.00567")
+    checkEvaluation(cast(inputScientific, ArrayType(StringType)), 
expectedScientific)
+  }
+
+  test("cast array element from bool to string") {
+    val inputWithNull = Literal.create(Seq(true, null, false), 
ArrayType(BooleanType))
+    val expectedWithNull = Seq("true", null, "false")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Boolean], ArrayType(BooleanType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
+  test("cast array element from date to string") {
+    val inputWithNull = Literal.create(
+      Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
+      ArrayType(DateType)
+    )
+    val expectedWithNull = Seq("2024-01-01", null, "2024-01-03")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputLeapYear = Literal.create(
+      Seq(Date.valueOf("2020-02-29")),
+      ArrayType(DateType)
+    )
+    val expectedLeapYear = Seq("2020-02-29")
+    checkEvaluation(cast(inputLeapYear, ArrayType(StringType)), 
expectedLeapYear)
+  }
+
+  test("cast array from timestamp to string") {
+    val inputWithNull = Literal.create(
+      Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null, 
Timestamp.valueOf("2023-12-31 23:59:59")),
+      ArrayType(TimestampType)
+    )
+    val expectedWithNull = Seq("2023-01-01 12:00:00", null, "2023-12-31 
23:59:59")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Timestamp], 
ArrayType(TimestampType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
   testGluten("missing cases - from boolean") {
     (DataTypeTestUtils.numericTypeWithoutDecimal + BooleanType).foreach {
       t =>
diff --git 
a/gluten-ut/spark33/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
 
b/gluten-ut/spark33/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
index 2d9444e7a6..e095d7760a 100644
--- 
a/gluten-ut/spark33/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
+++ 
b/gluten-ut/spark33/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
@@ -626,6 +626,11 @@ class ClickHouseTestSettings extends BackendTestSettings {
     .exclude("SPARK-36924: Cast YearMonthIntervalType to IntegralType")
     .exclude("SPARK-36924: Cast IntegralType to YearMonthIntervalType")
     .exclude("Cast should output null for invalid strings when ANSI is not 
enabled.")
+    .exclude("cast array element from integer to string")
+    .exclude("cast array element from double to string")
+    .exclude("cast array element from bool to string")
+    .exclude("cast array element from date to string")
+    .exclude("cast array from timestamp to string")
   enableSuite[GlutenCastSuiteWithAnsiModeOn]
     .exclude("null cast")
     .exclude("cast string to date")
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 2bc2f8b1a2..13eb8fa14c 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,6 +43,69 @@ 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 element from integer to string") {
+    val inputWithNull = Literal.create(Seq(1, null, 3), ArrayType(IntegerType))
+    val expectedWithNull = Seq("1", null, "3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Int], ArrayType(IntegerType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+
+    val inputNegative = Literal.create(Seq(-1, 0, 999999), 
ArrayType(IntegerType))
+    val expectedNegative = Seq("-1", "0", "999999")
+    checkEvaluation(cast(inputNegative, ArrayType(StringType)), 
expectedNegative)
+  }
+
+  test("cast array element from double to string") {
+    val inputWithNull = Literal.create(Seq(1.1, null, 3.3), 
ArrayType(DoubleType))
+    val expectedWithNull = Seq("1.1", null, "3.3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputScientific = Literal.create(Seq(1.23e4, -5.67e-3), 
ArrayType(DoubleType))
+    val expectedScientific = Seq("12300.0", "-0.00567")
+    checkEvaluation(cast(inputScientific, ArrayType(StringType)), 
expectedScientific)
+  }
+
+  test("cast array element from bool to string") {
+    val inputWithNull = Literal.create(Seq(true, null, false), 
ArrayType(BooleanType))
+    val expectedWithNull = Seq("true", null, "false")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Boolean], ArrayType(BooleanType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
+  test("cast array element from date to string") {
+    val inputWithNull = Literal.create(
+      Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
+      ArrayType(DateType)
+    )
+    val expectedWithNull = Seq("2024-01-01", null, "2024-01-03")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputLeapYear = Literal.create(
+      Seq(Date.valueOf("2020-02-29")), // Leap day
+      ArrayType(DateType)
+    )
+    val expectedLeapYear = Seq("2020-02-29")
+    checkEvaluation(cast(inputLeapYear, ArrayType(StringType)), 
expectedLeapYear)
+  }
+
+  test("cast array from timestamp to string") {
+    val inputWithNull = Literal.create(
+      Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null, 
Timestamp.valueOf("2023-12-31 23:59:59")),
+      ArrayType(TimestampType)
+    )
+    val expectedWithNull = Seq("2023-01-01 12:00:00", null, "2023-12-31 
23:59:59")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Timestamp], 
ArrayType(TimestampType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
   testGluten("missing cases - from boolean") {
     (DataTypeTestUtils.numericTypeWithoutDecimal + BooleanType).foreach {
       t =>
diff --git 
a/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
 
b/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
index 9c0d966ef4..d8527ea639 100644
--- 
a/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
+++ 
b/gluten-ut/spark34/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
@@ -565,6 +565,11 @@ class ClickHouseTestSettings extends BackendTestSettings {
     .exclude("SPARK-36924: Cast IntegralType to DayTimeIntervalType")
     .exclude("SPARK-36924: Cast YearMonthIntervalType to IntegralType")
     .exclude("SPARK-36924: Cast IntegralType to YearMonthIntervalType")
+    .exclude("cast array element from integer to string")
+    .exclude("cast array element from double to string")
+    .exclude("cast array element from bool to string")
+    .exclude("cast array element from date to string")
+    .exclude("cast array from timestamp to string")
   enableSuite[GlutenCollectionExpressionsSuite]
     .exclude("ArraysZip") // wait for 
https://github.com/ClickHouse/ClickHouse/pull/69576
     .exclude("Sequence of numbers")
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 e948601f29..07d3588885 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
@@ -44,6 +44,56 @@ 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 element from integer to string") {
+    val inputWithNull = Literal.create(Seq(1, null, 3), ArrayType(IntegerType))
+    val expectedWithNull = Seq("1", null, "3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Int], ArrayType(IntegerType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+
+    val inputNegative = Literal.create(Seq(-1, 0, 999999), 
ArrayType(IntegerType))
+    val expectedNegative = Seq("-1", "0", "999999")
+    checkEvaluation(cast(inputNegative, ArrayType(StringType)), 
expectedNegative)
+  }
+
+  test("cast array element from double to string") {
+    val inputWithNull = Literal.create(Seq(1.1, null, 3.3), 
ArrayType(DoubleType))
+    val expectedWithNull = Seq("1.1", null, "3.3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputScientific = Literal.create(Seq(1.23e4, -5.67e-3), 
ArrayType(DoubleType))
+    val expectedScientific = Seq("12300.0", "-0.00567")
+    checkEvaluation(cast(inputScientific, ArrayType(StringType)), 
expectedScientific)
+  }
+
+  test("cast array element from bool to string") {
+    val inputWithNull = Literal.create(Seq(true, null, false), 
ArrayType(BooleanType))
+    val expectedWithNull = Seq("true", null, "false")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Boolean], ArrayType(BooleanType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
+  test("cast array element from date to string") {
+    val inputWithNull = Literal.create(
+      Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
+      ArrayType(DateType)
+    )
+    val expectedWithNull = Seq("2024-01-01", null, "2024-01-03")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputLeapYear = Literal.create(
+      Seq(Date.valueOf("2020-02-29")),
+      ArrayType(DateType)
+    )
+    val expectedLeapYear = Seq("2020-02-29")
+    checkEvaluation(cast(inputLeapYear, ArrayType(StringType)), 
expectedLeapYear)
+  }
+
   testGluten("missing cases - from boolean") {
     (DataTypeTestUtils.numericTypeWithoutDecimal + BooleanType).foreach {
       case t @ BooleanType =>
@@ -55,6 +105,19 @@ class GlutenCastSuite extends CastWithAnsiOffSuite with 
GlutenTestsTrait {
     }
   }
 
+  test("cast array from timestamp to string") {
+    val inputWithNull = Literal.create(
+      Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null, 
Timestamp.valueOf("2023-12-31 23:59:59")),
+      ArrayType(TimestampType)
+    )
+    val expectedWithNull = Seq("2023-01-01 12:00:00", null, "2023-12-31 
23:59:59")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Timestamp], 
ArrayType(TimestampType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
   testGluten("missing cases - from byte") {
     DataTypeTestUtils.numericTypeWithoutDecimal.foreach {
       t =>
diff --git 
a/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
 
b/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
index ff01c5452d..64e75994e0 100644
--- 
a/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
+++ 
b/gluten-ut/spark35/src/test/scala/org/apache/gluten/utils/clickhouse/ClickHouseTestSettings.scala
@@ -382,6 +382,11 @@ class ClickHouseTestSettings extends BackendTestSettings {
     .exclude("SPARK-39749: cast Decimal to string")
     .exclude("SPARK-42176: cast boolean to timestamp")
     .exclude("null cast #2")
+    .exclude("cast array element from integer to string")
+    .exclude("cast array element from double to string")
+    .exclude("cast array element from bool to string")
+    .exclude("cast array element from date to string")
+    .exclude("cast array from timestamp to string")
   enableSuite[GlutenCoalesceShufflePartitionsSuite]
     .excludeByPrefix("determining the number of reducers")
     .excludeCH("SPARK-46590 adaptive query execution works correctly with 
broadcast join and union")
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 da611ca846..7debbf0c80 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,6 +44,69 @@ 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 element from integer to string") {
+    val inputWithNull = Literal.create(Seq(1, null, 3), ArrayType(IntegerType))
+    val expectedWithNull = Seq("1", null, "3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Int], ArrayType(IntegerType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+
+    val inputNegative = Literal.create(Seq(-1, 0, 999999), 
ArrayType(IntegerType))
+    val expectedNegative = Seq("-1", "0", "999999")
+    checkEvaluation(cast(inputNegative, ArrayType(StringType)), 
expectedNegative)
+  }
+
+  test("cast array element from double to string") {
+    val inputWithNull = Literal.create(Seq(1.1, null, 3.3), 
ArrayType(DoubleType))
+    val expectedWithNull = Seq("1.1", null, "3.3")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputScientific = Literal.create(Seq(1.23e4, -5.67e-3), 
ArrayType(DoubleType))
+    val expectedScientific = Seq("12300.0", "-0.00567")
+    checkEvaluation(cast(inputScientific, ArrayType(StringType)), 
expectedScientific)
+  }
+
+  test("cast array element from bool to string") {
+    val inputWithNull = Literal.create(Seq(true, null, false), 
ArrayType(BooleanType))
+    val expectedWithNull = Seq("true", null, "false")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Boolean], ArrayType(BooleanType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
+  test("cast array element from date to string") {
+    val inputWithNull = Literal.create(
+      Seq(Date.valueOf("2024-01-01"), null, Date.valueOf("2024-01-03")),
+      ArrayType(DateType)
+    )
+    val expectedWithNull = Seq("2024-01-01", null, "2024-01-03")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val inputLeapYear = Literal.create(
+      Seq(Date.valueOf("2020-02-29")),
+      ArrayType(DateType)
+    )
+    val expectedLeapYear = Seq("2020-02-29")
+    checkEvaluation(cast(inputLeapYear, ArrayType(StringType)), 
expectedLeapYear)
+  }
+
+  test("cast array from timestamp to string") {
+    val inputWithNull = Literal.create(
+      Seq(Timestamp.valueOf("2023-01-01 12:00:00"), null, 
Timestamp.valueOf("2023-12-31 23:59:59")),
+      ArrayType(TimestampType)
+    )
+    val expectedWithNull = Seq("2023-01-01 12:00:00", null, "2023-12-31 
23:59:59")
+    checkEvaluation(cast(inputWithNull, ArrayType(StringType)), 
expectedWithNull)
+
+    val emptyInput = Literal.create(Seq.empty[Timestamp], 
ArrayType(TimestampType))
+    val expectedEmpty = Seq.empty[String]
+    checkEvaluation(cast(emptyInput, ArrayType(StringType)), expectedEmpty)
+  }
+
   testGluten("missing cases - from boolean") {
     (DataTypeTestUtils.numericTypeWithoutDecimal ++ Set(BooleanType)).foreach {
       t =>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to