@@ -5,7 +5,15 @@ use crate::optimizer::OptimizerError;
55use  crate :: planner:: operator:: join:: JoinCondition ; 
66use  crate :: planner:: operator:: Operator ; 
77use  lazy_static:: lazy_static; 
8+ use  crate :: expression:: { BinaryOperator ,  ScalarExpression } ; 
9+ use  crate :: types:: value:: { DataValue ,  ValueRef } ; 
810lazy_static !  { 
11+     static  ref LIKE_REWRITE_RULE :  Pattern  = { 
12+         Pattern  { 
13+             predicate:  |op| matches!( op,  Operator :: Filter ( _) ) , 
14+             children:  PatternChildrenPredicate :: None , 
15+         } 
16+     } ; 
917    static  ref CONSTANT_CALCULATION_RULE :  Pattern  = { 
1018        Pattern  { 
1119            predicate:  |_| true , 
@@ -109,6 +117,84 @@ impl Rule for SimplifyFilter {
109117    } 
110118} 
111119
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+ 
112198#[ cfg( test) ]  
113199mod  test { 
114200    use  crate :: binder:: test:: select_sql_run; 
@@ -126,6 +212,15 @@ mod test {
126212    use  crate :: types:: LogicalType ; 
127213    use  std:: collections:: Bound ; 
128214    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+     } 
129224
130225    #[ tokio:: test]  
131226    async  fn  test_constant_calculation_omitted ( )  -> Result < ( ) ,  DatabaseError >  { 
@@ -302,6 +397,7 @@ mod test {
302397        Ok ( ( ) ) 
303398    } 
304399
400+ 
305401    #[ tokio:: test]  
306402    async  fn  test_simplify_filter_multiple_column ( )  -> Result < ( ) ,  DatabaseError >  { 
307403        // c1 + 1 < -1 => c1 < -2 
@@ -343,7 +439,7 @@ mod test {
343439            cb_1_c1, 
344440            Some ( ConstantBinary :: Scope  { 
345441                min:  Bound :: Unbounded , 
346-                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) ) 
442+                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) ) , 
347443            } ) 
348444        ) ; 
349445
@@ -353,7 +449,7 @@ mod test {
353449            cb_1_c2, 
354450            Some ( ConstantBinary :: Scope  { 
355451                min:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 2 ) ) ) ) , 
356-                 max:  Bound :: Unbounded 
452+                 max:  Bound :: Unbounded , 
357453            } ) 
358454        ) ; 
359455
@@ -363,7 +459,7 @@ mod test {
363459            cb_2_c1, 
364460            Some ( ConstantBinary :: Scope  { 
365461                min:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 2 ) ) ) ) , 
366-                 max:  Bound :: Unbounded 
462+                 max:  Bound :: Unbounded , 
367463            } ) 
368464        ) ; 
369465
@@ -373,7 +469,7 @@ mod test {
373469            cb_1_c1, 
374470            Some ( ConstantBinary :: Scope  { 
375471                min:  Bound :: Unbounded , 
376-                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) ) 
472+                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -2 ) ) ) ) , 
377473            } ) 
378474        ) ; 
379475
@@ -383,7 +479,7 @@ mod test {
383479            cb_3_c1, 
384480            Some ( ConstantBinary :: Scope  { 
385481                min:  Bound :: Unbounded , 
386-                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) ) 
482+                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) ) , 
387483            } ) 
388484        ) ; 
389485
@@ -393,7 +489,7 @@ mod test {
393489            cb_3_c2, 
394490            Some ( ConstantBinary :: Scope  { 
395491                min:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 0 ) ) ) ) , 
396-                 max:  Bound :: Unbounded 
492+                 max:  Bound :: Unbounded , 
397493            } ) 
398494        ) ; 
399495
@@ -403,7 +499,7 @@ mod test {
403499            cb_4_c1, 
404500            Some ( ConstantBinary :: Scope  { 
405501                min:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( 0 ) ) ) ) , 
406-                 max:  Bound :: Unbounded 
502+                 max:  Bound :: Unbounded , 
407503            } ) 
408504        ) ; 
409505
@@ -413,7 +509,7 @@ mod test {
413509            cb_4_c2, 
414510            Some ( ConstantBinary :: Scope  { 
415511                min:  Bound :: Unbounded , 
416-                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) ) 
512+                 max:  Bound :: Excluded ( Arc :: new( DataValue :: Int32 ( Some ( -1 ) ) ) ) , 
417513            } ) 
418514        ) ; 
419515
0 commit comments