Commit 94ecacdb authored by unknown's avatar unknown
Browse files

Allow IN to convert arguments into Unicode in some cases.

parent 705d5066
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -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');
+50 −4
Original line number Diff line number Diff line
@@ -1735,13 +1735,59 @@ 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 => 
    they can't be processed as static
+8 −4
Original line number Diff line number Diff line
@@ -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)
+5 −2
Original line number Diff line number Diff line
@@ -140,8 +140,11 @@ class Item_func :public Item_result_field
  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);
};