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

   ### What changes were proposed in this pull request?
   
   `EnsureRequirements` compares the two sides' reduced key types only when 
both sides have partition
   keys, and takes the types from the side that has them.
   
   `KeyedPartitioning.keyDataTypes` reports the types the partition key rows 
were built with. With no
   key row to read, it falls back to the partition expressions' own types. 
Those types describe the
   keys only while the expressions do, and a join that reduced both sides' keys 
leaves expressions
   that do not (`TransformExpression.reducedWith`, SPARK-59121). The fallback 
is then not an answer
   about the keys, and holding it against the other side's real answer fails 
the query.
   
   The `keyDataTypes` scaladoc states the rule the fix follows, in place of the 
paragraph that
   described the failure and pointed here.
   
   One check is given up along with the untruthful comparison. Where a side has 
a reducer, the
   comparison also holds the connector's `Reducer.resultType()` against the 
paired transform, which
   needs no key row. That diagnostic is now skipped whenever a filter empties 
that side. Only a
   connector that already breaks `r(f1(x)) = f2(x)` on types is affected, and 
it loses a message it
   used to get. In one shape it loses more than the message: with 
`v2BucketingShuffleEnabled` on, a
   third child shuffled onto the merged keys evaluates the target transform per 
row, so the mismatch
   surfaces as a `ClassCastException` instead.
   
   The alternative is to skip only an already-reduced pair, which would keep 
the check for a side that
   is empty but not marked. That was not taken. The fallback is untruthful for a
   `KeyedShuffleSpec.createPartitioning` result as well, so a narrower guard 
trades a lost message for
   a query that fails while it is correct, which is the worse of the two and is 
the bug being fixed
   here.
   
   ### Why are the changes needed?
   
   A storage-partitioned join whose two legs each reduced both of their sides 
onto one key space is
   co-partitioned, and joins without a shuffle. If a leg ends up with no 
partition key at all, the
   query fails instead. `v2BucketingPartitionFilterEnabled` produces such a leg 
whenever its two
   sides hold disjoint keys, i.e. whenever that leg is empty.
   
       SELECT coalesce(l.ts, r.ts) FROM
         (SELECT d.ts FROM days1 d JOIN years1 y ON y.ts = d.ts) l
         JOIN
         (SELECT y.ts FROM days2 d JOIN years2 y ON y.ts = d.ts) r
         ON l.ts = r.ts
   
   With `days2` and `years2` holding disjoint years, and `days` and `years` 
reducing onto a common
   `LongType` year key:
   
       [STORAGE_PARTITION_JOIN_INCOMPATIBLE_REDUCED_TYPES] Storage-partition 
join partition
       transforms produced incompatible reduced types, left reducers: [] 
returned: ["BIGINT"],
       right reducers: [] returned: ["INT"]. SQLSTATE: 42K09
   
   Both reducer lists are empty, which is the sign that there was nothing left 
to reduce and nothing
   to compare. `INT` is the `years` transform's own result type, not a type any 
key row holds.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. The query above returns its result instead of failing. Only unreleased 
versions are affected:
   the failure is reachable through SPARK-59121, and before that the same shape 
failed on a
   `ClassCastException` from applying the reduce a second time.
   
   ### How was this patch tested?
   
   A new `KeyGroupedPartitioningSuite` test covers the shape in both join 
orders, since the side to
   leave out can be either one, and with both an inner and a full outer join. 
The inner join
   intersects the two key sets to nothing and never sorts them, so the full 
outer join is what makes
   the reported types matter. Each of the three parts of the fix fails the test 
on its own when
   disabled.
   
   ### 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