mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-22 11:41:46 +00:00
Support IGNORE|RESPECT
NULLs clause in window functions (#998)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
8262abcd31
commit
b89edaa98b
14 changed files with 124 additions and 0 deletions
|
@ -1161,6 +1161,26 @@ impl fmt::Display for WindowFrameUnits {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies Ignore / Respect NULL within window functions.
|
||||
/// For example
|
||||
/// `FIRST_VALUE(column2) IGNORE NULLS OVER (PARTITION BY column1)`
|
||||
#[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 NullTreatment {
|
||||
IgnoreNulls,
|
||||
RespectNulls,
|
||||
}
|
||||
|
||||
impl fmt::Display for NullTreatment {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
NullTreatment::IgnoreNulls => "IGNORE NULLS",
|
||||
NullTreatment::RespectNulls => "RESPECT NULLS",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
|
@ -3757,6 +3777,8 @@ pub struct Function {
|
|||
pub args: Vec<FunctionArg>,
|
||||
/// e.g. `x > 5` in `COUNT(x) FILTER (WHERE x > 5)`
|
||||
pub filter: Option<Box<Expr>>,
|
||||
// Snowflake/MSSQL supports diffrent options for null treatment in rank functions
|
||||
pub null_treatment: Option<NullTreatment>,
|
||||
pub over: Option<WindowType>,
|
||||
// aggregate functions may specify eg `COUNT(DISTINCT x)`
|
||||
pub distinct: bool,
|
||||
|
@ -3809,6 +3831,10 @@ impl fmt::Display for Function {
|
|||
write!(f, " FILTER (WHERE {filter_cond})")?;
|
||||
}
|
||||
|
||||
if let Some(o) = &self.null_treatment {
|
||||
write!(f, " {o}")?;
|
||||
}
|
||||
|
||||
if let Some(o) = &self.over {
|
||||
write!(f, " OVER {o}")?;
|
||||
}
|
||||
|
|
|
@ -506,6 +506,7 @@ where
|
|||
/// *expr = Expr::Function(Function {
|
||||
/// name: ObjectName(vec![Ident::new("f")]),
|
||||
/// args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],
|
||||
/// null_treatment: None,
|
||||
/// filter: None, over: None, distinct: false, special: false, order_by: vec![],
|
||||
/// });
|
||||
/// }
|
||||
|
|
|
@ -518,6 +518,7 @@ define_keywords!(
|
|||
REPLACE,
|
||||
REPLICATION,
|
||||
RESET,
|
||||
RESPECT,
|
||||
RESTRICT,
|
||||
RESULT,
|
||||
RETAIN,
|
||||
|
|
|
@ -785,6 +785,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(Expr::Function(Function {
|
||||
name: ObjectName(vec![w.to_ident()]),
|
||||
args: vec![],
|
||||
null_treatment: None,
|
||||
filter: None,
|
||||
over: None,
|
||||
distinct: false,
|
||||
|
@ -987,6 +988,19 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let null_treatment = match self.parse_one_of_keywords(&[Keyword::RESPECT, Keyword::IGNORE])
|
||||
{
|
||||
Some(keyword) => {
|
||||
self.expect_keyword(Keyword::NULLS)?;
|
||||
|
||||
match keyword {
|
||||
Keyword::RESPECT => Some(NullTreatment::RespectNulls),
|
||||
Keyword::IGNORE => Some(NullTreatment::IgnoreNulls),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let over = if self.parse_keyword(Keyword::OVER) {
|
||||
if self.consume_token(&Token::LParen) {
|
||||
let window_spec = self.parse_window_spec()?;
|
||||
|
@ -1000,6 +1014,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(Expr::Function(Function {
|
||||
name,
|
||||
args,
|
||||
null_treatment,
|
||||
filter,
|
||||
over,
|
||||
distinct,
|
||||
|
@ -1018,6 +1033,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(Expr::Function(Function {
|
||||
name,
|
||||
args,
|
||||
null_treatment: None,
|
||||
filter: None,
|
||||
over: None,
|
||||
distinct: false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue