Skip to content

Commit e081039

Browse files
author
liudy1
committed
Fix aggregate FILTER subquery scheduling
1 parent c70a032 commit e081039

3 files changed

Lines changed: 69 additions & 5 deletions

File tree

core/translate/group_by.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,16 +363,25 @@ fn collect_agg_leaf_columns(aggregates: &[Aggregate], plan: &SelectPlan) -> Resu
363363
}
364364
Ok(WalkControl::SkipChildren)
365365
}
366-
ast::Expr::SubqueryResult { subquery_id, .. } => {
366+
ast::Expr::SubqueryResult {
367+
subquery_id,
368+
query_type,
369+
..
370+
} => {
367371
let is_correlated = plan
368372
.non_from_clause_subqueries
369373
.iter()
370374
.find(|s| s.internal_id == *subquery_id)
371375
.is_some_and(|s| s.correlated);
372376
if is_correlated && !leaf_columns.iter().any(|e| exprs_are_equivalent(e, expr)) {
373377
leaf_columns.push(expr.clone());
378+
return Ok(WalkControl::SkipChildren);
379+
}
380+
if matches!(query_type, ast::SubqueryType::In { .. }) {
381+
Ok(WalkControl::Continue)
382+
} else {
383+
Ok(WalkControl::SkipChildren)
374384
}
375-
Ok(WalkControl::SkipChildren)
376385
}
377386
_ => Ok(WalkControl::Continue),
378387
}

core/translate/subquery.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::sync::Arc;
22

33
use rustc_hash::FxHashMap as HashMap;
4-
use turso_parser::ast::{self, SortOrder, SubqueryType};
4+
use turso_parser::ast::{self, SortOrder, SubqueryType, TableInternalId};
55

66
use crate::{
77
alloc::TursoIteratorExt,
@@ -15,7 +15,8 @@ use crate::{
1515
emit_program_for_select_with_resolver, emit_query,
1616
},
1717
expr::{
18-
compare_affinity, get_expr_affinity_info, unwrap_parens, walk_expr_mut, WalkControl,
18+
compare_affinity, expr_references_subquery_id, get_expr_affinity_info, unwrap_parens,
19+
walk_expr_mut, WalkControl,
1920
},
2021
optimizer::optimize_select_plan,
2122
plan::{
@@ -1987,13 +1988,40 @@ fn assign_select_subquery_eval_phases(plan: &mut SelectPlan) {
19871988
.group_by
19881989
.as_ref()
19891990
.is_some_and(|group_by| !group_by.exprs.is_empty());
1991+
let aggregate_step_subquery_ids: Vec<TableInternalId> = plan
1992+
.non_from_clause_subqueries
1993+
.iter()
1994+
.filter_map(|subquery| {
1995+
aggregate_step_references_subquery(&plan.aggregates, subquery.internal_id)
1996+
.then_some(subquery.internal_id)
1997+
})
1998+
.collect();
19901999

19912000
for subquery in plan.non_from_clause_subqueries.iter_mut() {
2001+
let referenced_by_aggregate_step =
2002+
aggregate_step_subquery_ids.contains(&subquery.internal_id);
19922003
subquery.eval_phase = match subquery.origin {
1993-
SubqueryOrigin::SelectHaving | SubqueryOrigin::SelectOrderBy if has_grouped_output => {
2004+
SubqueryOrigin::SelectHaving | SubqueryOrigin::SelectOrderBy
2005+
if has_grouped_output && !referenced_by_aggregate_step =>
2006+
{
19942007
SubqueryEvalPhase::GroupedOutput
19952008
}
19962009
_ => subquery.origin.phase_floor(),
19972010
};
19982011
}
19992012
}
2013+
2014+
fn aggregate_step_references_subquery(
2015+
aggregates: &[Aggregate],
2016+
subquery_id: TableInternalId,
2017+
) -> bool {
2018+
aggregates.iter().any(|agg| {
2019+
agg.args
2020+
.iter()
2021+
.any(|arg| expr_references_subquery_id(arg, subquery_id))
2022+
|| agg
2023+
.filter_expr
2024+
.as_ref()
2025+
.is_some_and(|expr| expr_references_subquery_id(expr, subquery_id))
2026+
})
2027+
}

testing/sqltests/tests/agg-functions/memory.sqltest

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,33 @@ expect {
113113
1|null||
114114
}
115115

116+
@cross-check-integrity
117+
test grouped-having-aggregate-filter-constant-in-subquery {
118+
SELECT 1 GROUP BY 1 HAVING COUNT(*) FILTER (WHERE 1 IN (SELECT 1)) = 1;
119+
}
120+
expect {
121+
1
122+
}
123+
124+
@cross-check-integrity
125+
test grouped-having-aggregate-filter-empty-in-subquery {
126+
SELECT 1 GROUP BY 1 HAVING COUNT(*) FILTER (WHERE 1 IN (SELECT 2)) = 1;
127+
}
128+
expect {
129+
}
130+
131+
@cross-check-integrity
132+
test grouped-having-aggregate-filter-column-in-subquery {
133+
CREATE TABLE t (x INTEGER, y INTEGER);
134+
CREATE TABLE u (z INTEGER);
135+
INSERT INTO t VALUES (1, 1), (2, 2);
136+
INSERT INTO u VALUES (1);
137+
SELECT y, SUM(x) FROM t GROUP BY y HAVING AVG(x) FILTER (WHERE y IN (SELECT z FROM u ORDER BY z LIMIT 1)) > 0;
138+
}
139+
expect {
140+
1|1
141+
}
142+
116143
@cross-check-integrity
117144
test case-when-aggregate-returns-column-value {
118145
CREATE TABLE t1(a INTEGER, b TEXT);

0 commit comments

Comments
 (0)