Skip to content

Commit 80debb4

Browse files
committed
Fix precedence of unary NOT
get_next_precedence deals with left-binding power, not right binding power. Therefore, when it encounters a standalone NOT operator (i.e., a "NOT" token that is not followed by "BETWEEN", "LIKE", or "IN"), it should return 0, because unary NOT is not an infix operator, it's a prefix operator, and therefore it has no left-binding power.
1 parent 1f87083 commit 80debb4

File tree

2 files changed

+5
-5
lines changed

2 files changed

+5
-5
lines changed

src/sqlparser.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ impl Parser {
197197
"EXTRACT" => self.parse_extract_expression(),
198198
"NOT" => Ok(ASTNode::SQLUnary {
199199
operator: SQLOperator::Not,
200-
expr: Box::new(self.parse_subexpr(Self::UNARY_NOT_PREC)?),
200+
expr: Box::new(self.parse_subexpr(15)?),
201201
}),
202202
"TIME" => Ok(ASTNode::SQLValue(Value::Time(self.parse_literal_string()?))),
203203
"TIMESTAMP" => Ok(ASTNode::SQLValue(Value::Timestamp(
@@ -564,7 +564,6 @@ impl Parser {
564564
})
565565
}
566566

567-
const UNARY_NOT_PREC: u8 = 15;
568567
const BETWEEN_PREC: u8 = 20;
569568
const PLUS_MINUS_PREC: u8 = 30;
570569

@@ -580,11 +579,12 @@ impl Parser {
580579
// The precedence of NOT varies depending on keyword that
581580
// follows it. If it is followed by IN, BETWEEN, or LIKE,
582581
// it takes on the precedence of those tokens. Otherwise it
583-
// takes on UNARY_NOT_PREC.
582+
// is not an infix operator, and therefore has zero
583+
// precedence.
584584
Some(Token::SQLWord(k)) if k.keyword == "IN" => Ok(Self::BETWEEN_PREC),
585585
Some(Token::SQLWord(k)) if k.keyword == "BETWEEN" => Ok(Self::BETWEEN_PREC),
586586
Some(Token::SQLWord(k)) if k.keyword == "LIKE" => Ok(Self::BETWEEN_PREC),
587-
_ => Ok(Self::UNARY_NOT_PREC),
587+
_ => Ok(0),
588588
},
589589
Token::SQLWord(k) if k.keyword == "IS" => Ok(17),
590590
Token::SQLWord(k) if k.keyword == "IN" => Ok(Self::BETWEEN_PREC),

tests/sqlparser_common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ fn parse_not() {
352352
fn parse_invalid_infix_not() {
353353
let res = parse_sql_statements("SELECT c FROM t WHERE c NOT (");
354354
assert_eq!(
355-
ParserError::ParserError("Expected IN or BETWEEN after NOT, found: (".to_string()),
355+
ParserError::ParserError("Expected end of statement, found: NOT".to_string()),
356356
res.unwrap_err(),
357357
);
358358
}

0 commit comments

Comments
 (0)