From 7d0a8832d86b81d62ea6d69d84d3c9101216bad4 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sat, 17 Dec 2016 21:10:59 +0400 Subject: [PATCH] MDEV-11558 Split Item_type_holder::display_length into virtual methods in Type_handler --- sql/item.cc | 64 +++---------------------------------------------- sql/item.h | 31 ++++++++++++++++++++++-- sql/sql_type.cc | 31 ++++++++++++++++++++++++ sql/sql_type.h | 22 +++++++++++++++++ 4 files changed, 85 insertions(+), 63 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index c597eec3a45..68dc86083ff 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10085,12 +10085,12 @@ bool Item_type_holder::join_types(THD *thd, Item *item) if (collation.collation != &my_charset_bin) { max_length= MY_MAX(old_max_chars * collation.collation->mbmaxlen, - display_length(item) / + item->max_display_length() / item->collation.collation->mbmaxlen * collation.collation->mbmaxlen); } else - set_if_bigger(max_length, display_length(item)); + set_if_bigger(max_length, item->max_display_length()); break; } case REAL_RESULT: @@ -10127,7 +10127,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) break; } default: - max_length= MY_MAX(max_length, display_length(item)); + max_length= MY_MAX(max_length, item->max_display_length()); }; maybe_null|= item->maybe_null; get_full_info(item); @@ -10139,64 +10139,6 @@ bool Item_type_holder::join_types(THD *thd, Item *item) DBUG_RETURN(FALSE); } -/** - Calculate lenth for merging result for given Item type. - - @param item Item for length detection - - @return - length -*/ - -uint32 Item_type_holder::display_length(Item *item) -{ - if (item->type() == Item::FIELD_ITEM) - return ((Item_field *)item)->max_disp_length(); - - switch (item->field_type()) - { - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_NEWDECIMAL: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_GEOMETRY: - return item->max_length; - case MYSQL_TYPE_TINY: - return 4; - case MYSQL_TYPE_SHORT: - return 6; - case MYSQL_TYPE_LONG: - return MY_INT32_NUM_DECIMAL_DIGITS; - case MYSQL_TYPE_FLOAT: - return 25; - case MYSQL_TYPE_DOUBLE: - return 53; - case MYSQL_TYPE_NULL: - return 0; - case MYSQL_TYPE_LONGLONG: - return 20; - case MYSQL_TYPE_INT24: - return 8; - default: - DBUG_ASSERT(0); // we should never go there - return 0; - } -} - /** Make temporary table field according collected information about type diff --git a/sql/item.h b/sql/item.h index 0b60e20e0a0..cf915f74a5e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -721,6 +721,34 @@ public: { return Type_handler::string_type_handler(max_length)->field_type(); } + /* + Calculate the maximum length of an expression. + This method is used in data type aggregation for UNION, e.g.: + SELECT 'b' UNION SELECT COALESCE(double_10_3_field) FROM t1; + + The result is usually equal to max_length, except for some numeric types. + In case of the INT, FLOAT, DOUBLE data types Item::max_length and + Item::decimals are ignored, so the returned value depends only on the + data type itself. E.g. for an expression of the DOUBLE(10,3) data type, + the result is always 53 (length 10 and precision 3 do not matter). + + max_length is ignored for these numeric data types because the length limit + means only "expected maximum length", it is not a hard limit, so it does + not impose any data truncation. E.g. a column of the type INT(4) can + normally store big values up to 2147483647 without truncation. When we're + aggregating such column for UNION it's important to create a long enough + result column, not to lose any data. + + For detailed behaviour of various data types see implementations of + the corresponding Type_handler_xxx::max_display_length(). + + Note, Item_field::max_display_length() overrides this to get + max_display_length() from the underlying field. + */ + virtual uint32 max_display_length() const + { + return type_handler()->max_display_length(this); + } Item_cache* get_cache(THD *thd) const { return type_handler()->Item_get_cache(thd, this); @@ -2459,7 +2487,7 @@ public: Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *); Item *replace_equal_field(THD *thd, uchar *arg); - inline uint32 max_disp_length() { return field->max_display_length(); } + uint32 max_display_length() const { return field->max_display_length(); } Item_field *field_for_view_update() { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *update_value_transformer(THD *thd, uchar *select_arg); @@ -5545,7 +5573,6 @@ public: String *val_str(String*); bool join_types(THD *thd, Item *); Field *make_field_by_type(TABLE *table); - static uint32 display_length(Item *item); 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/sql_type.cc b/sql/sql_type.cc index fc34c7cca95..cc87c8e14e4 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -695,6 +695,37 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table, /*************************************************************************/ +uint32 Type_handler_decimal_result::max_display_length(const Item *item) const +{ + return item->max_length; +} + + +uint32 Type_handler_temporal_result::max_display_length(const Item *item) const +{ + return item->max_length; +} + + +uint32 Type_handler_string_result::max_display_length(const Item *item) const +{ + return item->max_length; +} + + +uint32 Type_handler_year::max_display_length(const Item *item) const +{ + return item->max_length; +} + + +uint32 Type_handler_bit::max_display_length(const Item *item) const +{ + return item->max_length; +} + +/*************************************************************************/ + int Type_handler_time_common::Item_save_in_field(Item *item, Field *field, bool no_conversions) const { diff --git a/sql/sql_type.h b/sql/sql_type.h index 6a694dfe661..d9bc0eb94a2 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -291,6 +291,7 @@ public: const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const= 0; + virtual uint32 max_display_length(const Item *item) const= 0; virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0; @@ -372,6 +373,11 @@ public: { DBUG_ASSERT(0); } + uint32 max_display_length(const Item *item) const + { + DBUG_ASSERT(0); + return 0; + } int Item_save_in_field(Item *item, Field *field, bool no_conversions) const { DBUG_ASSERT(0); @@ -493,6 +499,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + uint32 max_display_length(const Item *item) const; 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; @@ -564,6 +571,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + uint32 max_display_length(const Item *item) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; bool set_comparator_func(Arg_comparator *cmp) const; bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const; @@ -600,6 +608,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + uint32 max_display_length(const Item *item) const; 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; @@ -649,6 +658,7 @@ class Type_handler_tiny: public Type_handler_int_result public: virtual ~Type_handler_tiny() {} enum_field_types field_type() const { return MYSQL_TYPE_TINY; } + uint32 max_display_length(const Item *item) const { return 4; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; }; @@ -659,6 +669,7 @@ class Type_handler_short: public Type_handler_int_result public: virtual ~Type_handler_short() {} enum_field_types field_type() const { return MYSQL_TYPE_SHORT; } + uint32 max_display_length(const Item *item) const { return 6; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; }; @@ -669,6 +680,10 @@ class Type_handler_long: public Type_handler_int_result public: virtual ~Type_handler_long() {} enum_field_types field_type() const { return MYSQL_TYPE_LONG; } + uint32 max_display_length(const Item *item) const + { + return MY_INT32_NUM_DECIMAL_DIGITS; + } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; }; @@ -679,6 +694,7 @@ class Type_handler_longlong: public Type_handler_int_result public: virtual ~Type_handler_longlong() {} enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + uint32 max_display_length(const Item *item) const { return 20; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; }; @@ -689,6 +705,7 @@ class Type_handler_int24: public Type_handler_int_result public: virtual ~Type_handler_int24() {} enum_field_types field_type() const { return MYSQL_TYPE_INT24; } + uint32 max_display_length(const Item *item) const { return 8; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; @@ -699,6 +716,7 @@ class Type_handler_year: public Type_handler_int_result public: virtual ~Type_handler_year() {} enum_field_types field_type() const { return MYSQL_TYPE_YEAR; } + uint32 max_display_length(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; @@ -709,6 +727,7 @@ class Type_handler_bit: public Type_handler_int_result public: virtual ~Type_handler_bit() {} enum_field_types field_type() const { return MYSQL_TYPE_BIT; } + uint32 max_display_length(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; @@ -719,6 +738,7 @@ class Type_handler_float: public Type_handler_real_result public: virtual ~Type_handler_float() {} enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; } + uint32 max_display_length(const Item *item) const { return 25; } Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -730,6 +750,7 @@ class Type_handler_double: public Type_handler_real_result public: virtual ~Type_handler_double() {} enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + uint32 max_display_length(const Item *item) const { return 53; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; }; @@ -860,6 +881,7 @@ class Type_handler_null: public Type_handler_string_result public: virtual ~Type_handler_null() {} enum_field_types field_type() const { return MYSQL_TYPE_NULL; } + uint32 max_display_length(const Item *item) const { return 0; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; };