1use super::rewrite::rewrite_query_scalars;
10use super::scalar::{is_builtin_aggregate, lower_scalar_expression};
11use super::{
12 AccessPathPlan, AggregateClassifier, AssignmentPlan, ComputePlan, CteCyclePlan, CtePlan,
13 CteSearchPlan, Expr, ExpressionPlan, FromClause, JoinExecutionStrategy, MergeWhenPlan,
14 NoRegisteredAggregates, OrderBy, OrderPlan, Projection, ProjectionPlan, QueryBlockPlan,
15 QueryPlan, RelationalPlan, ScalarExpr, SelectStmt, SourcePlan, TableFunctionPlan, CTE,
16};
17
18impl QueryPlan {
19 pub fn rewrite_scalar_expressions(&mut self, rewrite: &mut dyn FnMut(&mut ScalarExpr)) {
22 rewrite_query_scalars(self, rewrite);
23 }
24
25 pub fn visit_sources_mut(&mut self, visit: &mut dyn FnMut(&mut SourcePlan)) {
27 super::rewrite::visit_query_sources(self, visit);
28 }
29
30 #[must_use]
31 pub fn lower(statement: SelectStmt) -> Self {
32 Self::lower_with(statement, &NoRegisteredAggregates)
33 }
34
35 #[must_use]
36 pub fn lower_with(mut statement: SelectStmt, aggregates: &dyn AggregateClassifier) -> Self {
37 let ctes = lower_ctes(&statement.with, aggregates);
38 statement.with.clear();
39 let root = lower_relational_root(statement, aggregates);
40 let mut plan = Self {
41 relations_bound: false,
42 ctes,
43 root,
44 };
45 plan.normalize_window_definitions()
46 .expect("compiler windows belong to their query block");
47 plan
48 }
49}
50
51pub(super) fn lower_ctes(ctes: &[CTE], aggregates: &dyn AggregateClassifier) -> Vec<CtePlan> {
52 ctes.iter()
53 .map(|cte| CtePlan {
54 name: cte.name.clone(),
55 columns: cte.columns.clone(),
56 recursive: cte.recursive,
57 materialization: cte.materialization,
58 search: cte.search.as_ref().map(|search| CteSearchPlan {
59 columns: search.columns.clone(),
60 breadth_first: search.breadth_first,
61 sequence_column: search.sequence_column.clone(),
62 }),
63 cycle: cte.cycle.as_ref().map(|cycle| CteCyclePlan {
64 columns: cycle.columns.clone(),
65 mark_column: cycle.mark_column.clone(),
66 mark_value: lower_scalar_expression(
67 cycle.mark_value.clone(),
68 aggregates,
69 &mut Vec::new(),
70 ),
71 mark_default: lower_scalar_expression(
72 cycle.mark_default.clone(),
73 aggregates,
74 &mut Vec::new(),
75 ),
76 path_column: cycle.path_column.clone(),
77 }),
78 body: super::CtePlanBody::from(super::UnifiedPlan::lower_with(
79 cte.body.clone().into_statement(),
80 aggregates,
81 )),
82 })
83 .collect()
84}
85
86pub(super) fn lower_assignments(
87 assignments: Vec<(crate::ast::AssignmentTargets, Expr)>,
88 aggregates: &dyn AggregateClassifier,
89 subqueries: &mut Vec<QueryPlan>,
90) -> Vec<AssignmentPlan> {
91 assignments
92 .into_iter()
93 .map(|(target, expression)| AssignmentPlan {
94 target: target
95 .map(|expression| lower_scalar_expression(expression, aggregates, subqueries)),
96 value: lower_scalar_expression(expression, aggregates, subqueries),
97 })
98 .collect()
99}
100
101pub(super) fn lower_targets(
102 targets: Vec<crate::ast::AssignmentTarget>,
103 aggregates: &dyn AggregateClassifier,
104 subqueries: &mut Vec<QueryPlan>,
105) -> Vec<crate::ast::AssignmentTarget<ScalarExpr>> {
106 targets
107 .into_iter()
108 .map(|target| {
109 target.map(|expression| lower_scalar_expression(expression, aggregates, subqueries))
110 })
111 .collect()
112}
113
114pub(super) fn lower_merge_when(
115 clause: crate::ast::MergeWhen,
116 aggregates: &dyn AggregateClassifier,
117 subqueries: &mut Vec<QueryPlan>,
118) -> MergeWhenPlan {
119 let mut lower_optional = |expression: Option<Expr>| {
120 expression.map(|expression| lower_scalar_expression(expression, aggregates, subqueries))
121 };
122 match clause {
123 crate::ast::MergeWhen::UpdateMatched {
124 condition,
125 assignments,
126 } => {
127 let condition = lower_optional(condition);
128 let assignments = lower_assignments(assignments, aggregates, subqueries);
129 MergeWhenPlan::UpdateMatched {
130 condition,
131 assignments,
132 }
133 }
134 crate::ast::MergeWhen::DeleteMatched { condition } => MergeWhenPlan::DeleteMatched {
135 condition: lower_optional(condition),
136 },
137 crate::ast::MergeWhen::UpdateNotMatchedBySource {
138 condition,
139 assignments,
140 } => {
141 let condition = lower_optional(condition);
142 let assignments = lower_assignments(assignments, aggregates, subqueries);
143 MergeWhenPlan::UpdateNotMatchedBySource {
144 condition,
145 assignments,
146 }
147 }
148 crate::ast::MergeWhen::DeleteNotMatchedBySource { condition } => {
149 MergeWhenPlan::DeleteNotMatchedBySource {
150 condition: lower_optional(condition),
151 }
152 }
153 crate::ast::MergeWhen::InsertNotMatched {
154 condition,
155 columns,
156 overriding,
157 values,
158 } => {
159 let condition = lower_optional(condition);
160 let values = values
161 .into_iter()
162 .map(|value| lower_scalar_expression(value, aggregates, subqueries))
163 .collect();
164 MergeWhenPlan::InsertNotMatched {
165 condition,
166 columns: lower_targets(columns, aggregates, subqueries),
167 overriding,
168 values,
169 }
170 }
171 crate::ast::MergeWhen::NothingMatched { condition } => MergeWhenPlan::NothingMatched {
172 condition: lower_optional(condition),
173 },
174 crate::ast::MergeWhen::NothingNotMatched { condition } => {
175 MergeWhenPlan::NothingNotMatched {
176 condition: lower_optional(condition),
177 }
178 }
179 crate::ast::MergeWhen::NothingNotMatchedBySource { condition } => {
180 MergeWhenPlan::NothingNotMatchedBySource {
181 condition: lower_optional(condition),
182 }
183 }
184 }
185}
186pub(super) fn lower_relational_root(
187 mut statement: SelectStmt,
188 aggregates: &dyn AggregateClassifier,
189) -> RelationalPlan {
190 if statement.set_op.is_none() && !statement.values.is_empty() {
191 let mut subqueries = Vec::new();
192 let rows = statement
193 .values
194 .into_iter()
195 .map(|row| {
196 row.into_iter()
197 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
198 .collect()
199 })
200 .collect();
201 return RelationalPlan::Values { rows, subqueries };
202 }
203 let Some(set_op) = statement.set_op.take() else {
204 return RelationalPlan::QueryBlock(Box::new(QueryBlockPlan::lower_with(
205 statement, aggregates,
206 )));
207 };
208
209 let left = if let Some(left) = set_op.left {
210 QueryPlan::lower_with(*left, aggregates)
211 } else {
212 QueryPlan {
213 relations_bound: false,
214 ctes: Vec::new(),
215 root: RelationalPlan::QueryBlock(Box::new(QueryBlockPlan::lower_with(
216 statement, aggregates,
217 ))),
218 }
219 };
220 let right = QueryPlan::lower_with(set_op.right, aggregates);
221 let mut subqueries = Vec::new();
222 RelationalPlan::SetOp {
223 kind: set_op.kind,
224 all: set_op.all,
225 left: Box::new(left),
226 right: Box::new(right),
227 order_by: set_op
228 .combined_order_by
229 .into_iter()
230 .map(|order| OrderPlan::lower_with(order, aggregates, &mut subqueries))
231 .collect(),
232 limit: set_op
233 .combined_limit
234 .map(|expr| Box::new(lower_scalar_expression(expr, aggregates, &mut subqueries))),
235 with_ties: set_op.combined_with_ties,
236 offset: set_op
237 .combined_offset
238 .map(|expr| Box::new(lower_scalar_expression(expr, aggregates, &mut subqueries))),
239 subqueries,
240 }
241}
242
243impl QueryBlockPlan {
244 fn lower_with(statement: SelectStmt, aggregates: &dyn AggregateClassifier) -> Self {
245 debug_assert_eq!(statement.with.len(), 0);
246 debug_assert!(statement.set_op.is_none());
247 let mut subqueries = Vec::new();
248 let projections: Vec<ProjectionPlan> = statement
249 .projections
250 .into_iter()
251 .map(|projection| ProjectionPlan::lower_with(projection, aggregates, &mut subqueries))
252 .collect();
253 let windows: Vec<_> = statement
254 .windows
255 .into_iter()
256 .map(|definition| crate::ast::WindowDefinition {
257 name: definition.name,
258 inherited: definition.inherited,
259 spec: super::scalar::lower_window_spec(
260 definition.spec,
261 aggregates,
262 &mut subqueries,
263 ),
264 })
265 .collect();
266 let is_aggregate =
267 |name: &str| is_builtin_aggregate(name) || aggregates.is_registered_aggregate(name);
268 let has_aggregate = !statement.group_by.is_empty()
269 || !statement.grouping_sets.is_empty()
270 || statement.having.is_some()
271 || projections
272 .iter()
273 .any(|projection| projection.expr.contains_aggregate(&is_aggregate))
274 || windows
275 .iter()
276 .flat_map(|window| window.spec.expressions())
277 .any(|expression| expression.contains_aggregate(&is_aggregate));
278 let has_window = projections
279 .iter()
280 .any(|projection| projection.expr.contains_window());
281 let compute = if has_aggregate {
282 ComputePlan::Aggregate
283 } else if has_window {
284 ComputePlan::Window
285 } else {
286 ComputePlan::Project
287 };
288 Self {
289 windows,
290 projections,
291 privilege_columns: std::collections::BTreeSet::default(),
292 from: statement
293 .from
294 .map(|source| SourcePlan::lower_with(source, aggregates, &mut subqueries)),
295 r#where: statement
296 .r#where
297 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries)),
298 compute,
299 group_by: statement
300 .group_by
301 .into_iter()
302 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
303 .collect(),
304 grouping_sets: statement
305 .grouping_sets
306 .into_iter()
307 .map(|set| {
308 set.into_iter()
309 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
310 .collect()
311 })
312 .collect(),
313 group_distinct: statement.group_distinct,
314 having: statement
315 .having
316 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries)),
317 order_by: statement
318 .order_by
319 .into_iter()
320 .map(|order| OrderPlan::lower_with(order, aggregates, &mut subqueries))
321 .collect(),
322 limit: statement
323 .limit
324 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries)),
325 with_ties: statement.with_ties,
326 offset: statement
327 .offset
328 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries)),
329 distinct: statement.distinct,
330 distinct_on: statement
331 .distinct_on
332 .into_iter()
333 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
334 .collect(),
335 subqueries,
336 access: AccessPathPlan::Row,
337 locking: statement.locking,
338 }
339 }
340
341 #[must_use]
345 pub fn expressions(&self) -> Vec<&ScalarExpr> {
346 let mut expressions = Vec::new();
347 if let Some(source) = &self.from {
348 source.push_expressions(&mut expressions);
349 }
350 if matches!(self.compute, ComputePlan::Project) {
352 expressions.extend(self.projections.iter().map(|projection| &projection.expr));
353 }
354 if let Some(filter) = &self.r#where {
355 expressions.push(filter);
356 }
357 if !matches!(self.compute, ComputePlan::Project) {
358 expressions.extend(self.projections.iter().map(|projection| &projection.expr));
359 }
360 expressions.extend(&self.group_by);
361 for set in &self.grouping_sets {
362 expressions.extend(set);
363 }
364 if let Some(having) = &self.having {
365 expressions.push(having);
366 }
367 expressions.extend(self.order_by.iter().map(|order| &order.expr));
368 if let Some(limit) = &self.limit {
369 expressions.push(limit);
370 }
371 if let Some(offset) = &self.offset {
372 expressions.push(offset);
373 }
374 expressions.extend(&self.distinct_on);
375 expressions.extend(
376 self.windows
377 .iter()
378 .flat_map(|window| window.spec.expressions()),
379 );
380 expressions
381 }
382}
383
384impl SourcePlan {
385 #[must_use]
387 pub fn visible_qualifier(&self) -> Option<&str> {
388 match self {
389 Self::Table {
390 qualifier, alias, ..
391 } => Some(alias.as_deref().unwrap_or(qualifier)),
392 Self::Function {
393 output_name, alias, ..
394 } => Some(alias.as_deref().unwrap_or(output_name)),
395 Self::FunctionGroup {
396 functions, alias, ..
397 } => alias.as_deref().or_else(|| {
398 functions
399 .first()
400 .map(|function| function.output_name.as_str())
401 }),
402 Self::Values {
403 alias,
404 internal_relation,
405 ..
406 } => internal_relation
407 .is_none()
408 .then_some(alias.as_deref())
409 .flatten(),
410 Self::Subquery { alias, .. } => alias.as_deref(),
411 Self::Join { alias, .. } => alias.as_deref(),
412 }
413 }
414
415 #[expect(
416 clippy::too_many_lines,
417 reason = "plan lowering preserves exhaustive variants and structural identities"
418 )]
419 pub(super) fn lower_with(
420 source: FromClause,
421 aggregates: &dyn AggregateClassifier,
422 subqueries: &mut Vec<QueryPlan>,
423 ) -> Self {
424 match source {
425 FromClause::Table {
426 name,
427 qualifier,
428 alias,
429 column_aliases,
430 bound_columns,
431 include_descendants,
432 } => Self::Table {
433 name,
434 qualifier,
435 alias,
436 column_aliases,
437 bound_columns,
438 include_descendants,
439 },
440 FromClause::Join {
441 left,
442 right,
443 kind,
444 on,
445 using,
446 natural,
447 alias,
448 column_aliases,
449 lateral,
450 } => Self::Join {
451 left: Box::new(Self::lower_with(*left, aggregates, subqueries)),
452 right: Box::new(Self::lower_with(*right, aggregates, subqueries)),
453 kind,
454 on: on.map(|expr| lower_scalar_expression(expr, aggregates, subqueries)),
455 using,
456 natural,
457 alias,
458 column_aliases,
459 lateral,
460 strategy: JoinExecutionStrategy::Auto,
461 },
462 FromClause::Values {
463 rows,
464 alias,
465 column_aliases,
466 internal_relation,
467 internal_column_types,
468 } => Self::Values {
469 rows: rows
470 .into_iter()
471 .map(|row| {
472 row.into_iter()
473 .map(|expr| lower_scalar_expression(expr, aggregates, subqueries))
474 .collect()
475 })
476 .collect(),
477 alias,
478 column_aliases,
479 internal_relation,
480 internal_column_types,
481 },
482 FromClause::Function {
483 name,
484 binding,
485 output_name,
486 relations,
487 args,
488 alias,
489 column_aliases,
490 ordinality,
491 column_types,
492 } => Self::Function {
493 name,
494 binding,
495 output_name,
496 relations,
497 args: args
498 .into_iter()
499 .map(|expr| lower_scalar_expression(expr, aggregates, subqueries))
500 .collect(),
501 alias,
502 column_aliases,
503 ordinality,
504 column_types,
505 },
506 FromClause::FunctionGroup {
507 functions,
508 alias,
509 column_aliases,
510 ordinality,
511 } => Self::FunctionGroup {
512 functions: functions
513 .into_iter()
514 .map(|function| TableFunctionPlan {
515 name: function.name,
516 binding: function.binding,
517 output_name: function.output_name,
518 relations: function.relations,
519 args: function
520 .args
521 .into_iter()
522 .map(|expr| lower_scalar_expression(expr, aggregates, subqueries))
523 .collect(),
524 column_aliases: function.column_aliases,
525 column_types: function.column_types,
526 })
527 .collect(),
528 alias,
529 column_aliases,
530 ordinality,
531 },
532 FromClause::Subquery {
533 body,
534 alias,
535 column_aliases,
536 } => Self::Subquery {
537 body: Box::new(QueryPlan::lower_with(*body, aggregates)),
538 alias,
539 column_aliases,
540 },
541 }
542 }
543
544 pub fn push_expressions<'a>(&'a self, output: &mut Vec<&'a ScalarExpr>) {
546 match self {
547 Self::Table { .. } | Self::Subquery { .. } => {}
548 Self::Join {
549 left, right, on, ..
550 } => {
551 left.push_expressions(output);
552 right.push_expressions(output);
553 if let Some(on) = on {
554 output.push(on);
555 }
556 }
557 Self::Values { rows, .. } => {
558 for row in rows {
559 output.extend(row);
560 }
561 }
562 Self::Function { args, .. } => output.extend(args),
563 Self::FunctionGroup { functions, .. } => {
564 for function in functions {
565 output.extend(&function.args);
566 }
567 }
568 }
569 }
570
571 pub fn collect_tables(&self, output: &mut Vec<(String, Option<String>)>) {
572 match self {
573 Self::Table {
574 name,
575 qualifier,
576 alias,
577 ..
578 } => output.push((
579 name.clone(),
580 Some(alias.as_ref().unwrap_or(qualifier).clone()),
581 )),
582 Self::Join { left, right, .. } => {
583 left.collect_tables(output);
584 right.collect_tables(output);
585 }
586 Self::Values { .. }
587 | Self::Function { .. }
588 | Self::FunctionGroup { .. }
589 | Self::Subquery { .. } => {}
590 }
591 }
592}
593
594impl ProjectionPlan {
595 pub(super) fn lower_with(
596 projection: Projection,
597 aggregates: &dyn AggregateClassifier,
598 subqueries: &mut Vec<QueryPlan>,
599 ) -> Self {
600 Self {
601 expr: lower_scalar_expression(projection.expr, aggregates, subqueries),
602 alias: projection.alias,
603 }
604 }
605}
606
607impl OrderPlan {
608 fn lower_with(
609 order: OrderBy,
610 aggregates: &dyn AggregateClassifier,
611 subqueries: &mut Vec<QueryPlan>,
612 ) -> Self {
613 Self {
614 expr: lower_scalar_expression(order.expr, aggregates, subqueries),
615 descending: order.descending,
616 nulls: order.nulls,
617 }
618 }
619}
620
621impl ExpressionPlan {
622 #[must_use]
623 pub fn lower(expression: Expr) -> Self {
624 Self::lower_with(expression, &NoRegisteredAggregates)
625 }
626
627 pub fn lower_with(expression: Expr, aggregates: &dyn AggregateClassifier) -> Self {
628 let mut subqueries = Vec::new();
629 let scalar = lower_scalar_expression(expression, aggregates, &mut subqueries);
630 Self { scalar, subqueries }
631 }
632}