From 50b70e765bcdb361e98ec6a3a5fc51d92e899630 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 2 May 2017 07:49:06 +0400 Subject: [PATCH] MDEV-12655 Move Item_func::count_xxx_length() to Type_std_attributes --- sql/item.cc | 14 +++--- sql/item.h | 76 +++++----------------------- sql/item_func.cc | 110 ---------------------------------------- sql/item_func.h | 37 -------------- sql/sql_type.cc | 124 ++++++++++++++++++++++++++++++++++++++++++++- sql/sql_type.h | 128 ++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 268 insertions(+), 221 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 8cb898e310f..c0c99dc22bb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2355,9 +2355,9 @@ void my_coll_agg_error(Item** args, uint count, 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) +bool Type_std_attributes::agg_item_collations(DTCollation &c, const char *fname, + Item **av, uint count, + uint flags, int item_sep) { uint i; Item **arg; @@ -2402,10 +2402,10 @@ bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname, } -bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll, - const char *fname, - Item **args, uint nargs, - uint flags, int item_sep) +bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, + const char *fname, + Item **args, uint nargs, + uint flags, int item_sep) { Item **arg, *safe_args[2]= {NULL, NULL}; diff --git a/sql/item.h b/sql/item.h index 440905b51f6..1123b4beb93 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4059,80 +4059,31 @@ class Item_func_or_sum: public Item_result_field, public Item_args, public Used_tables_and_const_cache { - 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: - /* - 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); + return Type_std_attributes::agg_arg_charsets(c, func_name(), + items, nitems, + flags, item_sep); } - /* - Aggregate arguments for string result, e.g: CONCAT(a,b) - - convert to @@character_set_connection if all arguments are numbers - - allow DERIVATION_NONE - */ bool agg_arg_charsets_for_string_result(DTCollation &c, 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; - return agg_arg_charsets(c, items, nitems, flags, item_sep); + return Type_std_attributes:: + agg_arg_charsets_for_string_result(c, func_name(), + items, nitems, item_sep); } - /* - Aggregate arguments for string result, when some comparison - is involved internally, e.g: REPLACE(a,b,c) - - convert to @@character_set_connection if all arguments are numbers - - disallow DERIVATION_NONE - */ bool agg_arg_charsets_for_string_result_with_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_ALLOW_NUMERIC_CONV | - MY_COLL_DISALLOW_NONE; - return agg_arg_charsets(c, items, nitems, flags, item_sep); + return Type_std_attributes:: + agg_arg_charsets_for_string_result_with_comparison(c, func_name(), + items, nitems, + item_sep); } /* @@ -4144,13 +4095,10 @@ protected: 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); + return Type_std_attributes:: + agg_arg_charsets_for_comparison(c, func_name(), items, nitems, item_sep); } - public: // This method is used by Arg_comparator bool agg_arg_charsets_for_comparison(CHARSET_INFO **cs, Item **a, Item **b) diff --git a/sql/item_func.cc b/sql/item_func.cc index 0bdf708aecb..ee5472a4de0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -592,116 +592,6 @@ void Item_udf_func::fix_num_length_and_dec() } -/** - Set max_length/decimals of function if function is fixed point and - result length/precision depends on argument ones. -*/ - -void Item_func::count_decimal_length(Item **item, uint nitems) -{ - int max_int_part= 0; - decimals= 0; - unsigned_flag= 1; - for (uint i=0 ; i < nitems ; i++) - { - set_if_bigger(decimals, item[i]->decimals); - set_if_bigger(max_int_part, item[i]->decimal_int_part()); - set_if_smaller(unsigned_flag, item[i]->unsigned_flag); - } - int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION); - fix_char_length(my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag)); -} - - -/** - Set max_length of if it is maximum length of its arguments. -*/ - -void Item_func::count_only_length(Item **item, uint nitems) -{ - uint32 char_length= 0; - unsigned_flag= 0; - for (uint i= 0; i < nitems ; i++) - { - set_if_bigger(char_length, item[i]->max_char_length()); - set_if_bigger(unsigned_flag, item[i]->unsigned_flag); - } - fix_char_length(char_length); -} - - -void Item_func::count_octet_length(Item **item, uint nitems) -{ - max_length= 0; - unsigned_flag= 0; - for (uint i= 0; i < nitems ; i++) - { - set_if_bigger(max_length, item[i]->max_length); - set_if_bigger(unsigned_flag, item[i]->unsigned_flag); - } -} - - -/** - Set max_length/decimals of function if function is floating point and - result length/precision depends on argument ones. -*/ - -void Item_func::count_real_length(Item **items, uint nitems) -{ - uint32 length= 0; - decimals= 0; - max_length= 0; - unsigned_flag= false; - for (uint i=0 ; i < nitems ; i++) - { - if (decimals < FLOATING_POINT_DECIMALS) - { - set_if_bigger(decimals, items[i]->decimals); - /* Will be ignored if items[i]->decimals >= FLOATING_POINT_DECIMALS */ - set_if_bigger(length, (items[i]->max_length - items[i]->decimals)); - } - set_if_bigger(max_length, items[i]->max_length); - } - if (decimals < FLOATING_POINT_DECIMALS) - { - max_length= length; - length+= decimals; - if (length < max_length) // If previous operation gave overflow - max_length= UINT_MAX32; - else - max_length= length; - } - // Corner case: COALESCE(DOUBLE(255,4), DOUBLE(255,3)) -> FLOAT(255, 4) - set_if_smaller(max_length, MAX_FIELD_CHARLENGTH); -} - - -/** - Calculate max_length and decimals for string functions. - - @param field_type Field type. - @param items Argument array. - @param nitems Number of arguments. - - @retval False on success, true on error. -*/ -bool Item_func::count_string_length(Item **items, uint nitems) -{ - DBUG_ASSERT(!is_temporal_type(field_type())); - if (agg_arg_charsets_for_string_result(collation, items, nitems, 1)) - return true; - if (collation.collation == &my_charset_bin) - count_octet_length(items, nitems); - else - count_only_length(items, nitems); - decimals= max_length ? NOT_FIXED_DEC : 0; - return false; -} - - void Item_func::signal_divide_by_null() { THD *thd= current_thd; diff --git a/sql/item_func.h b/sql/item_func.h index 71fa904a707..33f671c179a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -42,45 +42,8 @@ protected: uint allowed_arg_cols; String *val_str_from_val_str_ascii(String *str, String *str2); - void count_only_length(Item **item, uint nitems); - void count_octet_length(Item **item, uint nitems); - void count_real_length(Item **item, uint nitems); - void count_decimal_length(Item **item, uint nitems); - bool count_string_length(Item **item, uint nitems); - uint count_max_decimals(Item **item, uint nitems) - { - uint res= 0; - for (uint i= 0; i < nitems; i++) - set_if_bigger(res, item[i]->decimals); - return res; - } virtual bool check_allowed_arg_cols(uint argno); public: - void aggregate_attributes_int(Item **items, uint nitems) - { - collation.set_numeric(); - count_only_length(items, nitems); - decimals= 0; - } - void aggregate_attributes_real(Item **items, uint nitems) - { - collation.set_numeric(); - count_real_length(items, nitems); - } - void aggregate_attributes_decimal(Item **items, uint nitems) - { - collation.set_numeric(); - count_decimal_length(items, nitems); - } - bool aggregate_attributes_string(Item **item, uint nitems) - { - return count_string_length(item, nitems); - } - void aggregate_attributes_temporal(uint int_part_length, - Item **item, uint nitems) - { - fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); - } table_map not_null_tables_cache; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index ad9059ecd57..88ad5bd576c 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -129,6 +129,126 @@ void Type_std_attributes::set(const Field *field) } +uint Type_std_attributes::count_max_decimals(Item **item, uint nitems) +{ + uint res= 0; + for (uint i= 0; i < nitems; i++) + set_if_bigger(res, item[i]->decimals); + return res; +} + + +/** + Set max_length/decimals of function if function is fixed point and + result length/precision depends on argument ones. +*/ + +void Type_std_attributes::count_decimal_length(Item **item, uint nitems) +{ + int max_int_part= 0; + decimals= 0; + unsigned_flag= 1; + for (uint i=0 ; i < nitems ; i++) + { + set_if_bigger(decimals, item[i]->decimals); + set_if_bigger(max_int_part, item[i]->decimal_int_part()); + set_if_smaller(unsigned_flag, item[i]->unsigned_flag); + } + int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION); + fix_char_length(my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag)); +} + + +/** + Set max_length of if it is maximum length of its arguments. +*/ + +void Type_std_attributes::count_only_length(Item **item, uint nitems) +{ + uint32 char_length= 0; + unsigned_flag= 0; + for (uint i= 0; i < nitems ; i++) + { + set_if_bigger(char_length, item[i]->max_char_length()); + set_if_bigger(unsigned_flag, item[i]->unsigned_flag); + } + fix_char_length(char_length); +} + + +void Type_std_attributes::count_octet_length(Item **item, uint nitems) +{ + max_length= 0; + unsigned_flag= 0; + for (uint i= 0; i < nitems ; i++) + { + set_if_bigger(max_length, item[i]->max_length); + set_if_bigger(unsigned_flag, item[i]->unsigned_flag); + } +} + + +/** + Set max_length/decimals of function if function is floating point and + result length/precision depends on argument ones. +*/ + +void Type_std_attributes::count_real_length(Item **items, uint nitems) +{ + uint32 length= 0; + decimals= 0; + max_length= 0; + unsigned_flag= false; + for (uint i=0 ; i < nitems ; i++) + { + if (decimals < FLOATING_POINT_DECIMALS) + { + set_if_bigger(decimals, items[i]->decimals); + /* Will be ignored if items[i]->decimals >= FLOATING_POINT_DECIMALS */ + set_if_bigger(length, (items[i]->max_length - items[i]->decimals)); + } + set_if_bigger(max_length, items[i]->max_length); + } + if (decimals < FLOATING_POINT_DECIMALS) + { + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; + } + // Corner case: COALESCE(DOUBLE(255,4), DOUBLE(255,3)) -> FLOAT(255, 4) + set_if_smaller(max_length, MAX_FIELD_CHARLENGTH); +} + + +/** + Calculate max_length and decimals for string functions. + + @param field_type Field type. + @param items Argument array. + @param nitems Number of arguments. + + @retval False on success, true on error. +*/ +bool Type_std_attributes::count_string_length(const char *func_name, + Item **items, uint nitems) +{ + if (agg_arg_charsets_for_string_result(collation, func_name, + items, nitems, 1)) + return true; + if (collation.collation == &my_charset_bin) + count_octet_length(items, nitems); + else + count_only_length(items, nitems); + decimals= max_length ? NOT_FIXED_DEC : 0; + return false; +} + + /** This method is used by: - Item_user_var_as_out_param::field_type() @@ -1933,7 +2053,7 @@ bool Type_handler_string_result:: Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const { - return func->aggregate_attributes_string(items, nitems); + return func->aggregate_attributes_string(func->func_name(), items, nitems); } @@ -1941,7 +2061,7 @@ bool Type_handler_blob_common:: Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const { - if (func->aggregate_attributes_string(items, nitems)) + if (func->aggregate_attributes_string(func->func_name(), items, nitems)) return true; func->set_handler(blob_type_handler(func->max_length)); return false; diff --git a/sql/sql_type.h b/sql/sql_type.h index d9694c98cb8..a1a2beeb1d1 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -60,7 +60,6 @@ class Item_func_div; class Item_func_mod; class cmp_item; class in_vector; -class Type_std_attributes; class Sort_param; class Arg_comparator; struct st_value; @@ -327,6 +326,133 @@ public: { fix_attributes_temporal(MAX_DATETIME_WIDTH, dec); } + + void count_only_length(Item **item, uint nitems); + void count_octet_length(Item **item, uint nitems); + void count_real_length(Item **item, uint nitems); + void count_decimal_length(Item **item, uint nitems); + bool count_string_length(const char *func_name, Item **item, uint nitems); + uint count_max_decimals(Item **item, uint nitems); + + void aggregate_attributes_int(Item **items, uint nitems) + { + collation.set_numeric(); + count_only_length(items, nitems); + decimals= 0; + } + void aggregate_attributes_real(Item **items, uint nitems) + { + collation.set_numeric(); + count_real_length(items, nitems); + } + void aggregate_attributes_decimal(Item **items, uint nitems) + { + collation.set_numeric(); + count_decimal_length(items, nitems); + } + bool aggregate_attributes_string(const char *func_name, + Item **item, uint nitems) + { + return count_string_length(func_name, item, nitems); + } + void aggregate_attributes_temporal(uint int_part_length, + Item **item, uint nitems) + { + fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); + } + + 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); + + /* + 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, const char *func_name, + 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) + - convert to @@character_set_connection if all arguments are numbers + - allow DERIVATION_NONE + */ + bool agg_arg_charsets_for_string_result(DTCollation &c, const char *func_name, + Item **items, uint nitems, + int item_sep) + { + uint flags= MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_ALLOW_NUMERIC_CONV; + return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); + } + /* + Aggregate arguments for string result, when some comparison + is involved internally, e.g: REPLACE(a,b,c) + - convert to @@character_set_connection if all arguments are numbers + - disallow DERIVATION_NONE + */ + bool agg_arg_charsets_for_string_result_with_comparison(DTCollation &c, + const char *func_name, + Item **items, + uint nitems, + int item_sep) + { + uint flags= MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_ALLOW_NUMERIC_CONV | + MY_COLL_DISALLOW_NONE; + return agg_arg_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, + const char *func_name, + Item **items, uint nitems, + int item_sep) + { + uint flags= MY_COLL_ALLOW_SUPERSET_CONV | + MY_COLL_ALLOW_COERCIBLE_CONV | + MY_COLL_DISALLOW_NONE; + return agg_arg_charsets(c, func_name, items, nitems, flags, item_sep); + } + };