You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/07/30 09:17:30 UTC
(datafusion-sqlparser-rs) branch gh-readonly-queue/main/pr-2406-57a62aeddeb39130c2dafc25c626d4e2693a76bd created (now b2ff6aea)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a change to branch gh-readonly-queue/main/pr-2406-57a62aeddeb39130c2dafc25c626d4e2693a76bd
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
at b2ff6aea Add visitors for ORDER BY and GROUP BY (#2406)
This branch includes the following new commits:
new b2ff6aea Add visitors for ORDER BY and GROUP BY (#2406)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org
(datafusion-sqlparser-rs) 01/01: Add visitors for ORDER BY and GROUP BY (#2406)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-2406-57a62aeddeb39130c2dafc25c626d4e2693a76bd
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit b2ff6aeaa35a23e60032233fc836eb82193b0f3e
Author: Sidney Cammeresi <sa...@readyset.io>
AuthorDate: Thu Jul 30 02:17:06 2026 -0700
Add visitors for ORDER BY and GROUP BY (#2406)
---
src/ast/query.rs | 3 +
src/ast/visitor.rs | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/src/ast/query.rs b/src/ast/query.rs
index fdcacddf..c683d66c 100644
--- a/src/ast/query.rs
+++ b/src/ast/query.rs
@@ -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`).
@@ -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,
@@ -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 {
diff --git a/src/ast/visitor.rs b/src/ast/visitor.rs
index c70e83ec..9011a94d 100644
--- a/src/ast/visitor.rs
+++ b/src/ast/visitor.rs
@@ -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.
@@ -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.
@@ -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);
@@ -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 {
@@ -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",
@@ -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",
@@ -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)",
@@ -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)",
@@ -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",
@@ -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",
]
@@ -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();
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org