Add logical xor (#357)

This commit is contained in:
John 2021-09-18 19:39:35 +09:00 committed by GitHub
parent a8901becc3
commit 014b82f03d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 0 deletions

View file

@ -71,6 +71,7 @@ pub enum BinaryOperator {
NotEq,
And,
Or,
Xor,
Like,
NotLike,
ILike,
@ -105,6 +106,7 @@ impl fmt::Display for BinaryOperator {
BinaryOperator::NotEq => "<>",
BinaryOperator::And => "AND",
BinaryOperator::Or => "OR",
BinaryOperator::Xor => "XOR",
BinaryOperator::Like => "LIKE",
BinaryOperator::NotLike => "NOT LIKE",
BinaryOperator::ILike => "ILIKE",

View file

@ -494,6 +494,7 @@ define_keywords!(
WITHOUT,
WORK,
WRITE,
XOR,
YEAR,
ZONE
);

View file

@ -898,6 +898,7 @@ impl<'a> Parser<'a> {
None
}
}
Keyword::XOR => Some(BinaryOperator::Xor),
_ => None,
},
_ => None,
@ -1018,6 +1019,7 @@ impl<'a> Parser<'a> {
match token {
Token::Word(w) if w.keyword == Keyword::OR => Ok(5),
Token::Word(w) if w.keyword == Keyword::AND => Ok(10),
Token::Word(w) if w.keyword == Keyword::XOR => Ok(24),
Token::Word(w) if w.keyword == Keyword::NOT => match self.peek_nth_token(1) {
// The precedence of NOT varies depending on keyword that
// follows it. If it is followed by IN, BETWEEN, or LIKE,

View file

@ -824,7 +824,47 @@ mod tests {
Token::Whitespace(Whitespace::Space),
Token::make_word("three", None),
];
compare(expected, tokens);
}
#[test]
fn tokenize_logical_xor() {
let sql =
String::from("SELECT true XOR true, false XOR false, true XOR false, false XOR true");
let dialect = GenericDialect {};
let mut tokenizer = Tokenizer::new(&dialect, &sql);
let tokens = tokenizer.tokenize().unwrap();
let expected = vec![
Token::make_keyword("SELECT"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("true"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("XOR"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("true"),
Token::Comma,
Token::Whitespace(Whitespace::Space),
Token::make_keyword("false"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("XOR"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("false"),
Token::Comma,
Token::Whitespace(Whitespace::Space),
Token::make_keyword("true"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("XOR"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("false"),
Token::Comma,
Token::Whitespace(Whitespace::Space),
Token::make_keyword("false"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("XOR"),
Token::Whitespace(Whitespace::Space),
Token::make_keyword("true"),
];
compare(expected, tokens);
}

View file

@ -815,6 +815,44 @@ fn parse_bitwise_ops() {
}
}
#[test]
fn parse_logical_xor() {
let sql = "SELECT true XOR true, false XOR false, true XOR false, false XOR true";
let select = verified_only_select(sql);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Value(Value::Boolean(true))),
op: BinaryOperator::Xor,
right: Box::new(Expr::Value(Value::Boolean(true))),
}),
select.projection[0]
);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Value(Value::Boolean(false))),
op: BinaryOperator::Xor,
right: Box::new(Expr::Value(Value::Boolean(false))),
}),
select.projection[1]
);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Value(Value::Boolean(true))),
op: BinaryOperator::Xor,
right: Box::new(Expr::Value(Value::Boolean(false))),
}),
select.projection[2]
);
assert_eq!(
SelectItem::UnnamedExpr(Expr::BinaryOp {
left: Box::new(Expr::Value(Value::Boolean(false))),
op: BinaryOperator::Xor,
right: Box::new(Expr::Value(Value::Boolean(true))),
}),
select.projection[3]
);
}
#[test]
fn parse_between() {
fn chk(negated: bool) {