From d4b874cc4014abce4da6471955128b4a85bccdda Mon Sep 17 00:00:00 2001 From: Duy Dang <55247256+ddwalias@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:52:15 +0700 Subject: [PATCH] Fix EXISTS on LEFT JOIN null rows --- core/translate/main_loop.rs | 38 ++++++++++++++++++------------------- testing/subquery.test | 13 ++++++++++++- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/core/translate/main_loop.rs b/core/translate/main_loop.rs index 394ce778e..ccb7de12e 100644 --- a/core/translate/main_loop.rs +++ b/core/translate/main_loop.rs @@ -718,25 +718,6 @@ pub fn open_loop( } } - for subquery in subqueries.iter_mut().filter(|s| !s.has_been_evaluated()) { - assert!(subquery.correlated, "subquery must be correlated"); - let eval_at = subquery.get_eval_at(join_order)?; - - if eval_at != EvalAt::Loop(join_index) { - continue; - } - - let plan = subquery.consume_plan(eval_at); - - emit_non_from_clause_subquery( - program, - t_ctx, - *plan, - &subquery.query_type, - subquery.correlated, - )?; - } - // First emit outer join conditions, if any. emit_conditions( program, @@ -765,6 +746,25 @@ pub fn open_loop( } } + for subquery in subqueries.iter_mut().filter(|s| !s.has_been_evaluated()) { + assert!(subquery.correlated, "subquery must be correlated"); + let eval_at = subquery.get_eval_at(join_order)?; + + if eval_at != EvalAt::Loop(join_index) { + continue; + } + + let plan = subquery.consume_plan(eval_at); + + emit_non_from_clause_subquery( + program, + t_ctx, + *plan, + &subquery.query_type, + subquery.correlated, + )?; + } + // Now we can emit conditions from the WHERE clause. // If the right table produces a NULL row, control jumps to the point where the match flag is set. // The WHERE clause conditions may reference columns from that row, so they cannot be emitted diff --git a/testing/subquery.test b/testing/subquery.test index 67cbcf66a..ebd96e989 100755 --- a/testing/subquery.test +++ b/testing/subquery.test @@ -120,6 +120,17 @@ do_execsql_test nested-subquery-cte { select sub.loudest_hat from sub; } {HAT!!!} +do_execsql_test_on_specific_db {:memory:} correlated-left-join-exists { + create table t(a); + create table s(a); + insert into t values (1); + select t.a + from t + left join s + on t.a = s.a + where exists (select 1 where s.a is null); +} {1} + do_execsql_test subquery-orderby-limit { select upper(sub.loud_name) as loudest_name from ( @@ -987,4 +998,4 @@ do_execsql_test_in_memory_any_error subquery-vector-in-function-call { insert into t1 values (1); insert into t2 values (1, 2); select abs((select y, z from t2)) from t1; -} \ No newline at end of file +}