Skip to content
This repository was archived by the owner on Dec 25, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,19 @@ pub enum Expr {
/// A parenthesized subquery `(SELECT ...)`, used in expression like
/// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
Subquery(Box<Query>),
/// `<expr> <op> ANY/SOME (<query>)`
Any {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Query>,
some: bool, // just tracks which syntax was used
},
/// `<expr> <op> ALL (<query>)`
All {
left: Box<Expr>,
op: BinaryOperator,
right: Box<Query>,
}
}

impl fmt::Display for Expr {
Expand Down Expand Up @@ -267,6 +280,8 @@ impl fmt::Display for Expr {
}
Expr::Exists(s) => write!(f, "EXISTS ({})", s),
Expr::Subquery(s) => write!(f, "({})", s),
Expr::Any{left, op, right, some} => write!(f, "{} {} {} ({})", left, op, if *some { "SOME" } else { "ANY" }, right),
Expr::All{left, op, right} => write!(f, "{} {} ALL ({})", left, op, right),
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions src/ast/visit_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ macro_rules! make_visitor {
visit_subquery(self, subquery)
}

fn visit_any(&mut self, left: &'ast $($mut)* Expr, op: &'ast $($mut)* BinaryOperator, right: &'ast $($mut)* Query) {
visit_any(self, left, op, right)
}

fn visit_all(&mut self, left: &'ast $($mut)* Expr, op: &'ast $($mut)* BinaryOperator, right: &'ast $($mut)* Query) {
visit_all(self, left, op, right)
}

fn visit_insert(
&mut self,
table_name: &'ast $($mut)* ObjectName,
Expand Down Expand Up @@ -888,6 +896,8 @@ macro_rules! make_visitor {
),
Expr::Exists(query) => visitor.visit_exists(query),
Expr::Subquery(query) => visitor.visit_subquery(query),
Expr::Any{left, op, right, some: _} => visitor.visit_any(left, op, right),
Expr::All{left, op, right} => visitor.visit_all(left, op, right),
}
}

Expand Down Expand Up @@ -1089,6 +1099,14 @@ macro_rules! make_visitor {
visitor.visit_query(subquery)
}

pub fn visit_any<'ast, V: $name<'ast> + ?Sized>(visitor: &mut V, left: &'ast $($mut)* Expr, op: &'ast $($mut)* BinaryOperator, right: &'ast $($mut)* Query) {
visitor.visit_any(left, op, right)
}

pub fn visit_all<'ast, V: $name<'ast> + ?Sized>(visitor: &mut V, left: &'ast $($mut)* Expr, op: &'ast $($mut)* BinaryOperator, right: &'ast $($mut)* Query) {
visitor.visit_all(left, op, right)
}

pub fn visit_insert<'ast, V: $name<'ast> + ?Sized>(
visitor: &mut V,
table_name: &'ast $($mut)* ObjectName,
Expand Down
37 changes: 32 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,11 +670,38 @@ impl Parser {
};

if let Some(op) = regular_binary_operator {
Ok(Expr::BinaryOp {
left: Box::new(expr),
op,
right: Box::new(self.parse_subexpr(precedence)?),
})
let any = self.parse_keyword("ANY");
let some = !any && self.parse_keyword("SOME");
let all = !any && !some && self.parse_keyword("ALL");
if any || some || all {
use BinaryOperator::*;
match op {
Eq | NotEq | Gt | GtEq | Lt | LtEq => (),
_ => self.expected("comparison operator", Some(tok))?,
}
self.expect_token(&Token::LParen)?;
let query = self.parse_query()?;
self.expect_token(&Token::RParen)?;
if any || some {
Ok(Expr::Any{
left: Box::new(expr),
op,
right: Box::new(query),
some,
})
} else {
Ok(Expr::All{
left: Box::new(expr),
op,
right: Box::new(query),
})}
} else {
Ok(Expr::BinaryOp {
left: Box::new(expr),
op,
right: Box::new(self.parse_subexpr(precedence)?),
})
}
} else if let Token::Word(ref k) = tok {
match k.keyword.as_ref() {
"IS" => {
Expand Down
49 changes: 49 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2415,6 +2415,55 @@ fn parse_scalar_subqueries() {
});
}

#[test]
fn parse_any_some_all() {
let sql = "1 < ANY (SELECT 2)";
assert_matches!(verified_expr(sql), Expr::Any {
op: BinaryOperator::Lt, ..
//left: box Expr,
//right: box Query { .. },
});

let sql = "1 < SOME (SELECT 2)";
assert_matches!(verified_expr(sql), Expr::Any {
op: BinaryOperator::Lt, ..
//left: box Expr,
//right: box Query { .. },
});

let sql = "1 < ALL (SELECT 2)";
assert_matches!(verified_expr(sql), Expr::All {
op: BinaryOperator::Lt, ..
//left: box Expr,
//right: box Query { .. },
});

let res = parse_sql_statements("SELECT 1 WHERE 1 < ANY SELECT 2");
assert_eq!(
ParserError::ParserError("Expected (, found: SELECT".to_string()),
res.unwrap_err()
);

let res = parse_sql_statements("SELECT 1 WHERE 1 < NONE (SELECT 2)");
assert_eq!(
// TODO this is a pretty unhelpful error - it started parsing "NONE (SELECT" as applying the function NONE to the argument SELECT
ParserError::ParserError("Expected ), found: 2".to_string()),
res.unwrap_err()
);

let res = parse_sql_statements("SELECT 1 WHERE 1 < ANY (SELECT 2");
assert_eq!(
ParserError::ParserError("Expected ), found: EOF".to_string()),
res.unwrap_err()
);

let res = parse_sql_statements("SELECT 1 WHERE 1 + ANY (SELECT 2)");
assert_eq!(
ParserError::ParserError("Expected comparison operator, found: +".to_string()),
res.unwrap_err()
);
}

#[test]
fn parse_exists_subquery() {
let expected_inner = verified_query("SELECT 1");
Expand Down