diff --git a/src/dialect/generic_sql.rs b/src/dialect/generic_sql.rs index 0d358277..e187794a 100644 --- a/src/dialect/generic_sql.rs +++ b/src/dialect/generic_sql.rs @@ -11,7 +11,7 @@ impl Dialect for GenericSqlDialect { STORED, CSV, PARQUET, LOCATION, WITH, WITHOUT, HEADER, ROW, // SQL types CHAR, CHARACTER, VARYING, LARGE, OBJECT, VARCHAR, CLOB, BINARY, VARBINARY, BLOB, FLOAT, REAL, DOUBLE, PRECISION, INT, INTEGER, SMALLINT, BIGINT, NUMERIC, DECIMAL, DEC, - BOOLEAN, DATE, TIME, TIMESTAMP, CASE, WHEN, THEN, ELSE, END, + BOOLEAN, DATE, TIME, TIMESTAMP, CASE, WHEN, THEN, ELSE, END, LIKE, ]; } diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index e8682819..d46049e6 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -14,7 +14,7 @@ impl Dialect for PostgreSqlDialect { DOUBLE, PRECISION, INT, INTEGER, SMALLINT, BIGINT, NUMERIC, DECIMAL, DEC, BOOLEAN, DATE, TIME, TIMESTAMP, VALUES, DEFAULT, ZONE, REGCLASS, TEXT, BYTEA, TRUE, FALSE, COPY, STDIN, PRIMARY, KEY, UNIQUE, UUID, ADD, CONSTRAINT, FOREIGN, REFERENCES, - CASE, WHEN, THEN, ELSE, END, + CASE, WHEN, THEN, ELSE, END, LIKE, ]; } diff --git a/src/sqlast/sql_operator.rs b/src/sqlast/sql_operator.rs index 19e9d04e..8a09bbbe 100644 --- a/src/sqlast/sql_operator.rs +++ b/src/sqlast/sql_operator.rs @@ -14,6 +14,7 @@ pub enum SQLOperator { NotEq, And, Or, + Like, } impl ToString for SQLOperator { @@ -32,6 +33,7 @@ impl ToString for SQLOperator { SQLOperator::NotEq => "!=".to_string(), SQLOperator::And => "AND".to_string(), SQLOperator::Or => "OR".to_string(), + SQLOperator::Like => "LIKE".to_string(), } } } diff --git a/src/sqlparser.rs b/src/sqlparser.rs index 33d4487d..0a9f1ead 100644 --- a/src/sqlparser.rs +++ b/src/sqlparser.rs @@ -18,7 +18,7 @@ use super::dialect::Dialect; use super::sqlast::*; use super::sqltokenizer::*; use chrono::{ - offset::{FixedOffset}, + offset::FixedOffset, DateTime, NaiveDate, NaiveDateTime, NaiveTime, }; @@ -334,6 +334,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 == "LIKE" => Ok(SQLOperator::Like), _ => parser_err!(format!("Unsupported SQL operator {:?}", tok)), } } @@ -355,6 +356,7 @@ impl Parser { &Token::Keyword(ref k) if k == "OR" => Ok(5), &Token::Keyword(ref k) if k == "AND" => Ok(10), &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 => { Ok(20) } diff --git a/tests/sqlparser_ansi.rs b/tests/sqlparser_ansi.rs index aea3c843..432f3a4f 100644 --- a/tests/sqlparser_ansi.rs +++ b/tests/sqlparser_ansi.rs @@ -23,7 +23,7 @@ fn parse_simple_select() { fn parse_sql(sql: &str) -> ASTNode { let dialect = AnsiSqlDialect {}; - let mut tokenizer = Tokenizer::new(&dialect,&sql, ); + let mut tokenizer = Tokenizer::new(&dialect, &sql); let tokens = tokenizer.tokenize().unwrap(); let mut parser = Parser::new(tokens); let ast = parser.parse().unwrap(); diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index adc575fc..891f58fb 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -730,3 +730,23 @@ fn parser(sql: &str) -> Parser { debug!("tokens: {:#?}", tokens); Parser::new(tokens) } + +#[test] +fn parse_like() { + let sql = String::from("SELECT * FROM customers WHERE name 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::Like, + right: Box::new(ASTNode::SQLValue(Value::SingleQuotedString("%a".to_string()))), + }, + *selection.unwrap() + ); + } + _ => assert!(false), + } +}