peter-toth opened a new pull request, #58013:
URL: https://github.com/apache/spark/pull/58013

   ### What changes were proposed in this pull request?
   
   This PR makes `BatchScanExec.filteredPartitions` validate the partitions a 
data source reports after runtime filtering against the **unprojected** 
partitioning (`super.outputPartitioning`) instead of `outputPartitioning`.
   
   `BatchScanExec.outputPartitioning` projects the partition expressions and 
values down to the join keys when SPJ params were pushed down 
(`spjParams.joinKeyPositions`), and it also replaces the partition values with 
the common partition values of the join. But `filteredPartitions` wraps the 
re-planned partitions with their full, unprojected 
`HasPartitionKey.partitionKey()`, so the two sides of the comparison are in 
different spaces.
   
   Nothing else needs to change, because everything after the check already 
works in the full partition key space: `groupPartitions` groups by the 
unprojected keys, and the projection, the reducers, the common partition values 
and the empty-partition padding all happen later, in `inputRDD`.
   
   This PR targets `branch-4.1` (and later `branch-4.0`) only. `master` and 
`branch-4.2` are not affected: SPARK-55535 / SPARK-55092 moved the join key 
projection out of the scan into `GroupPartitionsExec`, so there both sides of 
the comparison are already unprojected. That refactor is too large for a 
maintenance branch, hence this targeted fix.
   
   ### Why are the changes needed?
   
   A storage-partitioned join and runtime filtering cannot coexist on the same 
scan when the join keys are a subset of the partition keys. The query fails on 
the driver before a single task runs:
   
   ```
   org.apache.spark.SparkException: During runtime filtering, data source must 
not report new partition values that are not present in the original 
partitioning.
     at 
org.apache.spark.sql.execution.datasources.v2.BatchScanExec.filteredPartitions$lzycompute(BatchScanExec.scala:100)
     at 
org.apache.spark.sql.execution.datasources.v2.BatchScanExec.inputRDD$lzycompute(BatchScanExec.scala:150)
   ```
   
   Three things have to come together, and removing any one of them makes the 
same query work:
   
   1. SPJ with 
`spark.sql.sources.v2.bucketing.allowJoinKeysSubsetOfPartitionKeys.enabled=true`,
 so Spark projects the scan partitioning down to the join keys.
   2. A scan reporting `KeyGroupedPartitioning` with more partition keys than 
the join key, where the join key is **not** the first partition key. If it is 
the first one the mismatch goes unnoticed, because 
`InternalRowComparableWrapper` compares only as many fields as it has data 
types, so it happens to compare the right column.
   3. A runtime filter on that same scan.
   
   A copy-on-write `MERGE INTO` hits all three by default, because the 
row-level operation group filter 
(`spark.sql.optimizer.runtime.rowLevelOperationGroupFilter.enabled`) is on: the 
target is partitioned by e.g. `months(created), bucket(4, id)` and the merge 
joins on `id`. This makes SPJ unusable for `MERGE`, which is the case it is 
most worth having. The only workaround is to turn the group filter off, which 
loses runtime file pruning for every row-level operation in the session.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes, it fixes the bug above: a query that failed with the exception now 
runs. There is no change for queries that don't combine SPJ, a join key that is 
a subset of the partition keys, and a runtime filter on the same scan. This is 
a change compared to released 4.0.x and 4.1.x; `master` and `branch-4.2` 
already behave this way.
   
   ### How was this patch tested?
   
   Added a test to `KeyGroupedPartitioningSuite` that joins on the second of 
two partition keys with a dynamic partition filter on that scan, over the 
`pushDownValues` x `partiallyClustered` matrix. It fails with the exception 
above without the fix and passes with it.
   
   Also ran the full `KeyGroupedPartitioningSuite` (71 tests, covering the 
partially-clustered and dynamic-filtering combinations that exercise the common 
partition values path), plus `GroupBasedMergeIntoTableSuite`, 
`GroupBasedDeleteFromTableSuite`, `GroupBasedUpdateTableSuite` and 
`DataSourceV2Suite`.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (Opus 5)
   


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