Implement is [not] distinct from (#361)

* Implement is [not] distinct from

* Simplify message

* Clippy
This commit is contained in:
Daniël Heres 2021-10-14 18:26:28 +02:00 committed by GitHub
parent c9f8a44b55
commit 0f0b327e97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 7 deletions

View file

@ -169,10 +169,14 @@ pub enum Expr {
QualifiedWildcard(Vec<Ident>),
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
CompoundIdentifier(Vec<Ident>),
/// `IS NULL` expression
/// `IS NULL` operator
IsNull(Box<Expr>),
/// `IS NOT NULL` expression
/// `IS NOT NULL` operator
IsNotNull(Box<Expr>),
/// `IS DISTINCT FROM` operator
IsDistinctFrom(Box<Expr>, Box<Expr>),
/// `IS NOT DISTINCT FROM` operator
IsNotDistinctFrom(Box<Expr>, Box<Expr>),
/// `[ NOT ] IN (val1, val2, ...)`
InList {
expr: Box<Expr>,
@ -387,6 +391,8 @@ impl fmt::Display for Expr {
write!(f, ")")
}
Expr::IsDistinctFrom(a, b) => write!(f, "{} IS DISTINCT FROM {}", a, b),
Expr::IsNotDistinctFrom(a, b) => write!(f, "{} IS NOT DISTINCT FROM {}", a, b),
Expr::Trim { expr, trim_where } => {
write!(f, "TRIM(")?;
if let Some((ident, trim_char)) = trim_where {

View file

@ -87,9 +87,8 @@ mod tests {
assert!(dialect_of!(generic_holder is GenericDialect | AnsiDialect),);
assert!(!dialect_of!(generic_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect),);
assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect),);
assert!(dialect_of!(ansi_holder is AnsiDialect));
assert!(dialect_of!(ansi_holder is GenericDialect | AnsiDialect));
assert!(!dialect_of!(ansi_holder is GenericDialect | MsSqlDialect));
}
}

View file

@ -917,8 +917,18 @@ impl<'a> Parser<'a> {
Ok(Expr::IsNull(Box::new(expr)))
} else if self.parse_keywords(&[Keyword::NOT, Keyword::NULL]) {
Ok(Expr::IsNotNull(Box::new(expr)))
} else if self.parse_keywords(&[Keyword::DISTINCT, Keyword::FROM]) {
let expr2 = self.parse_expr()?;
Ok(Expr::IsDistinctFrom(Box::new(expr), Box::new(expr2)))
} else if self.parse_keywords(&[Keyword::NOT, Keyword::DISTINCT, Keyword::FROM])
{
let expr2 = self.parse_expr()?;
Ok(Expr::IsNotDistinctFrom(Box::new(expr), Box::new(expr2)))
} else {
self.expected("NULL or NOT NULL after IS", self.peek_token())
self.expected(
"[NOT] NULL or [NOT] DISTINCT FROM after IS",
self.peek_token(),
)
}
}
Keyword::NOT | Keyword::IN | Keyword::BETWEEN => {

View file

@ -586,6 +586,31 @@ fn parse_is_not_null() {
);
}
#[test]
fn parse_is_distinct_from() {
use self::Expr::*;
let sql = "a IS DISTINCT FROM b";
assert_eq!(
IsDistinctFrom(
Box::new(Identifier(Ident::new("a"))),
Box::new(Identifier(Ident::new("b")))
),
verified_expr(sql)
);
}
#[test]
fn parse_is_not_distinct_from() {
use self::Expr::*;
let sql = "a IS NOT DISTINCT FROM b";
assert_eq!(
IsNotDistinctFrom(
Box::new(Identifier(Ident::new("a"))),
Box::new(Identifier(Ident::new("b")))
),
verified_expr(sql)
);
}
#[test]
fn parse_not_precedence() {
// NOT has higher precedence than OR/AND, so the following must parse as (NOT true) OR true