You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by lu...@apache.org on 2026/10/21 07:31:29 UTC

(datafusion-sqlparser-rs) 01/02: SQLite: Parse the `BETWEEN` lower bound up to its `AND`

This is an automated email from the ASF dual-hosted git repository.

LucaCappelletti94 pushed a commit to branch sqlite-between-operand-precedence
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit 2dd89ff5352fd30f3b744b93238f628129fb9680
Author: LucaCappelletti94 <ca...@gmail.com>
AuthorDate: Wed Sep 23 12:37:55 2026 +0200

    SQLite: Parse the `BETWEEN` lower bound up to its `AND`
---
 src/dialect/mod.rs        |  5 +++++
 src/dialect/sqlite.rs     |  5 +++++
 src/parser/mod.rs         |  4 +---
 tests/sqlparser_sqlite.rs | 33 +++++++++++++++++++++++++++++++++
 4 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 3ce71eb0b..55d6f81a9 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -1084,6 +1084,11 @@ pub trait Dialect: Debug + Any {
         0
     }
 
+    /// Precedence used to stop parsing the low bound expression of a BETWEEN predicate.
+    fn between_low_bound_precedence(&self) -> u8 {
+        self.prec_value(Precedence::Between)
+    }
+
     /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE`
     ///
     /// Defaults to false.
diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs
index 41b0e8be1..6aa313129 100644
--- a/src/dialect/sqlite.rs
+++ b/src/dialect/sqlite.rs
@@ -160,4 +160,9 @@ impl Dialect for SQLiteDialect {
     fn supports_unterminated_block_comments(&self) -> bool {
         true
     }
+
+    /// Comparison and postfix operators bind within the BETWEEN low bound in SQLite (<https://www.sqlite.org/lang_expr.html>).
+    fn between_low_bound_precedence(&self) -> u8 {
+        self.prec_value(Precedence::And)
+    }
 }
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 276b252ed..a10f559d4 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -4576,9 +4576,7 @@ impl<'a> Parser<'a> {
 
     /// Parses `BETWEEN <low> AND <high>`, assuming the `BETWEEN` keyword was already consumed.
     pub fn parse_between(&mut self, expr: Expr, negated: bool) -> Result<Expr, ParserError> {
-        // Stop parsing subexpressions for <low> and <high> on tokens with
-        // precedence lower than that of `BETWEEN`, such as `AND`, `IS`, etc.
-        let low = self.parse_subexpr(self.dialect.prec_value(Precedence::Between))?;
+        let low = self.parse_subexpr(self.dialect.between_low_bound_precedence())?;
         self.expect_keyword_is(Keyword::AND)?;
         let high = self.parse_subexpr(self.dialect.prec_value(Precedence::Between))?;
         Ok(Expr::Between {
diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs
index 1752e976c..740d8be7a 100644
--- a/tests/sqlparser_sqlite.rs
+++ b/tests/sqlparser_sqlite.rs
@@ -1161,6 +1161,39 @@ fn parse_unterminated_block_comment() {
     );
 }
 
+#[test]
+fn parse_between_low_bound_precedence() {
+    match sqlite().verified_expr("a BETWEEN b > 1 AND c") {
+        Expr::Between { low, .. } => assert!(
+            matches!(
+                *low,
+                Expr::BinaryOp {
+                    op: BinaryOperator::Gt,
+                    ..
+                }
+            ),
+            "{low:?}"
+        ),
+        other => panic!("expected BETWEEN, got {other:?}"),
+    }
+    sqlite().verified_expr("a BETWEEN b LIKE 'x' AND c");
+    sqlite().verified_expr("a BETWEEN b IS NOT NULL AND c");
+    sqlite().expr_parses_to("a BETWEEN b NOTNULL AND c", "a BETWEEN b IS NOT NULL AND c");
+    sqlite().verified_expr("a BETWEEN b BETWEEN 1 AND 2 AND c");
+
+    // Operators after the high bound apply to the whole BETWEEN.
+    sqlite().verified_expr("5 BETWEEN 1 AND NULL IS NULL");
+    sqlite().verified_expr("5 BETWEEN 1 AND 10 = 1");
+
+    assert_eq!(
+        TestedDialects::new(vec![Box::new(GenericDialect {})])
+            .parse_sql_statements("SELECT a BETWEEN b > 1 AND c FROM t"),
+        Err(ParserError::ParserError(
+            "Expected: AND, found: >".to_string()
+        ))
+    );
+}
+
 fn sqlite() -> TestedDialects {
     TestedDialects::new(vec![Box::new(SQLiteDialect {})])
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org