diff options
-rw-r--r-- | mysql-test/r/row.result | 14 | ||||
-rw-r--r-- | mysql-test/t/row.test | 18 | ||||
-rw-r--r-- | sql/item.cc | 76 | ||||
-rw-r--r-- | sql/item.h | 2 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 13 |
5 files changed, 89 insertions, 34 deletions
diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 98c79d4bc00..9afb528b6dd 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -443,3 +443,17 @@ SELECT ROW(a, 1) IN (SELECT SUM(b), 3) FROM t1 GROUP BY a; 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; diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index 1601f7afd0e..fcc4259168b 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -237,3 +237,21 @@ SELECT ROW(a, 1) IN (SELECT SUM(b), 1) FROM t1 GROUP BY a; 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; diff --git a/sql/item.cc b/sql/item.cc index c9edb7b8f6c..14422bd3e92 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1608,42 +1608,11 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, } -/* - 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, const char *fname, } +/* + 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; diff --git a/sql/item.h b/sql/item.h index 1058cc5dbb8..852b0fcc1ba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1169,6 +1169,8 @@ bool agg_item_collations(DTCollation &c, const char *name, 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); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3b1d18b4252..01d3e9bed52 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -490,7 +490,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) 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_bool_func2 *owner_arg, 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); } |