feat: Support ANY/ALL operators (#477)

* feat: Support ANY/ALL operators

* fix lint
This commit is contained in:
Dmitry Patsura 2022-05-06 20:32:04 +03:00 committed by GitHub
parent e68bdae5f2
commit 8ef5fc8624
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 5 deletions

View file

@ -270,6 +270,10 @@ pub enum Expr {
op: BinaryOperator, op: BinaryOperator,
right: Box<Expr>, right: Box<Expr>,
}, },
/// Any operation e.g. `1 ANY (1)` or `foo > ANY(bar)`, It will be wrapped in the right side of BinaryExpr
AnyOp(Box<Expr>),
/// ALL operation e.g. `1 ALL (1)` or `foo > ALL(bar)`, It will be wrapped in the right side of BinaryExpr
AllOp(Box<Expr>),
/// Unary operation e.g. `NOT foo` /// Unary operation e.g. `NOT foo`
UnaryOp { UnaryOp {
op: UnaryOperator, op: UnaryOperator,
@ -433,6 +437,8 @@ impl fmt::Display for Expr {
high high
), ),
Expr::BinaryOp { left, op, right } => write!(f, "{} {} {}", left, op, right), 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 } => { Expr::UnaryOp { op, expr } => {
if op == &UnaryOperator::PGPostfixFactorial { if op == &UnaryOperator::PGPostfixFactorial {
write!(f, "{}{}", expr, op) write!(f, "{}{}", expr, op)

View file

@ -1060,6 +1060,7 @@ impl<'a> Parser<'a> {
/// Parse an operator following an expression /// Parse an operator following an expression
pub fn parse_infix(&mut self, expr: Expr, precedence: u8) -> Result<Expr, ParserError> { pub fn parse_infix(&mut self, expr: Expr, precedence: u8) -> Result<Expr, ParserError> {
let tok = self.next_token(); let tok = self.next_token();
let regular_binary_operator = match &tok { let regular_binary_operator = match &tok {
Token::Spaceship => Some(BinaryOperator::Spaceship), Token::Spaceship => Some(BinaryOperator::Spaceship),
Token::DoubleEq => Some(BinaryOperator::Eq), Token::DoubleEq => Some(BinaryOperator::Eq),
@ -1112,11 +1113,29 @@ impl<'a> Parser<'a> {
}; };
if let Some(op) = regular_binary_operator { if let Some(op) = regular_binary_operator {
Ok(Expr::BinaryOp { if let Some(keyword) = self.parse_one_of_keywords(&[Keyword::ANY, Keyword::ALL]) {
left: Box::new(expr), self.expect_token(&Token::LParen)?;
op, let right = self.parse_subexpr(precedence)?;
right: Box::new(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 { } else if let Token::Word(w) = &tok {
match w.keyword { match w.keyword {
Keyword::IS => { Keyword::IS => {

View file

@ -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] #[test]
fn parse_logical_xor() { fn parse_logical_xor() {
let sql = "SELECT true XOR true, false XOR false, true XOR false, false XOR true"; let sql = "SELECT true XOR true, false XOR false, true XOR false, false XOR true";