uqa_sql/plan/
subqueries.rs1use crate::ScalarExpr;
10use std::collections::BTreeMap;
11
12use super::{CommandPlan, QueryPlan, RelationalPlan, SourcePlan};
13
14mod transform;
15pub(crate) use transform::{copy_occurrences, rewrite_expression_with_arena, rewrite_with_arenas};
16
17pub fn prune_command(command: &mut CommandPlan) {
19 let Some(arena) = command_arena(command) else {
20 return;
21 };
22 let arena = std::mem::take(arena);
23 let arena = compact(arena, |visitor| {
24 for expression in command.expressions_mut() {
25 super::rewrite_scalar_expression(expression, visitor);
26 }
27 if let Some(source) = command.source_input_mut() {
28 visit_source(source, visitor);
29 }
30 });
31 if let Some(target) = command_arena(command) {
32 *target = arena;
33 }
34}
35
36fn command_arena(command: &mut CommandPlan) -> Option<&mut Vec<QueryPlan>> {
37 match command {
38 CommandPlan::Insert(plan) => Some(&mut plan.subqueries),
39 CommandPlan::Update(plan) => Some(&mut plan.subqueries),
40 CommandPlan::Delete(plan) => Some(&mut plan.subqueries),
41 CommandPlan::Merge(plan) => Some(&mut plan.subqueries),
42 _ => None,
43 }
44}
45
46pub fn prune_query(query: &mut QueryPlan) {
48 let arena = std::mem::take(query_arena(&mut query.root));
49 let arena = compact(arena, |visitor| visit_root(&mut query.root, visitor));
50 *query_arena(&mut query.root) = arena;
51}
52
53fn query_arena(root: &mut RelationalPlan) -> &mut Vec<QueryPlan> {
54 match root {
55 RelationalPlan::QueryBlock(block) => &mut block.subqueries,
56 RelationalPlan::Values { subqueries, .. } | RelationalPlan::SetOp { subqueries, .. } => {
57 subqueries
58 }
59 }
60}
61
62fn compact(
63 arena: Vec<QueryPlan>,
64 mut visit: impl FnMut(&mut dyn FnMut(&mut ScalarExpr)),
65) -> Vec<QueryPlan> {
66 if arena.is_empty() {
67 return arena;
68 }
69 let mut remap = BTreeMap::new();
70 visit(&mut |expression| {
71 if let Some(id) = subquery_id(expression) {
72 remap.insert(*id, 0);
73 }
74 });
75 if remap.keys().any(|id| *id >= arena.len()) || remap.len() == arena.len() {
78 return arena;
79 }
80 for (position, value) in remap.values_mut().enumerate() {
81 *value = position;
82 }
83 visit(&mut |expression| {
84 if let Some(id) = subquery_id(expression) {
85 *id = remap[id];
86 }
87 });
88 arena
89 .into_iter()
90 .enumerate()
91 .filter_map(|(id, query)| remap.contains_key(&id).then_some(query))
92 .collect()
93}
94
95fn subquery_id(expression: &mut ScalarExpr) -> Option<&mut usize> {
96 match expression {
97 ScalarExpr::ScalarSubquery(id)
98 | ScalarExpr::Exists { subquery: id, .. }
99 | ScalarExpr::InSubquery { subquery: id, .. } => Some(id),
100 _ => None,
101 }
102}
103
104fn visit_root(root: &mut RelationalPlan, visitor: &mut dyn FnMut(&mut ScalarExpr)) {
105 match root {
106 RelationalPlan::QueryBlock(block) => {
107 if let Some(source) = &mut block.from {
108 visit_source(source, visitor);
109 }
110 for expression in block
111 .projections
112 .iter_mut()
113 .map(|projection| &mut projection.expr)
114 .chain(block.r#where.iter_mut())
115 .chain(block.group_by.iter_mut())
116 .chain(block.grouping_sets.iter_mut().flatten())
117 .chain(block.having.iter_mut())
118 .chain(block.order_by.iter_mut().map(|order| &mut order.expr))
119 .chain(block.limit.iter_mut())
120 .chain(block.offset.iter_mut())
121 .chain(block.distinct_on.iter_mut())
122 .chain(
123 block
124 .windows
125 .iter_mut()
126 .flat_map(|window| window.spec.expressions_mut()),
127 )
128 {
129 super::rewrite_scalar_expression(expression, visitor);
130 }
131 }
132 RelationalPlan::Values { rows, .. } => {
133 for expression in rows.iter_mut().flatten() {
134 super::rewrite_scalar_expression(expression, visitor);
135 }
136 }
137 RelationalPlan::SetOp {
138 order_by,
139 limit,
140 offset,
141 ..
142 } => {
143 for expression in order_by
144 .iter_mut()
145 .map(|order| &mut order.expr)
146 .chain(limit.as_deref_mut())
147 .chain(offset.as_deref_mut())
148 {
149 super::rewrite_scalar_expression(expression, visitor);
150 }
151 }
152 }
153}
154
155fn visit_source(source: &mut SourcePlan, visitor: &mut dyn FnMut(&mut ScalarExpr)) {
156 match source {
157 SourcePlan::Join {
158 left, right, on, ..
159 } => {
160 visit_source(left, visitor);
161 visit_source(right, visitor);
162 if let Some(on) = on {
163 super::rewrite_scalar_expression(on, visitor);
164 }
165 }
166 SourcePlan::Values { rows, .. } => {
167 for expression in rows.iter_mut().flatten() {
168 super::rewrite_scalar_expression(expression, visitor);
169 }
170 }
171 SourcePlan::Function { args, .. } => {
172 for argument in args {
173 super::rewrite_scalar_expression(argument, visitor);
174 }
175 }
176 SourcePlan::FunctionGroup { functions, .. } => {
177 for argument in functions.iter_mut().flat_map(|function| &mut function.args) {
178 super::rewrite_scalar_expression(argument, visitor);
179 }
180 }
181 SourcePlan::Subquery { .. } | SourcePlan::Table { .. } => {}
183 }
184}