Skip to content

Commit 3f874f4

Browse files
authored
use post_* visitors for mutable visits (#789)
My initial implementation of mutable visitors closely matched the existing immutable visitor implementations, and used pre_* visitors (a mutable expression was first passed the visitor, then its children were visited). After some initial usage, I realize this actually impractical, and can easily lead to infinite recursion when one isn't careful. For instance a mutable visitor would replace x by f(x), then would be called again on the nested x and result in f(f(x)), then again resulting in f(f(f(x))), and so on. So, this commit changes the behavior of the visit_*_mut functions to call the visitor on an expression only once all of its children have been visited. It also makes the documentation more explicit and adds an example.
1 parent 82cf554 commit 3f874f4

File tree

1 file changed

+44
-6
lines changed

1 file changed

+44
-6
lines changed

src/ast/visitor.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ impl<E, F: FnMut(&ObjectName) -> ControlFlow<E>> Visitor for RelationVisitor<F>
301301
impl<E, F: FnMut(&mut ObjectName) -> ControlFlow<E>> VisitorMut for RelationVisitor<F> {
302302
type Break = E;
303303

304-
fn pre_visit_relation(&mut self, relation: &mut ObjectName) -> ControlFlow<Self::Break> {
304+
fn post_visit_relation(&mut self, relation: &mut ObjectName) -> ControlFlow<Self::Break> {
305305
self.0(relation)
306306
}
307307
}
@@ -343,7 +343,10 @@ where
343343
ControlFlow::Continue(())
344344
}
345345

346-
/// Invokes the provided closure on all relations (e.g. table names) present in `v`
346+
/// Invokes the provided closure with a mutable reference to all relations (e.g. table names)
347+
/// present in `v`.
348+
///
349+
/// When the closure mutates its argument, the new mutated relation will not be visited again.
347350
///
348351
/// # Example
349352
/// ```
@@ -386,7 +389,7 @@ impl<E, F: FnMut(&Expr) -> ControlFlow<E>> Visitor for ExprVisitor<F> {
386389
impl<E, F: FnMut(&mut Expr) -> ControlFlow<E>> VisitorMut for ExprVisitor<F> {
387390
type Break = E;
388391

389-
fn pre_visit_expr(&mut self, expr: &mut Expr) -> ControlFlow<Self::Break> {
392+
fn post_visit_expr(&mut self, expr: &mut Expr) -> ControlFlow<Self::Break> {
390393
self.0(expr)
391394
}
392395
}
@@ -430,9 +433,14 @@ where
430433
ControlFlow::Continue(())
431434
}
432435

433-
/// Invokes the provided closure on all expressions present in `v`
436+
/// Invokes the provided closure iteratively with a mutable reference to all expressions
437+
/// present in `v`.
438+
///
439+
/// This performs a depth-first search, so if the closure mutates the expression
434440
///
435441
/// # Example
442+
///
443+
/// ## Remove all select limits in sub-queries
436444
/// ```
437445
/// # use sqlparser::parser::Parser;
438446
/// # use sqlparser::dialect::GenericDialect;
@@ -451,6 +459,35 @@ where
451459
///
452460
/// assert_eq!(statements[0].to_string(), "SELECT (SELECT y FROM z) FROM t LIMIT 3");
453461
/// ```
462+
///
463+
/// ## Wrap column name in function call
464+
///
465+
/// This demonstrates how to effectively replace an expression with another more complicated one
466+
/// that references the original. This example avoids unnecessary allocations by using the
467+
/// [`std::mem`](std::mem) family of functions.
468+
///
469+
/// ```
470+
/// # use sqlparser::parser::Parser;
471+
/// # use sqlparser::dialect::GenericDialect;
472+
/// # use sqlparser::ast::{Expr, Function, FunctionArg, FunctionArgExpr, Ident, ObjectName, Value, visit_expressions_mut, visit_statements_mut};
473+
/// # use core::ops::ControlFlow;
474+
/// let sql = "SELECT x, y FROM t";
475+
/// let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();
476+
///
477+
/// visit_expressions_mut(&mut statements, |expr| {
478+
/// if matches!(expr, Expr::Identifier(col_name) if col_name.value == "x") {
479+
/// let old_expr = std::mem::replace(expr, Expr::Value(Value::Null));
480+
/// *expr = Expr::Function(Function {
481+
/// name: ObjectName(vec![Ident::new("f")]),
482+
/// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],
483+
/// over: None, distinct: false, special: false,
484+
/// });
485+
/// }
486+
/// ControlFlow::<()>::Continue(())
487+
/// });
488+
///
489+
/// assert_eq!(statements[0].to_string(), "SELECT f(x), y FROM t");
490+
/// ```
454491
pub fn visit_expressions_mut<V, E, F>(v: &mut V, f: F) -> ControlFlow<E>
455492
where
456493
V: VisitMut,
@@ -473,12 +510,13 @@ impl<E, F: FnMut(&Statement) -> ControlFlow<E>> Visitor for StatementVisitor<F>
473510
impl<E, F: FnMut(&mut Statement) -> ControlFlow<E>> VisitorMut for StatementVisitor<F> {
474511
type Break = E;
475512

476-
fn pre_visit_statement(&mut self, statement: &mut Statement) -> ControlFlow<Self::Break> {
513+
fn post_visit_statement(&mut self, statement: &mut Statement) -> ControlFlow<Self::Break> {
477514
self.0(statement)
478515
}
479516
}
480517

481-
/// Invokes the provided closure on all statements (e.g. `SELECT`, `CREATE TABLE`, etc) present in `v`
518+
/// Invokes the provided closure iteratively with a mutable reference to all statements
519+
/// present in `v` (e.g. `SELECT`, `CREATE TABLE`, etc).
482520
///
483521
/// # Example
484522
/// ```

0 commit comments

Comments
 (0)