Commit 22cc8f99 authored by Alexander Barkov's avatar Alexander Barkov

Changing a number of functions to aggregate argument character sets

and collations from the global name space into private and protected
methods in Item_func_or_sum.
parent 9b9e36ed
...@@ -2035,8 +2035,9 @@ void my_coll_agg_error(Item** args, uint count, const char *fname, ...@@ -2035,8 +2035,9 @@ void my_coll_agg_error(Item** args, uint count, const char *fname,
} }
bool agg_item_collations(DTCollation &c, const char *fname, bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname,
Item **av, uint count, uint flags, int item_sep) Item **av, uint count,
uint flags, int item_sep)
{ {
uint i; uint i;
Item **arg; Item **arg;
...@@ -2081,16 +2082,10 @@ bool agg_item_collations(DTCollation &c, const char *fname, ...@@ -2081,16 +2082,10 @@ bool agg_item_collations(DTCollation &c, const char *fname,
} }
bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll,
Item **av, uint count, uint flags) const char *fname,
{ Item **args, uint nargs,
return (agg_item_collations(c, fname, av, count, uint flags, int item_sep)
flags | MY_COLL_DISALLOW_NONE, 1));
}
bool agg_item_set_converter(DTCollation &coll, const char *fname,
Item **args, uint nargs, uint flags, int item_sep)
{ {
Item **arg, *safe_args[2]= {NULL, NULL}; Item **arg, *safe_args[2]= {NULL, NULL};
...@@ -2167,46 +2162,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, ...@@ -2167,46 +2162,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
} }
/*
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)
Since this function calls THD::change_item_tree() on the passed Item **
pointers, it is necessary to pass the original Item **'s, not copies.
Otherwise their values will not be properly restored (see BUG#20769).
If the items are not consecutive (eg. args[2] and args[5]), use the
item_sep argument, ie.
agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
*/
bool agg_item_charsets(DTCollation &coll, const char *fname,
Item **args, uint nargs, uint flags, int item_sep)
{
if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
return TRUE;
return agg_item_set_converter(coll, fname, args, nargs, flags, item_sep);
}
void Item_ident_for_show::make_field(Send_field *tmp_field) void Item_ident_for_show::make_field(Send_field *tmp_field)
{ {
tmp_field->table_name= tmp_field->org_table_name= table_name; tmp_field->table_name= tmp_field->org_table_name= table_name;
......
...@@ -2153,38 +2153,6 @@ class Item_name_const : public Item ...@@ -2153,38 +2153,6 @@ class Item_name_const : public Item
} }
}; };
bool agg_item_collations(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags, int item_sep);
bool agg_item_collations_for_comparison(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags);
bool agg_item_set_converter(DTCollation &coll, const char *fname,
Item **args, uint nargs, uint flags, int item_sep);
bool agg_item_charsets(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags, int item_sep);
inline bool
agg_item_charsets_for_comparison(DTCollation &c, const char *name,
Item **items, uint nitems,
int item_sep= 1)
{
uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
MY_COLL_ALLOW_COERCIBLE_CONV |
MY_COLL_DISALLOW_NONE;
return agg_item_charsets(c, name, items, nitems, flags, item_sep);
}
inline bool
agg_item_charsets_for_string_result_with_comparison(DTCollation &c,
const char *name,
Item **items, uint nitems,
int item_sep= 1)
{
uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
MY_COLL_ALLOW_COERCIBLE_CONV |
MY_COLL_ALLOW_NUMERIC_CONV |
MY_COLL_DISALLOW_NONE;
return agg_item_charsets(c, name, items, nitems, flags, item_sep);
}
class Item_num: public Item_basic_constant class Item_num: public Item_basic_constant
{ {
public: public:
...@@ -3616,7 +3584,50 @@ class Used_tables_and_const_cache ...@@ -3616,7 +3584,50 @@ class Used_tables_and_const_cache
*/ */
class Item_func_or_sum: public Item_result_field, public Item_args class Item_func_or_sum: public Item_result_field, public Item_args
{ {
bool agg_item_collations(DTCollation &c, const char *name,
Item **items, uint nitems,
uint flags, int item_sep);
bool agg_item_set_converter(const DTCollation &coll, const char *fname,
Item **args, uint nargs,
uint flags, int item_sep);
protected: protected:
/*
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)
Since this function calls THD::change_item_tree() on the passed Item **
pointers, it is necessary to pass the original Item **'s, not copies.
Otherwise their values will not be properly restored (see BUG#20769).
If the items are not consecutive (eg. args[2] and args[5]), use the
item_sep argument, ie.
agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
*/
bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
uint flags, int item_sep)
{
if (agg_item_collations(c, func_name(), items, nitems, flags, item_sep))
return true;
return agg_item_set_converter(c, func_name(), items, nitems,
flags, item_sep);
}
/* /*
Aggregate arguments for string result, e.g: CONCAT(a,b) Aggregate arguments for string result, e.g: CONCAT(a,b)
- convert to @@character_set_connection if all arguments are numbers - convert to @@character_set_connection if all arguments are numbers
...@@ -3629,7 +3640,7 @@ class Item_func_or_sum: public Item_result_field, public Item_args ...@@ -3629,7 +3640,7 @@ class Item_func_or_sum: public Item_result_field, public Item_args
uint flags= MY_COLL_ALLOW_SUPERSET_CONV | uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
MY_COLL_ALLOW_COERCIBLE_CONV | MY_COLL_ALLOW_COERCIBLE_CONV |
MY_COLL_ALLOW_NUMERIC_CONV; MY_COLL_ALLOW_NUMERIC_CONV;
return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep); return agg_arg_charsets(c, items, nitems, flags, item_sep);
} }
/* /*
Aggregate arguments for string result, when some comparison Aggregate arguments for string result, when some comparison
...@@ -3646,7 +3657,48 @@ class Item_func_or_sum: public Item_result_field, public Item_args ...@@ -3646,7 +3657,48 @@ class Item_func_or_sum: public Item_result_field, public Item_args
MY_COLL_ALLOW_COERCIBLE_CONV | MY_COLL_ALLOW_COERCIBLE_CONV |
MY_COLL_ALLOW_NUMERIC_CONV | MY_COLL_ALLOW_NUMERIC_CONV |
MY_COLL_DISALLOW_NONE; MY_COLL_DISALLOW_NONE;
return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep); return agg_arg_charsets(c, items, nitems, flags, item_sep);
}
/*
Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b
- don't convert to @@character_set_connection if all arguments are numbers
- don't allow DERIVATION_NONE
*/
bool agg_arg_charsets_for_comparison(DTCollation &c,
Item **items, uint nitems,
int item_sep= 1)
{
uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
MY_COLL_ALLOW_COERCIBLE_CONV |
MY_COLL_DISALLOW_NONE;
return agg_arg_charsets(c, items, nitems, flags, item_sep);
}
public:
// This method is used by Arg_comparator
bool agg_arg_charsets_for_comparison(CHARSET_INFO **cs, Item **a, Item **b)
{
DTCollation tmp;
if (tmp.set((*a)->collation, (*b)->collation, MY_COLL_CMP_CONV) ||
tmp.derivation == DERIVATION_NONE)
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
(*a)->collation.collation->name,
(*a)->collation.derivation_name(),
(*b)->collation.collation->name,
(*b)->collation.derivation_name(),
func_name());
return true;
}
if (agg_item_set_converter(tmp, func_name(),
a, 1, MY_COLL_CMP_CONV, 1) ||
agg_item_set_converter(tmp, func_name(),
b, 1, MY_COLL_CMP_CONV, 1))
return true;
*cs= tmp.collation;
return false;
} }
public: public:
......
...@@ -253,15 +253,6 @@ static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE) ...@@ -253,15 +253,6 @@ static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE)
return found_types; return found_types;
} }
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);
}
/* /*
Test functions Test functions
...@@ -653,39 +644,6 @@ bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, ...@@ -653,39 +644,6 @@ bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type,
} }
/**
Aggregate comparator argument charsets for comparison.
One of the arguments ("a" or "b") can be replaced,
typically by Item_string or Item_func_conv_charset.
@return Aggregation result
@retval false - if no conversion is needed,
or if one of the arguments was converted
@retval true - on error, if arguments are not comparable.
TODO: get rid of this method eventually and refactor the calling code.
Argument conversion should happen on the Item_func level.
Arg_comparator should get comparable arguments.
*/
bool Arg_comparator::agg_arg_charsets_for_comparison()
{
DTCollation tmp;
if (tmp.set((*a)->collation, (*b)->collation, MY_COLL_CMP_CONV) ||
tmp.derivation == DERIVATION_NONE)
{
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
return true;
}
if (agg_item_set_converter(tmp, owner->func_name(),
a, 1, MY_COLL_CMP_CONV, 1) ||
agg_item_set_converter(tmp, owner->func_name(),
b, 1, MY_COLL_CMP_CONV, 1))
return true;
m_compare_collation= tmp.collation;
return false;
}
/** /**
Prepare the comparator (set the comparison function) for comparing Prepare the comparator (set the comparison function) for comparing
items *a1 and *a2 in the context of 'type'. items *a1 and *a2 in the context of 'type'.
...@@ -717,7 +675,7 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg, ...@@ -717,7 +675,7 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg,
We must set cmp_collation here as we may be called from for an automatic We must set cmp_collation here as we may be called from for an automatic
generated item, like in natural join generated item, like in natural join
*/ */
if (agg_arg_charsets_for_comparison()) if (owner->agg_arg_charsets_for_comparison(&m_compare_collation, a, b))
return 1; return 1;
} }
......
...@@ -60,7 +60,6 @@ class Arg_comparator: public Sql_alloc ...@@ -60,7 +60,6 @@ class Arg_comparator: public Sql_alloc
// when one of arguments is NULL. // when one of arguments is NULL.
int set_compare_func(Item_func_or_sum *owner, Item_result type); int set_compare_func(Item_func_or_sum *owner, Item_result type);
int set_cmp_func(Item_func_or_sum *owner_arg, Item **a1, Item **a2); int set_cmp_func(Item_func_or_sum *owner_arg, Item **a1, Item **a2);
bool agg_arg_charsets_for_comparison();
int compare_temporal(enum_field_types type); int compare_temporal(enum_field_types type);
int compare_e_temporal(enum_field_types type); int compare_e_temporal(enum_field_types type);
......
...@@ -187,23 +187,6 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache ...@@ -187,23 +187,6 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
else else
max_length= (uint32) max_result_length; max_length= (uint32) max_result_length;
} }
bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
uint flags, int item_sep)
{
return agg_item_charsets(c, func_name(), items, nitems, flags, item_sep);
}
/*
Aggregate arguments for comparison, e.g: a=b, a LIKE b, a RLIKE b
- don't convert to @@character_set_connection if all arguments are numbers
- don't allow DERIVATION_NONE
*/
bool agg_arg_charsets_for_comparison(DTCollation &c,
Item **items, uint nitems,
int item_sep= 1)
{
return agg_item_charsets_for_comparison(c, func_name(),
items, nitems, item_sep);
}
Item *transform(THD *thd, Item_transformer transformer, uchar *arg); Item *transform(THD *thd, Item_transformer transformer, uchar *arg);
Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t); Item_transformer transformer, uchar *arg_t);
......
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