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    }
155    for row in &mut select.values {
156        for value in row {
157            rewrite_expr(value, rewrite);
158        }
159    }
160    for (_, arm) in &mut select.compounds {
161        rewrite_select(arm, rewrite);
162    }
163    for window in &mut select.windows {
164        rewrite_window(window, rewrite);
165    }
166}
167
168/// Applies a rewrite to one column source.
169///
170/// @param source - where the column's value comes from
171/// @param rewrite - what to do to each expression
172fn rewrite_source(source: &mut ColumnSource, rewrite: Rewrite<'_>) {
173    match source {
174        ColumnSource::Row(_) => {}
175        ColumnSource::Expr(expr) | ColumnSource::Generated(expr) => rewrite_expr(expr, rewrite),
176    }
177}
178
179/// Applies a rewrite to every expression an `INSERT` holds, its own triggers
180/// excepted.
181///
182/// @param statement - the insert
183/// @param rewrite - what to do to each expression
184pub fn rewrite_insert(statement: &mut BoundInsert, rewrite: Rewrite<'_>) {
185    for column in &mut statement.columns {
186        rewrite_source(column, rewrite);
187    }
188    if let Some(rowid) = statement.rowid.as_mut() {
189        rewrite_source(rowid, rewrite);
190    }
191    match &mut statement.source {
192        BoundInsertSource::Values(rows) => {
193            for row in rows {
194                for value in row {
195                    rewrite_expr(value, rewrite);
196                }
197            }
198        }
199        BoundInsertSource::Select(select) => rewrite_select(select, rewrite),
200    }
201    for check in &mut statement.checks {
202        rewrite_expr(&mut check.expr, rewrite);
203    }
204    for upsert in &mut statement.upsert {
205        for assignment in &mut upsert.assignments {
206            rewrite_expr(&mut assignment.value, rewrite);
207        }
208        rewrite_option(upsert.filter.as_mut(), rewrite);
209    }
210    rewrite_columns(&mut statement.returning, rewrite);
211}
212
213/// Applies a rewrite to every expression an `UPDATE` holds, its own triggers
214/// excepted.
215///
216/// @param statement - the update
217/// @param rewrite - what to do to each expression
218pub fn rewrite_update(statement: &mut BoundUpdate, rewrite: Rewrite<'_>) {
219    for assignment in &mut statement.assignments {
220        rewrite_expr(&mut assignment.value, rewrite);
221    }
222    // **The `FROM` terms, and the queries a derived one holds.** They were
223    // left out, so no rewrite reached a derived table in `UPDATE ... FROM`:
224    // a correlated `IN` in its `WHERE` stayed an `IN` and the physical pass
225    // refused it as not built, while the same derived table in a `SELECT` was
226    // lowered to `EXISTS` and answered.
227    for source in &mut statement.from {
228        rewrite_option(source.constraint.as_mut(), rewrite);
229        match &mut source.rows {
230            SourceRows::Table | SourceRows::RecursiveSelf { .. } => {}
231            SourceRows::Subquery(block) => rewrite_select(block, rewrite),
232            SourceRows::Recursive(body) => {
233                for (_, arm) in body.seeds.iter_mut().chain(body.steps.iter_mut()) {
234                    rewrite_select(arm, rewrite);
235                }
236            }
237        }
238    }
239    rewrite_option(statement.filter.as_mut(), rewrite);
240    for check in &mut statement.checks {
241        rewrite_expr(&mut check.expr, rewrite);
242    }
243    rewrite_columns(&mut statement.returning, rewrite);
244    rewrite_order(&mut statement.order_by, rewrite);
245    rewrite_option(statement.limit.as_mut(), rewrite);
246    rewrite_option(statement.offset.as_mut(), rewrite);
247    if let Some(rows) = statement.view_rows.as_mut() {
248        rewrite_select(rows, rewrite);
249    }
250}
251
252/// Applies a rewrite to every expression a `DELETE` holds, its own triggers
253/// excepted.
254///
255/// @param statement - the delete
256/// @param rewrite - what to do to each expression
257pub fn rewrite_delete(statement: &mut BoundDelete, rewrite: Rewrite<'_>) {
258    rewrite_option(statement.filter.as_mut(), rewrite);
259    rewrite_columns(&mut statement.returning, rewrite);
260    rewrite_order(&mut statement.order_by, rewrite);
261    rewrite_option(statement.limit.as_mut(), rewrite);
262    rewrite_option(statement.offset.as_mut(), rewrite);
263    if let Some(rows) = statement.view_rows.as_mut() {
264        rewrite_select(rows, rewrite);
265    }
266}