diff options
author | unknown <bar@mysql.com> | 2004-09-01 15:39:15 +0500 |
---|---|---|
committer | unknown <bar@mysql.com> | 2004-09-01 15:39:15 +0500 |
commit | 94ecacdb97b97c74aae3eeb29965b80be28ac020 (patch) | |
tree | 77ebcecccdab54d0eed739c08f6404be23bc1aff | |
parent | 705d50660de96fd7d20d585348ace0d2eb512baf (diff) | |
download | mariadb-git-94ecacdb97b97c74aae3eeb29965b80be28ac020.tar.gz |
Allow IN to convert arguments into Unicode in some cases.
-rw-r--r-- | mysql-test/r/func_in.result | 10 | ||||
-rw-r--r-- | mysql-test/t/func_in.test | 7 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 54 | ||||
-rw-r--r-- | sql/item_func.cc | 12 | ||||
-rw-r--r-- | sql/item_func.h | 7 |
5 files changed, 80 insertions, 10 deletions
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index f66b3dea94b..374affce8c5 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -148,6 +148,16 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c` from test.t1 where (_latin1'a' in (test.t1.a,test.t1.b,(test.t1.c collate _latin1'latin1_bin'))) drop table t1; +set names utf8; +create table t1 (a char(10) character set utf8 not null); +insert into t1 values ('bbbb'),(_koi8r'ÃÃÃÃ'),(_latin1'ÄÄÄÄ'); +select a from t1 where a in ('bbbb',_koi8r'ÃÃÃÃ',_latin1'ÄÄÄÄ') order by a; +a +ÄÄÄÄ +bbbb +цццц +drop table t1; +set names latin1; select '1.0' in (1,2); '1.0' in (1,2) 1 diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 855a7cbd28f..22079377ad2 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -75,6 +75,13 @@ select * from t1 where 'a' in (a,b,c collate latin1_bin); explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); drop table t1; +set names utf8; +create table t1 (a char(10) character set utf8 not null); +insert into t1 values ('bbbb'),(_koi8r'ÃÃÃÃ'),(_latin1'ÄÄÄÄ'); +select a from t1 where a in ('bbbb',_koi8r'ÃÃÃÃ',_latin1'ÄÄÄÄ') order by a; +drop table t1; +set names latin1; + select '1.0' in (1,2); select 1 in ('1.0',2); select 1 in (1,'2.0'); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f91bc5c4bc5..4ddb648399a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1735,12 +1735,58 @@ void Item_func_in::fix_length_and_dec() uint const_itm= 1; agg_cmp_type(&cmp_type, args, arg_count); - if ((cmp_type == STRING_RESULT) && - (agg_arg_collations_for_comparison(cmp_collation, args, arg_count))) - return; - + for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++) const_itm&= arg[0]->const_item(); + + + if (cmp_type == STRING_RESULT) + { + /* + We allow consts character set conversion for + + item IN (const1, const2, const3, ...) + + if item is in a superset for all arguments, + and if it is a stong side according to coercibility rules. + + TODO: add covnersion for non-constant IN values + via creating Item_func_conv_charset(). + */ + + if (agg_arg_collations_for_comparison(cmp_collation, + args, arg_count, TRUE)) + return; + if ((!my_charset_same(args[0]->collation.collation, + cmp_collation.collation) || !const_itm)) + { + if (agg_arg_collations_for_comparison(cmp_collation, + args, arg_count, FALSE)) + return; + } + else + { + /* + Conversion is possible: + All IN arguments are constants. + */ + for (arg= args+1, arg_end= args+arg_count; arg < arg_end; arg++) + { + if (!my_charset_same(cmp_collation.collation, + arg[0]->collation.collation)) + { + Item_string *conv; + String tmp, cstr, *ostr= arg[0]->val_str(&tmp); + cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), + cmp_collation.collation); + conv= new Item_string(cstr.ptr(),cstr.length(), cstr.charset(), + arg[0]->collation.derivation); + conv->str_value.copy(); + arg[0]= conv; + } + } + } + } /* Row item with NULLs inside can return NULL or FALSE => diff --git a/sql/item_func.cc b/sql/item_func.cc index adcba34d56b..ef845bb8266 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -75,13 +75,16 @@ static void my_coll_agg_error(Item** args, uint count, const char *fname) } -bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count) +bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count, + bool allow_superset_conversion) { uint i; + c.nagg= 0; + c.strong= 0; c.set(av[0]->collation); for (i= 1; i < count; i++) { - if (c.aggregate(av[i]->collation)) + if (c.aggregate(av[i]->collation, allow_superset_conversion)) { my_coll_agg_error(av, count, func_name()); return TRUE; @@ -92,9 +95,10 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count) bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, - Item **av, uint count) + Item **av, uint count, + bool allow_superset_conv) { - if (agg_arg_collations(c, av, count)) + if (agg_arg_collations(c, av, count, allow_superset_conv)) return TRUE; if (c.derivation == DERIVATION_NONE) diff --git a/sql/item_func.h b/sql/item_func.h index eaa0a044fd6..d45f7244e55 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -140,8 +140,11 @@ public: Field *tmp_table_field(TABLE *t_arg); Item *get_tmp_table_item(THD *thd); - bool agg_arg_collations(DTCollation &c, Item **items, uint nitems); - bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems); + bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, + bool allow_superset_conversion= FALSE); + bool agg_arg_collations_for_comparison(DTCollation &c, + Item **items, uint nitems, + bool allow_superset_comversion= FALSE); bool walk(Item_processor processor, byte *arg); }; |