Skip to content

Commit 786b1cf

Browse files
committed
Support BETWEEN
1 parent 2643193 commit 786b1cf

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

src/sqlast/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ pub enum ASTNode {
6464
subquery: Box<SQLQuery>,
6565
negated: bool,
6666
},
67+
/// <expr> [ NOT ] BETWEEN <low> AND <high>
68+
SQLBetween {
69+
expr: Box<ASTNode>,
70+
negated: bool,
71+
low: Box<ASTNode>,
72+
high: Box<ASTNode>,
73+
},
6774
/// Binary expression e.g. `1 + 1` or `foo > bar`
6875
SQLBinaryExpr {
6976
left: Box<ASTNode>,
@@ -131,6 +138,18 @@ impl ToString for ASTNode {
131138
if *negated { "NOT " } else { "" },
132139
subquery.to_string()
133140
),
141+
ASTNode::SQLBetween {
142+
expr,
143+
negated,
144+
low,
145+
high,
146+
} => format!(
147+
"{} {}BETWEEN {} AND {}",
148+
expr.to_string(),
149+
if *negated { "NOT " } else { "" },
150+
low.to_string(),
151+
high.to_string()
152+
),
134153
ASTNode::SQLBinaryExpr { left, op, right } => format!(
135154
"{} {} {}",
136155
left.as_ref().to_string(),

src/sqlparser.rs

+17
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ impl Parser {
309309
Token::SQLWord(ref k) if k.keyword == "NOT" => {
310310
if self.parse_keyword("IN") {
311311
self.parse_in(expr, true)
312+
} else if self.parse_keyword("BETWEEN") {
313+
self.parse_between(expr, true)
312314
} else if self.parse_keyword("LIKE") {
313315
Ok(ASTNode::SQLBinaryExpr {
314316
left: Box::new(expr),
@@ -323,6 +325,7 @@ impl Parser {
323325
}
324326
}
325327
Token::SQLWord(ref k) if k.keyword == "IN" => self.parse_in(expr, false),
328+
Token::SQLWord(ref k) if k.keyword == "BETWEEN" => self.parse_between(expr, false),
326329
Token::DoubleColon => self.parse_pg_cast(expr),
327330
Token::SQLWord(_)
328331
| Token::Eq
@@ -369,6 +372,19 @@ impl Parser {
369372
Ok(in_op)
370373
}
371374

375+
/// Parses `BETWEEN <low> AND <high>`, assuming the `BETWEEN` keyword was already consumed
376+
pub fn parse_between(&mut self, expr: ASTNode, negated: bool) -> Result<ASTNode, ParserError> {
377+
let low = self.parse_prefix()?;
378+
self.expect_keyword("AND")?;
379+
let high = self.parse_prefix()?;
380+
Ok(ASTNode::SQLBetween {
381+
expr: Box::new(expr),
382+
negated,
383+
low: Box::new(low),
384+
high: Box::new(high),
385+
})
386+
}
387+
372388
/// Parse a postgresql casting style which is in the form of `expr::datatype`
373389
pub fn parse_pg_cast(&mut self, expr: ASTNode) -> Result<ASTNode, ParserError> {
374390
Ok(ASTNode::SQLCast {
@@ -418,6 +434,7 @@ impl Parser {
418434
&Token::SQLWord(ref k) if k.keyword == "NOT" => Ok(15),
419435
&Token::SQLWord(ref k) if k.keyword == "IS" => Ok(17),
420436
&Token::SQLWord(ref k) if k.keyword == "IN" => Ok(20),
437+
&Token::SQLWord(ref k) if k.keyword == "BETWEEN" => Ok(20),
421438
&Token::SQLWord(ref k) if k.keyword == "LIKE" => Ok(20),
422439
&Token::Eq | &Token::Lt | &Token::LtEq | &Token::Neq | &Token::Gt | &Token::GtEq => {
423440
Ok(20)

tests/sqlparser_generic.rs

+22
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,28 @@ fn parse_in_subquery() {
288288
);
289289
}
290290

291+
#[test]
292+
fn parse_between() {
293+
fn chk(negated: bool) {
294+
let sql = &format!(
295+
"SELECT * FROM customers WHERE age {}BETWEEN 25 AND 32",
296+
if negated { "NOT " } else { "" }
297+
);
298+
let select = verified_only_select(sql);
299+
assert_eq!(
300+
ASTNode::SQLBetween {
301+
expr: Box::new(ASTNode::SQLIdentifier("age".to_string())),
302+
low: Box::new(ASTNode::SQLValue(Value::Long(25))),
303+
high: Box::new(ASTNode::SQLValue(Value::Long(32))),
304+
negated,
305+
},
306+
select.selection.unwrap()
307+
);
308+
}
309+
chk(false);
310+
chk(true);
311+
}
312+
291313
#[test]
292314
fn parse_select_order_by() {
293315
fn chk(sql: &str) {

0 commit comments

Comments
 (0)