Found while reviewing #5293 against the Iceberg split-writer work in #4658.
Describe the bug
Spark's WriteFilesExec.doExecuteWrite guards against a child RDD with zero partitions (SPARK-23271):
val rddWithNonEmptyPartitions = if (rdd.partitions.length == 0) {
session.sparkContext.parallelize(Array.empty[InternalRow], 1)
} else {
rdd
}
Without it no write task runs at all, so the output directory ends up with no data file — not even the schema-only file Spark produces. IcebergWriteExec added in #4658 carries the same guard.
CometWriteFilesExec.doExecuteWrite has no equivalent: it calls child.executeColumnar() and goes straight to mapPartitionsInternal. With zero partitions, FileFormatWriter.writeAndCommit collects zero WriteTaskResults and commits an empty job. The result is a _SUCCESS marker over an empty directory, where Spark writes one file carrying the schema.
Note this is not a regression from #5293 — the CometNativeWriteExec it replaced had the same hole.
Steps to reproduce
Any write whose input plan yields a zero-partition RDD (for example a scan over an empty relation), with spark.comet.parquet.write.enabled=true.
Expected behavior
Match Spark: run one write task so the output carries the schema.
Harder here than in the Iceberg case because the dummy RDD must be columnar — parallelize(Array.empty[InternalRow], 1) is row-based, and CometWriteFilesExec feeds batches into an Arrow stream. Options are a single-partition empty ColumnarBatch RDD, or bypassing the native writer for this case and writing the schema-only file on the JVM.
Found while reviewing #5293 against the Iceberg split-writer work in #4658.
Describe the bug
Spark's
WriteFilesExec.doExecuteWriteguards against a child RDD with zero partitions (SPARK-23271):Without it no write task runs at all, so the output directory ends up with no data file — not even the schema-only file Spark produces.
IcebergWriteExecadded in #4658 carries the same guard.CometWriteFilesExec.doExecuteWritehas no equivalent: it callschild.executeColumnar()and goes straight tomapPartitionsInternal. With zero partitions,FileFormatWriter.writeAndCommitcollects zeroWriteTaskResults and commits an empty job. The result is a_SUCCESSmarker over an empty directory, where Spark writes one file carrying the schema.Note this is not a regression from #5293 — the
CometNativeWriteExecit replaced had the same hole.Steps to reproduce
Any write whose input plan yields a zero-partition RDD (for example a scan over an empty relation), with
spark.comet.parquet.write.enabled=true.Expected behavior
Match Spark: run one write task so the output carries the schema.
Harder here than in the Iceberg case because the dummy RDD must be columnar —
parallelize(Array.empty[InternalRow], 1)is row-based, andCometWriteFilesExecfeeds batches into an Arrow stream. Options are a single-partition emptyColumnarBatchRDD, or bypassing the native writer for this case and writing the schema-only file on the JVM.