[ 
https://issues.apache.org/jira/browse/SPARK-58411?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Josh Rosen updated SPARK-58411:
-------------------------------
    Labels: correctness pull-request-available  (was: pull-request-available)

> Fix bug for decorrelating Limit+Sort when partitionFields is empty
> ------------------------------------------------------------------
>
>                 Key: SPARK-58411
>                 URL: https://issues.apache.org/jira/browse/SPARK-58411
>             Project: Spark
>          Issue Type: Bug
>          Components: Optimizer
>    Affects Versions: 4.1.0, 4.0.0, 4.2.0, 4.3.0
>            Reporter: Avery Qi
>            Priority: Major
>              Labels: correctness, pull-request-available
>             Fix For: 4.3.0
>
>
> ## Summary
> Correlated scalar/predicate subqueries of the form ORDER BY ... LIMIT k 
> (optionally with OFFSET) can return wrong, non-deterministic results when the 
> subquery's correlated predicate references only the outer table. During 
> decorrelation, the ORDER BY is silently dropped, turning ORDER BY ... LIMIT k 
> into an arbitrary LIMIT k. The row that survives then depends on physical 
> execution order, so the query can return different results across 
> runs/engines.
> ## Affected versions
> 4.0.0 and later (4.0.x, 4.1.x, 4.2.x, master). Introduced by SPARK-46526 
> ("Support LIMIT over correlated subqueries where predicates only reference 
> outer table"). Not present in 3.5.x or earlier.
> ## Root cause
> In DecorrelateInnerQuery, the Limit case peels the Sort off the subquery and 
> saves its ordering into a local ordering value. When the correlation 
> references only outer columns, decorrelation produces no partitioning key 
> (partitionFields.isEmpty), and that branch re-emits the limit directly as 
> Limit(k, newChild) (or Limit(k, Offset(m, newChild))) without ever 
> re-applying the saved ordering. The ordering is only consumed by the other 
> branch (the row_number() window used when there is a partitioning key). As a 
> result the ordered limit degenerates into an unordered limit over the inner 
> relation.
> ## Example
> SELECT t1a, t1b
> FROM   t1
> WHERE  t1c = (SELECT t2c
>               FROM   t2
>               WHERE  t1b < t1d          -- references only outer columns
>               ORDER BY t2c LIMIT 1);
> The distinct values of t2c are \{12, 16, NULL}. In Spark, ORDER BY t2c 
> defaults to ASC NULLS FIRST, so the correct ordered LIMIT 1 returns NULL; the 
> scalar subquery is then NULL, t1c = NULL is never true, and the query 
> correctly returns no rows. With the bug, the dropped ORDER BY makes LIMIT 1 
> pick an arbitrary row (e.g. a non-null 12), which can incorrectly emit a row 
> and produces different results depending on runtime row order.
> ## Fix
> In the partitionFields.isEmpty branch of the Limit case, re-apply the saved 
> ordering by wrapping the decorrelated child in a global Sort before the 
> Limit/Offset when an ORDER BY was present. This makes ORDER BY ... LIMIT (and 
> ORDER BY ... LIMIT ... OFFSET) order-preserving and deterministic, matching 
> the subquery's declared semantics. The standalone Offset case (no LIMIT) is 
> not affected: it decorrelates the original input with the Sort retained, so 
> its ordering is already preserved.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to