diff --git a/src/ast/mod.rs b/src/ast/mod.rs index feec8bda1..5ae4679af 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -341,6 +341,9 @@ pub enum Expr { /// A parenthesized subquery `(SELECT ...)`, used in expression like /// `SELECT (subquery) AS x` or `WHERE (subquery) = x` Subquery(Box), + /// An ANY/ALL subquery `op ANY(SELECT ...)`, used in expression like + /// `SELECT x = ANY(subquery) AS c` + AnyAllSubquery(Box), /// The `LISTAGG` function `SELECT LISTAGG(...) WITHIN GROUP (ORDER BY ...)` ListAgg(ListAgg), /// The `ARRAY_AGG` function `SELECT ARRAY_AGG(... ORDER BY ...)` @@ -542,6 +545,7 @@ impl fmt::Display for Expr { } Expr::Exists(s) => write!(f, "EXISTS ({})", s), Expr::Subquery(s) => write!(f, "({})", s), + Expr::AnyAllSubquery(s) => write!(f, "{}", s), Expr::ArraySubquery(s) => write!(f, "ARRAY({})", s), Expr::ListAgg(listagg) => write!(f, "{}", listagg), Expr::ArrayAgg(arrayagg) => write!(f, "{}", arrayagg), diff --git a/src/parser.rs b/src/parser.rs index 238997200..753c6a11d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1247,14 +1247,20 @@ impl<'a> Parser<'a> { }; if let Some(op) = regular_binary_operator { - if let Some(keyword) = self.parse_one_of_keywords(&[Keyword::ANY, Keyword::ALL]) { + if let Some(keyword) = + self.parse_one_of_keywords(&[Keyword::ANY, Keyword::SOME, Keyword::ALL]) + { self.expect_token(&Token::LParen)?; - let right = self.parse_subexpr(precedence)?; + let right = if let Ok(query) = self.parse_query() { + Expr::AnyAllSubquery(Box::new(query)) + } else { + 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))), + Keyword::ANY | Keyword::SOME => Box::new(Expr::AnyOp(Box::new(right))), _ => unreachable!(), }; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 840db83c7..96071f1f2 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1145,6 +1145,11 @@ fn parse_binary_any() { ); } +#[test] +fn parse_select_some() { + one_statement_parses_to("SELECT a = SOME(b)", "SELECT a = ANY(b)"); +} + #[test] fn parse_binary_all() { let select = verified_only_select("SELECT a = ALL(b)"); @@ -1158,6 +1163,52 @@ fn parse_binary_all() { ); } +#[test] +fn parse_binary_any_subquery() { + let select = verified_only_select("SELECT a <> ANY(SELECT b FROM c)"); + assert_eq!( + SelectItem::UnnamedExpr(Expr::BinaryOp { + left: Box::new(Expr::Identifier(Ident::new("a"))), + op: BinaryOperator::NotEq, + right: Box::new(Expr::AnyOp(Box::new(Expr::AnyAllSubquery(Box::new( + Query { + with: None, + body: SetExpr::Select(Box::new(Select { + distinct: false, + top: None, + projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident::new( + "b" + )))], + into: None, + from: vec![TableWithJoins { + relation: TableFactor::Table { + name: ObjectName(vec![Ident::new("c")]), + alias: None, + args: vec![], + with_hints: vec![], + }, + joins: vec![] + }], + lateral_views: vec![], + selection: None, + group_by: vec![], + cluster_by: vec![], + distribute_by: vec![], + sort_by: vec![], + having: None + })), + order_by: vec![], + limit: None, + offset: None, + fetch: None, + lock: None, + } + ))))), + }), + select.projection[0] + ); +} + #[test] fn parse_logical_xor() { let sql = "SELECT true XOR true, false XOR false, true XOR false, false XOR true";