Skip to content

fix: report SinglePartition from a native Iceberg scan that replaces one - #7424

Queued
comphead wants to merge 3 commits into
apache:mainfrom
comphead:fix-iceberg-aqe-dpp-spark34-7422
Queued

comphead wants to merge 3 commits into
apache:mainfrom
comphead:fix-iceberg-aqe-dpp-spark34-7422

Conversation

@comphead

@comphead comphead commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Closes #7422.

Rationale for this change

On Spark 3.4, DataSourceV2ScanExecBase.outputPartitioning reports SinglePartition for a scan of one input partition. Spark 3.5 dropped that case. In the SPARK-34637 test, the two files that pass the units_sold = 70 filter form one split. Spark therefore plans the final aggregate of the DPP build side directly over the partial one, with no exchange between them. Comet then fuses both aggregates, the project, the filter and the native Iceberg scan into one native block. The scan reports UnknownPartitioning(0) (#6268).

AQE builds the DPP subquery's AdaptiveSparkPlanExec over that converted build side and runs EnsureRequirements on it again. Since #7231, the final CometHashAggregate reports Spark's ClusteredDistribution(store_id), while the partial aggregate below passes on the scan's UnknownPartitioning(0). So EnsureRequirements inserts an exchange inside the native block, which is already serialized with the scan inlined. findAllPlanData no longer reaches the scan through the new exchange, and the native IcebergScan gets no schema or tasks: Column index 1 is out of bound. This is the Spark 3.4 [scans] failure in the nightly run since #7231 landed.

What changes are included in this PR?

CometIcebergNativeScanExec.outputPartitioning reports SinglePartition when the BatchScanExec it replaces does, and UnknownPartitioning(0) otherwise, as before. Running EnsureRequirements again then finds the requirement satisfied, as Spark did.

  • Spark counts that one partition from planInputPartitions(), before runtime filtering, so reading it resolves no DPP subquery, which is the problem fix: do not resolve DPP subqueries when AQE reads a native scan's partitioning #6268 avoided.
  • When DPP prunes the only split, serializePartitions already keeps Spark's one empty partition, so the native block still runs exactly one partition.
  • On Spark 3.5 and later, BatchScanExec never reports SinglePartition, so nothing changes there.

How are these changes tested?

CometIcebergNativeSuite "AQE DPP - V2 broadcast query stage creation order (SPARK-34637)" reproduces the failure on Spark 3.4 and covers the fix. This PR removes the Spark 3.4 skip that #7423 added to it. Spark 3.4 runs only through run-all-spark-profiles, and the Iceberg suites through run-iceberg-tests. The Spark 3.4 profile does not build offline in my environment, so I have not run it locally yet. On Spark 4.1, the suite's 25 DPP tests pass.

On Spark 3.4, BatchScanExec reports SinglePartition for a scan of one
input partition, and Spark plans no exchange above it. The native Iceberg
scan reported UnknownPartitioning(0). Since the aggregates declare their
required distribution (apache#7231), EnsureRequirements, which AQE runs again
over a DPP subquery's converted plan, inserted an exchange inside a native
block that was already serialized, and the native scan lost its tasks.
Report SinglePartition when the replaced scan does.
@comphead
comphead marked this pull request as ready for review November 4, 2026 16:28

@andygrove andygrove left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @comphead. This is a tidy fix for the Spark 3.4 [scans] nightly failure.

I read DataSourceV2ScanExecBase and BatchScanExec at v3.4.3, v3.5.8 and v4.1.1. On 3.4, outputPartitioning is SinglePartition when partitions.length == 1, and partitions comes from the unfiltered inputPartitions. So reading it resolves no DPP subquery and the #6268 concern does not return. On 3.5 and later BatchScanExec never reports SinglePartition, so the new branch always falls through to UnknownPartitioning(0). The case where DPP prunes the only split is also covered, because serializePartitions keeps Spark's one empty partition in that case.

The originalPlan != null guard handles canonicalized instances. The SPARK-34637 test reproduces the failure and passes in CI with the Spark 3.4 profile. Looks good to me.

@comphead

comphead commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @andygrove for the review. 5fe99d2 drops the Spark 3.4 skip that #7423 added to the SPARK-34637 test, so the test exercises this fix on 3.4 again. The CometSubqueryBroadcastExec check stays limited to 3.5+, since native AQE DPP needs Spark 3.5.

I added run-iceberg-tests as well. The Iceberg suites have a Spark 3.4 target, the only version where the new branch applies, and they have not run on this PR yet.

@comphead
comphead enabled auto-merge November 5, 2026 17:18
@comphead
comphead added this pull request to the merge queue Nov 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 6, 2026
@comphead
comphead added this pull request to the merge queue Nov 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Iceberg area:scan Parquet scan / data reading bug Something isn't working run-all-spark-profiles Run the Comet test suites against every Spark profile on this pull request, ahead of the merge queue run-iceberg-tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spark 3.4: native Iceberg scan with AQE DPP fails with "Column index 1 is out of bound" when the build side needs an inserted exchange

2 participants