andygrove opened a new issue, #5689:
URL: https://github.com/apache/datafusion-comet/issues/5689

   ### Describe the bug
   
   With `spark.comet.iceberg.write.enabled=true` and adaptive query execution 
disabled, every Iceberg copy-on-write row-level operation (DELETE, UPDATE, 
MERGE) fails with:
   
   ```
   java.lang.ClassCastException: class 
org.apache.spark.sql.vectorized.ColumnarBatch
     cannot be cast to class org.apache.spark.sql.catalyst.InternalRow
       at scala.collection.Iterator$$anon$9.next(Iterator.scala:584)
       at 
org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIteratorForCodegenStage1.processNext
       at 
org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43)
       at 
...WholeStageCodegenEvaluatorFactory$WholeStageCodegenPartitionEvaluator$$anon$1.hasNext
       at 
org.apache.spark.sql.comet.execution.shuffle.CometBypassMergeSortShuffleWriter.write(CometBypassMergeSortShuffleWriter.java:158)
   ```
   
   Converting `IcebergWriteExec` into `CometIcebergWriteExec` rewrites the 
write subtree and loses the `ColumnarToRow` that Spark had inserted between 
Iceberg's columnar `BatchScan (IcebergCopyOnWriteScan)` and the whole-stage 
codegen stage above it. At runtime the codegen stage receives `ColumnarBatch` 
and casts it to `InternalRow`.
   
   Executed plan with `spark.comet.iceberg.write.enabled=false` (works):
   
   ```
   IcebergWrite
    +- *(2) CometColumnarToRow
       +- CometSort
          +- CometColumnarExchange hashpartitioning(dep, 10), 
REBALANCE_PARTITIONS_BY_COL, CometColumnarShuffle
             +- *(1) Project
                +- *(1) Filter
                   +- *(1) BroadcastHashJoin
                      :- *(1) ColumnarToRow                    <-- present
                      :  +- BatchScan IcebergCopyOnWriteScan
   ```
   
   Same query with `spark.comet.iceberg.write.enabled=true` (fails):
   
   ```
   CometIcebergWrite
    +- CometSort
       +- CometColumnarExchange hashpartitioning(dep, 10), 
REBALANCE_PARTITIONS_BY_COL, CometColumnarShuffle
          +- *(1) Project
             +- *(1) Filter
                +- *(1) BroadcastHashJoin
                   :- BatchScan IcebergCopyOnWriteScan         <-- 
ColumnarToRow gone
   ```
   
   With AQE enabled the failure disappears, because transitions are re-inserted 
when each stage is materialised. Every existing Comet Iceberg suite runs with 
AQE on, which is why this was never caught.
   
   ### Steps to reproduce
   
   Spark 4.1.3, Iceberg 1.11.0. Session config:
   
   ```
   spark.comet.scan.icebergNative.enabled = true
   spark.comet.write.iceberg.splitOperator.enabled = true
   spark.comet.iceberg.write.enabled = true
   spark.sql.adaptive.enabled = false
   ```
   
   ```sql
   CREATE TABLE cat.db.t (id INT, dep STRING, amount DOUBLE)
   USING iceberg PARTITIONED BY (dep)
   TBLPROPERTIES (
     'format-version'='2',
     'write.delete.mode'='copy-on-write',
     'write.distribution-mode'='none',
     'write.spark.fanout.enabled'='false');
   
   INSERT INTO cat.db.t VALUES 
(1,'hr',1.0),(2,'hr',2.0),(3,'eng',3.0),(4,'eng',4.0),(5,'ops',5.0);
   
   -- src is any small view, e.g. SELECT explode(array(1,3)) AS id
   DELETE FROM cat.db.t WHERE id IN (SELECT id FROM src);
   ```
   
   DELETE, UPDATE and MERGE all fail the same way, on the table's main branch 
and on a named branch.
   
   Isolated with a config matrix on that DELETE:
   
   | split operator | native write | localTableScan | result |
   | -------------- | ------------ | -------------- | --------------- |
   | on             | on           | on             | ClassCastException |
   | on             | on           | off            | ClassCastException |
   | on             | off          | on             | ok |
   | on             | off          | off            | ok |
   | off            | off          | off            | ok |
   
   So the split-operator plan alone does not trigger it and 
`spark.comet.exec.localTableScan.enabled` is irrelevant. It needs the native 
write flag plus AQE off.
   
   ### Expected behavior
   
   The copy-on-write operation succeeds with the native writer regardless of 
whether AQE is enabled, or the operator declines conversion rather than 
producing a plan that violates the columnar contract.
   
   ### Additional context
   
   Found by turning the two Iceberg write flags on by default in #5677 and 
reading the Iceberg Spark SQL job logs. This is the dominant failure in 
Iceberg's `spark-extensions` suites across Iceberg 1.8.1, 1.9.1, 1.10.0 and 
1.11.0.
   
   Note that Iceberg's `ExtensionsTestBase` sets `ADAPTIVE_EXECUTION_ENABLED` 
to `RANDOM.nextBoolean()` per session, so the number of extension tests this 
takes down swings a lot between runs of identical code (99 failures in one run 
and 31 in the next, on the same commit's behaviour). That randomisation should 
be kept in mind when reading those job results.
   
   Part of #5649.
   


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