List:Commits« Previous MessageNext Message »
From:Sergey Glukhov Date:February 19 2009 1:20pm
Subject:bzr commit into mysql-5.0-bugteam branch (Sergey.Glukhov:2753)
Bug#37601
View as plain text  
#At file:///home/gluh/MySQL/mysql-5.0-bugteam/ based on revid:alexey.kopytov@stripped

 2753 Sergey Glukhov	2009-02-19
      Bug#37601 Cast Is Not Done On Row Comparison
      In case of ROW item each compared pair does not
      check if argumet collations can be aggregated and
      thus appropiriate item conversion does not happen.
      The fix is to add the check and convertion for ROW
      pairs.
     @ mysql-test/r/row.result
        test result
     @ mysql-test/t/row.test
        test case
     @ sql/item.cc
        added agg_item_set_converter() function which was a part of
        agg_item_charsets() func. The only difference is that
        agg_item_set_converter() checks and converts items 
        using already known collation.
     @ sql/item.h
        added agg_item_set_converter() function
     @ sql/item_cmpfunc.cc
        In case of ROW item each compared pair does not
        check if argumet collations can be aggregated and
        thus appropiriate item conversion does not happen.
        The fix is to add the check and convertion for ROW
        pairs.

    modified:
      mysql-test/r/row.result
      mysql-test/t/row.test
      sql/item.cc
      sql/item.h
      sql/item_cmpfunc.cc
=== modified file 'mysql-test/r/row.result'
--- a/mysql-test/r/row.result	2008-02-28 18:53:31 +0000
+++ b/mysql-test/r/row.result	2009-02-19 13:20:44 +0000
@@ -443,3 +443,17 @@ SELECT ROW(a, 1) IN (SELECT SUM(b), 3) F
 ROW(a, 1) IN (SELECT SUM(b), 3)
 0
 DROP TABLE t1;
+create table t1 (a varchar(200),
+b int unsigned not null primary key auto_increment)
+default character set 'utf8';
+create table t2 (c varchar(200),
+d int unsigned not null primary key auto_increment)
+default character set 'latin1';
+insert into t1 (a) values('abc');
+insert into t2 (c) values('abc');
+select * from t1,t2 where (a,b) = (c,d);
+a	b	c	d
+abc	1	abc	1
+select host,user from mysql.user where (host,user) = ('localhost','test');
+host	user
+drop table t1,t2;

=== modified file 'mysql-test/t/row.test'
--- a/mysql-test/t/row.test	2008-02-28 18:53:31 +0000
+++ b/mysql-test/t/row.test	2009-02-19 13:20:44 +0000
@@ -237,3 +237,21 @@ SELECT ROW(a, 1) IN (SELECT SUM(b), 1) F
 SELECT ROW(a, 1) IN (SELECT SUM(b), 3) FROM t1 GROUP BY a;
 
 DROP TABLE t1;
+
+#
+# Bug#37601 Cast Is Not Done On Row Comparison
+#
+create table t1 (a varchar(200),
+                 b int unsigned not null primary key auto_increment)
+default character set 'utf8';
+
+create table t2 (c varchar(200),
+                 d int unsigned not null primary key auto_increment)
+default character set 'latin1';
+
+insert into t1 (a) values('abc');
+insert into t2 (c) values('abc');
+select * from t1,t2 where (a,b) = (c,d);
+
+select host,user from mysql.user where (host,user) = ('localhost','test');
+drop table t1,t2;

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2009-02-19 08:49:35 +0000
+++ b/sql/item.cc	2009-02-19 13:20:44 +0000
@@ -1608,42 +1608,11 @@ bool agg_item_collations_for_comparison(
 }
 
 
-/* 
-  Collect arguments' character sets together.
-  We allow to apply automatic character set conversion in some cases.
-  The conditions when conversion is possible are:
-  - arguments A and B have different charsets
-  - A wins according to coercibility rules
-    (i.e. a column is stronger than a string constant,
-     an explicit COLLATE clause is stronger than a column)
-  - character set of A is either superset for character set of B,
-    or B is a string constant which can be converted into the
-    character set of A without data loss.
-    
-  If all of the above is true, then it's possible to convert
-  B into the character set of A, and then compare according
-  to the collation of A.
-  
-  For functions with more than two arguments:
-
-    collect(A,B,C) ::= collect(collect(A,B),C)
 
-  Since this function calls THD::change_item_tree() on the passed Item **
-  pointers, it is necessary to pass the original Item **'s, not copies.
-  Otherwise their values will not be properly restored (see BUG#20769).
-  If the items are not consecutive (eg. args[2] and args[5]), use the
-  item_sep argument, ie.
-
-    agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
-
-*/
-
-bool agg_item_charsets(DTCollation &coll, const char *fname,
-                       Item **args, uint nargs, uint flags, int item_sep)
+bool agg_item_set_converter(DTCollation &coll, const char *fname,
+                            Item **args, uint nargs, uint flags, int item_sep)
 {
   Item **arg, *safe_args[2];
-  if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
-    return TRUE;
 
   /*
     For better error reporting: save the first and the second argument.
@@ -1724,6 +1693,47 @@ bool agg_item_charsets(DTCollation &coll
 }
 
 
+/* 
+  Collect arguments' character sets together.
+  We allow to apply automatic character set conversion in some cases.
+  The conditions when conversion is possible are:
+  - arguments A and B have different charsets
+  - A wins according to coercibility rules
+    (i.e. a column is stronger than a string constant,
+     an explicit COLLATE clause is stronger than a column)
+  - character set of A is either superset for character set of B,
+    or B is a string constant which can be converted into the
+    character set of A without data loss.
+    
+  If all of the above is true, then it's possible to convert
+  B into the character set of A, and then compare according
+  to the collation of A.
+  
+  For functions with more than two arguments:
+
+    collect(A,B,C) ::= collect(collect(A,B),C)
+
+  Since this function calls THD::change_item_tree() on the passed Item **
+  pointers, it is necessary to pass the original Item **'s, not copies.
+  Otherwise their values will not be properly restored (see BUG#20769).
+  If the items are not consecutive (eg. args[2] and args[5]), use the
+  item_sep argument, ie.
+
+    agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
+
+*/
+
+bool agg_item_charsets(DTCollation &coll, const char *fname,
+                       Item **args, uint nargs, uint flags, int item_sep)
+{
+  Item **arg, *safe_args[2];
+  if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
+    return TRUE;
+
+  return agg_item_set_converter(coll, fname, args, nargs, flags, item_sep);
+}
+
+
 void Item_ident_for_show::make_field(Send_field *tmp_field)
 {
   tmp_field->table_name= tmp_field->org_table_name= table_name;

=== modified file 'sql/item.h'
--- a/sql/item.h	2009-01-16 14:48:41 +0000
+++ b/sql/item.h	2009-02-19 13:20:44 +0000
@@ -1169,6 +1169,8 @@ bool agg_item_collations(DTCollation &c,
                          Item **items, uint nitems, uint flags, int item_sep);
 bool agg_item_collations_for_comparison(DTCollation &c, const char *name,
                                         Item **items, uint nitems, uint flags);
+bool agg_item_set_converter(DTCollation &coll, const char *fname,
+                            Item **args, uint nargs, uint flags, int item_sep);
 bool agg_item_charsets(DTCollation &c, const char *name,
                        Item **items, uint nitems, uint flags, int item_sep);
 

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2009-01-15 11:08:09 +0000
+++ b/sql/item_cmpfunc.cc	2009-02-19 13:20:44 +0000
@@ -490,7 +490,8 @@ int Arg_comparator::set_compare_func(Ite
 	my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols());
 	return 1;
       }
-      comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
+      if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)))
+        return 1;
     }
     break;
   }
@@ -835,6 +836,16 @@ int Arg_comparator::set_cmp_func(Item_bo
     get_value_func= &get_time_value;
     return 0;
   }
+  else if (type == STRING_RESULT &&
+           (*a)->result_type() == STRING_RESULT &&
+           (*b)->result_type() == STRING_RESULT)
+  {
+    DTCollation coll;
+    coll.set((*a)->collation.collation);
+    if (agg_item_set_converter(coll, owner_arg->func_name(),
+                               b, 1, MY_COLL_CMP_CONV, 1))
+      return 1;
+  }
 
   return set_compare_func(owner_arg, type);
 }


Attachment: [text/bzr-bundle] bzr/sergey.glukhov@sun.com-20090219132044-cc0xj52duw5j2aa3.bundle
Thread
bzr commit into mysql-5.0-bugteam branch (Sergey.Glukhov:2753)Bug#37601Sergey Glukhov19 Feb