mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-30 23:07:04 +00:00
Support GROUP BY WITH MODIFIER for ClickHouse (#1323)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
parent
0b1a413e64
commit
44d7a20f64
10 changed files with 215 additions and 76 deletions
|
|
@ -43,8 +43,8 @@ pub use self::operator::{BinaryOperator, UnaryOperator};
|
|||
pub use self::query::{
|
||||
AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct, EmptyMatchesMode,
|
||||
ExceptSelectItem, ExcludeSelectItem, ExprWithAlias, Fetch, ForClause, ForJson, ForXml,
|
||||
GroupByExpr, IdentWithAlias, IlikeSelectItem, Join, JoinConstraint, JoinOperator,
|
||||
JsonTableColumn, JsonTableColumnErrorHandling, LateralView, LockClause, LockType,
|
||||
GroupByExpr, GroupByWithModifier, IdentWithAlias, IlikeSelectItem, Join, JoinConstraint,
|
||||
JoinOperator, JsonTableColumn, JsonTableColumnErrorHandling, LateralView, LockClause, LockType,
|
||||
MatchRecognizePattern, MatchRecognizeSymbol, Measure, NamedWindowDefinition, NamedWindowExpr,
|
||||
NonBlock, Offset, OffsetRows, OrderByExpr, PivotValueSource, Query, RenameSelectItem,
|
||||
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,
|
||||
|
|
|
|||
|
|
@ -299,10 +299,10 @@ impl fmt::Display for Select {
|
|||
write!(f, " WHERE {selection}")?;
|
||||
}
|
||||
match &self.group_by {
|
||||
GroupByExpr::All => write!(f, " GROUP BY ALL")?,
|
||||
GroupByExpr::Expressions(exprs) => {
|
||||
GroupByExpr::All(_) => write!(f, " {}", self.group_by)?,
|
||||
GroupByExpr::Expressions(exprs, _) => {
|
||||
if !exprs.is_empty() {
|
||||
write!(f, " GROUP BY {}", display_comma_separated(exprs))?;
|
||||
write!(f, " {}", self.group_by)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1866,27 +1866,65 @@ impl fmt::Display for SelectInto {
|
|||
}
|
||||
}
|
||||
|
||||
/// ClickHouse supports GROUP BY WITH modifiers(includes ROLLUP|CUBE|TOTALS).
|
||||
/// e.g. GROUP BY year WITH ROLLUP WITH TOTALS
|
||||
///
|
||||
/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum GroupByWithModifier {
|
||||
Rollup,
|
||||
Cube,
|
||||
Totals,
|
||||
}
|
||||
|
||||
impl fmt::Display for GroupByWithModifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
GroupByWithModifier::Rollup => write!(f, "WITH ROLLUP"),
|
||||
GroupByWithModifier::Cube => write!(f, "WITH CUBE"),
|
||||
GroupByWithModifier::Totals => write!(f, "WITH TOTALS"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum GroupByExpr {
|
||||
/// ALL syntax of [Snowflake], and [DuckDB]
|
||||
/// ALL syntax of [Snowflake], [DuckDB] and [ClickHouse].
|
||||
///
|
||||
/// [Snowflake]: <https://docs.snowflake.com/en/sql-reference/constructs/group-by#label-group-by-all-columns>
|
||||
/// [DuckDB]: <https://duckdb.org/docs/sql/query_syntax/groupby.html>
|
||||
All,
|
||||
/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#group-by-all>
|
||||
///
|
||||
/// ClickHouse also supports WITH modifiers after GROUP BY ALL and expressions.
|
||||
///
|
||||
/// [ClickHouse]: <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
|
||||
All(Vec<GroupByWithModifier>),
|
||||
|
||||
/// Expressions
|
||||
Expressions(Vec<Expr>),
|
||||
Expressions(Vec<Expr>, Vec<GroupByWithModifier>),
|
||||
}
|
||||
|
||||
impl fmt::Display for GroupByExpr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
GroupByExpr::All => write!(f, "GROUP BY ALL"),
|
||||
GroupByExpr::Expressions(col_names) => {
|
||||
GroupByExpr::All(modifiers) => {
|
||||
write!(f, "GROUP BY ALL")?;
|
||||
if !modifiers.is_empty() {
|
||||
write!(f, " {}", display_separated(modifiers, " "))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
GroupByExpr::Expressions(col_names, modifiers) => {
|
||||
let col_names = display_comma_separated(col_names);
|
||||
write!(f, "GROUP BY ({col_names})")
|
||||
write!(f, "GROUP BY {col_names}")?;
|
||||
if !modifiers.is_empty() {
|
||||
write!(f, " {}", display_separated(modifiers, " "))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -721,6 +721,7 @@ define_keywords!(
|
|||
TINYINT,
|
||||
TO,
|
||||
TOP,
|
||||
TOTALS,
|
||||
TRAILING,
|
||||
TRANSACTION,
|
||||
TRANSIENT,
|
||||
|
|
|
|||
|
|
@ -8319,13 +8319,42 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
|
||||
let group_by = if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
|
||||
if self.parse_keyword(Keyword::ALL) {
|
||||
GroupByExpr::All
|
||||
let expressions = if self.parse_keyword(Keyword::ALL) {
|
||||
None
|
||||
} else {
|
||||
GroupByExpr::Expressions(self.parse_comma_separated(Parser::parse_group_by_expr)?)
|
||||
Some(self.parse_comma_separated(Parser::parse_group_by_expr)?)
|
||||
};
|
||||
|
||||
let mut modifiers = vec![];
|
||||
if dialect_of!(self is ClickHouseDialect | GenericDialect) {
|
||||
loop {
|
||||
if !self.parse_keyword(Keyword::WITH) {
|
||||
break;
|
||||
}
|
||||
let keyword = self.expect_one_of_keywords(&[
|
||||
Keyword::ROLLUP,
|
||||
Keyword::CUBE,
|
||||
Keyword::TOTALS,
|
||||
])?;
|
||||
modifiers.push(match keyword {
|
||||
Keyword::ROLLUP => GroupByWithModifier::Rollup,
|
||||
Keyword::CUBE => GroupByWithModifier::Cube,
|
||||
Keyword::TOTALS => GroupByWithModifier::Totals,
|
||||
_ => {
|
||||
return parser_err!(
|
||||
"BUG: expected to match GroupBy modifier keyword",
|
||||
self.peek_token().location
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
match expressions {
|
||||
None => GroupByExpr::All(modifiers),
|
||||
Some(exprs) => GroupByExpr::Expressions(exprs, modifiers),
|
||||
}
|
||||
} else {
|
||||
GroupByExpr::Expressions(vec![])
|
||||
GroupByExpr::Expressions(vec![], vec![])
|
||||
};
|
||||
|
||||
let cluster_by = if self.parse_keywords(&[Keyword::CLUSTER, Keyword::BY]) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue