1use crate::expressions::{Expression, JoinKind};
8use serde::{Deserialize, Serialize};
9use std::collections::{HashMap, HashSet};
10
11#[derive(Debug)]
13pub struct Plan {
14 pub root: Step,
16 dag: Option<HashMap<usize, HashSet<usize>>>,
18}
19
20impl Plan {
21 pub fn from_expression(expression: &Expression) -> Option<Self> {
23 let root = Step::from_expression(expression, &HashMap::new())?;
24 Some(Self { root, dag: None })
25 }
26
27 pub fn dag(&mut self) -> &HashMap<usize, HashSet<usize>> {
29 if self.dag.is_none() {
30 let mut dag = HashMap::new();
31 let mut next_id = 0;
32 Self::build_dag(&self.root, &mut dag, &mut next_id);
33 self.dag = Some(dag);
34 }
35 self.dag.as_ref().unwrap()
36 }
37
38 fn build_dag(
39 step: &Step,
40 dag: &mut HashMap<usize, HashSet<usize>>,
41 next_id: &mut usize,
42 ) -> usize {
43 let id = *next_id;
44 *next_id += 1;
45
46 let dependencies = step
47 .dependencies
48 .iter()
49 .map(|dependency| Self::build_dag(dependency, dag, next_id))
50 .collect();
51 dag.insert(id, dependencies);
52 id
53 }
54
55 pub fn leaves(&self) -> Vec<&Step> {
57 let mut leaves = Vec::new();
58 self.collect_leaves(&self.root, &mut leaves);
59 leaves
60 }
61
62 fn collect_leaves<'a>(&'a self, step: &'a Step, leaves: &mut Vec<&'a Step>) {
63 if step.dependencies.is_empty() {
64 leaves.push(step);
65 } else {
66 for dep in &step.dependencies {
67 self.collect_leaves(dep, leaves);
68 }
69 }
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct Step {
76 pub name: String,
78 pub kind: StepKind,
80 pub projections: Vec<Expression>,
82 pub dependencies: Vec<Step>,
84 pub aggregations: Vec<Expression>,
86 pub group_by: Vec<Expression>,
88 pub condition: Option<Expression>,
90 pub order_by: Vec<Expression>,
92 pub limit: Option<Expression>,
94}
95
96#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
98#[serde(rename_all = "snake_case")]
99pub enum StepKind {
100 Scan,
102 Join(JoinType),
104 Aggregate,
106 Sort,
108 SetOperation(SetOperationType),
110}
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
114#[serde(rename_all = "snake_case")]
115pub enum JoinType {
116 Inner,
117 Left,
118 Right,
119 Full,
120 Cross,
121}
122
123#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
125#[serde(rename_all = "snake_case")]
126pub enum SetOperationType {
127 Union,
128 UnionAll,
129 Intersect,
130 Except,
131}
132
133impl Step {
134 pub fn new(name: impl Into<String>, kind: StepKind) -> Self {
136 Self {
137 name: name.into(),
138 kind,
139 projections: Vec::new(),
140 dependencies: Vec::new(),
141 aggregations: Vec::new(),
142 group_by: Vec::new(),
143 condition: None,
144 order_by: Vec::new(),
145 limit: None,
146 }
147 }
148
149 pub fn from_expression(expression: &Expression, ctes: &HashMap<String, Step>) -> Option<Self> {
151 match expression {
152 Expression::Select(select) => {
153 let mut step = Self::from_select(select, ctes)?;
154
155 if let Some(ref order_by) = select.order_by {
157 let sort_step = Step {
158 name: step.name.clone(),
159 kind: StepKind::Sort,
160 projections: Vec::new(),
161 dependencies: vec![step],
162 aggregations: Vec::new(),
163 group_by: Vec::new(),
164 condition: None,
165 order_by: order_by
166 .expressions
167 .iter()
168 .map(|o| o.this.clone())
169 .collect(),
170 limit: None,
171 };
172 step = sort_step;
173 }
174
175 if let Some(ref limit) = select.limit {
177 step.limit = Some(limit.this.clone());
178 }
179
180 Some(step)
181 }
182 Expression::Union(union) => {
183 let left = Self::from_expression(&union.left, ctes)?;
184 let right = Self::from_expression(&union.right, ctes)?;
185
186 let op_type = if union.all {
187 SetOperationType::UnionAll
188 } else {
189 SetOperationType::Union
190 };
191
192 Some(Step {
193 name: "UNION".to_string(),
194 kind: StepKind::SetOperation(op_type),
195 projections: Vec::new(),
196 dependencies: vec![left, right],
197 aggregations: Vec::new(),
198 group_by: Vec::new(),
199 condition: None,
200 order_by: Vec::new(),
201 limit: None,
202 })
203 }
204 Expression::Intersect(intersect) => {
205 let left = Self::from_expression(&intersect.left, ctes)?;
206 let right = Self::from_expression(&intersect.right, ctes)?;
207
208 Some(Step {
209 name: "INTERSECT".to_string(),
210 kind: StepKind::SetOperation(SetOperationType::Intersect),
211 projections: Vec::new(),
212 dependencies: vec![left, right],
213 aggregations: Vec::new(),
214 group_by: Vec::new(),
215 condition: None,
216 order_by: Vec::new(),
217 limit: None,
218 })
219 }
220 Expression::Except(except) => {
221 let left = Self::from_expression(&except.left, ctes)?;
222 let right = Self::from_expression(&except.right, ctes)?;
223
224 Some(Step {
225 name: "EXCEPT".to_string(),
226 kind: StepKind::SetOperation(SetOperationType::Except),
227 projections: Vec::new(),
228 dependencies: vec![left, right],
229 aggregations: Vec::new(),
230 group_by: Vec::new(),
231 condition: None,
232 order_by: Vec::new(),
233 limit: None,
234 })
235 }
236 _ => None,
237 }
238 }
239
240 fn from_select(
241 select: &crate::expressions::Select,
242 ctes: &HashMap<String, Step>,
243 ) -> Option<Self> {
244 let mut ctes = ctes.clone();
246 if let Some(ref with) = select.with {
247 for cte in &with.ctes {
248 if let Some(step) = Self::from_expression(&cte.this, &ctes) {
249 ctes.insert(cte.alias.name.clone(), step);
250 }
251 }
252 }
253
254 let mut step = if let Some(ref from) = select.from {
256 if let Some(table_expr) = from.expressions.first() {
257 Self::from_table_expression(table_expr, &ctes)?
258 } else {
259 return None;
260 }
261 } else {
262 Step::new("", StepKind::Scan)
264 };
265
266 for join in &select.joins {
268 let right = Self::from_table_expression(&join.this, &ctes)?;
269
270 let join_type = match join.kind {
271 JoinKind::Inner => JoinType::Inner,
272 JoinKind::Left | JoinKind::NaturalLeft => JoinType::Left,
273 JoinKind::Right | JoinKind::NaturalRight => JoinType::Right,
274 JoinKind::Full | JoinKind::NaturalFull => JoinType::Full,
275 JoinKind::Cross | JoinKind::Natural => JoinType::Cross,
276 _ => JoinType::Inner,
277 };
278
279 let join_step = Step {
280 name: step.name.clone(),
281 kind: StepKind::Join(join_type),
282 projections: Vec::new(),
283 dependencies: vec![step, right],
284 aggregations: Vec::new(),
285 group_by: Vec::new(),
286 condition: join.on.clone(),
287 order_by: Vec::new(),
288 limit: None,
289 };
290 step = join_step;
291 }
292
293 let has_aggregations = select.expressions.iter().any(|e| contains_aggregate(e));
295 let has_group_by = select.group_by.is_some();
296
297 if has_aggregations || has_group_by {
298 let agg_step = Step {
300 name: step.name.clone(),
301 kind: StepKind::Aggregate,
302 projections: select.expressions.clone(),
303 dependencies: vec![step],
304 aggregations: extract_aggregations(&select.expressions),
305 group_by: select
306 .group_by
307 .as_ref()
308 .map(|g| g.expressions.clone())
309 .unwrap_or_default(),
310 condition: None,
311 order_by: Vec::new(),
312 limit: None,
313 };
314 step = agg_step;
315 } else {
316 step.projections = select.expressions.clone();
317 }
318
319 Some(step)
320 }
321
322 fn from_table_expression(expr: &Expression, ctes: &HashMap<String, Step>) -> Option<Self> {
323 match expr {
324 Expression::Table(table) => {
325 if let Some(cte_step) = ctes.get(&table.name.name) {
327 return Some(cte_step.clone());
328 }
329
330 Some(Step::new(&table.name.name, StepKind::Scan))
332 }
333 Expression::Alias(alias) => {
334 let mut step = Self::from_table_expression(&alias.this, ctes)?;
335 step.name = alias.alias.name.clone();
336 Some(step)
337 }
338 Expression::Subquery(sq) => {
339 let step = Self::from_expression(&sq.this, ctes)?;
340 Some(step)
341 }
342 _ => None,
343 }
344 }
345
346 pub fn add_dependency(&mut self, dep: Step) {
348 self.dependencies.push(dep);
349 }
350}
351
352fn contains_aggregate(expr: &Expression) -> bool {
354 match expr {
355 Expression::Sum(_)
357 | Expression::Count(_)
358 | Expression::Avg(_)
359 | Expression::Min(_)
360 | Expression::Max(_)
361 | Expression::ArrayAgg(_)
362 | Expression::StringAgg(_)
363 | Expression::ListAgg(_)
364 | Expression::Stddev(_)
365 | Expression::StddevPop(_)
366 | Expression::StddevSamp(_)
367 | Expression::Variance(_)
368 | Expression::VarPop(_)
369 | Expression::VarSamp(_)
370 | Expression::Median(_)
371 | Expression::Mode(_)
372 | Expression::First(_)
373 | Expression::Last(_)
374 | Expression::AnyValue(_)
375 | Expression::ApproxDistinct(_)
376 | Expression::ApproxCountDistinct(_)
377 | Expression::LogicalAnd(_)
378 | Expression::LogicalOr(_)
379 | Expression::AggregateFunction(_) => true,
380
381 Expression::Alias(alias) => contains_aggregate(&alias.this),
382 Expression::Add(op) | Expression::Sub(op) | Expression::Mul(op) | Expression::Div(op) => {
383 contains_aggregate(&op.left) || contains_aggregate(&op.right)
384 }
385 Expression::Function(func) => {
386 let name = func.name.to_uppercase();
388 matches!(
389 name.as_str(),
390 "SUM"
391 | "COUNT"
392 | "AVG"
393 | "MIN"
394 | "MAX"
395 | "ARRAY_AGG"
396 | "STRING_AGG"
397 | "GROUP_CONCAT"
398 )
399 }
400 _ => false,
401 }
402}
403
404fn extract_aggregations(expressions: &[Expression]) -> Vec<Expression> {
406 let mut aggs = Vec::new();
407 for expr in expressions {
408 collect_aggregations(expr, &mut aggs);
409 }
410 aggs
411}
412
413fn collect_aggregations(expr: &Expression, aggs: &mut Vec<Expression>) {
414 match expr {
415 Expression::Sum(_)
417 | Expression::Count(_)
418 | Expression::Avg(_)
419 | Expression::Min(_)
420 | Expression::Max(_)
421 | Expression::ArrayAgg(_)
422 | Expression::StringAgg(_)
423 | Expression::ListAgg(_)
424 | Expression::Stddev(_)
425 | Expression::StddevPop(_)
426 | Expression::StddevSamp(_)
427 | Expression::Variance(_)
428 | Expression::VarPop(_)
429 | Expression::VarSamp(_)
430 | Expression::Median(_)
431 | Expression::Mode(_)
432 | Expression::First(_)
433 | Expression::Last(_)
434 | Expression::AnyValue(_)
435 | Expression::ApproxDistinct(_)
436 | Expression::ApproxCountDistinct(_)
437 | Expression::LogicalAnd(_)
438 | Expression::LogicalOr(_)
439 | Expression::AggregateFunction(_) => {
440 aggs.push(expr.clone());
441 }
442 Expression::Alias(alias) => {
443 collect_aggregations(&alias.this, aggs);
444 }
445 Expression::Add(op) | Expression::Sub(op) | Expression::Mul(op) | Expression::Div(op) => {
446 collect_aggregations(&op.left, aggs);
447 collect_aggregations(&op.right, aggs);
448 }
449 Expression::Function(func) => {
450 let name = func.name.to_uppercase();
451 if matches!(
452 name.as_str(),
453 "SUM"
454 | "COUNT"
455 | "AVG"
456 | "MIN"
457 | "MAX"
458 | "ARRAY_AGG"
459 | "STRING_AGG"
460 | "GROUP_CONCAT"
461 ) {
462 aggs.push(expr.clone());
463 } else {
464 for arg in &func.args {
465 collect_aggregations(arg, aggs);
466 }
467 }
468 }
469 _ => {}
470 }
471}
472
473#[cfg(test)]
474mod tests {
475 use super::*;
476 use crate::dialects::{Dialect, DialectType};
477
478 fn parse(sql: &str) -> Expression {
479 let dialect = Dialect::get(DialectType::Generic);
480 let ast = dialect.parse(sql).unwrap();
481 ast.into_iter().next().unwrap()
482 }
483
484 #[test]
485 fn test_simple_scan() {
486 let sql = "SELECT a, b FROM t";
487 let expr = parse(sql);
488 let plan = Plan::from_expression(&expr);
489
490 assert!(plan.is_some());
491 let plan = plan.unwrap();
492 assert_eq!(plan.root.kind, StepKind::Scan);
493 assert_eq!(plan.root.name, "t");
494 }
495
496 #[test]
497 fn test_join() {
498 let sql = "SELECT t1.a, t2.b FROM t1 JOIN t2 ON t1.id = t2.id";
499 let expr = parse(sql);
500 let plan = Plan::from_expression(&expr);
501
502 assert!(plan.is_some());
503 let plan = plan.unwrap();
504 assert!(matches!(plan.root.kind, StepKind::Join(_)));
505 assert_eq!(plan.root.dependencies.len(), 2);
506 }
507
508 #[test]
509 fn test_nested_join_dag_has_unique_preorder_ids() {
510 let expr = parse(
511 "SELECT t1.a FROM t1 \
512 JOIN t2 ON t1.id = t2.id \
513 JOIN t3 ON t2.id = t3.id",
514 );
515 let mut plan = Plan::from_expression(&expr).unwrap();
516 let dag = plan.dag();
517
518 assert_eq!(dag.len(), 5);
519 assert_eq!(dag.get(&0), Some(&HashSet::from([1, 4])));
520 assert_eq!(dag.get(&1), Some(&HashSet::from([2, 3])));
521 assert_eq!(dag.get(&2), Some(&HashSet::new()));
522 assert_eq!(dag.get(&3), Some(&HashSet::new()));
523 assert_eq!(dag.get(&4), Some(&HashSet::new()));
524
525 assert!(dag
526 .values()
527 .flat_map(|dependencies| dependencies.iter())
528 .all(|dependency| dag.contains_key(dependency)));
529 }
530
531 #[test]
532 fn test_aggregate() {
533 let sql = "SELECT x, SUM(y) FROM t GROUP BY x";
534 let expr = parse(sql);
535 let plan = Plan::from_expression(&expr);
536
537 assert!(plan.is_some());
538 let plan = plan.unwrap();
539 assert_eq!(plan.root.kind, StepKind::Aggregate);
540 }
541
542 #[test]
543 fn test_union() {
544 let sql = "SELECT a FROM t1 UNION SELECT b FROM t2";
545 let expr = parse(sql);
546 let plan = Plan::from_expression(&expr);
547
548 assert!(plan.is_some());
549 let plan = plan.unwrap();
550 assert!(matches!(
551 plan.root.kind,
552 StepKind::SetOperation(SetOperationType::Union)
553 ));
554 }
555
556 #[test]
557 fn test_contains_aggregate() {
558 let select_with_agg = parse("SELECT SUM(x) FROM t");
560 if let Expression::Select(ref sel) = select_with_agg {
561 assert!(!sel.expressions.is_empty());
562 assert!(
563 contains_aggregate(&sel.expressions[0]),
564 "Expected SUM to be detected as aggregate function"
565 );
566 } else {
567 panic!("Expected SELECT expression");
568 }
569
570 let select_without_agg = parse("SELECT x + 1 FROM t");
572 if let Expression::Select(ref sel) = select_without_agg {
573 assert!(!sel.expressions.is_empty());
574 assert!(
575 !contains_aggregate(&sel.expressions[0]),
576 "Expected x + 1 to not be an aggregate function"
577 );
578 } else {
579 panic!("Expected SELECT expression");
580 }
581 }
582}