Skip to content

Commit 2687b1f

Browse files
committed
Fix Scala 2.13 compatibility for nested arrays
- Convert mutable.ArraySeq to Array in ClickHouseJsonReader to ensure immutable collections - Add test workaround for Spark's Row.getSeq behavior in Scala 2.13 - Fix Spotless formatting: remove trailing whitespace in ClickHouseBinaryReader - Applied to all Spark versions: 3.3, 3.4, 3.5
1 parent 8beb2bc commit 2687b1f

File tree

8 files changed

+31
-23
lines changed

8 files changed

+31
-23
lines changed

spark-3.3/clickhouse-spark-it/src/test/scala/org/apache/spark/sql/clickhouse/single/ClickHouseWriterTestBase.scala

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,14 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
9090

9191
val result = spark.table("test_db.test_write_nested_array").orderBy("id").collect()
9292
assert(result.length == 3)
93-
assert(result(0).getSeq[Seq[Int]](1) == Seq(Seq(1, 2), Seq(3, 4)))
94-
assert(result(1).getSeq[Seq[Int]](1) == Seq(Seq(10, 20, 30)))
95-
assert(result(2).getSeq[Seq[Int]](1)(0).isEmpty)
96-
assert(result(2).getSeq[Seq[Int]](1)(1) == Seq(100))
93+
// Convert to List for Scala 2.12/2.13 compatibility
94+
val row0 = result(0).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
95+
val row1 = result(1).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
96+
val row2 = result(2).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
97+
assert(row0 == Seq(Seq(1, 2), Seq(3, 4)))
98+
assert(row1 == Seq(Seq(10, 20, 30)))
99+
assert(row2(0).isEmpty)
100+
assert(row2(1) == Seq(100))
97101
}
98102
}
99103

@@ -284,7 +288,6 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
284288
}
285289
}
286290

287-
288291
test("write DecimalType - Decimal(18,4)") {
289292
// Note: High-precision decimals (>15-17 significant digits) may lose precision in JSON/Arrow formats.
290293
// This appears to be related to the serialization/deserialization path, possibly due to intermediate
@@ -706,7 +709,6 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
706709
}
707710
}
708711

709-
710712
test("write TimestampType - nullable with null values") {
711713
val schema = StructType(Seq(
712714
StructField("id", IntegerType, nullable = false),

spark-3.3/clickhouse-spark/src/main/scala/com/clickhouse/spark/read/format/ClickHouseBinaryReader.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class ClickHouseBinaryReader(
108108
case TimestampType =>
109109
var _instant = value.asInstanceOf[ZonedDateTime].withZoneSameInstant(ZoneOffset.UTC)
110110
TimeUnit.SECONDS.toMicros(_instant.toEpochSecond) + TimeUnit.NANOSECONDS.toMicros(_instant.getNano())
111-
case StringType =>
111+
case StringType =>
112112
val strValue = value match {
113113
case uuid: java.util.UUID => uuid.toString
114114
case inet: java.net.InetAddress => inet.getHostAddress
@@ -117,7 +117,7 @@ class ClickHouseBinaryReader(
117117
case _ => value.toString
118118
}
119119
UTF8String.fromString(strValue)
120-
case DateType =>
120+
case DateType =>
121121
val localDate = value match {
122122
case ld: LocalDate => ld
123123
case zdt: ZonedDateTime => zdt.toLocalDate

spark-3.3/clickhouse-spark/src/main/scala/com/clickhouse/spark/read/format/ClickHouseJsonReader.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class ClickHouseJsonReader(
9393
jsonNode.binaryValue
9494
case ArrayType(_dataType, _nullable) =>
9595
val _structField = StructField(s"${structField.name}__array_element__", _dataType, _nullable)
96-
new GenericArrayData(jsonNode.asScala.map(decodeValue(_, _structField)))
96+
new GenericArrayData(jsonNode.asScala.map(decodeValue(_, _structField)).toArray)
9797
case MapType(StringType, _valueType, _valueNullable) =>
9898
val mapData = jsonNode.fields.asScala.map { entry =>
9999
val _structField = StructField(s"${structField.name}__map_value__", _valueType, _valueNullable)

spark-3.4/clickhouse-spark-it/src/test/scala/org/apache/spark/sql/clickhouse/single/ClickHouseWriterTestBase.scala

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,14 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
9090

9191
val result = spark.table("test_db.test_write_nested_array").orderBy("id").collect()
9292
assert(result.length == 3)
93-
assert(result(0).getSeq[Seq[Int]](1) == Seq(Seq(1, 2), Seq(3, 4)))
94-
assert(result(1).getSeq[Seq[Int]](1) == Seq(Seq(10, 20, 30)))
95-
assert(result(2).getSeq[Seq[Int]](1)(0).isEmpty)
96-
assert(result(2).getSeq[Seq[Int]](1)(1) == Seq(100))
93+
// Convert to List for Scala 2.12/2.13 compatibility
94+
val row0 = result(0).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
95+
val row1 = result(1).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
96+
val row2 = result(2).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
97+
assert(row0 == Seq(Seq(1, 2), Seq(3, 4)))
98+
assert(row1 == Seq(Seq(10, 20, 30)))
99+
assert(row2(0).isEmpty)
100+
assert(row2(1) == Seq(100))
97101
}
98102
}
99103

@@ -284,7 +288,6 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
284288
}
285289
}
286290

287-
288291
test("write DecimalType - Decimal(18,4)") {
289292
// Note: High-precision decimals (>15-17 significant digits) may lose precision in JSON/Arrow formats.
290293
// This appears to be related to the serialization/deserialization path, possibly due to intermediate
@@ -706,7 +709,6 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
706709
}
707710
}
708711

709-
710712
test("write TimestampType - nullable with null values") {
711713
val schema = StructType(Seq(
712714
StructField("id", IntegerType, nullable = false),

spark-3.4/clickhouse-spark/src/main/scala/com/clickhouse/spark/read/format/ClickHouseBinaryReader.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class ClickHouseBinaryReader(
108108
case TimestampType =>
109109
var _instant = value.asInstanceOf[ZonedDateTime].withZoneSameInstant(ZoneOffset.UTC)
110110
TimeUnit.SECONDS.toMicros(_instant.toEpochSecond) + TimeUnit.NANOSECONDS.toMicros(_instant.getNano())
111-
case StringType =>
111+
case StringType =>
112112
val strValue = value match {
113113
case uuid: java.util.UUID => uuid.toString
114114
case inet: java.net.InetAddress => inet.getHostAddress
@@ -117,7 +117,7 @@ class ClickHouseBinaryReader(
117117
case _ => value.toString
118118
}
119119
UTF8String.fromString(strValue)
120-
case DateType =>
120+
case DateType =>
121121
val localDate = value match {
122122
case ld: LocalDate => ld
123123
case zdt: ZonedDateTime => zdt.toLocalDate

spark-3.4/clickhouse-spark/src/main/scala/com/clickhouse/spark/read/format/ClickHouseJsonReader.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class ClickHouseJsonReader(
9393
jsonNode.binaryValue
9494
case ArrayType(_dataType, _nullable) =>
9595
val _structField = StructField(s"${structField.name}__array_element__", _dataType, _nullable)
96-
new GenericArrayData(jsonNode.asScala.map(decodeValue(_, _structField)))
96+
new GenericArrayData(jsonNode.asScala.map(decodeValue(_, _structField)).toArray)
9797
case MapType(StringType, _valueType, _valueNullable) =>
9898
val mapData = jsonNode.fields.asScala.map { entry =>
9999
val _structField = StructField(s"${structField.name}__map_value__", _valueType, _valueNullable)

spark-3.5/clickhouse-spark-it/src/test/scala/org/apache/spark/sql/clickhouse/single/ClickHouseWriterTestBase.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,14 @@ trait ClickHouseWriterTestBase extends SparkClickHouseSingleTest {
9090

9191
val result = spark.table("test_db.test_write_nested_array").orderBy("id").collect()
9292
assert(result.length == 3)
93-
assert(result(0).getSeq[Seq[Int]](1) == Seq(Seq(1, 2), Seq(3, 4)))
94-
assert(result(1).getSeq[Seq[Int]](1) == Seq(Seq(10, 20, 30)))
95-
assert(result(2).getSeq[Seq[Int]](1)(0).isEmpty)
96-
assert(result(2).getSeq[Seq[Int]](1)(1) == Seq(100))
93+
// Convert to List for Scala 2.12/2.13 compatibility
94+
val row0 = result(0).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
95+
val row1 = result(1).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
96+
val row2 = result(2).getAs[scala.collection.Seq[scala.collection.Seq[Int]]](1).map(_.toList).toList
97+
assert(row0 == Seq(Seq(1, 2), Seq(3, 4)))
98+
assert(row1 == Seq(Seq(10, 20, 30)))
99+
assert(row2(0).isEmpty)
100+
assert(row2(1) == Seq(100))
97101
}
98102
}
99103

spark-3.5/clickhouse-spark/src/main/scala/com/clickhouse/spark/read/format/ClickHouseJsonReader.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class ClickHouseJsonReader(
9393
jsonNode.binaryValue
9494
case ArrayType(_dataType, _nullable) =>
9595
val _structField = StructField(s"${structField.name}__array_element__", _dataType, _nullable)
96-
new GenericArrayData(jsonNode.asScala.map(decodeValue(_, _structField)))
96+
new GenericArrayData(jsonNode.asScala.map(decodeValue(_, _structField)).toArray)
9797
case MapType(StringType, _valueType, _valueNullable) =>
9898
val mapData = jsonNode.fields.asScala.map { entry =>
9999
val _structField = StructField(s"${structField.name}__map_value__", _valueType, _valueNullable)

0 commit comments

Comments
 (0)