Skip to content

Commit 702e117

Browse files
authored
remove Operator::{Like,NotLike,ILike,NotILike} (#4792)
* remove Operator::{Like,NotLike,ILike,NotILike} * fix comments
1 parent 24023b5 commit 702e117

18 files changed

Lines changed: 684 additions & 187 deletions

File tree

‎datafusion/core/src/physical_plan/planner.rs‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2019,14 +2019,6 @@ mod tests {
20192019
col("c1").eq(bool_expr.clone()),
20202020
// u32 AND bool
20212021
col("c2").and(bool_expr),
2022-
// utf8 LIKE u32
2023-
col("c1").like(col("c2")),
2024-
// utf8 NOT LIKE u32
2025-
col("c1").not_like(col("c2")),
2026-
// utf8 ILIKE u32
2027-
col("c1").ilike(col("c2")),
2028-
// utf8 NOT ILIKE u32
2029-
col("c1").not_ilike(col("c2")),
20302022
];
20312023
for case in cases {
20322024
let logical_plan = test_csv_scan().await?.project(vec![case.clone()]);

‎datafusion/expr/src/expr.rs‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,6 @@ impl BinaryExpr {
245245
match self.op {
246246
Operator::Or => 5,
247247
Operator::And => 10,
248-
Operator::Like | Operator::NotLike | Operator::ILike | Operator::NotILike => {
249-
19
250-
}
251248
Operator::NotEq
252249
| Operator::Eq
253250
| Operator::Lt
@@ -685,22 +682,22 @@ impl Expr {
685682

686683
/// Return `self LIKE other`
687684
pub fn like(self, other: Expr) -> Expr {
688-
binary_expr(self, Operator::Like, other)
685+
Expr::Like(Like::new(false, Box::new(self), Box::new(other), None))
689686
}
690687

691688
/// Return `self NOT LIKE other`
692689
pub fn not_like(self, other: Expr) -> Expr {
693-
binary_expr(self, Operator::NotLike, other)
690+
Expr::Like(Like::new(true, Box::new(self), Box::new(other), None))
694691
}
695692

696693
/// Return `self ILIKE other`
697694
pub fn ilike(self, other: Expr) -> Expr {
698-
binary_expr(self, Operator::ILike, other)
695+
Expr::ILike(Like::new(false, Box::new(self), Box::new(other), None))
699696
}
700697

701698
/// Return `self NOT ILIKE other`
702699
pub fn not_ilike(self, other: Expr) -> Expr {
703-
binary_expr(self, Operator::NotILike, other)
700+
Expr::ILike(Like::new(true, Box::new(self), Box::new(other), None))
704701
}
705702

706703
/// Return `self AS name` alias expression

‎datafusion/expr/src/operator.rs‎

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,6 @@ pub enum Operator {
5151
And,
5252
/// Logical OR, like `||`
5353
Or,
54-
/// Matches a wildcard pattern
55-
Like,
56-
/// Does not match a wildcard pattern
57-
NotLike,
58-
/// Matches a wildcard pattern, ignores case
59-
ILike,
60-
/// Does not match a wildcard pattern, ignores case
61-
NotILike,
6254
/// IS DISTINCT FROM
6355
IsDistinctFrom,
6456
/// IS NOT DISTINCT FROM
@@ -96,10 +88,6 @@ impl Operator {
9688
Operator::LtEq => Some(Operator::Gt),
9789
Operator::Gt => Some(Operator::LtEq),
9890
Operator::GtEq => Some(Operator::Lt),
99-
Operator::Like => Some(Operator::NotLike),
100-
Operator::NotLike => Some(Operator::Like),
101-
Operator::ILike => Some(Operator::NotILike),
102-
Operator::NotILike => Some(Operator::ILike),
10391
Operator::IsDistinctFrom => Some(Operator::IsNotDistinctFrom),
10492
Operator::IsNotDistinctFrom => Some(Operator::IsDistinctFrom),
10593
Operator::Plus
@@ -133,11 +121,7 @@ impl Operator {
133121
Operator::LtEq => Some(Operator::GtEq),
134122
Operator::Gt => Some(Operator::Lt),
135123
Operator::GtEq => Some(Operator::LtEq),
136-
Operator::Like
137-
| Operator::NotLike
138-
| Operator::ILike
139-
| Operator::NotILike
140-
| Operator::IsDistinctFrom
124+
Operator::IsDistinctFrom
141125
| Operator::IsNotDistinctFrom
142126
| Operator::Plus
143127
| Operator::Minus
@@ -176,10 +160,6 @@ impl fmt::Display for Operator {
176160
Operator::Modulo => "%",
177161
Operator::And => "AND",
178162
Operator::Or => "OR",
179-
Operator::Like => "LIKE",
180-
Operator::NotLike => "NOT LIKE",
181-
Operator::ILike => "ILIKE",
182-
Operator::NotILike => "NOT ILIKE",
183163
Operator::RegexMatch => "~",
184164
Operator::RegexIMatch => "~*",
185165
Operator::RegexNotMatch => "!~",

‎datafusion/expr/src/type_coercion/binary.rs‎

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ pub fn binary_operator_data_type(
4545
| Operator::NotEq
4646
| Operator::And
4747
| Operator::Or
48-
| Operator::Like
49-
| Operator::NotLike
50-
| Operator::ILike
51-
| Operator::NotILike
5248
| Operator::Lt
5349
| Operator::Gt
5450
| Operator::GtEq
@@ -117,10 +113,6 @@ pub fn coerce_types(
117113
| Operator::Gt
118114
| Operator::GtEq
119115
| Operator::LtEq => comparison_coercion(lhs_type, rhs_type),
120-
// "like" operators operate on strings and always return a boolean
121-
Operator::Like | Operator::NotLike | Operator::ILike | Operator::NotILike => {
122-
like_coercion(lhs_type, rhs_type)
123-
}
124116
Operator::Plus | Operator::Minus
125117
if is_date(lhs_type) || is_timestamp(lhs_type) =>
126118
{
@@ -525,7 +517,7 @@ fn string_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType>
525517

526518
/// coercion rules for like operations.
527519
/// This is a union of string coercion rules and dictionary coercion rules
528-
fn like_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
520+
pub fn like_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
529521
string_coercion(lhs_type, rhs_type)
530522
.or_else(|| dictionary_coercion(lhs_type, rhs_type, false))
531523
.or_else(|| null_coercion(lhs_type, rhs_type))
@@ -879,30 +871,10 @@ mod tests {
879871

880872
#[test]
881873
fn test_type_coercion() -> Result<()> {
882-
test_coercion_binary_rule!(
883-
DataType::Utf8,
884-
DataType::Utf8,
885-
Operator::Like,
886-
DataType::Utf8
887-
);
888-
test_coercion_binary_rule!(
889-
DataType::Utf8,
890-
DataType::Utf8,
891-
Operator::NotLike,
892-
DataType::Utf8
893-
);
894-
test_coercion_binary_rule!(
895-
DataType::Utf8,
896-
DataType::Utf8,
897-
Operator::ILike,
898-
DataType::Utf8
899-
);
900-
test_coercion_binary_rule!(
901-
DataType::Utf8,
902-
DataType::Utf8,
903-
Operator::NotILike,
904-
DataType::Utf8
905-
);
874+
// test like coercion rule
875+
let result = like_coercion(&DataType::Utf8, &DataType::Utf8);
876+
assert_eq!(result, Some(DataType::Utf8));
877+
906878
test_coercion_binary_rule!(
907879
DataType::Utf8,
908880
DataType::Date32,

‎datafusion/optimizer/src/simplify_expressions/utils.rs‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use datafusion_common::{DataFusionError, Result, ScalarValue};
2121
use datafusion_expr::{
2222
expr::{Between, BinaryExpr},
2323
expr_fn::{and, concat_ws, or},
24-
lit, BuiltinScalarFunction, Expr, Operator,
24+
lit, BuiltinScalarFunction, Expr, Like, Operator,
2525
};
2626

2727
pub static POWS_OF_TEN: [i128; 38] = [
@@ -232,6 +232,20 @@ pub fn negate_clause(expr: Expr) -> Expr {
232232
between.low,
233233
between.high,
234234
)),
235+
// not (A like B) ===> A not like B
236+
Expr::Like(like) => Expr::Like(Like::new(
237+
!like.negated,
238+
like.expr,
239+
like.pattern,
240+
like.escape_char,
241+
)),
242+
// not (A ilike B) ===> A not ilike B
243+
Expr::ILike(like) => Expr::ILike(Like::new(
244+
!like.negated,
245+
like.expr,
246+
like.pattern,
247+
like.escape_char,
248+
)),
235249
// use not clause
236250
_ => Expr::Not(Box::new(expr)),
237251
}

‎datafusion/optimizer/src/type_coercion.rs‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ use datafusion_common::{
2727
use datafusion_expr::expr::{self, Between, BinaryExpr, Case, Like, WindowFunction};
2828
use datafusion_expr::expr_rewriter::{ExprRewriter, RewriteRecursion};
2929
use datafusion_expr::logical_plan::Subquery;
30-
use datafusion_expr::type_coercion::binary::{coerce_types, comparison_coercion};
30+
use datafusion_expr::type_coercion::binary::{
31+
coerce_types, comparison_coercion, like_coercion,
32+
};
3133
use datafusion_expr::type_coercion::functions::data_types;
3234
use datafusion_expr::type_coercion::other::{
3335
get_coerce_type_for_case_when, get_coerce_type_for_list,
@@ -175,8 +177,11 @@ impl ExprRewriter for TypeCoercionRewriter {
175177
}) => {
176178
let left_type = expr.get_type(&self.schema)?;
177179
let right_type = pattern.get_type(&self.schema)?;
178-
let coerced_type =
179-
coerce_types(&left_type, &Operator::Like, &right_type)?;
180+
let coerced_type = like_coercion(&left_type, &right_type).ok_or_else(|| {
181+
DataFusionError::Plan(format!(
182+
"There isn't a common type to coerce {left_type} and {right_type} in LIKE expression"
183+
))
184+
})?;
180185
let expr = Box::new(expr.cast_to(&coerced_type, &self.schema)?);
181186
let pattern = Box::new(pattern.cast_to(&coerced_type, &self.schema)?);
182187
let expr = Expr::Like(Like::new(negated, expr, pattern, escape_char));
@@ -190,8 +195,11 @@ impl ExprRewriter for TypeCoercionRewriter {
190195
}) => {
191196
let left_type = expr.get_type(&self.schema)?;
192197
let right_type = pattern.get_type(&self.schema)?;
193-
let coerced_type =
194-
coerce_types(&left_type, &Operator::ILike, &right_type)?;
198+
let coerced_type = like_coercion(&left_type, &right_type).ok_or_else(|| {
199+
DataFusionError::Plan(format!(
200+
"There isn't a common type to coerce {left_type} and {right_type} in ILIKE expression"
201+
))
202+
})?;
195203
let expr = Box::new(expr.cast_to(&coerced_type, &self.schema)?);
196204
let pattern = Box::new(pattern.cast_to(&coerced_type, &self.schema)?);
197205
let expr = Expr::ILike(Like::new(negated, expr, pattern, escape_char));
@@ -932,7 +940,9 @@ mod test {
932940
let plan = LogicalPlan::Projection(Projection::try_new(vec![like_expr], empty)?);
933941
let err = assert_optimized_plan_eq(&plan, expected);
934942
assert!(err.is_err());
935-
assert!(err.unwrap_err().to_string().contains("'Int64 LIKE Utf8' can't be evaluated because there isn't a common type to coerce the types to"));
943+
assert!(err.unwrap_err().to_string().contains(
944+
"There isn't a common type to coerce Int64 and Utf8 in LIKE expression"
945+
));
936946
Ok(())
937947
}
938948

‎datafusion/physical-expr/src/expressions/binary.rs‎

Lines changed: 2 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ use arrow::compute::kernels::arithmetic::{
2828
multiply_scalar, subtract, subtract_scalar,
2929
};
3030
use arrow::compute::kernels::boolean::{and_kleene, not, or_kleene};
31+
use arrow::compute::kernels::comparison::regexp_is_match_utf8;
32+
use arrow::compute::kernels::comparison::regexp_is_match_utf8_scalar;
3133
use arrow::compute::kernels::comparison::{
3234
eq_dyn_binary_scalar, gt_dyn_binary_scalar, gt_eq_dyn_binary_scalar,
3335
lt_dyn_binary_scalar, lt_eq_dyn_binary_scalar, neq_dyn_binary_scalar,
@@ -47,13 +49,6 @@ use arrow::compute::kernels::comparison::{
4749
use arrow::compute::kernels::comparison::{
4850
eq_scalar, gt_eq_scalar, gt_scalar, lt_eq_scalar, lt_scalar, neq_scalar,
4951
};
50-
use arrow::compute::kernels::comparison::{
51-
ilike_utf8, like_utf8, nilike_utf8, nlike_utf8, regexp_is_match_utf8,
52-
};
53-
use arrow::compute::kernels::comparison::{
54-
ilike_utf8_scalar, like_utf8_scalar, nilike_utf8_scalar, nlike_utf8_scalar,
55-
regexp_is_match_utf8_scalar,
56-
};
5752

5853
use adapter::{eq_dyn, gt_dyn, gt_eq_dyn, lt_dyn, lt_eq_dyn, neq_dyn};
5954
use arrow::compute::kernels::concat_elements::concat_elements_utf8;
@@ -344,19 +339,6 @@ macro_rules! compute_op {
344339
}};
345340
}
346341

347-
macro_rules! binary_string_array_op_scalar {
348-
($LEFT:expr, $RIGHT:expr, $OP:ident, $OP_TYPE:expr) => {{
349-
let result: Result<Arc<dyn Array>> = match $LEFT.data_type() {
350-
DataType::Utf8 => compute_utf8_op_scalar!($LEFT, $RIGHT, $OP, StringArray, $OP_TYPE),
351-
other => Err(DataFusionError::Internal(format!(
352-
"Data type {:?} not supported for scalar operation '{}' on string array",
353-
other, stringify!($OP)
354-
))),
355-
};
356-
Some(result)
357-
}};
358-
}
359-
360342
macro_rules! binary_string_array_op {
361343
($LEFT:expr, $RIGHT:expr, $OP:ident) => {{
362344
match $LEFT.data_type() {
@@ -941,18 +923,6 @@ impl BinaryExpr {
941923
Operator::NotEq => {
942924
binary_array_op_dyn_scalar!(array, scalar.clone(), neq, bool_type)
943925
}
944-
Operator::Like => {
945-
binary_string_array_op_scalar!(array, scalar.clone(), like, bool_type)
946-
}
947-
Operator::NotLike => {
948-
binary_string_array_op_scalar!(array, scalar.clone(), nlike, bool_type)
949-
}
950-
Operator::ILike => {
951-
binary_string_array_op_scalar!(array, scalar.clone(), ilike, bool_type)
952-
}
953-
Operator::NotILike => {
954-
binary_string_array_op_scalar!(array, scalar.clone(), nilike, bool_type)
955-
}
956926
Operator::Plus => {
957927
binary_primitive_array_op_scalar!(array, scalar.clone(), add)
958928
}
@@ -1053,10 +1023,6 @@ impl BinaryExpr {
10531023
right_data_type: &DataType,
10541024
) -> Result<ArrayRef> {
10551025
match &self.op {
1056-
Operator::Like => binary_string_array_op!(left, right, like),
1057-
Operator::NotLike => binary_string_array_op!(left, right, nlike),
1058-
Operator::ILike => binary_string_array_op!(left, right, ilike),
1059-
Operator::NotILike => binary_string_array_op!(left, right, nilike),
10601026
Operator::Lt => lt_dyn(&left, &right),
10611027
Operator::LtEq => lt_eq_dyn(&left, &right),
10621028
Operator::Gt => gt_dyn(&left, &right),
@@ -1347,54 +1313,6 @@ mod tests {
13471313
DataType::Float32,
13481314
vec![2f32],
13491315
);
1350-
test_coercion!(
1351-
StringArray,
1352-
DataType::Utf8,
1353-
vec!["hello world", "world"],
1354-
StringArray,
1355-
DataType::Utf8,
1356-
vec!["%hello%", "%hello%"],
1357-
Operator::Like,
1358-
BooleanArray,
1359-
DataType::Boolean,
1360-
vec![true, false],
1361-
);
1362-
test_coercion!(
1363-
StringArray,
1364-
DataType::Utf8,
1365-
vec!["hello world", "world"],
1366-
StringArray,
1367-
DataType::Utf8,
1368-
vec!["%hello%", "%hello%"],
1369-
Operator::NotLike,
1370-
BooleanArray,
1371-
DataType::Boolean,
1372-
vec![false, true],
1373-
);
1374-
test_coercion!(
1375-
StringArray,
1376-
DataType::Utf8,
1377-
vec!["hEllo world", "world"],
1378-
StringArray,
1379-
DataType::Utf8,
1380-
vec!["%helLo%", "%helLo%"],
1381-
Operator::ILike,
1382-
BooleanArray,
1383-
DataType::Boolean,
1384-
vec![true, false],
1385-
);
1386-
test_coercion!(
1387-
StringArray,
1388-
DataType::Utf8,
1389-
vec!["hEllo world", "world"],
1390-
StringArray,
1391-
DataType::Utf8,
1392-
vec!["%helLo%", "%helLo%"],
1393-
Operator::NotILike,
1394-
BooleanArray,
1395-
DataType::Boolean,
1396-
vec![false, true],
1397-
);
13981316
test_coercion!(
13991317
StringArray,
14001318
DataType::Utf8,

0 commit comments

Comments
 (0)