From 3aacf48d551dbe59c84cd28461aa97f3a710d032 Mon Sep 17 00:00:00 2001 From: Ilya Biryukov Date: Wed, 15 Sep 2021 15:59:24 +0300 Subject: [PATCH] Support ILIKE operators --- datafusion/Cargo.toml | 2 +- datafusion/src/logical_plan/expr.rs | 10 ++++++++++ datafusion/src/logical_plan/operators.rs | 6 ++++++ .../src/physical_plan/expressions/binary.rs | 19 ++++++++++++++++--- datafusion/src/sql/planner.rs | 2 ++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/datafusion/Cargo.toml b/datafusion/Cargo.toml index ff6e8f2385273..2eae19dfa1dec 100644 --- a/datafusion/Cargo.toml +++ b/datafusion/Cargo.toml @@ -48,7 +48,7 @@ ahash = "0.7" hashbrown = "0.11" arrow = { git = "https://github.com/cube-js/arrow-rs.git", branch = "cube", features = ["prettyprint"] } parquet = { git = "https://github.com/cube-js/arrow-rs.git", branch = "cube", features = ["arrow"] } -sqlparser = { git = "https://github.com/cube-js/sqlparser-rs.git", rev = "b1d144a2cb5cc47ac950fd1d518bc28b4dc33ab9" } +sqlparser = { git = "https://github.com/cube-js/sqlparser-rs.git", rev = "c3c77dd2aa408a7cb0c9f27e5e9fc1b101351dcd" } paste = "^1.0" num_cpus = "1.13.0" chrono = "0.4" diff --git a/datafusion/src/logical_plan/expr.rs b/datafusion/src/logical_plan/expr.rs index 17a5986af18db..aaf3997ad4f6e 100644 --- a/datafusion/src/logical_plan/expr.rs +++ b/datafusion/src/logical_plan/expr.rs @@ -615,6 +615,16 @@ impl Expr { binary_expr(self, Operator::NotLike, other) } + /// Return `self LIKE other` + pub fn ilike(self, other: Expr) -> Expr { + binary_expr(self, Operator::ILike, other) + } + + /// Return `self NOT LIKE other` + pub fn not_ilike(self, other: Expr) -> Expr { + binary_expr(self, Operator::NotILike, other) + } + /// Return `self AS name` alias expression pub fn alias(self, name: &str) -> Expr { Expr::Alias(Box::new(self), name.to_owned()) diff --git a/datafusion/src/logical_plan/operators.rs b/datafusion/src/logical_plan/operators.rs index cfd3c664251ad..e43b5cb2c7117 100644 --- a/datafusion/src/logical_plan/operators.rs +++ b/datafusion/src/logical_plan/operators.rs @@ -53,6 +53,10 @@ pub enum Operator { Like, /// Does not match a wildcard pattern NotLike, + /// Matches a wildcard pattern (case-insensitive) + ILike, + /// Does not match a wildcard pattern (case-insensitive) + NotILike, } impl fmt::Display for Operator { @@ -73,6 +77,8 @@ impl fmt::Display for Operator { Operator::Or => "OR", Operator::Like => "LIKE", Operator::NotLike => "NOT LIKE", + Operator::ILike => "ILIKE", + Operator::NotILike => "NOT ILIKE", }; write!(f, "{}", display) } diff --git a/datafusion/src/physical_plan/expressions/binary.rs b/datafusion/src/physical_plan/expressions/binary.rs index e9d7aeee6811a..10c775471f9dc 100644 --- a/datafusion/src/physical_plan/expressions/binary.rs +++ b/datafusion/src/physical_plan/expressions/binary.rs @@ -32,8 +32,9 @@ use arrow::compute::kernels::comparison::{ eq_scalar, gt_eq_scalar, gt_scalar, lt_eq_scalar, lt_scalar, neq_scalar, }; use arrow::compute::kernels::comparison::{ - eq_utf8, gt_eq_utf8, gt_utf8, like_utf8, like_utf8_scalar, lt_eq_utf8, lt_utf8, - neq_utf8, nlike_utf8, nlike_utf8_scalar, + eq_utf8, gt_eq_utf8, gt_utf8, ilike_utf8, ilike_utf8_scalar, like_utf8, + like_utf8_scalar, lt_eq_utf8, lt_utf8, neq_utf8, nilike_utf8, nilike_utf8_scalar, + nlike_utf8, nlike_utf8_scalar, }; use arrow::compute::kernels::comparison::{ eq_utf8_scalar, gt_eq_utf8_scalar, gt_utf8_scalar, lt_eq_utf8_scalar, lt_utf8_scalar, @@ -503,7 +504,9 @@ fn common_binary_type( // logical equality operators have their own rules, and always return a boolean Operator::Eq | Operator::NotEq => eq_coercion(lhs_type, rhs_type), // "like" operators operate on strings and always return a boolean - Operator::Like | Operator::NotLike => string_coercion(lhs_type, rhs_type), + Operator::Like | Operator::NotLike | Operator::ILike | Operator::NotILike => { + string_coercion(lhs_type, rhs_type) + } // order-comparison operators have their own rules Operator::Lt | Operator::Gt | Operator::GtEq | Operator::LtEq => { order_coercion(lhs_type, rhs_type) @@ -552,6 +555,8 @@ pub fn binary_operator_data_type( | Operator::Or | Operator::Like | Operator::NotLike + | Operator::ILike + | Operator::NotILike | Operator::Lt | Operator::Gt | Operator::GtEq @@ -618,6 +623,12 @@ impl PhysicalExpr for BinaryExpr { Operator::NotLike => { binary_string_array_op_scalar!(array, scalar.clone(), nlike) } + Operator::ILike => { + binary_string_array_op_scalar!(array, scalar.clone(), ilike) + } + Operator::NotILike => { + binary_string_array_op_scalar!(array, scalar.clone(), nilike) + } Operator::Divide => { binary_primitive_array_op_scalar!(array, scalar.clone(), divide) } @@ -685,6 +696,8 @@ impl PhysicalExpr for BinaryExpr { let result: Result = match &self.op { Operator::Like => binary_string_array_op!(left, right, like), Operator::NotLike => binary_string_array_op!(left, right, nlike), + Operator::ILike => binary_string_array_op!(left, right, ilike), + Operator::NotILike => binary_string_array_op!(left, right, nilike), Operator::Lt => binary_array_op!(left, right, lt), Operator::LtEq => binary_array_op!(left, right, lt_eq), Operator::Gt => binary_array_op!(left, right, gt), diff --git a/datafusion/src/sql/planner.rs b/datafusion/src/sql/planner.rs index 4c56c9d4c3168..b053f56801c3b 100644 --- a/datafusion/src/sql/planner.rs +++ b/datafusion/src/sql/planner.rs @@ -1348,6 +1348,8 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { BinaryOperator::Or => Ok(Operator::Or), BinaryOperator::Like => Ok(Operator::Like), BinaryOperator::NotLike => Ok(Operator::NotLike), + BinaryOperator::ILike => Ok(Operator::ILike), + BinaryOperator::NotILike => Ok(Operator::NotILike), _ => Err(DataFusionError::NotImplemented(format!( "Unsupported SQL binary operator {:?}", op