From 6c18867ba039b4ac5518221a853935e91af81ef8 Mon Sep 17 00:00:00 2001 From: Alex Qyoun-ae <4062971+mazterqyou@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:06:07 +0400 Subject: [PATCH] feat: Support ANY/ALL subquery (#42) --- src/ast/mod.rs | 4 +++ src/parser.rs | 12 ++++++--- tests/sqlparser_common.rs | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 1f33526f5..7dac98d15 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -385,6 +385,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 ...)` @@ -581,6 +584,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 b135ddc05..8bec5a626 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1248,14 +1248,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 5fbe3ae77..ac8521784 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1149,6 +1149,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)"); @@ -1162,6 +1167,53 @@ 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, + qualify: 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";