Commit d66c9e50 authored by unknown's avatar unknown

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

into  mysql.com:/usr/home/bar/mysql-5.0

parents 74e00311 4d7aaed1
...@@ -46,6 +46,7 @@ extern "C" { ...@@ -46,6 +46,7 @@ extern "C" {
#undef HAVE_SYS_MMAN_H #undef HAVE_SYS_MMAN_H
#undef HAVE_SYNCH_H #undef HAVE_SYNCH_H
#undef HAVE_MMAP #undef HAVE_MMAP
#undef HAVE_RINT
#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1
#define HAVE_PTHREAD_SIGMASK 1 #define HAVE_PTHREAD_SIGMASK 1
......
...@@ -148,6 +148,7 @@ EXPORTS ...@@ -148,6 +148,7 @@ EXPORTS
mysql_embedded mysql_embedded
mysql_server_init mysql_server_init
mysql_server_end mysql_server_end
get_defaults_files
mysql_set_character_set mysql_set_character_set
mysql_get_character_set_info mysql_get_character_set_info
get_defaults_options get_defaults_options
......
...@@ -445,6 +445,30 @@ group_concat(distinct b order by b) ...@@ -445,6 +445,30 @@ group_concat(distinct b order by b)
Warnings: Warnings:
Warning 1260 2 line(s) were cut by GROUP_CONCAT() Warning 1260 2 line(s) were cut by GROUP_CONCAT()
drop table t1; 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` varchar(400) character set cp1250 default NULL
) 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); CREATE TABLE t1 (id int);
SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL;
gc gc
......
...@@ -263,6 +263,24 @@ select group_concat(distinct b order by b) from t1 group by a; ...@@ -263,6 +263,24 @@ select group_concat(distinct b order by b) from t1 group by a;
drop table t1; 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 # bug #7769: group_concat returning null is checked in having
# #
......
...@@ -1082,6 +1082,176 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) ...@@ -1082,6 +1082,176 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
return 0; 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;
Query_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".
}
if ((*arg)->type() == Item::FIELD_ITEM)
((Item_field *)(*arg))->no_const_subst= 1;
/*
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);
/*
We do not check conv->fixed, because Item_func_conv_charset which can
be return by safe_charset_converter can't be fixed at creation
*/
conv->fix_fields(thd, arg);
}
if (arena)
thd->restore_backup_item_arena(arena, &backup);
return res;
}
/**********************************************/
Item_field::Item_field(Field *f) Item_field::Item_field(Field *f)
:Item_ident(0, NullS, *f->table_name, f->field_name), :Item_ident(0, NullS, *f->table_name, f->field_name),
item_equal(0), no_const_subst(0), item_equal(0), no_const_subst(0),
......
...@@ -767,6 +767,15 @@ class Item_splocal : public Item ...@@ -767,6 +767,15 @@ class Item_splocal : public 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 class Item_num: public Item
{ {
public: public:
......
...@@ -42,73 +42,6 @@ bool check_reserved_words(LEX_STRING *name) ...@@ -42,73 +42,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 */ /* return TRUE if item is a constant */
bool bool
...@@ -118,107 +51,6 @@ eval_const_cond(COND *cond) ...@@ -118,107 +51,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;
Query_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".
}
if ((*arg)->type() == FIELD_ITEM)
((Item_field *)(*arg))->no_const_subst= 1;
/*
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);
/*
We do not check conv->fixed, because Item_func_conv_charset which can
be return by safe_charset_converter can't be fixed at creation
*/
conv->fix_fields(thd, arg);
}
if (arena)
thd->restore_backup_item_arena(arena, &backup);
return res;
}
void Item_func::set_arguments(List<Item> &list) void Item_func::set_arguments(List<Item> &list)
{ {
allowed_arg_cols= 1; allowed_arg_cols= 1;
......
...@@ -166,12 +166,22 @@ class Item_func :public Item_result_field ...@@ -166,12 +166,22 @@ class Item_func :public Item_result_field
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, bool agg_arg_collations(DTCollation &c, Item **items, uint nitems,
uint flags= 0); uint flags= 0)
{
return agg_item_collations(c, func_name(), items, nitems, flags);
}
bool agg_arg_collations_for_comparison(DTCollation &c, bool agg_arg_collations_for_comparison(DTCollation &c,
Item **items, uint nitems, Item **items, uint nitems,
uint flags= 0); uint flags= 0)
{
return agg_item_collations_for_comparison(c, func_name(),
items, nitems, flags);
}
bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems, bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
uint flags= 0); uint flags= 0)
{
return agg_item_charsets(c, func_name(), items, nitems, flags);
}
bool walk(Item_processor processor, byte *arg); bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg); Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Cond_traverser traverser, void traverse_cond(Cond_traverser traverser,
......
...@@ -2976,6 +2976,10 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) ...@@ -2976,6 +2976,10 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
maybe_null|= args[i]->maybe_null; maybe_null|= args[i]->maybe_null;
} }
if (agg_item_charsets(collation, func_name(),
args, arg_count, MY_COLL_ALLOW_CONV))
return 1;
result_field= 0; result_field= 0;
null_value= 1; null_value= 1;
thd->allow_sum_func= 1; thd->allow_sum_func= 1;
......
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