summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <bar@mysql.com>2004-09-01 15:39:15 +0500
committerunknown <bar@mysql.com>2004-09-01 15:39:15 +0500
commit94ecacdb97b97c74aae3eeb29965b80be28ac020 (patch)
tree77ebcecccdab54d0eed739c08f6404be23bc1aff
parent705d50660de96fd7d20d585348ace0d2eb512baf (diff)
downloadmariadb-git-94ecacdb97b97c74aae3eeb29965b80be28ac020.tar.gz
Allow IN to convert arguments into Unicode in some cases.
-rw-r--r--mysql-test/r/func_in.result10
-rw-r--r--mysql-test/t/func_in.test7
-rw-r--r--sql/item_cmpfunc.cc54
-rw-r--r--sql/item_func.cc12
-rw-r--r--sql/item_func.h7
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);
};