viirya commented on code in PR #6036:
URL: https://github.com/apache/datafusion-comet/pull/6036#discussion_r4054174214


##########
spark/src/test/scala/org/apache/comet/exec/CometExecSuite.scala:
##########
@@ -3821,6 +3834,78 @@ class CometExecSuite extends CometTestBase {
     }
   }
 
+  test("SparkToColumnar string maps cross RDD and Parquet native boundaries") {

Review Comment:
   This test is close to line-for-line with "SparkToColumnar string arrays 
cross JSON and Parquet native boundaries" at line 3772 — same conf block, same 
`conversions.size == 1` / `supportsColumnar` assertions, same native-shuffle 
check, same `limit(1)` early-stop, same disabled-control block. The differences 
are the schema, the row fixtures, and the projected expression.
   
   Worth folding into one test parameterized over the collection type. If the 
gate becomes recursive per my top-level comment, this falls out naturally as 
one more entry in a `dataType` loop rather than a third copy.



##########
spark/src/main/scala/org/apache/spark/sql/comet/CometSparkToColumnarExec.scala:
##########
@@ -142,6 +142,7 @@ object CometSparkToColumnarExec extends 
CometSink[SparkPlan] with DataTypeSuppor
       name: String,
       fallbackReasons: ListBuffer[String]): Boolean = dt match {
     case ArrayType(StringType, _) => true
+    case MapType(StringType, StringType, _) => true

Review Comment:
   This line depends on a Scala/Spark subtlety that nothing here records: in 
Spark 4.x `StringType` is a `case object` extending 
`StringType(UTF8_BINARY_COLLATION_ID, NoConstraint)`, and its `equals` compares 
`collationId` and `constraint`. So this pattern compiles to an object-equality 
check and a collated `StringType` instance does not match — which is exactly 
what makes the `UTF8_LCASE` assertions below pass.
   
   The hazard is that "tidying" this to `MapType(_: StringType, _: StringType, 
_)` looks equivalent, compiles fine, and *silently* drops the collation guard. 
Same applies to the `ArrayType(StringType, _)` line above, inherited from #5954.
   
   Could you add something like:
   
   ```scala
   // `StringType` is the UTF8_BINARY case object; a collated StringType 
instance
   // is not equal to it, so collated maps/arrays fall through to the reject 
case
   // below. Do NOT rewrite these as `_: StringType`.
   ```
   
   Also worth noting: the `case _: ArrayType | _: MapType => false` catch-all 
on the next line is order-dependent, and every future supported type has to be 
inserted above it. A brief note would help.



##########
docs/source/user-guide/latest/datasources.md:
##########
@@ -31,7 +31,7 @@ Arrow format, allowing the Comet pipeline to take over after 
that, but the proce
 
 Comet accelerates Iceberg scans of Parquet files. See the [Iceberg Guide] for 
more information.
 
-[Iceberg Guide]: iceberg.md
+[iceberg guide]: iceberg.md

Review Comment:
   Unrelated to this PR — this is prettier normalizing the reference-link label 
to lowercase. Harmless (CommonMark matches labels case-insensitively, so 
`[Iceberg Guide]` on line 32 still resolves), but it's drive-by churn in a docs 
section the PR doesn't otherwise touch. Either drop it or mention it in the 
description so reviewers don't have to work out whether the link broke.



##########
spark/src/test/scala/org/apache/comet/exec/CometExecSuite.scala:
##########
@@ -3821,6 +3834,78 @@ class CometExecSuite extends CometTestBase {
     }
   }
 
+  test("SparkToColumnar string maps cross RDD and Parquet native boundaries") {
+    val schema = new StructType()
+      .add("id", IntegerType)
+      .add("partitionValues", MapType(StringType, StringType))
+      .add("nested", new StructType().add("tags", MapType(StringType, 
StringType)))
+    val rows = Seq(
+      Row(1, null, null),
+      Row(2, Map.empty[String, String], Row(null)),
+      Row(3, Map("hour" -> null), Row(Map.empty[String, String])),
+      Row(
+        4,
+        Map("hour" -> "2026-09-02T22", "" -> "é", "東京" -> "a\u0000b"),
+        Row(Map("nullable" -> null, "x" -> "value"))),
+      Row(5, Map("hour" -> "2026-09-03T00", "long" -> ("東京" * 32768)), null),
+      Row(6, Map("hour" -> "2026-09-03T01"), Row(Map("x" -> "value"))))
+    for (sourceType <- Seq("rdd", "parquet-row", "parquet-columnar")) {
+      val vectorized = sourceType == "parquet-columnar"
+      withSQLConf(
+        SQLConf.ADAPTIVE_EXECUTION_ENABLED.key -> "false",
+        SQLConf.PARQUET_VECTORIZED_READER_ENABLED.key -> vectorized.toString,
+        "spark.sql.parquet.enableNestedColumnVectorizedReader" -> "true",
+        CometConf.COMET_NATIVE_SCAN_ENABLED.key -> "false",
+        CometConf.COMET_BATCH_SIZE.key -> "2",
+        CometConf.COMET_SHUFFLE_MODE.key -> "native",
+        CometConf.COMET_CONVERT_FROM_PARQUET_ENABLED.key -> "true",
+        CometConf.COMET_SPARK_TO_ARROW_ENABLED.key -> "true",
+        CometConf.COMET_SPARK_TO_ARROW_SUPPORTED_OPERATOR_LIST.key -> 
"RDDScan") {

Review Comment:
   This conf block never sets `SQLConf.USE_V1_SOURCE_LIST`, so the Parquet 
cases here only reach the V1 `FileSourceScanExec` branch of 
`shouldApplySparkToColumnar`. The array test at line 3772 loops `v1 ∈ {"", 
format}` and therefore also covers the `BatchScanExec` (DSv2 `ParquetScan`) 
branch, which is a separate `case` in `CometExecRule`.
   
   So the DSv2 admission path is currently untested for maps — the existing 
"SparkToColumnar over BatchScan" test doesn't include a map column either. 
Adding `v1` to the loop the same way the array test does would close this. Same 
question for JSON: the array test covers it and this one drops it, and the PR 
description doesn't say whether that was deliberate.



##########
spark/src/test/scala/org/apache/spark/sql/comet/execution/arrow/CometArrowStreamSuite.scala:
##########
@@ -599,6 +599,182 @@ class CometArrowStreamSuite extends AnyFunSuite with 
Matchers {
     }
   }
 
+  for (nullable <- Seq(false, true); valueContainsNull <- Seq(false, true);
+    columnar <- Seq(false, true)) {
+    test(s"string maps preserve slices and ownership: 
$nullable/$valueContainsNull/$columnar") {
+      val mapType = MapType(StringType, StringType, valueContainsNull)
+      val schema = StructType(Seq(StructField("tags", mapType, nullable)))
+      val arrowSchema = Utils.toArrowSchema(schema, "UTC")
+      val values: Seq[Seq[(String, String)]] = Seq(
+        Seq("" -> "", "é" -> "東京", "a\u0000b" -> "duplicate", "b" -> 
"duplicate"),

Review Comment:
   Minor, but the `"duplicate"` labels read as if this row covers duplicate map 
*keys* — the keys here (`a\u0000b`, `b`) are distinct and it's the *values* 
that repeat. The array test's `"dup", "dup"` at line 365 is genuinely about 
repeated elements, so the parallel naming is misleading for maps.
   
   Duplicate keys are the case actually worth having: 
`mapKeyDedupPolicy=LAST_WIN` lets them reach execution, Arrow Map doesn't 
enforce uniqueness, and the `CometExecSuite` test already does 
`partitionValues['hour']` lookups. Adding a row with a repeated key and 
asserting the lookup matches Spark would cover the one map-specific semantic 
that arrays don't have.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to