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,
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`
UnaryOp {
op: UnaryOperator,
@ -433,6 +437,8 @@ impl fmt::Display for Expr {
high
),
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 } => {
if op == &UnaryOperator::PGPostfixFactorial {
write!(f, "{}{}", expr, op)

View file

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