From 48c59f394bb9bd4dfd34be19ff4cf933557eb017 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 24 Mar 2017 17:52:55 +0400 Subject: [PATCH] MDEV-12338 Split Item_type_holder::get_real_type() into virtual Item::real_type_handler() --- sql/item.cc | 134 ++++++++++++------------------------------ sql/item.h | 28 +++++++-- sql/item_sum.h | 8 ++- sql/item_windowfunc.h | 2 - sql/sql_type.cc | 6 +- sql/sql_type.h | 18 ++---- 6 files changed, 70 insertions(+), 126 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index b0337efff9ec3..2f2b773b79502 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5670,6 +5670,25 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return TRUE; } + +const Type_handler *Item_field::real_type_handler() const +{ + /* + Item_field::field_type ask Field_type() but sometimes field return + a different type, like for enum/set, so we need to ask real type. + */ + if (field->is_created_from_null_item) + return &type_handler_null; + /* work around about varchar type field detection */ + enum_field_types type= field->real_type(); + // TODO: We should add Field::real_type_handler() eventually + if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING) + type= MYSQL_TYPE_VAR_STRING; + return Type_handler::get_handler_by_real_type(type); + +} + + /* @brief Mark virtual columns as used in a partitioning expression @@ -10009,7 +10028,7 @@ void Item_cache_row::set_null() Item_type_holder::Item_type_holder(THD *thd, Item *item) :Item(thd, item), - Type_handler_hybrid_real_field_type(get_real_type(item)), + Type_handler_hybrid_field_type(item->real_type_handler()), enum_set_typelib(0) { DBUG_ASSERT(item->fixed); @@ -10024,87 +10043,6 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) } -/** - Find real field type of item. - - @return - type of field which should be created to store item value -*/ - -enum_field_types Item_type_holder::get_real_type(Item *item) -{ - if (item->type() == REF_ITEM) - item= item->real_item(); - switch(item->type()) - { - case FIELD_ITEM: - { - /* - Item_field::field_type ask Field_type() but sometimes field return - a different type, like for enum/set, so we need to ask real type. - */ - Field *field= ((Item_field *) item)->field; - enum_field_types type= field->real_type(); - if (field->is_created_from_null_item) - return MYSQL_TYPE_NULL; - /* work around about varchar type field detection */ - if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING) - return MYSQL_TYPE_VAR_STRING; - return type; - } - case SUM_FUNC_ITEM: - { - /* - Argument of aggregate function sometimes should be asked about field - type - */ - Item_sum *item_sum= (Item_sum *) item; - if (item_sum->keep_field_type()) - return get_real_type(item_sum->get_arg(0)); - break; - } - case FUNC_ITEM: - if (((Item_func *) item)->functype() == Item_func::GUSERVAR_FUNC) - { - /* - There are work around of problem with changing variable type on the - fly and variable always report "string" as field type to get - acceptable information for client in send_field, so we make field - type from expression type. - */ - switch (item->result_type()) { - case STRING_RESULT: - return MYSQL_TYPE_VARCHAR; - case INT_RESULT: - return MYSQL_TYPE_LONGLONG; - case REAL_RESULT: - return MYSQL_TYPE_DOUBLE; - case DECIMAL_RESULT: - return MYSQL_TYPE_NEWDECIMAL; - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); - return MYSQL_TYPE_VARCHAR; - } - } - break; - case TYPE_HOLDER: - /* - Item_type_holder and Item_blob should not appear in this context. - In case they for some reasons do, returning field_type() is wrong anyway. - They must return Item_type_holder::real_field_type() instead, to make - the code in sql_type.cc and sql_type.h happy, as it expectes - Field::real_type()-compatible rather than Field::field_type()-compatible - valies in some places, and may in the future add some asserts preventing - use of field_type() instead of real_type() and the other way around. - */ - DBUG_ASSERT(0); - default: - break; - } - return item->field_type(); -} - /** Find field type which can carry current Item_type_holder type and type of given Item. @@ -10123,14 +10061,13 @@ bool Item_type_holder::join_types(THD *thd, Item *item) uint max_length_orig= max_length; uint decimals_orig= decimals; DBUG_ENTER("Item_type_holder::join_types"); - DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s", - real_field_type(), max_length, decimals, + DBUG_PRINT("info:", ("was type %s len %d, dec %d name %s", + real_type_handler()->name().ptr(), max_length, decimals, (name ? name : ""))); - DBUG_PRINT("info:", ("in type %d len %d, dec %d", - get_real_type(item), + DBUG_PRINT("info:", ("in type %s len %d, dec %d", + item->real_type_handler()->name().ptr(), item->max_length, item->decimals)); - const Type_handler *item_type_handler= - Type_handler::get_handler_by_real_type(get_real_type(item)); + const Type_handler *item_type_handler= item->real_type_handler(); if (aggregate_for_result(item_type_handler)) { my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), @@ -10218,13 +10155,13 @@ bool Item_type_holder::join_types(THD *thd, Item *item) int delta1= max_length_orig - decimals_orig; int delta2= item->max_length - item->decimals; max_length= MY_MAX(delta1, delta2) + decimals; - if (Item_type_holder::real_field_type() == MYSQL_TYPE_FLOAT && + if (Item_type_holder::real_type_handler() == &type_handler_float && max_length > FLT_DIG + 2) { max_length= MAX_FLOAT_STR_LENGTH; decimals= NOT_FIXED_DEC; } - else if (Item_type_holder::real_field_type() == MYSQL_TYPE_DOUBLE && + else if (Item_type_holder::real_type_handler() == &type_handler_double && max_length > DBL_DIG + 2) { max_length= MAX_DOUBLE_STR_LENGTH; @@ -10245,8 +10182,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item) /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ prev_decimal_int_part= decimal_int_part(); - DBUG_PRINT("info", ("become type: %d len: %u dec: %u", - (int) real_field_type(), max_length, (uint) decimals)); + DBUG_PRINT("info", ("become type: %s len: %u dec: %u", + real_type_handler()->name().ptr(), + max_length, (uint) decimals)); DBUG_RETURN(FALSE); } @@ -10269,7 +10207,7 @@ Field *Item_type_holder::make_field_by_type(TABLE *table) uchar *null_ptr= maybe_null ? (uchar*) "" : 0; Field *field; - switch (Item_type_holder::real_field_type()) { + switch (Item_type_holder::real_type_handler()->real_field_type()) { case MYSQL_TYPE_ENUM: DBUG_ASSERT(enum_set_typelib); field= new Field_enum((uchar *) 0, max_length, null_ptr, 0, @@ -10305,8 +10243,8 @@ Field *Item_type_holder::make_field_by_type(TABLE *table) */ void Item_type_holder::get_full_info(Item *item) { - if (Item_type_holder::real_field_type() == MYSQL_TYPE_ENUM || - Item_type_holder::real_field_type() == MYSQL_TYPE_SET) + if (Item_type_holder::real_type_handler() == &type_handler_enum || + Item_type_holder::real_type_handler() == &type_handler_set) { if (item->type() == Item::SUM_FUNC_ITEM && (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC || @@ -10317,11 +10255,11 @@ void Item_type_holder::get_full_info(Item *item) field (or MIN|MAX(enum|set field)) and number of NULL fields */ DBUG_ASSERT((enum_set_typelib && - get_real_type(item) == MYSQL_TYPE_NULL) || + item->real_type_handler() == &type_handler_null) || (!enum_set_typelib && item->real_item()->type() == Item::FIELD_ITEM && - (get_real_type(item->real_item()) == MYSQL_TYPE_ENUM || - get_real_type(item->real_item()) == MYSQL_TYPE_SET) && + (item->real_type_handler() == &type_handler_enum || + item->real_type_handler() == &type_handler_set) && ((Field_enum*)((Item_field *) item->real_item())->field)->typelib)); if (!enum_set_typelib) { diff --git a/sql/item.h b/sql/item.h index d3b1189f80fe3..e7086a5cbb39b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -699,6 +699,10 @@ class Item: public Value_source, { return Type_handler::get_handler_by_field_type(field_type()); } + virtual const Type_handler *real_type_handler() const + { + return type_handler(); + } virtual const Type_handler *cast_to_int_type_handler() const { return type_handler(); @@ -2409,6 +2413,7 @@ class Item_field :public Item_ident { return field->type(); } + const Type_handler *real_type_handler() const; enum_monotonicity_info get_monotonicity_info() const { return MONOTONIC_STRICT_INCREASING; @@ -3355,6 +3360,12 @@ class Item_blob :public Item_partition_func_safe_string { max_length= length; } enum Type type() const { return TYPE_HOLDER; } enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + const Type_handler *real_type_handler() const + { + // Should not be called, Item_blob is used for SHOW purposes only. + DBUG_ASSERT(0); + return &type_handler_varchar; + } Field *create_field_for_schema(THD *thd, TABLE *table) { return tmp_table_field_from_field_type(table, false, true); } }; @@ -4072,6 +4083,8 @@ class Item_ref :public Item_ident { return (*ref)->setup_fast_field_copier(field); } enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } + const Type_handler *real_type_handler() const + { return (*ref)->real_type_handler(); } Field *get_tmp_table_field() { return result_field ? result_field : (*ref)->get_tmp_table_field(); } Item *get_tmp_table_item(THD *thd); @@ -5602,7 +5615,7 @@ class Item_cache_row: public Item_cache single SP/PS execution. */ class Item_type_holder: public Item, - public Type_handler_hybrid_real_field_type + public Type_handler_hybrid_field_type { protected: TYPELIB *enum_set_typelib; @@ -5616,11 +5629,11 @@ class Item_type_holder: public Item, Item_type_holder(THD*, Item*); const Type_handler *type_handler() const - { return Type_handler_hybrid_real_field_type::type_handler(); } + { return Type_handler_hybrid_field_type::type_handler(); } enum_field_types field_type() const - { return Type_handler_hybrid_real_field_type::field_type(); } + { return Type_handler_hybrid_field_type::field_type(); } enum_field_types real_field_type() const - { return Type_handler_hybrid_real_field_type::real_field_type(); } + { return Type_handler_hybrid_field_type::real_field_type(); } enum Item_result result_type () const { /* @@ -5635,7 +5648,11 @@ class Item_type_holder: public Item, As soon as we get BIT as one of the joined types, the result field type cannot be numeric: it's either BIT, or VARBINARY. */ - return Type_handler_hybrid_real_field_type::result_type(); + return Type_handler_hybrid_field_type::result_type(); + } + const Type_handler *real_type_handler() const + { + return Item_type_holder::type_handler(); } enum Type type() const { return TYPE_HOLDER; } @@ -5645,7 +5662,6 @@ class Item_type_holder: public Item, String *val_str(String*); bool join_types(THD *thd, Item *); Field *make_field_by_type(TABLE *table); - static enum_field_types get_real_type(Item *); Field::geometry_type get_geometry_type() const { return geometry_type; }; Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; diff --git a/sql/item_sum.h b/sql/item_sum.h index 3ceb2a04dcca7..ee1c10f9fbe3f 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -456,7 +456,6 @@ class Item_sum :public Item_func_or_sum Updated value is then saved in the field. */ virtual void update_field()=0; - virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } virtual Item *result_item(THD *thd, Field *field); @@ -520,7 +519,7 @@ class Item_sum :public Item_func_or_sum st_select_lex *depended_from() { return (nest_level == aggr_level ? 0 : aggr_sel); } - Item *get_arg(uint i) { return args[i]; } + Item *get_arg(uint i) const { return args[i]; } Item *set_arg(uint i, THD *thd, Item *new_val); uint get_arg_count() const { return arg_count; } @@ -1047,7 +1046,10 @@ class Item_sum_hybrid :public Item_sum, public Type_handler_hybrid_field_type my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); - bool keep_field_type(void) const { return 1; } + const Type_handler *real_type_handler() const + { + return get_arg(0)->real_type_handler(); + } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } enum Item_result result_type () const diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index b4953c8a6ac27..193ac04b315b1 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -303,8 +303,6 @@ class Item_sum_hybrid_simple : public Item_sum, my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); - /* TODO(cvicentiu) copied from Item_sum_hybrid, what does it do? */ - bool keep_field_type(void) const { return 1; } enum Item_result result_type() const { return Type_handler_hybrid_field_type::result_type(); } enum Item_result cmp_type() const diff --git a/sql/sql_type.cc b/sql/sql_type.cc index f9d7586f784e7..67ecd2af45ed7 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -25,7 +25,6 @@ static Type_handler_short type_handler_short; static Type_handler_long type_handler_long; static Type_handler_int24 type_handler_int24; static Type_handler_year type_handler_year; -static Type_handler_float type_handler_float; static Type_handler_time type_handler_time; static Type_handler_time2 type_handler_time2; static Type_handler_date type_handler_date; @@ -39,18 +38,19 @@ static Type_handler_tiny_blob type_handler_tiny_blob; static Type_handler_medium_blob type_handler_medium_blob; static Type_handler_long_blob type_handler_long_blob; static Type_handler_blob type_handler_blob; -static Type_handler_enum type_handler_enum; -static Type_handler_set type_handler_set; Type_handler_null type_handler_null; Type_handler_row type_handler_row; Type_handler_varchar type_handler_varchar; Type_handler_longlong type_handler_longlong; +Type_handler_float type_handler_float; Type_handler_double type_handler_double; Type_handler_newdecimal type_handler_newdecimal; Type_handler_datetime type_handler_datetime; Type_handler_bit type_handler_bit; +Type_handler_enum type_handler_enum; +Type_handler_set type_handler_set; #ifdef HAVE_SPATIAL Type_handler_geometry type_handler_geometry; diff --git a/sql/sql_type.h b/sql/sql_type.h index 963e10a57a75e..189b1b0dc276c 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1450,29 +1450,19 @@ class Type_handler_hybrid_field_type }; -/** - This class is used for Item_type_holder, which preserves real_type. -*/ -class Type_handler_hybrid_real_field_type: - public Type_handler_hybrid_field_type -{ -public: - Type_handler_hybrid_real_field_type(enum_field_types type) - :Type_handler_hybrid_field_type(Type_handler:: - get_handler_by_real_type(type)) - { } -}; - - extern Type_handler_row type_handler_row; extern Type_handler_null type_handler_null; extern Type_handler_varchar type_handler_varchar; extern Type_handler_longlong type_handler_longlong; +extern Type_handler_float type_handler_float; extern Type_handler_double type_handler_double; extern Type_handler_newdecimal type_handler_newdecimal; extern Type_handler_datetime type_handler_datetime; extern Type_handler_longlong type_handler_longlong; extern Type_handler_bit type_handler_bit; +extern Type_handler_enum type_handler_enum; +extern Type_handler_set type_handler_set; + class Type_aggregator {