← Back to team overview

maria-developers team mailing list archive

Please review: MDEV-8222 "string_field LIKE int_const" returns a wrong result in case of UCS2

 

Hi Sergey,

please review my patch for MDEV-8222.

It also moves Arg_compatator from Item_bool_func2 to Item_bool_rowready_func2.

Thanks.
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 740319a..5b4d132 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -5542,5 +5542,14 @@ select collation(cast("a" as char(10) binary unicode));
 collation(cast("a" as char(10) binary unicode))
 ucs2_bin
 #
+# MDEV-8222 "string_field LIKE int_const" returns a wrong result in case of UCS2
+#
+CREATE TABLE t1 (a VARCHAR(10) CHARSET ucs2);
+INSERT INTO t1 VALUES ('1');
+SELECT * FROM t1 WHERE a LIKE 1;
+a
+1
+DROP TABLE t1;
+#
 # End of 10.1 tests
 #
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 1dee393..6e5b085 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -925,5 +925,13 @@ select collation(cast("a" as char(10) unicode binary));
 select collation(cast("a" as char(10) binary unicode));
 
 --echo #
+--echo # MDEV-8222 "string_field LIKE int_const" returns a wrong result in case of UCS2
+--echo #
+CREATE TABLE t1 (a VARCHAR(10) CHARSET ucs2);
+INSERT INTO t1 VALUES ('1');
+SELECT * FROM t1 WHERE a LIKE 1;
+DROP TABLE t1;
+
+--echo #
 --echo # End of 10.1 tests
 --echo #
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 5bea5da..a192675 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -503,15 +503,15 @@ bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp)
   args[0]->cmp_context= args[1]->cmp_context=
     item_cmp_type(args[0]->result_type(), args[1]->result_type());
 
-  //  Convert constants when compared to int/year field, unless this is LIKE
-  if (functype() != LIKE_FUNC)
-    convert_const_compared_to_int_field(thd);
+  //  Convert constants when compared to int/year field
+  DBUG_ASSERT(functype() != LIKE_FUNC);
+  convert_const_compared_to_int_field(thd);
 
   return cmp->set_cmp_func(this, tmp_arg, tmp_arg + 1, true);
 }
 
 
-void Item_bool_func2::fix_length_and_dec()
+void Item_bool_rowready_func2::fix_length_and_dec()
 {
   max_length= 1;				     // Function returns 0 or 1
 
@@ -1881,7 +1881,7 @@ longlong Item_func_eq::val_int()
 
 void Item_func_equal::fix_length_and_dec()
 {
-  Item_bool_func2::fix_length_and_dec();
+  Item_bool_rowready_func2::fix_length_and_dec();
   maybe_null=null_value=0;
 }
 
@@ -4784,13 +4784,13 @@ void Item_func_isnotnull::print(String *str, enum_query_type query_type)
 longlong Item_func_like::val_int()
 {
   DBUG_ASSERT(fixed == 1);
-  String* res = args[0]->val_str(&cmp.value1);
+  String* res= args[0]->val_str(&cmp_value1);
   if (args[0]->null_value)
   {
     null_value=1;
     return 0;
   }
-  String* res2 = args[1]->val_str(&cmp.value2);
+  String* res2= args[1]->val_str(&cmp_value2);
   if (args[1]->null_value)
   {
     null_value=1;
@@ -4799,7 +4799,7 @@ longlong Item_func_like::val_int()
   null_value=0;
   if (canDoTurboBM)
     return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
-  return my_wildcmp(cmp.cmp_collation.collation,
+  return my_wildcmp(cmp_collation.collation,
 		    res->ptr(),res->ptr()+res->length(),
 		    res2->ptr(),res2->ptr()+res2->length(),
 		    escape,wild_one,wild_many) ? 0 : 1;
@@ -4815,7 +4815,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const
   if (!args[1]->const_item() || args[1]->is_expensive())
     return OPTIMIZE_NONE;
 
-  String* res2= args[1]->val_str((String *)&cmp.value2);
+  String* res2= args[1]->val_str((String *) &cmp_value2);
   if (!res2)
     return OPTIMIZE_NONE;
 
@@ -4845,7 +4845,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
   if (escape_item->const_item())
   {
     /* If we are on execution stage */
-    String *escape_str= escape_item->val_str(&cmp.value1);
+    String *escape_str= escape_item->val_str(&cmp_value1);
     if (escape_str)
     {
       const char *escape_str_ptr= escape_str->ptr();
@@ -4858,7 +4858,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
         return TRUE;
       }
 
-      if (use_mb(cmp.cmp_collation.collation))
+      if (use_mb(cmp_collation.collation))
       {
         CHARSET_INFO *cs= escape_str->charset();
         my_wc_t wc;
@@ -4875,7 +4875,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
           code instead of Unicode code as "escape" argument.
           Convert to "cs" if charset of escape differs.
         */
-        CHARSET_INFO *cs= cmp.cmp_collation.collation;
+        CHARSET_INFO *cs= cmp_collation.collation;
         uint32 unused;
         if (escape_str->needs_conversion(escape_str->length(),
                                          escape_str->charset(), cs, &unused))
@@ -4901,7 +4901,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
     if (args[1]->const_item() && !use_strnxfrm(collation.collation) &&
         !args[1]->is_expensive())
     {
-      String* res2 = args[1]->val_str(&cmp.value2);
+      String* res2= args[1]->val_str(&cmp_value2);
       if (!res2)
         return FALSE;				// Null argument
       
@@ -5182,7 +5182,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
   int            f = 0;
   int            g = plm1;
   int *const splm1 = suff + plm1;
-  CHARSET_INFO	*cs= cmp.cmp_collation.collation;
+  CHARSET_INFO	*cs= cmp_collation.collation;
 
   *splm1 = pattern_len;
 
@@ -5282,7 +5282,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
   int *end = bmBc + alphabet_size;
   int j;
   const int plm1 = pattern_len - 1;
-  CHARSET_INFO	*cs= cmp.cmp_collation.collation;
+  CHARSET_INFO	*cs= cmp_collation.collation;
 
   for (i = bmBc; i < end; i++)
     *i = pattern_len;
@@ -5314,7 +5314,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
   int shift = pattern_len;
   int j     = 0;
   int u     = 0;
-  CHARSET_INFO	*cs= cmp.cmp_collation.collation;
+  CHARSET_INFO	*cs= cmp_collation.collation;
 
   const int plm1=  pattern_len - 1;
   const int tlmpl= text_len - pattern_len;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 06a0c39..f2d0032 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -290,18 +290,10 @@ class Item_in_optimizer: public Item_bool_func
 };
 
 class Item_bool_func2 :public Item_bool_func
-{						/* Bool with 2 string args */
-protected:
-  Arg_comparator cmp;
-
+{                                              /* Bool with 2 string args */
 public:
   Item_bool_func2(Item *a,Item *b)
-    :Item_bool_func(a,b), cmp(tmp_arg, tmp_arg+1) { sargable= TRUE; }
-  void fix_length_and_dec();
-  int set_cmp_func()
-  {
-    return cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, TRUE);
-  }
+    :Item_bool_func(a,b) { sargable= TRUE; }
   optimize_type select_optimize() const { return OPTIMIZE_OP; }
   virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
   bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
@@ -312,14 +304,6 @@ class Item_bool_func2 :public Item_bool_func
   }
 
   bool is_null() { return MY_TEST(args[0]->is_null() || args[1]->is_null()); }
-  CHARSET_INFO *compare_collation() const
-  { return cmp.cmp_collation.collation; }
-  Arg_comparator *get_comparator() { return &cmp; }
-  void cleanup()
-  {
-    Item_bool_func::cleanup();
-    cmp.cleanup();
-  }
   COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
                         bool top_level);
 
@@ -327,8 +311,11 @@ class Item_bool_func2 :public Item_bool_func
 
 class Item_bool_rowready_func2 :public Item_bool_func2
 {
+protected:
+  Arg_comparator cmp;
 public:
-  Item_bool_rowready_func2(Item *a, Item *b) :Item_bool_func2(a, b)
+  Item_bool_rowready_func2(Item *a, Item *b)
+    :Item_bool_func2(a, b), cmp(tmp_arg, tmp_arg+1) 
   {
     allowed_arg_cols= 0;  // Fetch this value from first argument
   }
@@ -338,6 +325,19 @@ class Item_bool_rowready_func2 :public Item_bool_func2
   {
     return (*arg != NULL);     
   }
+  void fix_length_and_dec();
+  int set_cmp_func()
+  {
+    return cmp.set_cmp_func(this, tmp_arg, tmp_arg + 1, true);
+  }
+  CHARSET_INFO *compare_collation() const
+  { return cmp.cmp_collation.collation; }
+  Arg_comparator *get_comparator() { return &cmp; }
+  void cleanup()
+  {
+    Item_bool_func2::cleanup();
+    cmp.cleanup();
+  }
   bool can_optimize_group_min_max(Item_field *min_max_arg_item,
                                   const Item *const_item) const
   {
@@ -1490,6 +1490,8 @@ class Item_func_like :public Item_bool_func2
   bool escape_used_in_parsing;
   bool use_sampling;
 
+  DTCollation cmp_collation;
+  String cmp_value1, cmp_value2;
 public:
   int escape;
 
@@ -1500,6 +1502,8 @@ class Item_func_like :public Item_bool_func2
   longlong val_int();
   enum Functype functype() const { return LIKE_FUNC; }
   optimize_type select_optimize() const;
+  CHARSET_INFO *compare_collation() const
+  { return cmp_collation.collation; }
   cond_result eq_cmp_result() const
   {
     /**
@@ -1539,6 +1543,12 @@ class Item_func_like :public Item_bool_func2
                       table_map usable_tables, SARGABLE_PARAM **sargables);
   const char *func_name() const { return "like"; }
   bool fix_fields(THD *thd, Item **ref);
+  void fix_length_and_dec()
+  {
+    max_length= 1;
+    args[0]->cmp_context= args[1]->cmp_context= STRING_RESULT;
+    agg_arg_charsets_for_comparison(cmp_collation, args, 2);
+  }
   void cleanup();
 
   bool find_selective_predicates_list_processor(uchar *arg);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index dccad7a..0638910 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -13887,7 +13887,8 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
 	if ((tmp2=new COND_CMP(and_father,func)))
 	  save_list->push_back(tmp2);
       }
-      func->set_cmp_func();
+      if (functype != Item_func::LIKE_FUNC)
+        ((Item_bool_rowready_func2*) func)->set_cmp_func();
     }
   }
   else if (can_change_cond_ref_to_const(func, left_item, right_item,
@@ -13910,7 +13911,8 @@ change_cond_ref_to_const(THD *thd, I_List<COND_CMP> *save_list,
 	if ((tmp2=new COND_CMP(and_father,func)))
 	  save_list->push_back(tmp2);
       }
-      func->set_cmp_func();
+      if (functype != Item_func::LIKE_FUNC)
+        ((Item_bool_rowready_func2*)func)->set_cmp_func();
     }
   }
 }