From ba21ce9d37018d220e6126996e010e9392f8aab3 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Fri, 24 May 2019 14:04:42 -0400 Subject: [PATCH] Support nested expressions in BETWEEN `BETWEEN AND ` allows to be any expr that doesn't contain boolean operators. (Allowing boolean operators would wreak havoc, because of the repurposing of AND as both a boolean operation and part of the syntax of BETWEEN.) --- src/sqlparser.rs | 7 ++++-- tests/sqlparser_common.rs | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/sqlparser.rs b/src/sqlparser.rs index edfa0c573..c96d3519d 100644 --- a/src/sqlparser.rs +++ b/src/sqlparser.rs @@ -478,9 +478,12 @@ impl Parser { /// Parses `BETWEEN AND `, assuming the `BETWEEN` keyword was already consumed pub fn parse_between(&mut self, expr: ASTNode, negated: bool) -> Result { - let low = self.parse_prefix()?; + // Stop parsing subexpressions for and on tokens with + // precedence lower than that of `BETWEEN`, such as `AND`, `IS`, etc. + let prec = self.get_precedence(&Token::make_keyword("BETWEEN"))?; + let low = self.parse_subexpr(prec)?; self.expect_keyword("AND")?; - let high = self.parse_prefix()?; + let high = self.parse_subexpr(prec)?; Ok(ASTNode::SQLBetween { expr: Box::new(expr), negated, diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index e141c840c..118427050 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -450,6 +450,55 @@ fn parse_between() { chk(true); } +#[test] +fn parse_between_with_expr() { + use self::ASTNode::*; + use self::SQLOperator::*; + let sql = "SELECT * FROM t WHERE 1 BETWEEN 1 + 2 AND 3 + 4 IS NULL"; + let select = verified_only_select(sql); + assert_eq!( + ASTNode::SQLIsNull(Box::new(ASTNode::SQLBetween { + expr: Box::new(ASTNode::SQLValue(Value::Long(1))), + low: Box::new(SQLBinaryExpr { + left: Box::new(ASTNode::SQLValue(Value::Long(1))), + op: Plus, + right: Box::new(ASTNode::SQLValue(Value::Long(2))), + }), + high: Box::new(SQLBinaryExpr { + left: Box::new(ASTNode::SQLValue(Value::Long(3))), + op: Plus, + right: Box::new(ASTNode::SQLValue(Value::Long(4))), + }), + negated: false, + })), + select.selection.unwrap() + ); + + let sql = "SELECT * FROM t WHERE 1 = 1 AND 1 + x BETWEEN 1 AND 2"; + let select = verified_only_select(sql); + assert_eq!( + ASTNode::SQLBinaryExpr { + left: Box::new(ASTNode::SQLBinaryExpr { + left: Box::new(ASTNode::SQLValue(Value::Long(1))), + op: SQLOperator::Eq, + right: Box::new(ASTNode::SQLValue(Value::Long(1))), + }), + op: SQLOperator::And, + right: Box::new(ASTNode::SQLBetween { + expr: Box::new(ASTNode::SQLBinaryExpr { + left: Box::new(ASTNode::SQLValue(Value::Long(1))), + op: SQLOperator::Plus, + right: Box::new(ASTNode::SQLIdentifier("x".to_string())), + }), + low: Box::new(ASTNode::SQLValue(Value::Long(1))), + high: Box::new(ASTNode::SQLValue(Value::Long(2))), + negated: false, + }), + }, + select.selection.unwrap(), + ) +} + #[test] fn parse_select_order_by() { fn chk(sql: &str) {