Skip to content

Commit c4e7dc5

Browse files
Honour operator precedence in SQLite REGEXP, MATCH and GLOB (#2419)
1 parent 2f3b5b8 commit c4e7dc5

2 files changed

Lines changed: 33 additions & 2 deletions

File tree

src/dialect/sqlite.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl Dialect for SQLiteDialect {
7979
&self,
8080
parser: &mut crate::parser::Parser,
8181
expr: &crate::ast::Expr,
82-
_precedence: u8,
82+
precedence: u8,
8383
) -> Option<Result<crate::ast::Expr, ParserError>> {
8484
// Parse MATCH, REGEXP and GLOB as operators
8585
// See <https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators>
@@ -90,7 +90,7 @@ impl Dialect for SQLiteDialect {
9090
] {
9191
if parser.parse_keyword(keyword) {
9292
let left = Box::new(expr.clone());
93-
let right = Box::new(match parser.parse_expr() {
93+
let right = Box::new(match parser.parse_subexpr(precedence) {
9494
Ok(expr) => expr,
9595
Err(e) => return Some(Err(e)),
9696
});

tests/sqlparser_sqlite.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,37 @@ fn test_drop_trigger() {
926926
}
927927
}
928928

929+
#[test]
930+
fn parse_pattern_operators_bind_at_like_precedence() {
931+
fn where_operator(sql: &str) -> BinaryOperator {
932+
let Statement::Query(query) = sqlite().verified_stmt(sql) else {
933+
panic!("expected a query");
934+
};
935+
let SetExpr::Select(select) = *query.body else {
936+
panic!("expected a select");
937+
};
938+
let Some(Expr::BinaryOp { op, .. }) = select.selection else {
939+
panic!("expected a WHERE binary operator");
940+
};
941+
op
942+
}
943+
944+
// Above AND, so the pattern does not swallow the rest of the expression.
945+
for operator in ["REGEXP", "MATCH", "GLOB", "LIKE"] {
946+
let sql = format!("SELECT 1 FROM t WHERE a {operator} 'p' AND b = 1");
947+
assert_eq!(where_operator(&sql), BinaryOperator::And, "{operator}");
948+
}
949+
// Below string concatenation, so the pattern is not cut short either.
950+
for (operator, expected) in [
951+
("REGEXP", BinaryOperator::Regexp),
952+
("MATCH", BinaryOperator::Match),
953+
("GLOB", BinaryOperator::Glob),
954+
] {
955+
let sql = format!("SELECT 1 FROM t WHERE a {operator} 'p' || 'q'");
956+
assert_eq!(where_operator(&sql), expected, "{operator}");
957+
}
958+
}
959+
929960
fn sqlite() -> TestedDialects {
930961
TestedDialects::new(vec![Box::new(SQLiteDialect {})])
931962
}

0 commit comments

Comments
 (0)