Commit d66d45ef authored by unknown's avatar unknown
Browse files

Merge abarkov@bk-internal.mysql.com:/home/bk/mysql-4.1

into  mysql.com:/usr/home/bar/mysql-4.1.b10201

parents 6bac3d43 8624bcfd
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -445,6 +445,30 @@ group_concat(distinct b order by b)
Warnings:
Warning	1260	2 line(s) were cut by GROUP_CONCAT()
drop table t1;
create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci,
b varchar(255) character set koi8r);
insert into t1 values ('xxx','yyy');
select collation(a) from t1;
collation(a)
cp1250_general_ci
select collation(group_concat(a)) from t1;
collation(group_concat(a))
cp1250_general_ci
create table t2 select group_concat(a) as a from t1;
show create table t2;
Table	Create Table
t2	CREATE TABLE `t2` (
  `a` longtext character set cp1250
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select collation(group_concat(a,_koi8r'test')) from t1;
collation(group_concat(a,_koi8r'test'))
cp1250_general_ci
select collation(group_concat(a,_koi8r 0xC1C2)) from t1;
ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,COERCIBLE) for operation 'group_concat'
select collation(group_concat(a,b)) from t1;
ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat'
drop table t1;
drop table t2;
CREATE TABLE t1 (id int);
SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
gc
+18 −0
Original line number Diff line number Diff line
@@ -263,6 +263,24 @@ select group_concat(distinct b order by b) from t1 group by a;

drop table t1;

#
# Bug#10201
#
create table t1 (a varchar(255) character set cp1250 collate cp1250_general_ci,
                 b varchar(255) character set koi8r);
insert into t1 values ('xxx','yyy');
select collation(a) from t1;
select collation(group_concat(a)) from t1;
create table t2 select group_concat(a) as a from t1;
show create table t2;
select collation(group_concat(a,_koi8r'test')) from t1;
--error 1267
select collation(group_concat(a,_koi8r 0xC1C2)) from t1;
--error 1267
select collation(group_concat(a,b)) from t1;
drop table t1;
drop table t2;

#
# bug #7769: group_concat returning null is checked in having
#
+164 −0
Original line number Diff line number Diff line
@@ -523,6 +523,170 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
  return 0;
}

/******************************/
static
void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
{
  my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
           c1.collation->name,c1.derivation_name(),
           c2.collation->name,c2.derivation_name(),
           fname);
}


static
void my_coll_agg_error(DTCollation &c1, DTCollation &c2, DTCollation &c3,
                       const char *fname)
{
  my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
  	   c1.collation->name,c1.derivation_name(),
	   c2.collation->name,c2.derivation_name(),
	   c3.collation->name,c3.derivation_name(),
	   fname);
}


static
void my_coll_agg_error(Item** args, uint count, const char *fname)
{
  if (count == 2)
    my_coll_agg_error(args[0]->collation, args[1]->collation, fname);
  else if (count == 3)
    my_coll_agg_error(args[0]->collation, args[1]->collation,
                      args[2]->collation, fname);
  else
    my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
}


bool agg_item_collations(DTCollation &c, const char *fname,
                         Item **av, uint count, uint flags)
{
  uint i;
  c.set(av[0]->collation);
  for (i= 1; i < count; i++)
  {
    if (c.aggregate(av[i]->collation, flags))
    {
      my_coll_agg_error(av, count, fname);
      return TRUE;
    }
  }
  if ((flags & MY_COLL_DISALLOW_NONE) &&
      c.derivation == DERIVATION_NONE)
  {
    my_coll_agg_error(av, count, fname);
    return TRUE;
  }
  return FALSE;
}


bool agg_item_collations_for_comparison(DTCollation &c, const char *fname,
                                        Item **av, uint count, uint flags)
{
  return (agg_item_collations(c, fname, av, count,
                              flags | MY_COLL_DISALLOW_NONE));
}


/* 
  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)
*/

bool agg_item_charsets(DTCollation &coll, const char *fname,
                       Item **args, uint nargs, uint flags)
{
  Item **arg, **last, *safe_args[2];
  if (agg_item_collations(coll, fname, args, nargs, flags))
    return TRUE;

  /*
    For better error reporting: save the first and the second argument.
    We need this only if the the number of args is 3 or 2:
    - for a longer argument list, "Illegal mix of collations"
      doesn't display each argument's characteristics.
    - if nargs is 1, then this error cannot happen.
  */
  if (nargs >=2 && nargs <= 3)
  {
    safe_args[0]= args[0];
    safe_args[1]= args[1];
  }

  THD *thd= current_thd;
  Item_arena *arena, backup;
  bool res= FALSE;
  /*
    In case we're in statement prepare, create conversion item
    in its memory: it will be reused on each execute.
  */
  arena= thd->change_arena_if_needed(&backup);

  for (arg= args, last= args + nargs; arg < last; arg++)
  {
    Item* conv;
    uint32 dummy_offset;
    if (!String::needs_conversion(0, coll.collation,
                                  (*arg)->collation.collation,
                                  &dummy_offset))
      continue;

    if (!(conv= (*arg)->safe_charset_converter(coll.collation)))
    {
      if (nargs >=2 && nargs <= 3)
      {
        /* restore the original arguments for better error message */
        args[0]= safe_args[0];
        args[1]= safe_args[1];
      }
      my_coll_agg_error(args, nargs, fname);
      res= TRUE;
      break; // we cannot return here, we need to restore "arena".
    }
    conv->fix_fields(thd, 0, &conv);
    /*
      If in statement prepare, then we create a converter for two
      constant items, do it once and then reuse it.
      If we're in execution of a prepared statement, arena is NULL,
      and the conv was created in runtime memory. This can be
      the case only if the argument is a parameter marker ('?'),
      because for all true constants the charset converter has already
      been created in prepare. In this case register the change for
      rollback.
    */
    if (arena)
      *arg= conv;
    else
      thd->change_item_tree(arg, conv);
  }
  if (arena)
    thd->restore_backup_item_arena(arena, &backup);
  return res;
}




/**********************************************/

Item_field::Item_field(Field *f)
  :Item_ident(NullS, f->table_name, f->field_name)
{
+9 −0
Original line number Diff line number Diff line
@@ -330,6 +330,15 @@ class Item {
};


bool agg_item_collations(DTCollation &c, const char *name,
                         Item **items, uint nitems, uint flags= 0);
bool agg_item_collations_for_comparison(DTCollation &c, const char *name,
                                        Item **items, uint nitems,
                                        uint flags= 0);
bool agg_item_charsets(DTCollation &c, const char *name,
                       Item **items, uint nitems, uint flags= 0);


class Item_num: public Item
{
public:
+0 −162
Original line number Diff line number Diff line
@@ -39,73 +39,6 @@ bool check_reserved_words(LEX_STRING *name)
}


static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
			      const char *fname)
{
  my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
	   c1.collation->name,c1.derivation_name(),
	   c2.collation->name,c2.derivation_name(),
	   fname);
}

static void my_coll_agg_error(DTCollation &c1,
			       DTCollation &c2,
			       DTCollation &c3,
			       const char *fname)
{
  my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
  	   c1.collation->name,c1.derivation_name(),
	   c2.collation->name,c2.derivation_name(),
	   c3.collation->name,c3.derivation_name(),
	   fname);
}


static void my_coll_agg_error(Item** args, uint count, const char *fname)
{
  if (count == 2)
    my_coll_agg_error(args[0]->collation, args[1]->collation, fname);
  else if (count == 3)
    my_coll_agg_error(args[0]->collation,
		      args[1]->collation,
		      args[2]->collation,
		      fname);
  else
    my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
}


bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count,
                                   uint flags)
{
  uint i;
  c.set(av[0]->collation);
  for (i= 1; i < count; i++)
  {
    if (c.aggregate(av[i]->collation, flags))
    {
      my_coll_agg_error(av, count, func_name());
      return TRUE;
    }
  }
  if ((flags & MY_COLL_DISALLOW_NONE) &&
      c.derivation == DERIVATION_NONE)
  {
    my_coll_agg_error(av, count, func_name());
    return TRUE;
  }
  return FALSE;
}


bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
						  Item **av, uint count,
                                                  uint flags)
{
  return (agg_arg_collations(c, av, count, flags | MY_COLL_DISALLOW_NONE));
}


/* return TRUE if item is a constant */

bool
@@ -115,101 +48,6 @@ eval_const_cond(COND *cond)
}



/* 
  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)
*/

bool Item_func::agg_arg_charsets(DTCollation &coll,
                                 Item **args, uint nargs, uint flags)
{
  Item **arg, **last, *safe_args[2];
  if (agg_arg_collations(coll, args, nargs, flags))
    return TRUE;

  /*
    For better error reporting: save the first and the second argument.
    We need this only if the the number of args is 3 or 2:
    - for a longer argument list, "Illegal mix of collations"
      doesn't display each argument's characteristics.
    - if nargs is 1, then this error cannot happen.
  */
  if (nargs >=2 && nargs <= 3)
  {
    safe_args[0]= args[0];
    safe_args[1]= args[1];
  }

  THD *thd= current_thd;
  Item_arena *arena, backup;
  bool res= FALSE;
  /*
    In case we're in statement prepare, create conversion item
    in its memory: it will be reused on each execute.
  */
  arena= thd->change_arena_if_needed(&backup);

  for (arg= args, last= args + nargs; arg < last; arg++)
  {
    Item* conv;
    uint32 dummy_offset;
    if (!String::needs_conversion(0, coll.collation,
                                  (*arg)->collation.collation,
                                  &dummy_offset))
      continue;

    if (!(conv= (*arg)->safe_charset_converter(coll.collation)))
    {
      if (nargs >=2 && nargs <= 3)
      {
        /* restore the original arguments for better error message */
        args[0]= safe_args[0];
        args[1]= safe_args[1];
      }
      my_coll_agg_error(args, nargs, func_name());
      res= TRUE;
      break; // we cannot return here, we need to restore "arena".
    }
    conv->fix_fields(thd, 0, &conv);
    /*
      If in statement prepare, then we create a converter for two
      constant items, do it once and then reuse it.
      If we're in execution of a prepared statement, arena is NULL,
      and the conv was created in runtime memory. This can be
      the case only if the argument is a parameter marker ('?'),
      because for all true constants the charset converter has already
      been created in prepare. In this case register the change for
      rollback.
    */
    if (arena)
      *arg= conv;
    else
      thd->change_item_tree(arg, conv);
  }
  if (arena)
    thd->restore_backup_item_arena(arena, &backup);
  return res;
}



void Item_func::set_arguments(List<Item> &list)
{
  allowed_arg_cols= 1;
Loading