Skip to main content

inillucent_sql/
rewrite.rs

1//! Rewriting a bound tree in place, exhaustively.
2//!
3//! Invariant: a walk here reaches every expression a statement holds - result
4//! columns, filters, join constraints, window frames, `VALUES` rows, compound
5//! arms and subquery blocks alike - or it is a defect rather than an omission.
6//! The walks are written beside the definitions they mirror for that reason: a
7//! field added to `BoundSelect` and not added here is a subtree some rewrite
8//! silently skips, and the symptom is a wrong answer rather than a refusal.
9//!
10//! ## What it is for
11//!
12//! The trigger firing point. A trigger body is bound once, against the
13//! statement that fires it, and its expressions read `OLD` and `NEW` through
14//! the two sentinel source numbers [`crate::bind::OLD_SOURCE`] and
15//! [`crate::bind::NEW_SOURCE`]. At the moment a trigger fires, both rows are
16//! values the write path is already holding - so the body is copied, every
17//! `OLD` and `NEW` read in it is replaced by the value itself, and what is left
18//! is an ordinary statement with no external references that the ordinary
19//! planner plans and the ordinary write path applies.
20//!
21//! That is what makes `DELETE FROM child WHERE parent_id = OLD.id` reach the
22//! same index probe the same `DELETE` typed by hand reaches, and it is why
23//! there is no second execution path for a trigger body.
24//!
25//! ## The one subtree a rewrite must not enter
26//!
27//! A body statement carries its **own** triggers, and those have their own
28//! `OLD` and `NEW`. Substituting the firing statement's rows into them would
29//! give an inner trigger the outer row, which is a wrong answer of exactly the
30//! kind this engine is not allowed to have. So [`rewrite_insert`],
31//! [`rewrite_update`] and [`rewrite_delete`] walk every field of their
32//! statement except `triggers` and `replace_triggers`, and each nested fire
33//! substitutes its own rows when its own turn comes.
34
35use crate::bind::{
36    BoundExpr, BoundFrameBound, BoundOrderTerm, BoundResultColumn, BoundSelect, BoundWindow,
37    SourceRows,
38};
39use crate::dml::{BoundDelete, BoundInsert, BoundInsertSource, BoundUpdate, ColumnSource};
40
41/// A rewrite applied to one expression before its children are walked.
42pub type Rewrite<'a> = &'a mut dyn FnMut(&mut BoundExpr);
43
44/// Applies a rewrite to one expression and everything under it.
45///
46/// The expression itself first, then its children, then the block a subquery
47/// holds - so a rewrite that replaces a node does not then walk the children of
48/// the node it put there.
49///
50/// @param expr - the expression to rewrite
51/// @param rewrite - what to do to each expression
52pub fn rewrite_expr(expr: &mut BoundExpr, rewrite: Rewrite<'_>) {
53    rewrite(expr);
54    for child in expr.children_mut() {
55        rewrite_expr(child, rewrite);
56    }
57    if let Some(block) = expr.block_mut() {
58        rewrite_select(block, rewrite);
59    }
60}
61
62/// Applies a rewrite to an optional expression.
63///
64/// @param expr - the expression, when there is one
65/// @param rewrite - what to do to each expression
66fn rewrite_option(expr: Option<&mut BoundExpr>, rewrite: Rewrite<'_>) {
67    if let Some(expr) = expr {
68        rewrite_expr(expr, rewrite);
69    }
70}
71
72/// Applies a rewrite to a list of result columns.
73///
74/// @param columns - the result columns
75/// @param rewrite - what to do to each expression
76fn rewrite_columns(columns: &mut [BoundResultColumn], rewrite: Rewrite<'_>) {
77    for column in columns {
78        rewrite_expr(&mut column.expr, rewrite);
79    }
80}
81
82/// Applies a rewrite to a list of order terms.
83///
84/// @param terms - the order terms
85/// @param rewrite - what to do to each expression
86fn rewrite_order(terms: &mut [BoundOrderTerm], rewrite: Rewrite<'_>) {
87    for term in terms {
88        rewrite_expr(&mut term.expr, rewrite);
89    }
90}
91
92/// Applies a rewrite to one frame bound.
93///
94/// @param bound - the frame bound
95/// @param rewrite - what to do to each expression
96fn rewrite_bound(bound: &mut BoundFrameBound, rewrite: Rewrite<'_>) {
97    match bound {
98        BoundFrameBound::Preceding(expr) | BoundFrameBound::Following(expr) => {
99            rewrite_expr(expr, rewrite)
100        }
101        BoundFrameBound::UnboundedPreceding
102        | BoundFrameBound::CurrentRow
103        | BoundFrameBound::UnboundedFollowing => {}
104    }
105}
106
107/// Applies a rewrite to one window definition.
108///
109/// @param window - the window
110/// @param rewrite - what to do to each expression
111fn rewrite_window(window: &mut BoundWindow, rewrite: Rewrite<'_>) {
112    for argument in &mut window.arguments {
113        rewrite_expr(argument, rewrite);
114    }
115    rewrite_option(window.filter.as_mut(), rewrite);
116    for term in &mut window.partition_by {
117        rewrite_expr(term, rewrite);
118    }
119    rewrite_order(&mut window.order_by, rewrite);
120    rewrite_bound(&mut window.start, rewrite);
121    rewrite_bound(&mut window.end, rewrite);
122}
123
124/// Applies a rewrite to every expression a query holds.
125///
126/// @param select - the query
127/// @param rewrite - what to do to each expression
128pub fn rewrite_select(select: &mut BoundSelect, rewrite: Rewrite<'_>) {
129    for source in &mut select.sources {
130        rewrite_option(source.constraint.as_mut(), rewrite);
131        match &mut source.rows {
132            SourceRows::Table | SourceRows::RecursiveSelf { .. } => {}
133            SourceRows::Subquery(block) => rewrite_select(block, rewrite),
134            SourceRows::Recursive(body) => {
135                for (_, arm) in body.seeds.iter_mut().chain(body.steps.iter_mut()) {
136                    rewrite_select(arm, rewrite);
137                }
138            }
139        }
140    }
141    rewrite_option(select.filter.as_mut(), rewrite);
142    for term in &mut select.group_by {
143        rewrite_expr(term, rewrite);
144    }
145    rewrite_option(select.having.as_mut(), rewrite);
146    rewrite_columns(&mut select.columns, rewrite);
147    rewrite_order(&mut select.order_by, rewrite);
148    rewrite_option(select.limit.as_mut(), rewrite);
149    rewrite_option(select.offset.as_mut(), rewrite);
150    for aggregate in &mut select.aggregates {
151        for argument in &mut aggregate.arguments {
152            rewrite_expr(argument, rewrite);
153        }
154        // The call's own `FILTER` and `ORDER BY` read the row as its arguments
155        // do. Leaving them out kept a flattened derived table's column in
156        // `count(s.a ORDER BY s.a)`, and the statement was refused as misuse.
157        rewrite_option(aggregate.filter.as_mut(), rewrite);
158        rewrite_order(&mut aggregate.order_by, rewrite);
159    }
160    for row in &mut select.values {
161        for value in row {
162            rewrite_expr(value, rewrite);
163        }
164    }
165    for (_, arm) in &mut select.compounds {
166        rewrite_select(arm, rewrite);
167    }
168    for window in &mut select.windows {
169        rewrite_window(window, rewrite);
170    }
171}
172
173/// Applies a rewrite to one column source.
174///
175/// @param source - where the column's value comes from
176/// @param rewrite - what to do to each expression
177fn rewrite_source(source: &mut ColumnSource, rewrite: Rewrite<'_>) {
178    match source {
179        ColumnSource::Row(_) => {}
180        ColumnSource::Expr(expr) | ColumnSource::Generated(expr) => rewrite_expr(expr, rewrite),
181    }
182}
183
184/// Applies a rewrite to every expression an `INSERT` holds, its own triggers
185/// excepted.
186///
187/// @param statement - the insert
188/// @param rewrite - what to do to each expression
189pub fn rewrite_insert(statement: &mut BoundInsert, rewrite: Rewrite<'_>) {
190    for column in &mut statement.columns {
191        rewrite_source(column, rewrite);
192    }
193    if let Some(rowid) = statement.rowid.as_mut() {
194        rewrite_source(rowid, rewrite);
195    }
196    match &mut statement.source {
197        BoundInsertSource::Values(rows) => {
198            for row in rows {
199                for value in row {
200                    rewrite_expr(value, rewrite);
201                }
202            }
203        }
204        BoundInsertSource::Select(select) => rewrite_select(select, rewrite),
205    }
206    for check in &mut statement.checks {
207        rewrite_expr(&mut check.expr, rewrite);
208    }
209    for upsert in &mut statement.upsert {
210        for assignment in &mut upsert.assignments {
211            rewrite_expr(&mut assignment.value, rewrite);
212        }
213        rewrite_option(upsert.filter.as_mut(), rewrite);
214    }
215    rewrite_columns(&mut statement.returning, rewrite);
216}
217
218/// Applies a rewrite to every expression an `UPDATE` holds, its own triggers
219/// excepted.
220///
221/// @param statement - the update
222/// @param rewrite - what to do to each expression
223pub fn rewrite_update(statement: &mut BoundUpdate, rewrite: Rewrite<'_>) {
224    for assignment in &mut statement.assignments {
225        rewrite_expr(&mut assignment.value, rewrite);
226    }
227    // **The `FROM` terms, and the queries a derived one holds.** They were
228    // left out, so no rewrite reached a derived table in `UPDATE ... FROM`:
229    // a correlated `IN` in its `WHERE` stayed an `IN` and the physical pass
230    // refused it as not built, while the same derived table in a `SELECT` was
231    // lowered to `EXISTS` and answered.
232    for source in &mut statement.from {
233        rewrite_option(source.constraint.as_mut(), rewrite);
234        match &mut source.rows {
235            SourceRows::Table | SourceRows::RecursiveSelf { .. } => {}
236            SourceRows::Subquery(block) => rewrite_select(block, rewrite),
237            SourceRows::Recursive(body) => {
238                for (_, arm) in body.seeds.iter_mut().chain(body.steps.iter_mut()) {
239                    rewrite_select(arm, rewrite);
240                }
241            }
242        }
243    }
244    rewrite_option(statement.filter.as_mut(), rewrite);
245    for check in &mut statement.checks {
246        rewrite_expr(&mut check.expr, rewrite);
247    }
248    rewrite_columns(&mut statement.returning, rewrite);
249    rewrite_order(&mut statement.order_by, rewrite);
250    rewrite_option(statement.limit.as_mut(), rewrite);
251    rewrite_option(statement.offset.as_mut(), rewrite);
252    if let Some(rows) = statement.view_rows.as_mut() {
253        rewrite_select(rows, rewrite);
254    }
255}
256
257/// Applies a rewrite to every expression a `DELETE` holds, its own triggers
258/// excepted.
259///
260/// @param statement - the delete
261/// @param rewrite - what to do to each expression
262pub fn rewrite_delete(statement: &mut BoundDelete, rewrite: Rewrite<'_>) {
263    rewrite_option(statement.filter.as_mut(), rewrite);
264    rewrite_columns(&mut statement.returning, rewrite);
265    rewrite_order(&mut statement.order_by, rewrite);
266    rewrite_option(statement.limit.as_mut(), rewrite);
267    rewrite_option(statement.offset.as_mut(), rewrite);
268    if let Some(rows) = statement.view_rows.as_mut() {
269        rewrite_select(rows, rewrite);
270    }
271}