mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-28 14:09:56 +00:00
Support FILTER in over clause (#1007)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
e857a45201
commit
ce62fe6d27
15 changed files with 102 additions and 2 deletions
|
|
@ -1070,8 +1070,11 @@ impl Display for WindowType {
|
|||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct WindowSpec {
|
||||
/// `OVER (PARTITION BY ...)`
|
||||
pub partition_by: Vec<Expr>,
|
||||
/// `OVER (ORDER BY ...)`
|
||||
pub order_by: Vec<OrderByExpr>,
|
||||
/// `OVER (window frame)`
|
||||
pub window_frame: Option<WindowFrame>,
|
||||
}
|
||||
|
||||
|
|
@ -3729,6 +3732,8 @@ impl fmt::Display for CloseCursor {
|
|||
pub struct Function {
|
||||
pub name: ObjectName,
|
||||
pub args: Vec<FunctionArg>,
|
||||
/// e.g. `x > 5` in `COUNT(x) FILTER (WHERE x > 5)`
|
||||
pub filter: Option<Box<Expr>>,
|
||||
pub over: Option<WindowType>,
|
||||
// aggregate functions may specify eg `COUNT(DISTINCT x)`
|
||||
pub distinct: bool,
|
||||
|
|
@ -3777,6 +3782,10 @@ impl fmt::Display for Function {
|
|||
display_comma_separated(&self.order_by),
|
||||
)?;
|
||||
|
||||
if let Some(filter_cond) = &self.filter {
|
||||
write!(f, " FILTER (WHERE {filter_cond})")?;
|
||||
}
|
||||
|
||||
if let Some(o) = &self.over {
|
||||
write!(f, " OVER {o}")?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ where
|
|||
/// *expr = Expr::Function(Function {
|
||||
/// name: ObjectName(vec![Ident::new("f")]),
|
||||
/// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],
|
||||
/// over: None, distinct: false, special: false, order_by: vec![],
|
||||
/// filter: None, over: None, distinct: false, special: false, order_by: vec![],
|
||||
/// });
|
||||
/// }
|
||||
/// ControlFlow::<()>::Continue(())
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ impl Dialect for SQLiteDialect {
|
|||
|| ('\u{007f}'..='\u{ffff}').contains(&ch)
|
||||
}
|
||||
|
||||
fn supports_filter_during_aggregation(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn is_identifier_part(&self, ch: char) -> bool {
|
||||
self.is_identifier_start(ch) || ch.is_ascii_digit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -772,6 +772,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(Expr::Function(Function {
|
||||
name: ObjectName(vec![w.to_ident()]),
|
||||
args: vec![],
|
||||
filter: None,
|
||||
over: None,
|
||||
distinct: false,
|
||||
special: true,
|
||||
|
|
@ -957,6 +958,17 @@ impl<'a> Parser<'a> {
|
|||
self.expect_token(&Token::LParen)?;
|
||||
let distinct = self.parse_all_or_distinct()?.is_some();
|
||||
let (args, order_by) = self.parse_optional_args_with_orderby()?;
|
||||
let filter = if self.dialect.supports_filter_during_aggregation()
|
||||
&& self.parse_keyword(Keyword::FILTER)
|
||||
&& self.consume_token(&Token::LParen)
|
||||
&& self.parse_keyword(Keyword::WHERE)
|
||||
{
|
||||
let filter = Some(Box::new(self.parse_expr()?));
|
||||
self.expect_token(&Token::RParen)?;
|
||||
filter
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let over = if self.parse_keyword(Keyword::OVER) {
|
||||
if self.consume_token(&Token::LParen) {
|
||||
let window_spec = self.parse_window_spec()?;
|
||||
|
|
@ -970,6 +982,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(Expr::Function(Function {
|
||||
name,
|
||||
args,
|
||||
filter,
|
||||
over,
|
||||
distinct,
|
||||
special: false,
|
||||
|
|
@ -987,6 +1000,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(Expr::Function(Function {
|
||||
name,
|
||||
args,
|
||||
filter: None,
|
||||
over: None,
|
||||
distinct: false,
|
||||
special,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue