Commit 2f72e059 authored by bar@mysql.com's avatar bar@mysql.com

Bug#10446 Illegal mix of collations:

item_strfunc.h, item_strfunc.cc, item.cc:
  Try to convert a const item into destination 
  character set. If conversion happens without
  data loss, then cache the converted value
  and return it during val_str().
  Otherwise, if conversion loses data, return
  Illeral mix of collations error, as it happened
  previously.
ctype_recoding.result, ctype_recoding.test:
  Fixing tests accordingly.
parent 133c00be
......@@ -181,11 +181,18 @@ select * from t1 where a=_koi8r'
a
select * from t1 where a=concat(_koi8r'');
ERROR HY000: Illegal mix of collations (cp1251_general_ci,IMPLICIT) and (koi8r_general_ci,COERCIBLE) for operation '='
a
select * from t1 where a=_latin1'';
ERROR HY000: Illegal mix of collations (cp1251_general_ci,IMPLICIT) and (latin1_swedish_ci,COERCIBLE) for operation '='
drop table t1;
set names latin1;
create table t1 (a char(10) character set utf8 collate utf8_bin);
insert into t1 values (' xxx');
select * from t1 where a=lpad('xxx',10,' ');
a
xxx
drop table t1;
set names koi8r;
create table t1 (c1 char(10) character set cp1251);
insert into t1 values ('');
......
......@@ -144,8 +144,7 @@ create table t1 (a char(10) character set cp1251);
insert into t1 values (_koi8r'');
# this is possible:
select * from t1 where a=_koi8r'';
# this is not possible, because we have a function, not just a constant:
--error 1267
# this is possible, because we have a function with constant arguments:
select * from t1 where a=concat(_koi8r'');
# this is not posible, cannot convert _latin1'' into cp1251:
--error 1267
......@@ -153,6 +152,14 @@ select * from t1 where a=_latin1'
drop table t1;
set names latin1;
#
# Bug#10446 Illegal mix of collations
#
create table t1 (a char(10) character set utf8 collate utf8_bin);
insert into t1 values (' xxx');
select * from t1 where a=lpad('xxx',10,' ');
drop table t1;
#
# Check more automatic conversion
#
......
......@@ -211,16 +211,8 @@ bool Item::eq(const Item *item, bool binary_cmp) const
Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
{
/*
Allow conversion from and to "binary".
Don't allow automatic conversion to non-Unicode charsets,
as it potentially loses data.
*/
if (collation.collation != &my_charset_bin &&
tocs != &my_charset_bin &&
!(tocs->state & MY_CS_UNICODE))
return NULL; // safe conversion is not possible
return new Item_func_conv_charset(this, tocs);
Item_func_conv_charset *conv= new Item_func_conv_charset(this, tocs, 1);
return conv->safe ? conv : NULL;
}
......
......@@ -2252,6 +2252,8 @@ String *Item_func_conv::val_str(String *str)
String *Item_func_conv_charset::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
if (use_cached_value)
return null_value ? 0 : &str_value;
String *arg= args[0]->val_str(str);
uint dummy_errors;
if (!arg)
......
......@@ -614,10 +614,40 @@ class Item_func_quote :public Item_str_func
class Item_func_conv_charset :public Item_str_func
{
bool use_cached_value;
public:
bool safe;
CHARSET_INFO *conv_charset; // keep it public
Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
{ conv_charset=cs; }
Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
{ conv_charset= cs; use_cached_value= 0; safe= 0; }
Item_func_conv_charset(Item *a, CHARSET_INFO *cs, bool cache_if_const)
:Item_str_func(a)
{
DBUG_ASSERT(args[0]->fixed);
conv_charset= cs;
if (cache_if_const && args[0]->const_item())
{
uint errors= 0;
String tmp, *str= args[0]->val_str(&tmp);
if (!str || str_value.copy(str->ptr(), str->length(),
str->charset(), conv_charset, &errors))
null_value= 1;
use_cached_value= 1;
safe= (errors == 0);
}
else
{
use_cached_value= 0;
/*
Conversion from and to "binary" is safe.
Conversion to Unicode is safe.
Other kind of conversions are potentially lossy.
*/
safe= (args[0]->collation.collation == &my_charset_bin ||
cs == &my_charset_bin ||
(cs->state & MY_CS_UNICODE));
}
}
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "convert"; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment