From 773294c4ddbb28e4e03ff9790ec178c229907fc8 Mon Sep 17 00:00:00 2001 From: Dmitry Patsura Date: Thu, 28 Apr 2022 17:14:42 +0300 Subject: [PATCH 1/2] feat: Support ANY/ALL operators --- src/ast/mod.rs | 6 ++++++ src/parser.rs | 29 ++++++++++++++++++++++++----- tests/sqlparser_common.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 89e1357567..6c2594fc8a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -270,6 +270,10 @@ pub enum Expr { op: BinaryOperator, right: Box, }, + /// Any operation e.g. `1 ANY (1)` or `foo > ANY(bar)`, It will be wrapped in the right side of BinaryExpr + AnyOp(Box), + /// ALL operation e.g. `1 ALL (1)` or `foo > ALL(bar)`, It will be wrapped in the right side of BinaryExpr + AllOp(Box), /// Unary operation e.g. `NOT foo` UnaryOp { op: UnaryOperator, @@ -433,6 +437,8 @@ impl fmt::Display for Expr { high ), Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right), + Expr::AnyOp(expr) => write!(f, "ANY({})", expr), + Expr::AllOp(expr) => write!(f, "ALL({})", expr), Expr::UnaryOp { op, expr } => { if op == &UnaryOperator::PGPostfixFactorial { write!(f, "{}{}", expr, op) diff --git a/src/parser.rs b/src/parser.rs index 1ca493b981..463b70b5e9 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1059,6 +1059,7 @@ impl<'a> Parser<'a> { /// Parse an operator following an expression pub fn parse_infix(&mut self, expr: Expr, precedence: u8) -> Result { let tok = self.next_token(); + let regular_binary_operator = match &tok { Token::Spaceship => Some(BinaryOperator::Spaceship), Token::DoubleEq => Some(BinaryOperator::Eq), @@ -1111,11 +1112,29 @@ impl<'a> Parser<'a> { }; if let Some(op) = regular_binary_operator { - Ok(Expr::BinaryOp { - left: Box::new(expr), - op, - right: Box::new(self.parse_subexpr(precedence)?), - }) + if let Some(keyword) = self.parse_one_of_keywords(&[Keyword::ANY, Keyword::ALL]) { + self.expect_token(&Token::LParen)?; + let right = self.parse_subexpr(precedence)?; + self.expect_token(&Token::RParen)?; + + let right = match keyword { + Keyword::ALL => Box::new(Expr::AllOp(Box::new(right))), + Keyword::ANY => Box::new(Expr::AnyOp(Box::new(right))), + _ => unreachable!(), + }; + + Ok(Expr::BinaryOp { + left: Box::new(expr), + op, + right, + }) + } else { + Ok(Expr::BinaryOp { + left: Box::new(expr), + op, + right: Box::new(self.parse_subexpr(precedence)?), + }) + } } else if let Token::Word(w) = &tok { match w.keyword { Keyword::IS => { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 8471b2c5fb..e8d260be89 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -998,6 +998,32 @@ fn parse_bitwise_ops() { } } +#[test] +fn parse_binary_any() { + let select = verified_only_select(&"SELECT a = ANY(b)"); + assert_eq!( + SelectItem::UnnamedExpr(Expr::BinaryOp { + left: Box::new(Expr::Identifier(Ident::new("a"))), + op: BinaryOperator::Eq, + right: Box::new(Expr::AnyOp(Box::new(Expr::Identifier(Ident::new("b"))))), + }), + select.projection[0] + ); +} + +#[test] +fn parse_binary_all() { + let select = verified_only_select(&"SELECT a = ALL(b)"); + assert_eq!( + SelectItem::UnnamedExpr(Expr::BinaryOp { + left: Box::new(Expr::Identifier(Ident::new("a"))), + op: BinaryOperator::Eq, + right: Box::new(Expr::AllOp(Box::new(Expr::Identifier(Ident::new("b"))))), + }), + select.projection[0] + ); +} + #[test] fn parse_logical_xor() { let sql = "SELECT true XOR true, false XOR false, true XOR false, false XOR true"; From 19be72cbf4c52b7f54315a89962231cefebca499 Mon Sep 17 00:00:00 2001 From: Dmitry Patsura Date: Thu, 5 May 2022 21:18:50 +0300 Subject: [PATCH 2/2] fix lint --- tests/sqlparser_common.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index e8d260be89..794ff67563 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1000,7 +1000,7 @@ fn parse_bitwise_ops() { #[test] fn parse_binary_any() { - let select = verified_only_select(&"SELECT a = ANY(b)"); + let select = verified_only_select("SELECT a = ANY(b)"); assert_eq!( SelectItem::UnnamedExpr(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident::new("a"))), @@ -1013,7 +1013,7 @@ fn parse_binary_any() { #[test] fn parse_binary_all() { - let select = verified_only_select(&"SELECT a = ALL(b)"); + let select = verified_only_select("SELECT a = ALL(b)"); assert_eq!( SelectItem::UnnamedExpr(Expr::BinaryOp { left: Box::new(Expr::Identifier(Ident::new("a"))),