@@ -5,7 +5,15 @@ use crate::optimizer::OptimizerError;
5
5
use crate :: planner:: operator:: join:: JoinCondition ;
6
6
use crate :: planner:: operator:: Operator ;
7
7
use lazy_static:: lazy_static;
8
+ use crate :: expression:: { BinaryOperator , ScalarExpression } ;
9
+ use crate :: types:: value:: { DataValue , ValueRef } ;
8
10
lazy_static ! {
11
+ static ref LIKE_REWRITE_RULE : Pattern = {
12
+ Pattern {
13
+ predicate: |op| matches!( op, Operator :: Filter ( _) ) ,
14
+ children: PatternChildrenPredicate :: None ,
15
+ }
16
+ } ;
9
17
static ref CONSTANT_CALCULATION_RULE : Pattern = {
10
18
Pattern {
11
19
predicate: |_| true ,
@@ -109,6 +117,84 @@ impl Rule for SimplifyFilter {
109
117
}
110
118
}
111
119
120
+ pub struct LikeRewrite ;
121
+
122
+ impl Rule for LikeRewrite {
123
+ fn pattern ( & self ) -> & Pattern {
124
+ & LIKE_REWRITE_RULE
125
+ }
126
+
127
+ fn apply ( & self , node_id : HepNodeId , graph : & mut HepGraph ) -> Result < ( ) , OptimizerError > {
128
+ if let Operator :: Filter ( mut filter_op) = graph. operator ( node_id) . clone ( ) {
129
+ // if is like expression
130
+ if let ScalarExpression :: Binary {
131
+ op : BinaryOperator :: Like ,
132
+ left_expr,
133
+ right_expr,
134
+ ty,
135
+ } = & mut filter_op. predicate
136
+ {
137
+ // if left is column and right is constant
138
+ if let ScalarExpression :: ColumnRef ( _) = left_expr. as_ref ( ) {
139
+ if let ScalarExpression :: Constant ( value) = right_expr. as_ref ( ) {
140
+ match value. as_ref ( ) {
141
+ DataValue :: Utf8 ( val_str) => {
142
+ let mut value = val_str. clone ( ) . unwrap_or_else ( || "" . to_string ( ) ) ;
143
+
144
+ if value. ends_with ( '%' ) {
145
+ value. pop ( ) ; // remove '%'
146
+ if let Some ( last_char) = value. clone ( ) . pop ( ) {
147
+ if let Some ( next_char) = increment_char ( last_char) {
148
+ let mut new_value = value. clone ( ) ;
149
+ new_value. pop ( ) ;
150
+ new_value. push ( next_char) ;
151
+
152
+ let new_expr = ScalarExpression :: Binary {
153
+ op : BinaryOperator :: And ,
154
+ left_expr : Box :: new ( ScalarExpression :: Binary {
155
+ op : BinaryOperator :: GtEq ,
156
+ left_expr : left_expr. clone ( ) ,
157
+ right_expr : Box :: new ( ScalarExpression :: Constant ( ValueRef :: from ( DataValue :: Utf8 ( Some ( value) ) ) ) ) ,
158
+ ty : ty. clone ( ) ,
159
+ } ) ,
160
+ right_expr : Box :: new ( ScalarExpression :: Binary {
161
+ op : BinaryOperator :: Lt ,
162
+ left_expr : left_expr. clone ( ) ,
163
+ right_expr : Box :: new ( ScalarExpression :: Constant ( ValueRef :: from ( DataValue :: Utf8 ( Some ( new_value) ) ) ) ) ,
164
+ ty : ty. clone ( ) ,
165
+ } ) ,
166
+ ty : ty. clone ( ) ,
167
+ } ;
168
+ filter_op. predicate = new_expr;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ _ => {
174
+ graph. version += 1 ;
175
+ return Ok ( ( ) ) ;
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ graph. replace_node ( node_id, Operator :: Filter ( filter_op) )
182
+ }
183
+ // mark changed to skip this rule batch
184
+ graph. version += 1 ;
185
+ Ok ( ( ) )
186
+ }
187
+ }
188
+
189
+ fn increment_char ( v : char ) -> Option < char > {
190
+ match v {
191
+ 'z' => None ,
192
+ 'Z' => None ,
193
+ _ => std:: char:: from_u32 ( v as u32 + 1 ) ,
194
+ }
195
+ }
196
+
197
+
112
198
#[ cfg( test) ]
113
199
mod test {
114
200
use crate :: binder:: test:: select_sql_run;
@@ -126,6 +212,15 @@ mod test {
126
212
use crate :: types:: LogicalType ;
127
213
use std:: collections:: Bound ;
128
214
use std:: sync:: Arc ;
215
+ use crate :: optimizer:: rule:: simplification:: increment_char;
216
+
217
+
218
+ #[ test]
219
+ fn test_increment_char ( ) {
220
+ assert_eq ! ( increment_char( 'a' ) , Some ( 'b' ) ) ;
221
+ assert_eq ! ( increment_char( 'z' ) , None ) ;
222
+ assert_eq ! ( increment_char( 'A' ) , Some ( 'B' ) ) ;
223
+ }
129
224
130
225
#[ tokio:: test]
131
226
async fn test_constant_calculation_omitted ( ) -> Result < ( ) , DatabaseError > {
@@ -302,6 +397,7 @@ mod test {
302
397
Ok ( ( ) )
303
398
}
304
399
400
+
305
401
#[ tokio:: test]
306
402
async fn test_simplify_filter_multiple_column ( ) -> Result < ( ) , DatabaseError > {
307
403
// c1 + 1 < -1 => c1 < -2
@@ -343,7 +439,7 @@ mod test {
343
439
cb_1_c1,
344
440
Some ( ConstantBinary :: Scope {
345
441
min: Bound :: Unbounded ,
346
- max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) )
442
+ max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) ) ,
347
443
} )
348
444
) ;
349
445
@@ -353,7 +449,7 @@ mod test {
353
449
cb_1_c2,
354
450
Some ( ConstantBinary :: Scope {
355
451
min: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 2 ) ) ) ) ,
356
- max: Bound :: Unbounded
452
+ max: Bound :: Unbounded ,
357
453
} )
358
454
) ;
359
455
@@ -363,7 +459,7 @@ mod test {
363
459
cb_2_c1,
364
460
Some ( ConstantBinary :: Scope {
365
461
min: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 2 ) ) ) ) ,
366
- max: Bound :: Unbounded
462
+ max: Bound :: Unbounded ,
367
463
} )
368
464
) ;
369
465
@@ -373,7 +469,7 @@ mod test {
373
469
cb_1_c1,
374
470
Some ( ConstantBinary :: Scope {
375
471
min: Bound :: Unbounded ,
376
- max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) )
472
+ max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) ) ,
377
473
} )
378
474
) ;
379
475
@@ -383,7 +479,7 @@ mod test {
383
479
cb_3_c1,
384
480
Some ( ConstantBinary :: Scope {
385
481
min: Bound :: Unbounded ,
386
- max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) )
482
+ max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) ) ,
387
483
} )
388
484
) ;
389
485
@@ -393,7 +489,7 @@ mod test {
393
489
cb_3_c2,
394
490
Some ( ConstantBinary :: Scope {
395
491
min: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 0 ) ) ) ) ,
396
- max: Bound :: Unbounded
492
+ max: Bound :: Unbounded ,
397
493
} )
398
494
) ;
399
495
@@ -403,7 +499,7 @@ mod test {
403
499
cb_4_c1,
404
500
Some ( ConstantBinary :: Scope {
405
501
min: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 0 ) ) ) ) ,
406
- max: Bound :: Unbounded
502
+ max: Bound :: Unbounded ,
407
503
} )
408
504
) ;
409
505
@@ -413,7 +509,7 @@ mod test {
413
509
cb_4_c2,
414
510
Some ( ConstantBinary :: Scope {
415
511
min: Bound :: Unbounded ,
416
- max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) )
512
+ max: Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) ) ,
417
513
} )
418
514
) ;
419
515
0 commit comments