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

   ### What changes were proposed in this pull request?
   
   When `EnsureRequirements` serves an `ORDER BY` by putting a keyed child's 
partitions in key order, it now compares the key rows position by position. 
Sort order `i` reads field `i` of the key row. It used to bind the ordering to 
the references of the partition expressions instead.
   
   ### Why are the changes needed?
   
   A key row holds the values of the partition expressions. Binding the 
ordering to their references is right only when each expression is a bare 
column, the only thing a scan reports that an `ORDER BY` can name. A one-side 
shuffle reports the other side's join key instead.
   
   With `spark.sql.sources.v2.bucketing.shuffle.enabled` and 
`spark.sql.sources.v2.bucketing.sorting.enabled` on, this query returns `b` as 
0 to 6 instead of 6 to 0. `ident(id)` is identity-partitioned and holds 94 to 
100, and `plain(b)` holds 0 to 6:
   
   ```sql
   SELECT p.b FROM ident i JOIN plain p ON i.id = 100 - p.b ORDER BY 100 - p.b
   ```
   
   1. The join shuffles `plain` onto `ident`'s layout and reports `100 - b` as 
`plain`'s partition expression. Its key rows hold 94 to 100.
   2. `KeyedPartitioning.keysSatisfy` admits that partitioning for `ORDER BY 
100 - p.b`, since its expression is the ordering's. So no range shuffle is 
planned, and the global sort is dropped as redundant.
   3. `EnsureRequirements` binds `100 - b` to `b` and evaluates it on the key 
rows, so it computes `100 - (100 - b)`. The partitions end up in the reverse 
order.
   
   Two other join keys fail planning instead:
   - For a join on `i.id = p.b + p.c`, `ORDER BY p.b + p.c` binds two 
references to a key row with one field. Planning fails with an 
`ArrayIndexOutOfBoundsException`.
   - For a join on `i.id = p.s.a`, `ORDER BY p.s.a` binds the struct `s` to the 
long key and reads a field of it. Planning fails with a `ClassCastException`.
   
   `keysSatisfy` admits a partitioning here only when its expressions are the 
ordering's, position by position 
(`OrderedDistribution.areAllClusterKeysMatched`). So reading field `i` for sort 
order `i` is exact.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. Such a query returns its rows in the right order, and the two other 
forms no longer fail planning. They all need 
`spark.sql.sources.v2.bucketing.shuffle.enabled` and 
`spark.sql.sources.v2.bucketing.sorting.enabled`, which are off by default. No 
range shuffle is added.
   
   ### How was this patch tested?
   
   New test in `KeyGroupedPartitioningSuite`, "SPARK-59905: ORDER BY the 
join-key expression of a one-side shuffle". It runs four queries: `ORDER BY 100 
- p.b` ascending and descending, `ORDER BY p.b + p.c` and `ORDER BY p.s.a`. For 
each it checks the order of the rows, that the one-side shuffle is the only 
shuffle, and whether a `GroupPartitionsExec` sorts the partitions (only the 
descending one needs it). Each query fails on master:
   - the two `100 - p.b` queries return their rows in the reverse order, and 
get the `GroupPartitionsExec` the wrong way round;
   - the `p.b + p.c` one fails with the `ArrayIndexOutOfBoundsException`;
   - the `p.s.a` one fails with the `ClassCastException`.
   
   The test runs with AQE off. With AQE on, AQE's plan validation fails on the 
`p.b + p.c` query for SPARK-59901, which #59165 fixes.
   
   Also ran the `KeyGroupedPartitioning*` suites, `EnsureRequirementsSuite`, 
`GroupPartitionsExecSuite`, `ProjectedOrderingAndPartitioningSuite` and 
`PlannerSuite`, 427 tests in all, plus `dev/lint-scala`.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code
   


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