Skip to content

Commit

Permalink
feat: Support ANY/ALL subquery (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
MazterQyou authored Feb 28, 2024
1 parent 347f769 commit 6a54d27
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
4 changes: 4 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Query>),
/// An ANY/ALL subquery `op ANY(SELECT ...)`, used in expression like
/// `SELECT x = ANY(subquery) AS c`
AnyAllSubquery(Box<Query>),
/// The `LISTAGG` function `SELECT LISTAGG(...) WITHIN GROUP (ORDER BY ...)`
ListAgg(ListAgg),
/// The `ARRAY_AGG` function `SELECT ARRAY_AGG(... ORDER BY ...)`
Expand Down Expand Up @@ -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),
Expand Down
12 changes: 9 additions & 3 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(),
};

Expand Down
51 changes: 51 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)");
Expand All @@ -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";
Expand Down

0 comments on commit 6a54d27

Please sign in to comment.