sunchao commented on code in PR #5414:
URL: https://github.com/apache/datafusion-comet/pull/5414#discussion_r3836790423


##########
spark/src/main/scala/org/apache/comet/DataTypeSupport.scala:
##########
@@ -54,8 +54,9 @@ trait DataTypeSupport {
           CalendarIntervalType =>
         true
       case StructType(fields) =>
-        fields.nonEmpty && fields.forall(f =>
-          isTypeSupported(f.dataType, f.name, fallbackReasons))
+        // A struct's `fields` can be empty -- e.g. Iceberg's `_partition` 
metadata column is
+        // exactly that on an unpartitioned table. It's still a value Comet 
can represent.
+        fields.forall(f => isTypeSupported(f.dataType, f.name, 
fallbackReasons))

Review Comment:
   [P2] Apply the empty-struct guard to collect_set too
   
   Could we also reject empty-struct-containing inputs in `CometCollectSet`? 
With the `marker: struct<>` LocalRelation from the new tests, 
`spark.comet.exec.localTableScan.enabled=true` and native shuffle, `SELECT 
collect_set(marker) FROM t` is now admitted to native aggregation. 
`SparkCollectSet` wraps DataFusion 54.1's `DistinctArrayAggAccumulator`, which 
calls `ScalarValue::compacted()` for each non-null input and hits the same 
zero-field `StructArray::new` panic as FIRST/LAST. I reproduced this through 
the pinned accumulator with both top-level and nested empty structs, while 
Spark 3.5.2 and 4.0.4 return a one-element array. The ordinary Partial/Final 
plan has no PartialMerge stage, so the existing collect-buffer fallback does 
not contain it. Please reuse the recursive guard for `collect_set` and add a 
regression query.



##########
spark/src/main/scala/org/apache/comet/serde/QueryPlanSerde.scala:
##########
@@ -539,7 +539,9 @@ object QueryPlanSerde extends Logging with CometExprShim 
with CometTypeShim {
     case dt if isTimeType(dt) =>
       true
     case s: StructType if allowComplex =>
-      s.fields.nonEmpty && 
s.fields.map(_.dataType).forall(supportedDataType(_, allowComplex))
+      // A struct's `fields` can be empty -- e.g. Iceberg's `_partition` 
metadata column is
+      // exactly that on an unpartitioned table. It's still a value Comet can 
represent.
+      s.fields.map(_.dataType).forall(supportedDataType(_, allowComplex))

Review Comment:
   [P2] Preserve fallback for nested-array empty-struct literals
   
   Could we keep literal fallback until these element types can be serialized? 
Over a Parquet-backed table, `SELECT id, array(array(struct())) FROM t` folds 
to a non-null `array<array<struct<>>>` literal. The widened predicate changes 
`CometLiteral.getSupportLevel` from `Unsupported` to `Compatible`, but 
`makeListLiteral` recursively reaches `StructType()` without a matching branch 
and throws `scala.MatchError` during planning. I reproduced that base/head 
difference using the complete literal serializer, with Spark 4.0.4 successfully 
executing the query over an `id: bigint` Parquet scan. The exception is not 
caught by the expression or operator conversion path. Please either implement 
this serialization or recursively restrict the literal element types, and add a 
regression test that keeps constant folding enabled.



-- 
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