From d8c695ead448ae36be7b98f586a67e858c270147 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 27 Dec 2016 09:32:54 +0400 Subject: [PATCH] MDEV-11615 Split Item_hybrid_func::fix_attributes into virtual methods in Type_handler --- sql/item_cmpfunc.cc | 59 +++++++++++------------------------- sql/item_func.cc | 39 ++++-------------------- sql/item_func.h | 48 +++++++++++++++++++++++++---- sql/sql_type.cc | 73 +++++++++++++++++++++++++++++++++++++++++++++ sql/sql_type.h | 67 +++++++++++++++++++++++++++++++++-------- 5 files changed, 193 insertions(+), 93 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a81dd4694a9..f4bd211c714 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3108,25 +3108,19 @@ void Item_func_case::fix_length_and_dec() set_handler_by_field_type(agg_field_type(agg, nagg, true)); - if (Item_func_case::result_type() == STRING_RESULT) - { - if (count_string_result_length(Item_func_case::field_type(), agg, nagg)) - return; - /* - Copy all THEN and ELSE items back to args[] array. - Some of the items might have been changed to Item_func_conv_charset. - */ - for (nagg= 0 ; nagg < ncases / 2 ; nagg++) - change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg]); + if (fix_attributes(agg, nagg)) + return; + + /* + Copy all modified THEN and ELSE items back to args[] array. + Some of the items might have been changed to Item_func_conv_charset. + */ + for (nagg= 0 ; nagg < ncases / 2 ; nagg++) + change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg]); + + if (else_expr_num != -1) + change_item_tree_if_needed(thd, &args[else_expr_num], agg[nagg++]); - if (else_expr_num != -1) - change_item_tree_if_needed(thd, &args[else_expr_num], agg[nagg++]); - } - else - { - fix_attributes(agg, nagg); - } - /* Aggregate first expression and all WHEN expression types and collations when string comparison @@ -3405,31 +3399,12 @@ my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) } -void Item_hybrid_func::fix_attributes(Item **items, uint nitems) +bool Item_hybrid_func::fix_attributes(Item **items, uint nitems) { - switch (Item_hybrid_func::result_type()) { - case STRING_RESULT: - if (count_string_result_length(Item_hybrid_func::field_type(), - items, nitems)) - return; - break; - case DECIMAL_RESULT: - collation.set_numeric(); - count_decimal_length(items, nitems); - break; - case REAL_RESULT: - collation.set_numeric(); - count_real_length(items, nitems); - break; - case INT_RESULT: - collation.set_numeric(); - count_only_length(items, nitems); - decimals= 0; - break; - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); - } + bool rc= Item_hybrid_func::type_handler()-> + Item_hybrid_func_fix_attributes(current_thd, this, items, nitems); + DBUG_ASSERT(!rc || current_thd->is_error()); + return rc; } /**************************************************************************** diff --git a/sql/item_func.cc b/sql/item_func.cc index 716c47eec8b..d1c373722e4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -567,30 +567,6 @@ void Item_udf_func::fix_num_length_and_dec() } -/** - Count max_length and decimals for temporal functions. - - @param item Argument array - @param nitems Number of arguments in the array. - - @retval False on success, true on error. -*/ -void Item_func::count_datetime_length(enum_field_types field_type_arg, - Item **item, uint nitems) -{ - unsigned_flag= 0; - decimals= 0; - if (field_type_arg != MYSQL_TYPE_DATE) - { - for (uint i= 0; i < nitems; i++) - set_if_bigger(decimals, item[i]->decimals); - } - set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); - uint len= decimals ? (decimals + 1) : 0; - len+= mysql_temporal_int_part_length(field_type_arg); - fix_char_length(len); -} - /** Set max_length/decimals of function if function is fixed point and result length/precision depends on argument ones. @@ -665,7 +641,7 @@ void Item_func::count_real_length(Item **items, uint nitems) /** - Calculate max_length and decimals for STRING_RESULT functions. + Calculate max_length and decimals for string functions. @param field_type Field type. @param items Argument array. @@ -673,18 +649,13 @@ void Item_func::count_real_length(Item **items, uint nitems) @retval False on success, true on error. */ -bool Item_func::count_string_result_length(enum_field_types field_type_arg, - Item **items, uint nitems) +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 (is_temporal_type(field_type_arg)) - count_datetime_length(field_type_arg, items, nitems); - else - { - count_only_length(items, nitems); - decimals= max_length ? NOT_FIXED_DEC : 0; - } + count_only_length(items, nitems); + decimals= max_length ? NOT_FIXED_DEC : 0; return false; } diff --git a/sql/item_func.h b/sql/item_func.h index dbe23e372e3..458be997906 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -45,11 +45,49 @@ protected: void count_only_length(Item **item, uint nitems); void count_real_length(Item **item, uint nitems); void count_decimal_length(Item **item, uint nitems); - void count_datetime_length(enum_field_types field_type, - Item **item, uint nitems); - bool count_string_result_length(enum_field_types field_type, - 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; + } 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 set_attributes_temporal(uint int_part_length, uint dec) + { + collation.set_numeric(); + unsigned_flag= 0; + decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS); + uint length= decimals + int_part_length + (dec ? 1 : 0); + fix_char_length(length); + } + void aggregate_attributes_temporal(uint int_part_length, + Item **item, uint nitems) + { + set_attributes_temporal(int_part_length, count_max_decimals(item, nitems)); + } + table_map not_null_tables_cache; enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC, @@ -389,7 +427,7 @@ class Item_hybrid_func: public Item_func, public Type_handler_hybrid_field_type { protected: - void fix_attributes(Item **item, uint nitems); + bool fix_attributes(Item **item, uint nitems); public: Item_hybrid_func(THD *thd): Item_func(thd) { } Item_hybrid_func(THD *thd, Item *a): Item_func(thd, a) { } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index b7dd4c23ade..0f6424e8ab8 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -888,6 +888,79 @@ Type_handler_temporal_result::Item_get_cache(THD *thd, const Item *item) const return new (thd->mem_root) Item_cache_temporal(thd, item->field_type()); } +/*************************************************************************/ + +bool Type_handler_int_result:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->aggregate_attributes_int(items, nitems); + return false; +} + + +bool Type_handler_real_result:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->aggregate_attributes_real(items, nitems); + return false; +} + + +bool Type_handler_decimal_result:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->aggregate_attributes_decimal(items, nitems); + return false; +} + + +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); +} + + +bool Type_handler_date_common:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->set_attributes_temporal(MAX_DATE_WIDTH, 0); + return false; +} + + +bool Type_handler_time_common:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->aggregate_attributes_temporal(MIN_TIME_WIDTH, items, nitems); + return false; +} + + +bool Type_handler_datetime_common:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems); + return false; +} + + +bool Type_handler_timestamp_common:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems); + return false; +} + + /*************************************************************************/ /** diff --git a/sql/sql_type.h b/sql/sql_type.h index 1f82f5bbeb0..e1a588377cc 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -28,6 +28,7 @@ class Item; class Item_cache; class Item_sum_hybrid; class Item_func_hex; +class Item_hybrid_func; class Item_func_hybrid_field_type; class Item_func_between; class Item_func_in; @@ -298,6 +299,9 @@ public: bool no_conversions) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; virtual bool set_comparator_func(Arg_comparator *cmp) const= 0; + virtual bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, + uint nitems) const= 0; virtual bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const= 0; virtual String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const= 0; @@ -391,6 +395,12 @@ public: } Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const + { + DBUG_ASSERT(0); + return true; + } bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const { DBUG_ASSERT(0); @@ -473,6 +483,8 @@ public: int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, @@ -513,6 +525,8 @@ public: int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, @@ -551,6 +565,8 @@ public: int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, @@ -626,6 +642,8 @@ public: int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *, @@ -778,6 +796,8 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const Type_handler *type_handler_for_comparison() const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const; }; @@ -813,62 +833,85 @@ public: }; -class Type_handler_date: public Type_handler_temporal_with_date +class Type_handler_date_common: public Type_handler_temporal_with_date +{ +public: + virtual ~Type_handler_date_common() {} + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; +}; + +class Type_handler_date: public Type_handler_date_common { public: virtual ~Type_handler_date() {} - enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_newdate: public Type_handler_temporal_with_date +class Type_handler_newdate: public Type_handler_date_common { public: virtual ~Type_handler_newdate() {} - enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_datetime: public Type_handler_temporal_with_date +class Type_handler_datetime_common: public Type_handler_temporal_with_date +{ +public: + virtual ~Type_handler_datetime_common() {} + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; +}; + + +class Type_handler_datetime: public Type_handler_datetime_common { public: virtual ~Type_handler_datetime() {} - enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_datetime2: public Type_handler_temporal_with_date +class Type_handler_datetime2: public Type_handler_datetime_common { public: virtual ~Type_handler_datetime2() {} - enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_timestamp: public Type_handler_temporal_with_date +class Type_handler_timestamp_common: public Type_handler_temporal_with_date +{ +public: + virtual ~Type_handler_timestamp_common() {} + enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; } + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; +}; + + +class Type_handler_timestamp: public Type_handler_timestamp_common { public: virtual ~Type_handler_timestamp() {} - enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; -class Type_handler_timestamp2: public Type_handler_temporal_with_date +class Type_handler_timestamp2: public Type_handler_timestamp_common { public: virtual ~Type_handler_timestamp2() {} - enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; } enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const;