Skip to content

Commit 35ef0ee

Browse files
Merge pull request #300 from maxcountryman/feature/ilike
provide ILIKE support
2 parents 1e87ab8 + a9e6f77 commit 35ef0ee

File tree

5 files changed

+62
-1
lines changed

5 files changed

+62
-1
lines changed

src/ast/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,7 @@ impl fmt::Display for TransactionIsolationLevel {
15461546
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15471547
pub enum ShowStatementFilter {
15481548
Like(String),
1549+
ILike(String),
15491550
Where(Expr),
15501551
}
15511552

@@ -1554,6 +1555,7 @@ impl fmt::Display for ShowStatementFilter {
15541555
use ShowStatementFilter::*;
15551556
match self {
15561557
Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)),
1558+
ILike(pattern) => write!(f, "ILIKE {}", value::escape_single_quote_string(pattern)),
15571559
Where(expr) => write!(f, "WHERE {}", expr),
15581560
}
15591561
}

src/ast/operator.rs

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub enum BinaryOperator {
7272
Or,
7373
Like,
7474
NotLike,
75+
ILike,
76+
NotILike,
7577
BitwiseOr,
7678
BitwiseAnd,
7779
BitwiseXor,
@@ -100,6 +102,8 @@ impl fmt::Display for BinaryOperator {
100102
BinaryOperator::Or => "OR",
101103
BinaryOperator::Like => "LIKE",
102104
BinaryOperator::NotLike => "NOT LIKE",
105+
BinaryOperator::ILike => "ILIKE",
106+
BinaryOperator::NotILike => "NOT ILIKE",
103107
BinaryOperator::BitwiseOr => "|",
104108
BinaryOperator::BitwiseAnd => "&",
105109
BinaryOperator::BitwiseXor => "^",

src/dialect/keywords.rs

+1
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ define_keywords!(
236236
IDENTITY,
237237
IF,
238238
IGNORE,
239+
ILIKE,
239240
IN,
240241
INDEX,
241242
INDICATOR,

src/parser.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -839,9 +839,12 @@ impl<'a> Parser<'a> {
839839
Keyword::AND => Some(BinaryOperator::And),
840840
Keyword::OR => Some(BinaryOperator::Or),
841841
Keyword::LIKE => Some(BinaryOperator::Like),
842+
Keyword::ILIKE => Some(BinaryOperator::ILike),
842843
Keyword::NOT => {
843844
if self.parse_keyword(Keyword::LIKE) {
844845
Some(BinaryOperator::NotLike)
846+
} else if self.parse_keyword(Keyword::ILIKE) {
847+
Some(BinaryOperator::NotILike)
845848
} else {
846849
None
847850
}
@@ -975,12 +978,14 @@ impl<'a> Parser<'a> {
975978
Token::Word(w) if w.keyword == Keyword::IN => Ok(Self::BETWEEN_PREC),
976979
Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(Self::BETWEEN_PREC),
977980
Token::Word(w) if w.keyword == Keyword::LIKE => Ok(Self::BETWEEN_PREC),
981+
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(Self::BETWEEN_PREC),
978982
_ => Ok(0),
979983
},
980984
Token::Word(w) if w.keyword == Keyword::IS => Ok(17),
981985
Token::Word(w) if w.keyword == Keyword::IN => Ok(Self::BETWEEN_PREC),
982986
Token::Word(w) if w.keyword == Keyword::BETWEEN => Ok(Self::BETWEEN_PREC),
983987
Token::Word(w) if w.keyword == Keyword::LIKE => Ok(Self::BETWEEN_PREC),
988+
Token::Word(w) if w.keyword == Keyword::ILIKE => Ok(Self::BETWEEN_PREC),
984989
Token::Eq
985990
| Token::Lt
986991
| Token::LtEq
@@ -1472,7 +1477,7 @@ impl<'a> Parser<'a> {
14721477
) -> Result<Statement, ParserError> {
14731478
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
14741479
let table_name = self.parse_object_name()?;
1475-
let like = if self.parse_keyword(Keyword::LIKE) {
1480+
let like = if self.parse_keyword(Keyword::LIKE) || self.parse_keyword(Keyword::ILIKE) {
14761481
self.parse_object_name().ok()
14771482
} else {
14781483
None
@@ -2497,6 +2502,10 @@ impl<'a> Parser<'a> {
24972502
Ok(Some(ShowStatementFilter::Like(
24982503
self.parse_literal_string()?,
24992504
)))
2505+
} else if self.parse_keyword(Keyword::ILIKE) {
2506+
Ok(Some(ShowStatementFilter::ILike(
2507+
self.parse_literal_string()?,
2508+
)))
25002509
} else if self.parse_keyword(Keyword::WHERE) {
25012510
Ok(Some(ShowStatementFilter::Where(self.parse_expr()?)))
25022511
} else {

tests/sqlparser_common.rs

+45
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,51 @@ fn parse_like() {
687687
chk(true);
688688
}
689689

690+
#[test]
691+
fn parse_ilike() {
692+
fn chk(negated: bool) {
693+
let sql = &format!(
694+
"SELECT * FROM customers WHERE name {}ILIKE '%a'",
695+
if negated { "NOT " } else { "" }
696+
);
697+
let select = verified_only_select(sql);
698+
assert_eq!(
699+
Expr::BinaryOp {
700+
left: Box::new(Expr::Identifier(Ident::new("name"))),
701+
op: if negated {
702+
BinaryOperator::NotILike
703+
} else {
704+
BinaryOperator::ILike
705+
},
706+
right: Box::new(Expr::Value(Value::SingleQuotedString("%a".to_string()))),
707+
},
708+
select.selection.unwrap()
709+
);
710+
711+
// This statement tests that LIKE and NOT LIKE have the same precedence.
712+
// This was previously mishandled (#81).
713+
let sql = &format!(
714+
"SELECT * FROM customers WHERE name {}ILIKE '%a' IS NULL",
715+
if negated { "NOT " } else { "" }
716+
);
717+
let select = verified_only_select(sql);
718+
assert_eq!(
719+
Expr::IsNull(Box::new(Expr::BinaryOp {
720+
left: Box::new(Expr::Identifier(Ident::new("name"))),
721+
op: if negated {
722+
BinaryOperator::NotILike
723+
} else {
724+
BinaryOperator::ILike
725+
},
726+
right: Box::new(Expr::Value(Value::SingleQuotedString("%a".to_string()))),
727+
})),
728+
select.selection.unwrap()
729+
);
730+
}
731+
chk(false);
732+
chk(true);
733+
}
734+
690735
#[test]
691736
fn parse_in_list() {
692737
fn chk(negated: bool) {

0 commit comments

Comments
 (0)