From ee1944b9d94bd22f0da651b39dc6b433c45a00b3 Mon Sep 17 00:00:00 2001 From: Andy Grove Date: Sun, 16 Dec 2018 16:30:32 -0700 Subject: [PATCH] Implemented NOT LIKE --- src/sqlast/sql_operator.rs | 2 ++ src/sqlparser.rs | 39 +++++++++++++++++++++++-------------- tests/sqlparser_postgres.rs | 22 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/sqlast/sql_operator.rs b/src/sqlast/sql_operator.rs index 5ea52c6b..2cc5baa9 100644 --- a/src/sqlast/sql_operator.rs +++ b/src/sqlast/sql_operator.rs @@ -16,6 +16,7 @@ pub enum SQLOperator { Or, Not, Like, + NotLike, } impl ToString for SQLOperator { @@ -36,6 +37,7 @@ impl ToString for SQLOperator { SQLOperator::Or => "OR".to_string(), SQLOperator::Not => "NOT".to_string(), SQLOperator::Like => "LIKE".to_string(), + SQLOperator::NotLike => "NOT LIKE".to_string(), } } } diff --git a/src/sqlparser.rs b/src/sqlparser.rs index 87fa0ffc..3476f8d4 100644 --- a/src/sqlparser.rs +++ b/src/sqlparser.rs @@ -275,23 +275,31 @@ impl Parser { debug!("parsing infix"); match self.next_token() { Some(tok) => match tok { - Token::Keyword(ref k) => { - if k == "IS" { - if self.parse_keywords(vec!["NULL"]) { - Ok(Some(ASTNode::SQLIsNull(Box::new(expr)))) - } else if self.parse_keywords(vec!["NOT", "NULL"]) { - Ok(Some(ASTNode::SQLIsNotNull(Box::new(expr)))) - } else { - parser_err!("Invalid tokens after IS") - } + Token::Keyword(ref k) if k == "IS" => { + if self.parse_keywords(vec!["NULL"]) { + Ok(Some(ASTNode::SQLIsNull(Box::new(expr)))) + } else if self.parse_keywords(vec!["NOT", "NULL"]) { + Ok(Some(ASTNode::SQLIsNotNull(Box::new(expr)))) } else { - Ok(Some(ASTNode::SQLBinaryExpr { - left: Box::new(expr), - op: self.to_sql_operator(&tok)?, - right: Box::new(self.parse_expr(precedence)?), - })) + parser_err!("Invalid tokens after IS") } } + Token::Keyword(ref k) if k == "NOT" => { + if self.parse_keywords(vec!["LIKE"]) { + Ok(Some(ASTNode::SQLBinaryExpr { + left: Box::new(expr), + op: SQLOperator::NotLike, + right: Box::new(self.parse_expr(precedence)?), + })) + } else { + parser_err!("Invalid tokens after NOT") + } + } + Token::Keyword(_) => Ok(Some(ASTNode::SQLBinaryExpr { + left: Box::new(expr), + op: self.to_sql_operator(&tok)?, + right: Box::new(self.parse_expr(precedence)?), + })), Token::Eq | Token::Neq | Token::Gt @@ -333,7 +341,7 @@ impl Parser { &Token::Mod => Ok(SQLOperator::Modulus), &Token::Keyword(ref k) if k == "AND" => Ok(SQLOperator::And), &Token::Keyword(ref k) if k == "OR" => Ok(SQLOperator::Or), - &Token::Keyword(ref k) if k == "NOT" => Ok(SQLOperator::Not), + //&Token::Keyword(ref k) if k == "NOT" => Ok(SQLOperator::Not), &Token::Keyword(ref k) if k == "LIKE" => Ok(SQLOperator::Like), _ => parser_err!(format!("Unsupported SQL operator {:?}", tok)), } @@ -355,6 +363,7 @@ impl Parser { match tok { &Token::Keyword(ref k) if k == "OR" => Ok(5), &Token::Keyword(ref k) if k == "AND" => Ok(10), + &Token::Keyword(ref k) if k == "NOT" => Ok(15), &Token::Keyword(ref k) if k == "IS" => Ok(15), &Token::Keyword(ref k) if k == "LIKE" => Ok(20), &Token::Eq | &Token::Lt | &Token::LtEq | &Token::Neq | &Token::Gt | &Token::GtEq => { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index e731e56f..710a1ee4 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -753,3 +753,25 @@ fn parse_like() { _ => assert!(false), } } + +#[test] +fn parse_not_like() { + let sql = String::from("SELECT * FROM customers WHERE name NOT LIKE '%a'"); + let ast = parse_sql(&sql); + assert_eq!(sql, ast.to_string()); + match ast { + ASTNode::SQLSelect { selection, .. } => { + assert_eq!( + ASTNode::SQLBinaryExpr { + left: Box::new(ASTNode::SQLIdentifier("name".to_string())), + op: SQLOperator::NotLike, + right: Box::new(ASTNode::SQLValue(Value::SingleQuotedString( + "%a".to_string() + ))), + }, + *selection.unwrap() + ); + } + _ => assert!(false), + } +}