Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2888,6 +2888,7 @@ pub enum OrderByKind {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "visitor", visit(with = "visit_order_by"))]
/// Represents an `ORDER BY` clause with its kind and optional `INTERPOLATE`.
pub struct OrderBy {
/// The kind of ordering (expressions or `ALL`).
Expand Down Expand Up @@ -2924,6 +2925,7 @@ impl fmt::Display for OrderBy {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "visitor", visit(with = "visit_order_by_expr"))]
pub struct OrderByExpr {
/// The expression to order by.
pub expr: Expr,
Expand Down Expand Up @@ -3776,6 +3778,7 @@ impl fmt::Display for GroupByWithModifier {
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
#[cfg_attr(feature = "visitor", visit(with = "visit_group_by"))]
/// Represents the two syntactic forms that `GROUP BY` can take, including
/// `GROUP BY ALL` with optional modifiers and ordinary `GROUP BY <exprs>`.
pub enum GroupByExpr {
Expand Down
189 changes: 188 additions & 1 deletion src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
use alloc::{boxed::Box, string::String, vec::Vec};
use core::ops::ControlFlow;

use crate::ast::{Expr, Ident, ObjectName, Query, Select, Statement, TableFactor, ValueWithSpan};
use crate::ast::{
Expr, GroupByExpr, Ident, ObjectName, OrderBy, OrderByExpr, Query, Select, Statement,
TableFactor, ValueWithSpan,
};

/// A type that can be visited by a [`Visitor`]. See [`Visitor`] for
/// recursively visiting parsed SQL statements.
Expand Down Expand Up @@ -279,6 +282,42 @@ pub trait Visitor {
fn post_visit_ident(&mut self, _ident: &Ident) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` clauses that appear in the AST before visiting children
fn pre_visit_order_by(&mut self, _order_by: &OrderBy) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` clauses that appear in the AST after visiting children
fn post_visit_order_by(&mut self, _order_by: &OrderBy) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` expressions that appear in the AST before visiting children
fn pre_visit_order_by_expr(
&mut self,
_order_by_expr: &OrderByExpr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` expressions that appear in the AST after visiting children
fn post_visit_order_by_expr(
&mut self,
_order_by_expr: &OrderByExpr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `GROUP BY` clauses that appear in the AST before visiting children
fn pre_visit_group_by(&mut self, _group_by: &GroupByExpr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `GROUP BY` clauses that appear in the AST after visiting children
fn post_visit_group_by(&mut self, _group_by: &GroupByExpr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
}

/// A visitor that can be used to mutate an AST tree.
Expand Down Expand Up @@ -417,6 +456,42 @@ pub trait VisitorMut {
fn post_visit_ident(&mut self, _ident: &mut Ident) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` clauses that appear in the AST before visiting children
fn pre_visit_order_by(&mut self, _order_by: &mut OrderBy) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` clauses that appear in the AST after visiting children
fn post_visit_order_by(&mut self, _order_by: &mut OrderBy) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` expressions that appear in the AST before visiting children
fn pre_visit_order_by_expr(
&mut self,
_order_by_expr: &mut OrderByExpr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `ORDER BY` expressions that appear in the AST after visiting children
fn post_visit_order_by_expr(
&mut self,
_order_by_expr: &mut OrderByExpr,
) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `GROUP BY` clauses that appear in the AST before visiting children
fn pre_visit_group_by(&mut self, _group_by: &mut GroupByExpr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}

/// Invoked for any `GROUP BY` clauses that appear in the AST after visiting children
fn post_visit_group_by(&mut self, _group_by: &mut GroupByExpr) -> ControlFlow<Self::Break> {
ControlFlow::Continue(())
}
}

struct RelationVisitor<F>(F);
Expand Down Expand Up @@ -809,6 +884,44 @@ mod tests {
self.visited.push(format!("POST: STATEMENT: {statement}"));
ControlFlow::Continue(())
}

fn pre_visit_order_by(&mut self, order_by: &OrderBy) -> ControlFlow<Self::Break> {
self.visited.push(format!("PRE: ORDER BY: {order_by}"));
ControlFlow::Continue(())
}

fn post_visit_order_by(&mut self, order_by: &OrderBy) -> ControlFlow<Self::Break> {
self.visited.push(format!("POST: ORDER BY: {order_by}"));
ControlFlow::Continue(())
}

fn pre_visit_order_by_expr(
&mut self,
order_by_expr: &OrderByExpr,
) -> ControlFlow<Self::Break> {
self.visited
.push(format!("PRE: ORDER BY EXPR: {order_by_expr}"));
ControlFlow::Continue(())
}

fn post_visit_order_by_expr(
&mut self,
order_by_expr: &OrderByExpr,
) -> ControlFlow<Self::Break> {
self.visited
.push(format!("POST: ORDER BY EXPR: {order_by_expr}"));
ControlFlow::Continue(())
}

fn pre_visit_group_by(&mut self, group_by: &GroupByExpr) -> ControlFlow<Self::Break> {
self.visited.push(format!("PRE: GROUP BY: {group_by}"));
ControlFlow::Continue(())
}

fn post_visit_group_by(&mut self, group_by: &GroupByExpr) -> ControlFlow<Self::Break> {
self.visited.push(format!("POST: GROUP BY: {group_by}"));
ControlFlow::Continue(())
}
}

fn do_visit<V: Visitor<Break = ()>>(sql: &str, visitor: &mut V) -> Statement {
Expand Down Expand Up @@ -837,6 +950,8 @@ mod tests {
"PRE: RELATION: table_name",
"POST: RELATION: table_name",
"POST: TABLE FACTOR: table_name AS my_table",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM table_name AS my_table",
"POST: QUERY: SELECT * FROM table_name AS my_table",
"POST: STATEMENT: SELECT * FROM table_name AS my_table",
Expand All @@ -862,6 +977,8 @@ mod tests {
"PRE: EXPR: t2.t1_id",
"POST: EXPR: t2.t1_id",
"POST: EXPR: t1.id = t2.t1_id",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id",
"POST: QUERY: SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id",
"POST: STATEMENT: SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id",
Expand All @@ -886,9 +1003,13 @@ mod tests {
"PRE: RELATION: t2",
"POST: RELATION: t2",
"POST: TABLE FACTOR: t2",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT column FROM t2",
"POST: QUERY: SELECT column FROM t2",
"POST: EXPR: EXISTS (SELECT column FROM t2)",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
"POST: QUERY: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
"POST: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
Expand All @@ -913,9 +1034,13 @@ mod tests {
"PRE: RELATION: t2",
"POST: RELATION: t2",
"POST: TABLE FACTOR: t2",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT column FROM t2",
"POST: QUERY: SELECT column FROM t2",
"POST: EXPR: EXISTS (SELECT column FROM t2)",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
"POST: QUERY: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
"POST: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
Expand All @@ -940,15 +1065,21 @@ mod tests {
"PRE: RELATION: t2",
"POST: RELATION: t2",
"POST: TABLE FACTOR: t2",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT column FROM t2",
"POST: QUERY: SELECT column FROM t2",
"POST: EXPR: EXISTS (SELECT column FROM t2)",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
"PRE: SELECT: SELECT * FROM t3",
"PRE: TABLE FACTOR: t3",
"PRE: RELATION: t3",
"POST: RELATION: t3",
"POST: TABLE FACTOR: t3",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM t3",
"POST: QUERY: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2) UNION SELECT * FROM t3",
"POST: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2) UNION SELECT * FROM t3",
Expand Down Expand Up @@ -984,9 +1115,15 @@ mod tests {
"PRE: EXPR: 'APR'",
"POST: EXPR: 'APR'",
"POST: TABLE FACTOR: monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d)",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d)",
"PRE: ORDER BY: ORDER BY EMPID",
"PRE: ORDER BY EXPR: EMPID",
"PRE: EXPR: EMPID",
"POST: EXPR: EMPID",
"POST: ORDER BY EXPR: EMPID",
"POST: ORDER BY: ORDER BY EMPID",
"POST: QUERY: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ORDER BY EMPID",
"POST: STATEMENT: SELECT * FROM monthly_sales PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ORDER BY EMPID",
]
Expand All @@ -1000,6 +1137,56 @@ mod tests {
"POST: STATEMENT: SHOW COLUMNS FROM t1",
],
),
(
"SELECT * FROM t1 ORDER BY a DESC, b",
vec![
"PRE: STATEMENT: SELECT * FROM t1 ORDER BY a DESC, b",
"PRE: QUERY: SELECT * FROM t1 ORDER BY a DESC, b",
"PRE: SELECT: SELECT * FROM t1",
"PRE: TABLE FACTOR: t1",
"PRE: RELATION: t1",
"POST: RELATION: t1",
"POST: TABLE FACTOR: t1",
"PRE: GROUP BY: GROUP BY ",
"POST: GROUP BY: GROUP BY ",
"POST: SELECT: SELECT * FROM t1",
"PRE: ORDER BY: ORDER BY a DESC, b",
"PRE: ORDER BY EXPR: a DESC",
"PRE: EXPR: a",
"POST: EXPR: a",
"POST: ORDER BY EXPR: a DESC",
"PRE: ORDER BY EXPR: b",
"PRE: EXPR: b",
"POST: EXPR: b",
"POST: ORDER BY EXPR: b",
"POST: ORDER BY: ORDER BY a DESC, b",
"POST: QUERY: SELECT * FROM t1 ORDER BY a DESC, b",
"POST: STATEMENT: SELECT * FROM t1 ORDER BY a DESC, b",
],
),
(
"SELECT a FROM t GROUP BY a, b",
vec![
"PRE: STATEMENT: SELECT a FROM t GROUP BY a, b",
"PRE: QUERY: SELECT a FROM t GROUP BY a, b",
"PRE: SELECT: SELECT a FROM t GROUP BY a, b",
"PRE: EXPR: a",
"POST: EXPR: a",
"PRE: TABLE FACTOR: t",
"PRE: RELATION: t",
"POST: RELATION: t",
"POST: TABLE FACTOR: t",
"PRE: GROUP BY: GROUP BY a, b",
"PRE: EXPR: a",
"POST: EXPR: a",
"PRE: EXPR: b",
"POST: EXPR: b",
"POST: GROUP BY: GROUP BY a, b",
"POST: SELECT: SELECT a FROM t GROUP BY a, b",
"POST: QUERY: SELECT a FROM t GROUP BY a, b",
"POST: STATEMENT: SELECT a FROM t GROUP BY a, b",
],
),
];
for (sql, expected) in tests {
let mut visitor = TestVisitor::default();
Expand Down
Loading