From 3cd7690a5e79d73ccb3f8e1e071c523e7c6ef9b1 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 24 Apr 2017 10:57:31 +0400 Subject: [PATCH 01/20] MDEV-12568 Add Type_handler::subquery_type_allows_materialization() --- sql/item.cc | 7 +++--- sql/item_func.cc | 8 +++---- sql/item_timefunc.cc | 4 ++-- sql/opt_subselect.cc | 29 ++---------------------- sql/sql_type.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++ sql/sql_type.h | 53 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 37 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index d5d8e39ea54..1889ecd6f39 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9711,9 +9711,8 @@ Item_cache_temporal::Item_cache_temporal(THD *thd, enum_field_types field_type_arg): Item_cache_int(thd, field_type_arg) { - if (mysql_type_to_time_type(Item_cache_temporal::field_type()) == - MYSQL_TIMESTAMP_ERROR) - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + if (mysql_timestamp_type() == MYSQL_TIMESTAMP_ERROR) + set_handler(&type_handler_datetime2); } @@ -9821,7 +9820,7 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) } unpack_time(value, ltime); - ltime->time_type= mysql_type_to_time_type(field_type()); + ltime->time_type= mysql_timestamp_type(); if (ltime->time_type == MYSQL_TIMESTAMP_TIME) { ltime->hour+= (ltime->month*32+ltime->day)*24; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4f3cc54b42e..00e0c8caa07 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -890,7 +890,7 @@ String *Item_func_hybrid_field_type::val_str_from_date_op(String *str) if (date_op_with_null_check(<ime) || (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH))) return (String *) 0; - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); str->length(my_TIME_to_str(<ime, const_cast(str->ptr()), decimals)); str->set_charset(&my_charset_bin); DBUG_ASSERT(!null_value); @@ -902,7 +902,7 @@ double Item_func_hybrid_field_type::val_real_from_date_op() MYSQL_TIME ltime; if (date_op_with_null_check(<ime)) return 0; - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); return TIME_to_double(<ime); } longlong Item_func_hybrid_field_type::val_int_from_date_op() @@ -910,7 +910,7 @@ longlong Item_func_hybrid_field_type::val_int_from_date_op() MYSQL_TIME ltime; if (date_op_with_null_check(<ime)) return 0; - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); return TIME_to_ulonglong(<ime); } @@ -923,7 +923,7 @@ Item_func_hybrid_field_type::val_decimal_from_date_op(my_decimal *dec) my_decimal_set_zero(dec); return 0; } - ltime.time_type= mysql_type_to_time_type(field_type()); + ltime.time_type= mysql_timestamp_type(); return date2my_decimal(<ime, dec); } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d637fa12ad1..a7f131f384b 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1532,7 +1532,7 @@ String *Item_temporal_hybrid_func::val_str_ascii(String *str) /* Check that the returned timestamp type matches to the function type */ DBUG_ASSERT(field_type() == MYSQL_TYPE_STRING || ltime.time_type == MYSQL_TIMESTAMP_NONE || - mysql_type_to_time_type(field_type()) == ltime.time_type); + ltime.time_type == mysql_timestamp_type()); return str; } @@ -3226,7 +3226,7 @@ void Item_func_str_to_date::fix_length_and_dec() } } } - cached_timestamp_type= mysql_type_to_time_type(field_type()); + cached_timestamp_type= mysql_timestamp_type(); } diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index b5808ea9315..b18fb8f2ae5 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -843,34 +843,9 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM && inner->real_item()->type() == Item::FIELD_ITEM); total_key_length += inner->max_length; - if (outer->cmp_type() != inner->cmp_type()) + if (!inner->type_handler()->subquery_type_allows_materialization(inner, + outer)) DBUG_RETURN(FALSE); - switch (outer->cmp_type()) { - case STRING_RESULT: - if (!(outer->collation.collation == inner->collation.collation)) - DBUG_RETURN(FALSE); - // Materialization does not work with BLOB columns - if (inner->field_type() == MYSQL_TYPE_BLOB || - inner->field_type() == MYSQL_TYPE_GEOMETRY) - DBUG_RETURN(FALSE); - /* - Materialization also is unable to work when create_tmp_table() will - create a blob column because item->max_length is too big. - The following check is copied from Item::make_string_field(): - */ - if (inner->too_big_for_varchar()) - { - DBUG_RETURN(FALSE); - } - break; - case TIME_RESULT: - if (mysql_type_to_time_type(outer->field_type()) != - mysql_type_to_time_type(inner->field_type())) - DBUG_RETURN(FALSE); - default: - /* suitable for materialization */ - break; - } } /* diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 43c27372546..a34619b5e36 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3187,3 +3187,57 @@ uint Type_handler_string_result::Item_temporal_precision(Item *item, } /***************************************************************************/ + +bool Type_handler_real_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == REAL_RESULT); + return outer->cmp_type() == REAL_RESULT; +} + + +bool Type_handler_int_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == INT_RESULT); + return outer->cmp_type() == INT_RESULT; +} + + +bool Type_handler_decimal_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == DECIMAL_RESULT); + return outer->cmp_type() == DECIMAL_RESULT; +} + + +bool Type_handler_string_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == STRING_RESULT); + return outer->cmp_type() == STRING_RESULT && + outer->collation.collation == inner->collation.collation && + /* + Materialization also is unable to work when create_tmp_table() will + create a blob column because item->max_length is too big. + The following test is copied from Item::make_string_field(): + */ + !inner->too_big_for_varchar(); +} + + +bool Type_handler_temporal_result:: + subquery_type_allows_materialization(const Item *inner, + const Item *outer) const +{ + DBUG_ASSERT(inner->cmp_type() == TIME_RESULT); + return mysql_timestamp_type() == + outer->type_handler()->mysql_timestamp_type(); +} + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 21b8e75db11..0652e56da4f 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -367,6 +367,10 @@ public: virtual enum_field_types real_field_type() const { return field_type(); } virtual Item_result result_type() const= 0; virtual Item_result cmp_type() const= 0; + virtual enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_ERROR; + } /** Prepared statement long data: Check whether this parameter data type is compatible with long data. @@ -480,6 +484,9 @@ public: Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const= 0; + virtual bool + subquery_type_allows_materialization(const Item *inner, + const Item *outer) 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, @@ -605,6 +612,12 @@ public: return ROW_RESULT; } const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const + { + DBUG_ASSERT(0); + return false; + } Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const { DBUG_ASSERT(0); @@ -834,6 +847,8 @@ public: Item_result cmp_type() const { return REAL_RESULT; } virtual ~Type_handler_real_result() {} const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const; void sortlength(THD *thd, @@ -889,6 +904,8 @@ public: Item_result cmp_type() const { return DECIMAL_RESULT; } virtual ~Type_handler_decimal_result() {}; const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const; @@ -943,6 +960,8 @@ public: Item_result cmp_type() const { return INT_RESULT; } virtual ~Type_handler_int_result() {} const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const; Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const; @@ -1005,6 +1024,8 @@ public: Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) 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; @@ -1081,6 +1102,8 @@ public: Item *target_expr, Item *target_value, Item_bool_func2 *source, Item *source_expr, Item *source_const) const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) 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, @@ -1278,6 +1301,10 @@ public: virtual ~Type_handler_time_common() { } const Name name() const { return m_name_time; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_TIME; + } const Type_handler *type_handler_for_comparison() const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const; @@ -1325,6 +1352,10 @@ public: virtual ~Type_handler_date_common() {} const Name name() const { return m_name_date; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_DATE; + } String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; @@ -1355,6 +1386,10 @@ public: virtual ~Type_handler_datetime_common() {} const Name name() const { return m_name_datetime; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_DATETIME; + } String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; @@ -1387,6 +1422,10 @@ public: virtual ~Type_handler_timestamp_common() {} const Name name() const { return m_name_timestamp; } enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return MYSQL_TIMESTAMP_DATETIME; + } String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; @@ -1480,6 +1519,11 @@ class Type_handler_blob_common: public Type_handler_string_result { public: virtual ~Type_handler_blob_common() { } + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const + { + return false; // Materialization does not work with BLOB columns + } bool is_param_long_data_type() const { return true; } }; @@ -1542,6 +1586,11 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } bool is_param_long_data_type() const { return true; } const Type_handler *type_handler_for_comparison() const; + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer) const + { + return false; // Materialization does not work with GEOMETRY columns + } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; bool is_traditional_type() const @@ -1628,6 +1677,10 @@ public: } Item_result result_type() const { return m_type_handler->result_type(); } Item_result cmp_type() const { return m_type_handler->cmp_type(); } + enum_mysql_timestamp_type mysql_timestamp_type() const + { + return m_type_handler->mysql_timestamp_type(); + } void set_handler(const Type_handler *other) { m_type_handler= other; From 791374354c9f11fde2325777276522cdd71679c2 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 24 Apr 2017 12:09:25 +0400 Subject: [PATCH 02/20] MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler - Adding Type_handler::make_table_field() and moving pieces of the code from Item::tmp_table_field_from_field_type() to virtual implementations for various type handlers. - Adding a new Type_all_attributes, to access to Item's extended attributes, such as decimal_precision() and geometry_type(). - Adding a new class Record_addr, to pass record related information to Type_handler methods (ptr, null_ptr and null_bit) as a single structure. Note, later it will possibly be extended for BIT-alike field purposes, by adding new members (bit_ptr_arg, bit_ofs_arg). - Moving the code from Field_new_decimal::create_from_item() to Type_handler_newdecimal::make_table_field(). - Removing Field_new_decimal() and Field_geom() helper constructor variants that were used for temporary field creation. - Adding Item_field::type_handler(), Field::type_handler() and Field_blob::type_handler() to return correct type handlers for blob variants, according to Field_blob::packlength. - Adding Type_handler_blob_common, as a common parent for Type_handler_tiny_blob, Type_handler_blob, Type_handler_medium_blob and Type_handler_long_blob. - Implementing Type_handler_blob_common::Item_hybrid_func_fix_attributes(). It's needed for cases when TEXT variants of different character sets are mixed in LEAST, GREATEST, CASE and its abreviations (IF, IFNULL, COALESCE), e.g.: CREATE TABLE t1 ( a TINYTEXT CHARACTER SET latin1, b TINYTEXT CHARACTER SET utf8 ); CREATE TABLE t2 AS SELECT COALESCE(a,b) FROM t1; Type handler aggregation returns TINYTEXT as a common data type for the two columns. But as conversion from latin1 to utf8 happens for "a", the maximum possible length of "a" grows from 255 to 255*3. Type_handler_blob_common::Item_hybrid_func_fix_attributes() makes sure to update the blob type handler according to max_length. - Adding Type_handler::blob_type_handler(uint max_octet_length). - Adding a few m_type_aggregator_for_result.add() pairs, because now Item_xxx::type_handler() can return pointers to type_handler_tiny_blob, type_handler_blob, type_handler_medium_blob, type_handler_long_blob. Before the patch only type_handler_blob was possible result of type_handler(). - Making type_handler_tiny_blob, type_handler_blob, type_handler_medium_blob, type_handler_long_blob public. - Removing the condition in Item_sum_avg::create_tmp_field() checking Item_sum_avg::result_type() against DECIMAL_RESULT. Now both REAL_RESULT and DECIMAL_RESULT are symmetrically handled by tmp_table_field_from_field_type(). - Removing Item_geometry_func::create_field_for_create_select(), as the inherited version perfectly works. - Fixing Item_func_as_wkb::field_type() to return MYSQL_TYPE_LONG_BLOB rather than MYSQL_TYPE_BLOB. It's needed to make sure that tmp_table_field_from_field_type() creates a LONGBLOB field for AsWKB(). - Fixing Item_func_as_wkt::fix_length_and_dec() to set max_length to UINT32_MAX rather than MAX_BLOB_WIDTH, to make sure that tmp_table_field_from_field_type() creates a LONGTEXT field for AsWKT(). - Removing Item_func_set_user_var::create_field_for_create_select(), as the inherited version works fine. - Adding Item_func_get_user_var::create_field_for_create_select() to make sure that "CREATE TABLE t1 AS SELECT @string_user variable" always creates a field of LONGTEXT/LONGBLOB type. - Item_func_ifnull::create_field_for_create_select() behavior has changed. Before the patch it passed set_blob_packflag=false, which meant to create LONGBLOB for all blob variants. Now it takes into account max_length, which gives better column data types for: CREATE TABLE t2 AS SELECT IFNULL(blob_column1, blob_column2) FROM t1; - Fixing Item_func_nullif::fix_length_and_dec() to use set_handler(args[2]->type_handler()) instead of set_handler_by_field_type(args[2]->field_type()). This is needed to distinguish between BLOB variants. - Implementing Item_blob::type_handler(), to make sure to create proper BLOB field variant, according to max_length, for queries like: CREATE TABLE t1 AS SELECT some_blob_field FROM INFORMATION_SCHEMA.SOME_TABLE; - Fixing Item_field::real_type_handler() to make sure that the code aggregating fields for UNION gets a proper BLOB variant type handler from fields. - Adding a special code into Item_type_holder::make_field_by_type(), to make sure that after aggregating field types it also properly takes into account max_length when mixing TEXT variants of different character sets and chooses a proper TEXT variant: CREATE TABLE t1 ( a TINYTEXT CHARACTER SET latin1, b TINYTEXT CHARACTER SET utf8 ); CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1; - Adding tests, for better coverage of IFNULL, NULLIF, UNION. - The fact that tmp_table_field_from_field_type() now takes into account BLOB variants (instead of always creating LONGBLOB), tests results for WEIGHT_STRING() and NULLIF() and UNION have become more precise. --- mysql-test/r/create.result | 24 +- mysql-test/r/func_weight_string.result | 2 +- mysql-test/r/gis.result | 2 +- mysql-test/r/null.result | 304 +++++++++++++-- mysql-test/r/union.result | 22 ++ mysql-test/suite/innodb_gis/r/1.result | 2 +- mysql-test/suite/innodb_gis/r/gis.result | 2 +- mysql-test/t/create.test | 16 + mysql-test/t/null.test | 135 ++++++- mysql-test/t/union.test | 16 + sql/field.cc | 65 +--- sql/field.h | 25 +- sql/item.cc | 125 +----- sql/item.h | 25 +- sql/item_cmpfunc.cc | 2 +- sql/item_cmpfunc.h | 2 +- sql/item_func.cc | 4 +- sql/item_func.h | 18 +- sql/item_geofunc.cc | 13 +- sql/item_geofunc.h | 3 +- sql/item_sum.cc | 20 +- sql/item_timefunc.h | 4 +- sql/sql_select.cc | 10 +- sql/sql_show.cc | 2 +- sql/sql_table.cc | 2 +- sql/sql_type.cc | 459 ++++++++++++++++++++++- sql/sql_type.h | 186 +++++++++ 27 files changed, 1213 insertions(+), 277 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 1f032faaa40..1a3289b2618 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -488,13 +488,35 @@ d date YES NULL e varchar(1) YES NULL f datetime YES NULL g time YES NULL -h longblob YES NULL +h blob YES NULL dd time YES NULL select * from t2; a b c d e f g h dd 1 -7 7 2000-01-01 b 2000-01-01 00:00:00 05:04:03 yet another binary data 02:00:00 2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data 02:00:00 drop table t1, t2; +CREATE TABLE t1 ( +c_tinytext tinytext, +c_text text, +c_mediumtext mediumtext, +c_longtext longtext +); +CREATE TABLE t2 AS SELECT +ifnull(c_tinytext, CAST('yet another binary data' AS BINARY)), +ifnull(c_text, CAST('yet another binary data' AS BINARY)), +ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY)), +ifnull(c_longtext, CAST('yet another binary data' AS BINARY)) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `ifnull(c_tinytext, CAST('yet another binary data' AS BINARY))` tinyblob DEFAULT NULL, + `ifnull(c_text, CAST('yet another binary data' AS BINARY))` blob DEFAULT NULL, + `ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY))` mediumblob DEFAULT NULL, + `ifnull(c_longtext, CAST('yet another binary data' AS BINARY))` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, l datetime, m enum('a','b'), n set('a','b'), o char(10)); create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1; show create table t2; diff --git a/mysql-test/r/func_weight_string.result b/mysql-test/r/func_weight_string.result index 04fd9962218..5fa78c861a9 100644 --- a/mysql-test/r/func_weight_string.result +++ b/mysql-test/r/func_weight_string.result @@ -57,7 +57,7 @@ create table t1 select weight_string(repeat('t',66000)) as w; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `w` longblob DEFAULT NULL + `w` mediumblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; select weight_string(NULL); diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 77150ee3142..43de7d2e7d6 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -709,7 +709,7 @@ def test t1 t1 g g 255 4294967295 0 Y 144 0 63 g select asbinary(g) from t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def asbinary(g) 252 4294967295 0 Y 128 0 63 +def asbinary(g) 251 4294967295 0 Y 128 0 63 asbinary(g) drop table t1; create table t1 (a TEXT, b GEOMETRY NOT NULL, SPATIAL KEY(b)); diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 0ff5c3243d8..8bbdfb2f90b 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -575,8 +575,14 @@ c_float FLOAT, c_double DOUBLE, c_decimal103 DECIMAL(10,3), c_varchar10 VARCHAR(10), +c_tinytext TINYTEXT, c_text TEXT, +c_mediumtext MEDIUMTEXT, +c_longtext LONGTEXT, +c_tinyblob TINYBLOB, c_blob BLOB, +c_mediumblob MEDIUMBLOB, +c_longblob LONGBLOB, c_enum ENUM('one','two','tree'), c_datetime3 DATETIME(3), c_timestamp3 TIMESTAMP(3), @@ -899,6 +905,45 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; CREATE TABLE t2 AS SELECT +NULLIF(c_tinytext, 1), +NULLIF(c_tinytext, c_smallint), +NULLIF(c_tinytext, c_tinyint), +NULLIF(c_tinytext, c_int), +NULLIF(c_tinytext, c_bigint), +NULLIF(c_tinytext, c_float), +NULLIF(c_tinytext, c_double), +NULLIF(c_tinytext, c_decimal103), +NULLIF(c_tinytext, c_varchar10), +NULLIF(c_tinytext, c_text), +NULLIF(c_tinytext, c_blob), +NULLIF(c_tinytext, c_enum), +NULLIF(c_tinytext, c_datetime3), +NULLIF(c_tinytext, c_timestamp3), +NULLIF(c_tinytext, c_date), +NULLIF(c_tinytext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_tinytext, 1)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_smallint)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_tinyint)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_int)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_bigint)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_float)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_double)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_decimal103)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_varchar10)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_text)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_blob)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_enum)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_datetime3)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_timestamp3)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_date)` tinytext DEFAULT NULL, + `NULLIF(c_tinytext, c_time)` tinytext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT NULLIF(c_text, 1), NULLIF(c_text, c_smallint), NULLIF(c_text, c_tinyint), @@ -919,22 +964,139 @@ FROM t1; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `NULLIF(c_text, 1)` longtext DEFAULT NULL, - `NULLIF(c_text, c_smallint)` longtext DEFAULT NULL, - `NULLIF(c_text, c_tinyint)` longtext DEFAULT NULL, - `NULLIF(c_text, c_int)` longtext DEFAULT NULL, - `NULLIF(c_text, c_bigint)` longtext DEFAULT NULL, - `NULLIF(c_text, c_float)` longtext DEFAULT NULL, - `NULLIF(c_text, c_double)` longtext DEFAULT NULL, - `NULLIF(c_text, c_decimal103)` longtext DEFAULT NULL, - `NULLIF(c_text, c_varchar10)` longtext DEFAULT NULL, - `NULLIF(c_text, c_text)` longtext DEFAULT NULL, - `NULLIF(c_text, c_blob)` longtext DEFAULT NULL, - `NULLIF(c_text, c_enum)` longtext DEFAULT NULL, - `NULLIF(c_text, c_datetime3)` longtext DEFAULT NULL, - `NULLIF(c_text, c_timestamp3)` longtext DEFAULT NULL, - `NULLIF(c_text, c_date)` longtext DEFAULT NULL, - `NULLIF(c_text, c_time)` longtext DEFAULT NULL + `NULLIF(c_text, 1)` text DEFAULT NULL, + `NULLIF(c_text, c_smallint)` text DEFAULT NULL, + `NULLIF(c_text, c_tinyint)` text DEFAULT NULL, + `NULLIF(c_text, c_int)` text DEFAULT NULL, + `NULLIF(c_text, c_bigint)` text DEFAULT NULL, + `NULLIF(c_text, c_float)` text DEFAULT NULL, + `NULLIF(c_text, c_double)` text DEFAULT NULL, + `NULLIF(c_text, c_decimal103)` text DEFAULT NULL, + `NULLIF(c_text, c_varchar10)` text DEFAULT NULL, + `NULLIF(c_text, c_text)` text DEFAULT NULL, + `NULLIF(c_text, c_blob)` text DEFAULT NULL, + `NULLIF(c_text, c_enum)` text DEFAULT NULL, + `NULLIF(c_text, c_datetime3)` text DEFAULT NULL, + `NULLIF(c_text, c_timestamp3)` text DEFAULT NULL, + `NULLIF(c_text, c_date)` text DEFAULT NULL, + `NULLIF(c_text, c_time)` text DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_mediumtext, 1), +NULLIF(c_mediumtext, c_smallint), +NULLIF(c_mediumtext, c_tinyint), +NULLIF(c_mediumtext, c_int), +NULLIF(c_mediumtext, c_bigint), +NULLIF(c_mediumtext, c_float), +NULLIF(c_mediumtext, c_double), +NULLIF(c_mediumtext, c_decimal103), +NULLIF(c_mediumtext, c_varchar10), +NULLIF(c_mediumtext, c_text), +NULLIF(c_mediumtext, c_blob), +NULLIF(c_mediumtext, c_enum), +NULLIF(c_mediumtext, c_datetime3), +NULLIF(c_mediumtext, c_timestamp3), +NULLIF(c_mediumtext, c_date), +NULLIF(c_mediumtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_mediumtext, 1)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_smallint)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_tinyint)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_int)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_bigint)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_float)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_double)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_decimal103)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_varchar10)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_text)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_blob)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_enum)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_datetime3)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_timestamp3)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_date)` mediumtext DEFAULT NULL, + `NULLIF(c_mediumtext, c_time)` mediumtext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_longtext, 1), +NULLIF(c_longtext, c_smallint), +NULLIF(c_longtext, c_tinyint), +NULLIF(c_longtext, c_int), +NULLIF(c_longtext, c_bigint), +NULLIF(c_longtext, c_float), +NULLIF(c_longtext, c_double), +NULLIF(c_longtext, c_decimal103), +NULLIF(c_longtext, c_varchar10), +NULLIF(c_longtext, c_text), +NULLIF(c_longtext, c_blob), +NULLIF(c_longtext, c_enum), +NULLIF(c_longtext, c_datetime3), +NULLIF(c_longtext, c_timestamp3), +NULLIF(c_longtext, c_date), +NULLIF(c_longtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_longtext, 1)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_smallint)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_tinyint)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_int)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_bigint)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_float)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_double)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_decimal103)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_varchar10)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_text)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_blob)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_enum)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_datetime3)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_timestamp3)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_date)` longtext DEFAULT NULL, + `NULLIF(c_longtext, c_time)` longtext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_tinyblob, 1), +NULLIF(c_tinyblob, c_smallint), +NULLIF(c_tinyblob, c_tinyint), +NULLIF(c_tinyblob, c_int), +NULLIF(c_tinyblob, c_bigint), +NULLIF(c_tinyblob, c_float), +NULLIF(c_tinyblob, c_double), +NULLIF(c_tinyblob, c_decimal103), +NULLIF(c_tinyblob, c_varchar10), +NULLIF(c_tinyblob, c_text), +NULLIF(c_tinyblob, c_blob), +NULLIF(c_tinyblob, c_enum), +NULLIF(c_tinyblob, c_datetime3), +NULLIF(c_tinyblob, c_timestamp3), +NULLIF(c_tinyblob, c_date), +NULLIF(c_tinyblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_tinyblob, 1)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_smallint)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_tinyint)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_int)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_bigint)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_float)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_double)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_decimal103)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_varchar10)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_text)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_blob)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_enum)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_datetime3)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_timestamp3)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_date)` tinyblob DEFAULT NULL, + `NULLIF(c_tinyblob, c_time)` tinyblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; CREATE TABLE t2 AS SELECT @@ -958,22 +1120,100 @@ FROM t1; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `NULLIF(c_blob, 1)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_smallint)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_tinyint)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_int)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_bigint)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_float)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_double)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_decimal103)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_varchar10)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_text)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_blob)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_enum)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_datetime3)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_timestamp3)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_date)` longblob DEFAULT NULL, - `NULLIF(c_blob, c_time)` longblob DEFAULT NULL + `NULLIF(c_blob, 1)` blob DEFAULT NULL, + `NULLIF(c_blob, c_smallint)` blob DEFAULT NULL, + `NULLIF(c_blob, c_tinyint)` blob DEFAULT NULL, + `NULLIF(c_blob, c_int)` blob DEFAULT NULL, + `NULLIF(c_blob, c_bigint)` blob DEFAULT NULL, + `NULLIF(c_blob, c_float)` blob DEFAULT NULL, + `NULLIF(c_blob, c_double)` blob DEFAULT NULL, + `NULLIF(c_blob, c_decimal103)` blob DEFAULT NULL, + `NULLIF(c_blob, c_varchar10)` blob DEFAULT NULL, + `NULLIF(c_blob, c_text)` blob DEFAULT NULL, + `NULLIF(c_blob, c_blob)` blob DEFAULT NULL, + `NULLIF(c_blob, c_enum)` blob DEFAULT NULL, + `NULLIF(c_blob, c_datetime3)` blob DEFAULT NULL, + `NULLIF(c_blob, c_timestamp3)` blob DEFAULT NULL, + `NULLIF(c_blob, c_date)` blob DEFAULT NULL, + `NULLIF(c_blob, c_time)` blob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_mediumblob, 1), +NULLIF(c_mediumblob, c_smallint), +NULLIF(c_mediumblob, c_tinyint), +NULLIF(c_mediumblob, c_int), +NULLIF(c_mediumblob, c_bigint), +NULLIF(c_mediumblob, c_float), +NULLIF(c_mediumblob, c_double), +NULLIF(c_mediumblob, c_decimal103), +NULLIF(c_mediumblob, c_varchar10), +NULLIF(c_mediumblob, c_text), +NULLIF(c_mediumblob, c_blob), +NULLIF(c_mediumblob, c_enum), +NULLIF(c_mediumblob, c_datetime3), +NULLIF(c_mediumblob, c_timestamp3), +NULLIF(c_mediumblob, c_date), +NULLIF(c_mediumblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_mediumblob, 1)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_smallint)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_tinyint)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_int)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_bigint)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_float)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_double)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_decimal103)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_varchar10)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_text)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_blob)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_enum)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_datetime3)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_timestamp3)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_date)` mediumblob DEFAULT NULL, + `NULLIF(c_mediumblob, c_time)` mediumblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +NULLIF(c_longblob, 1), +NULLIF(c_longblob, c_smallint), +NULLIF(c_longblob, c_tinyint), +NULLIF(c_longblob, c_int), +NULLIF(c_longblob, c_bigint), +NULLIF(c_longblob, c_float), +NULLIF(c_longblob, c_double), +NULLIF(c_longblob, c_decimal103), +NULLIF(c_longblob, c_varchar10), +NULLIF(c_longblob, c_text), +NULLIF(c_longblob, c_blob), +NULLIF(c_longblob, c_enum), +NULLIF(c_longblob, c_datetime3), +NULLIF(c_longblob, c_timestamp3), +NULLIF(c_longblob, c_date), +NULLIF(c_longblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `NULLIF(c_longblob, 1)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_smallint)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_tinyint)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_int)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_bigint)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_float)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_double)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_decimal103)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_varchar10)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_text)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_blob)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_enum)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_datetime3)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_timestamp3)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_date)` longblob DEFAULT NULL, + `NULLIF(c_longblob, c_time)` longblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; CREATE TABLE t2 AS SELECT diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index fe456e2aa80..807a194e773 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1449,6 +1449,28 @@ t2 CREATE TABLE `t2` ( `f8` mediumtext CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1, t2; +CREATE TABLE t1 +( +c_varchar varchar(1) character set utf8 collate utf8_general_ci, +c_tinytext tinytext, +c_text text, +c_mediumtext mediumtext, +c_longtext longtext +); +CREATE TABLE t2 AS +SELECT c_tinytext, c_text, c_mediumtext, c_longtext FROM t1 +UNION +SELECT c_varchar, c_varchar, c_varchar, c_varchar FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `c_tinytext` text CHARACTER SET utf8 DEFAULT NULL, + `c_text` mediumtext CHARACTER SET utf8 DEFAULT NULL, + `c_mediumtext` longtext CHARACTER SET utf8 DEFAULT NULL, + `c_longtext` longtext CHARACTER SET utf8 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union (select avg(1)) union diff --git a/mysql-test/suite/innodb_gis/r/1.result b/mysql-test/suite/innodb_gis/r/1.result index 31579a18ea0..3ab57babc43 100644 --- a/mysql-test/suite/innodb_gis/r/1.result +++ b/mysql-test/suite/innodb_gis/r/1.result @@ -681,7 +681,7 @@ def test t1 t1 g g 255 4294967295 0 Y 144 0 63 g select ST_asbinary(g) from t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ST_asbinary(g) 252 4294967295 0 Y 128 0 63 +def ST_asbinary(g) 251 4294967295 0 Y 128 0 63 ST_asbinary(g) drop table t1; create table t1 (a TEXT, b GEOMETRY NOT NULL, INDEX(b(5))); diff --git a/mysql-test/suite/innodb_gis/r/gis.result b/mysql-test/suite/innodb_gis/r/gis.result index 4257413f816..beb411505f9 100644 --- a/mysql-test/suite/innodb_gis/r/gis.result +++ b/mysql-test/suite/innodb_gis/r/gis.result @@ -681,7 +681,7 @@ def test t1 t1 g g 255 4294967295 0 Y 144 0 63 g select ST_asbinary(g) from t1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def ST_asbinary(g) 252 4294967295 0 Y 128 0 63 +def ST_asbinary(g) 251 4294967295 0 Y 128 0 63 ST_asbinary(g) drop table t1; create table t1 (a TEXT, b GEOMETRY NOT NULL, SPATIAL KEY(b)); diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 6461204f06e..bd89f220060 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -402,6 +402,22 @@ explain t2; select * from t2; drop table t1, t2; +CREATE TABLE t1 ( + c_tinytext tinytext, + c_text text, + c_mediumtext mediumtext, + c_longtext longtext +); +CREATE TABLE t2 AS SELECT + ifnull(c_tinytext, CAST('yet another binary data' AS BINARY)), + ifnull(c_text, CAST('yet another binary data' AS BINARY)), + ifnull(c_mediumtext, CAST('yet another binary data' AS BINARY)), + ifnull(c_longtext, CAST('yet another binary data' AS BINARY)) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + create table t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float(3,2), g double(4,3), h decimal(5,4), i year, j date, k timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, l datetime, m enum('a','b'), n set('a','b'), o char(10)); create table t2 select ifnull(a,a), ifnull(b,b), ifnull(c,c), ifnull(d,d), ifnull(e,e), ifnull(f,f), ifnull(g,g), ifnull(h,h), ifnull(i,i), ifnull(j,j), ifnull(k,k), ifnull(l,l), ifnull(m,m), ifnull(n,n), ifnull(o,o) from t1; show create table t2; diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index 3de35a74a73..403790356ce 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -414,8 +414,14 @@ CREATE TABLE t1 c_double DOUBLE, c_decimal103 DECIMAL(10,3), c_varchar10 VARCHAR(10), + c_tinytext TINYTEXT, c_text TEXT, + c_mediumtext MEDIUMTEXT, + c_longtext LONGTEXT, + c_tinyblob TINYBLOB, c_blob BLOB, + c_mediumblob MEDIUMBLOB, + c_longblob LONGBLOB, c_enum ENUM('one','two','tree'), c_datetime3 DATETIME(3), c_timestamp3 TIMESTAMP(3), @@ -596,6 +602,27 @@ FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2; +CREATE TABLE t2 AS SELECT + NULLIF(c_tinytext, 1), + NULLIF(c_tinytext, c_smallint), + NULLIF(c_tinytext, c_tinyint), + NULLIF(c_tinytext, c_int), + NULLIF(c_tinytext, c_bigint), + NULLIF(c_tinytext, c_float), + NULLIF(c_tinytext, c_double), + NULLIF(c_tinytext, c_decimal103), + NULLIF(c_tinytext, c_varchar10), + NULLIF(c_tinytext, c_text), + NULLIF(c_tinytext, c_blob), + NULLIF(c_tinytext, c_enum), + NULLIF(c_tinytext, c_datetime3), + NULLIF(c_tinytext, c_timestamp3), + NULLIF(c_tinytext, c_date), + NULLIF(c_tinytext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + CREATE TABLE t2 AS SELECT NULLIF(c_text, 1), NULLIF(c_text, c_smallint), @@ -617,7 +644,70 @@ FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2; -# QQ: this should probably create BLOB instead of LONGBLOB +CREATE TABLE t2 AS SELECT + NULLIF(c_mediumtext, 1), + NULLIF(c_mediumtext, c_smallint), + NULLIF(c_mediumtext, c_tinyint), + NULLIF(c_mediumtext, c_int), + NULLIF(c_mediumtext, c_bigint), + NULLIF(c_mediumtext, c_float), + NULLIF(c_mediumtext, c_double), + NULLIF(c_mediumtext, c_decimal103), + NULLIF(c_mediumtext, c_varchar10), + NULLIF(c_mediumtext, c_text), + NULLIF(c_mediumtext, c_blob), + NULLIF(c_mediumtext, c_enum), + NULLIF(c_mediumtext, c_datetime3), + NULLIF(c_mediumtext, c_timestamp3), + NULLIF(c_mediumtext, c_date), + NULLIF(c_mediumtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + NULLIF(c_longtext, 1), + NULLIF(c_longtext, c_smallint), + NULLIF(c_longtext, c_tinyint), + NULLIF(c_longtext, c_int), + NULLIF(c_longtext, c_bigint), + NULLIF(c_longtext, c_float), + NULLIF(c_longtext, c_double), + NULLIF(c_longtext, c_decimal103), + NULLIF(c_longtext, c_varchar10), + NULLIF(c_longtext, c_text), + NULLIF(c_longtext, c_blob), + NULLIF(c_longtext, c_enum), + NULLIF(c_longtext, c_datetime3), + NULLIF(c_longtext, c_timestamp3), + NULLIF(c_longtext, c_date), + NULLIF(c_longtext, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + + +CREATE TABLE t2 AS SELECT + NULLIF(c_tinyblob, 1), + NULLIF(c_tinyblob, c_smallint), + NULLIF(c_tinyblob, c_tinyint), + NULLIF(c_tinyblob, c_int), + NULLIF(c_tinyblob, c_bigint), + NULLIF(c_tinyblob, c_float), + NULLIF(c_tinyblob, c_double), + NULLIF(c_tinyblob, c_decimal103), + NULLIF(c_tinyblob, c_varchar10), + NULLIF(c_tinyblob, c_text), + NULLIF(c_tinyblob, c_blob), + NULLIF(c_tinyblob, c_enum), + NULLIF(c_tinyblob, c_datetime3), + NULLIF(c_tinyblob, c_timestamp3), + NULLIF(c_tinyblob, c_date), + NULLIF(c_tinyblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + CREATE TABLE t2 AS SELECT NULLIF(c_blob, 1), NULLIF(c_blob, c_smallint), @@ -639,6 +729,49 @@ FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2; +CREATE TABLE t2 AS SELECT + NULLIF(c_mediumblob, 1), + NULLIF(c_mediumblob, c_smallint), + NULLIF(c_mediumblob, c_tinyint), + NULLIF(c_mediumblob, c_int), + NULLIF(c_mediumblob, c_bigint), + NULLIF(c_mediumblob, c_float), + NULLIF(c_mediumblob, c_double), + NULLIF(c_mediumblob, c_decimal103), + NULLIF(c_mediumblob, c_varchar10), + NULLIF(c_mediumblob, c_text), + NULLIF(c_mediumblob, c_blob), + NULLIF(c_mediumblob, c_enum), + NULLIF(c_mediumblob, c_datetime3), + NULLIF(c_mediumblob, c_timestamp3), + NULLIF(c_mediumblob, c_date), + NULLIF(c_mediumblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + NULLIF(c_longblob, 1), + NULLIF(c_longblob, c_smallint), + NULLIF(c_longblob, c_tinyint), + NULLIF(c_longblob, c_int), + NULLIF(c_longblob, c_bigint), + NULLIF(c_longblob, c_float), + NULLIF(c_longblob, c_double), + NULLIF(c_longblob, c_decimal103), + NULLIF(c_longblob, c_varchar10), + NULLIF(c_longblob, c_text), + NULLIF(c_longblob, c_blob), + NULLIF(c_longblob, c_enum), + NULLIF(c_longblob, c_datetime3), + NULLIF(c_longblob, c_timestamp3), + NULLIF(c_longblob, c_date), + NULLIF(c_longblob, c_time) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + + # QQ: this should probably create a ENUM column instead of VARCHAR(4) CREATE TABLE t2 AS SELECT NULLIF(c_enum, 1), diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index e0c011e3d20..fa07dc22dbb 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -889,6 +889,22 @@ create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; show create table t2; drop table t1, t2; +CREATE TABLE t1 +( + c_varchar varchar(1) character set utf8 collate utf8_general_ci, + c_tinytext tinytext, + c_text text, + c_mediumtext mediumtext, + c_longtext longtext +); +CREATE TABLE t2 AS +SELECT c_tinytext, c_text, c_mediumtext, c_longtext FROM t1 +UNION +SELECT c_varchar, c_varchar, c_varchar, c_varchar FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + # # Bug#18175: Union select over 129 tables with a sum function fails. # diff --git a/sql/field.cc b/sql/field.cc index 9215a6b8e60..91efcd52b0f 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2912,67 +2912,6 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg, } -Field_new_decimal::Field_new_decimal(uint32 len_arg, - bool maybe_null_arg, - const LEX_CSTRING *name, - uint8 dec_arg, - bool unsigned_arg) - :Field_num((uchar*) 0, len_arg, - maybe_null_arg ? (uchar*) "": 0, 0, - NONE, name, dec_arg, 0, unsigned_arg) -{ - precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg); - set_if_smaller(precision, DECIMAL_MAX_PRECISION); - DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) && - (dec <= DECIMAL_MAX_SCALE)); - bin_size= my_decimal_get_binary_size(precision, dec); -} - - -Field *Field_new_decimal::create_from_item(MEM_ROOT *mem_root, Item *item) -{ - uint8 dec= item->decimals; - uint8 intg= item->decimal_precision() - dec; - uint32 len= item->max_char_length(); - DBUG_ASSERT (item->result_type() == DECIMAL_RESULT); - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - signed int overflow; - - dec= MY_MIN(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - +1: for decimal point - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - item->unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= MY_MAX(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - return new (mem_root) - Field_new_decimal(len, item->maybe_null, &item->name, - dec, item->unsigned_flag); -} - - int Field_new_decimal::reset(void) { store_value(&decimal_zero); @@ -10717,7 +10656,7 @@ uint32 Field_blob::char_length() const case 3: return 16777215; case 4: - return (uint32) 4294967295U; + return (uint32) UINT_MAX32; default: DBUG_ASSERT(0); // we should never go here return 0; @@ -10770,7 +10709,7 @@ uint32 Field_blob::max_display_length() case 3: return 16777215 * field_charset->mbmaxlen; case 4: - return (uint32) 4294967295U; + return (uint32) UINT_MAX32; default: DBUG_ASSERT(0); // we should never go here return 0; diff --git a/sql/field.h b/sql/field.h index e62b98936b7..5f5fd83b407 100644 --- a/sql/field.h +++ b/sql/field.h @@ -971,6 +971,10 @@ public: virtual bool zero_pack() const { return 1; } virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } virtual uint32 key_length() const { return pack_length(); } + virtual const Type_handler *type_handler() const + { + return Type_handler::get_handler_by_field_type(type()); + } virtual enum_field_types type() const =0; virtual enum_field_types real_type() const { return type(); } virtual enum_field_types binlog_type() const @@ -1842,9 +1846,6 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg, bool zero_arg, bool unsigned_arg); - Field_new_decimal(uint32 len_arg, bool maybe_null_arg, - const LEX_CSTRING *field_name_arg, uint8 dec_arg, - bool unsigned_arg); enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } Item_result result_type () const { return DECIMAL_RESULT; } @@ -1897,7 +1898,6 @@ public: uint16 mflags, int *order_var); uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); - static Field *create_from_item(MEM_ROOT *root, Item *); Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); }; @@ -3231,6 +3231,15 @@ public: :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, &temp_lex_str, system_charset_info), packlength(packlength_arg) {} + const Type_handler *type_handler() const + { + switch (packlength) { + case 1: return &type_handler_tiny_blob; + case 2: return &type_handler_blob; + case 3: return &type_handler_medium_blob; + } + return &type_handler_long_blob; + } /* Note that the default copy constructor is used, in clone() */ enum_field_types type() const { return MYSQL_TYPE_BLOB;} enum ha_base_keytype key_type() const @@ -3417,11 +3426,11 @@ public: :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, blob_pack_length, &my_charset_bin) { geom_type= geom_type_arg; srid= field_srid; } - Field_geom(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, enum geometry_type geom_type_arg) - :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) - { geom_type= geom_type_arg; srid= 0; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } + const Type_handler *type_handler() const + { + return &type_handler_geometry; + } enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } bool can_optimize_range(const Item_bool_func *cond, const Item *item, diff --git a/sql/item.cc b/sql/item.cc index 1889ecd6f39..307c299e410 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -518,7 +518,7 @@ Item::Item(THD *thd): tables. */ Item::Item(THD *thd, Item *item): - Type_std_attributes(item), + Type_all_attributes(item), join_tab_idx(item->join_tab_idx), is_expensive_cache(-1), rsize(0), @@ -5854,6 +5854,8 @@ const Type_handler *Item_field::real_type_handler() const // 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; + else if (type == MYSQL_TYPE_BLOB) + return field->type_handler(); return Type_handler::get_handler_by_real_type(type); } @@ -6276,122 +6278,23 @@ Field *Item::make_string_field(TABLE *table) \# Created field */ -Field *Item::tmp_table_field_from_field_type(TABLE *table, - bool fixed_length, - bool set_blob_packlength) +Field *Item::tmp_table_field_from_field_type(TABLE *table) { - /* - The field functions defines a field to be not null if null_ptr is not 0 - */ - uchar *null_ptr= maybe_null ? (uchar*) "" : 0; - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; + const Type_handler *handler= type_handler(); + Record_addr addr(maybe_null); - switch (field_type()) { - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - field= Field_new_decimal::create_from_item(mem_root, this); - break; - case MYSQL_TYPE_TINY: - field= new (mem_root) - Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; - case MYSQL_TYPE_SHORT: - field= new (mem_root) - Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; - case MYSQL_TYPE_LONG: - field= new (mem_root) - Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; -#ifdef HAVE_LONG_LONG - case MYSQL_TYPE_LONGLONG: - field= new (mem_root) - Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; -#endif - case MYSQL_TYPE_FLOAT: - field= new (mem_root) - Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, decimals, 0, unsigned_flag); - break; - case MYSQL_TYPE_DOUBLE: - field= new (mem_root) - Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, decimals, 0, unsigned_flag); - break; - case MYSQL_TYPE_INT24: - field= new (mem_root) - Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name, 0, unsigned_flag); - break; - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: - field= new (mem_root) - Field_newdate(0, null_ptr, 0, Field::NONE, &name); - break; - case MYSQL_TYPE_TIME: - field= new_Field_time(mem_root, 0, null_ptr, 0, Field::NONE, &name, - decimals); - break; - case MYSQL_TYPE_TIMESTAMP: - field= new_Field_timestamp(mem_root, 0, null_ptr, 0, - Field::NONE, &name, 0, decimals); - break; - case MYSQL_TYPE_DATETIME: - field= new_Field_datetime(mem_root, 0, null_ptr, 0, Field::NONE, - &name, decimals); - break; - case MYSQL_TYPE_YEAR: - field= new (mem_root) - Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, - &name); - break; - case MYSQL_TYPE_BIT: - field= new (mem_root) - Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, - &name); - break; - default: - /* This case should never be chosen */ - DBUG_ASSERT(0); - /* If something goes awfully wrong, it's better to get a string than die */ + switch (handler->field_type()) { case MYSQL_TYPE_NULL: case MYSQL_TYPE_STRING: - if (fixed_length && !too_big_for_varchar()) - { - field= new (mem_root) - Field_string(max_length, maybe_null, &name, collation.collation); - break; - } - /* Fall through to make_string_field() */ case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: return make_string_field(table); - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - field= new (mem_root) - Field_blob(max_length, maybe_null, &name, - collation.collation, set_blob_packlength); - break; // Blob handled outside of case -#ifdef HAVE_SPATIAL - case MYSQL_TYPE_GEOMETRY: - field= new (mem_root) - Field_geom(max_length, maybe_null, &name, table->s, - get_geometry_type()); -#endif /* HAVE_SPATIAL */ + default: + break; } - if (field) - field->init(table); - return field; + return handler->make_and_init_table_field(&name, addr, *this, table); } @@ -10423,10 +10326,16 @@ Field *Item_type_holder::make_field_by_type(TABLE *table) } case MYSQL_TYPE_NULL: return make_string_field(table); + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + set_handler(Type_handler::blob_type_handler(max_length)); + break; default: break; } - return tmp_table_field_from_field_type(table, false, true); + return tmp_table_field_from_field_type(table); } diff --git a/sql/item.h b/sql/item.h index e3d6c4e365f..0d4dbf77d6d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -483,7 +483,7 @@ public: class Item: public Value_source, - public Type_std_attributes + public Type_all_attributes { void operator=(Item &); /** @@ -537,9 +537,7 @@ protected: SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); virtual Field *make_string_field(TABLE *table); - Field *tmp_table_field_from_field_type(TABLE *table, - bool fixed_length, - bool set_blob_packlength); + Field *tmp_table_field_from_field_type(TABLE *table); Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length); void push_note_converted_to_negative_complement(THD *thd); @@ -1744,6 +1742,8 @@ public: } virtual Field::geometry_type get_geometry_type() const { return Field::GEOM_GEOMETRY; }; + uint uint_geometry_type() const + { return get_geometry_type(); } String *check_well_formed_result(String *str, bool send_error= 0); bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); bool too_big_for_varchar() const @@ -2262,7 +2262,7 @@ public: based on result_type(), which is less exact. */ Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, true); } + { return tmp_table_field_from_field_type(table); } }; @@ -2638,6 +2638,10 @@ public: fast_field_copier setup_fast_field_copier(Field *field); table_map used_tables() const; table_map all_used_tables() const; + const Type_handler *type_handler() const + { + return field->type_handler(); + } enum Item_result result_type () const { return field->result_type(); @@ -3637,7 +3641,14 @@ public: Item_partition_func_safe_string(thd, name_arg, safe_strlen(name_arg), &my_charset_bin) { max_length= length; } enum Type type() const { return TYPE_HOLDER; } - enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + enum_field_types field_type() const + { + return Item_blob::type_handler()->field_type(); + } + const Type_handler *type_handler() const + { + return Type_handler::blob_type_handler(max_length); + } const Type_handler *real_type_handler() const { // Should not be called, Item_blob is used for SHOW purposes only. @@ -3645,7 +3656,7 @@ public: return &type_handler_varchar; } Field *create_field_for_schema(THD *thd, TABLE *table) - { return tmp_table_field_from_field_type(table, false, true); } + { return tmp_table_field_from_field_type(table); } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6d2135db91e..6712b98dbc3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2577,7 +2577,7 @@ Item_func_nullif::fix_length_and_dec() thd->change_item_tree(&args[0], m_cache); thd->change_item_tree(&args[2], m_cache); } - set_handler_by_field_type(args[2]->field_type()); + set_handler(args[2]->type_handler()); collation.set(args[2]->collation); decimals= args[2]->decimals; unsigned_flag= args[2]->unsigned_flag; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a94105b352d..6a6adb28ebd 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1057,7 +1057,7 @@ public: } const char *func_name() const { return "ifnull"; } Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } + { return tmp_table_field_from_field_type(table); } table_map not_null_tables() const { return 0; } uint decimal_precision() const diff --git a/sql/item_func.cc b/sql/item_func.cc index 00e0c8caa07..584d387f89c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2254,8 +2254,8 @@ void Item_func_int_val::fix_length_and_dec_int_or_decimal() { ulonglong tmp_max_length= (ulonglong ) args[0]->max_length - (args[0]->decimals ? args[0]->decimals + 1 : 0) + 2; - max_length= tmp_max_length > (ulonglong) 4294967295U ? - (uint32) 4294967295U : (uint32) tmp_max_length; + max_length= tmp_max_length > (ulonglong) UINT_MAX32 ? + (uint32) UINT_MAX32 : (uint32) tmp_max_length; uint tmp= float_length(decimals); set_if_smaller(max_length,tmp); decimals= 0; diff --git a/sql/item_func.h b/sql/item_func.h index e16b3bd8fa6..4e93c93aec6 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -208,7 +208,7 @@ public: { return result_type() != STRING_RESULT ? create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : - tmp_table_field_from_field_type(table, false, false); + tmp_table_field_from_field_type(table); } Item *get_tmp_table_item(THD *thd); @@ -2255,12 +2255,6 @@ public: bool update(); bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); - Field *create_field_for_create_select(TABLE *table) - { - return result_type() != STRING_RESULT ? - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : - tmp_table_field_from_field_type(table, false, true); - } table_map used_tables() const { return used_tables_cache | RAND_TABLE_BIT; @@ -2302,6 +2296,14 @@ public: my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); + Field *create_field_for_create_select(TABLE *table) + { + return cmp_type() == STRING_RESULT ? + type_handler_long_blob.make_and_init_table_field(&(Item::name), + Record_addr(maybe_null), + *this, table) : + create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS); + } virtual void print(String *str, enum_query_type query_type); /* We must always return variables as strings to guard against selects of type @@ -2655,7 +2657,7 @@ public: { return result_type() != STRING_RESULT ? sp_result_field : - tmp_table_field_from_field_type(table, false, false); + tmp_table_field_from_field_type(table); } void make_field(THD *thd, Send_field *tmp_field); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index e361793f77d..8a61ab583c9 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -40,20 +40,11 @@ #include "opt_range.h" -Field *Item_geometry_func::create_field_for_create_select(TABLE *t_arg) -{ - Field *result; - if ((result= new Field_geom(max_length, maybe_null, &name, t_arg->s, - get_geometry_type()))) - result->init(t_arg); - return result; -} - void Item_geometry_func::fix_length_and_dec() { collation.set(&my_charset_bin); decimals=0; - max_length= (uint32) 4294967295U; + max_length= (uint32) UINT_MAX32; maybe_null= 1; } @@ -206,7 +197,7 @@ String *Item_func_as_wkt::val_str_ascii(String *str) void Item_func_as_wkt::fix_length_and_dec() { collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - max_length=MAX_BLOB_WIDTH; + max_length= (uint32) UINT_MAX32; maybe_null= 1; } diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index a164f9dec89..b6a49a38743 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -40,7 +40,6 @@ public: Item_geometry_func(THD *thd, List &list): Item_str_func(thd, list) {} void fix_length_and_dec(); enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } - Field *create_field_for_create_select(TABLE *table); }; class Item_func_geometry_from_text: public Item_geometry_func @@ -101,7 +100,7 @@ public: Item_func_as_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {} const char *func_name() const { return "st_aswkb"; } String *val_str(String *); - enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } + enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d95240d6d6d..42e634b1caa 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1669,8 +1669,6 @@ Item *Item_sum_avg::copy_or_same(THD* thd) Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table) { - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; if (group) { @@ -1679,21 +1677,15 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table) The easiest way is to do this is to store both value in a string and unpack on access. */ - field= new (mem_root) + Field *field= new (table->in_use->mem_root) Field_string(((Item_sum_avg::result_type() == DECIMAL_RESULT) ? - dec_bin_size : sizeof(double)) + sizeof(longlong), + dec_bin_size : sizeof(double)) + sizeof(longlong), 0, &name, &my_charset_bin); + if (field) + field->init(table); + return field; } - else if (Item_sum_avg::result_type() == DECIMAL_RESULT) - field= Field_new_decimal::create_from_item(mem_root, this); - else - { - field= new (mem_root) Field_double(max_length, maybe_null, &name, - decimals, TRUE); - } - if (field) - field->init(table); - return field; + return tmp_table_field_from_field_type(table); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 5caeea489f6..d52eeba1f15 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -536,7 +536,7 @@ public: my_decimal *val_decimal(my_decimal *decimal_value) { return val_decimal_from_date(decimal_value); } Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } + { return tmp_table_field_from_field_type(table); } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } }; @@ -1018,7 +1018,7 @@ class Item_extract :public Item_int_func return true; } Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } + { return tmp_table_field_from_field_type(table); } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f82c7580469..3eecd9b2544 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15879,7 +15879,8 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) break; } case TIME_RESULT: - new_field= tmp_table_field_from_field_type(table, true, false); + case DECIMAL_RESULT: + new_field= tmp_table_field_from_field_type(table); break; case STRING_RESULT: DBUG_ASSERT(collation.collation); @@ -15888,14 +15889,11 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) To preserve type they needed to be handled separately. */ if (field_type() == MYSQL_TYPE_GEOMETRY) - new_field= tmp_table_field_from_field_type(table, true, false); + new_field= tmp_table_field_from_field_type(table); else new_field= make_string_field(table); new_field->set_derivation(collation.derivation, collation.repertoire); break; - case DECIMAL_RESULT: - new_field= Field_new_decimal::create_from_item(mem_root, this); - break; case ROW_RESULT: // This case should never be choosen DBUG_ASSERT(0); @@ -15980,7 +15978,7 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) field->init(table); return field; } - return tmp_table_field_from_field_type(table, false, false); + return tmp_table_field_from_field_type(table); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2f4993f0437..1fbd631b754 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5439,7 +5439,7 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs, field->real_type() == MYSQL_TYPE_STRING) // For binary type { uint32 octet_max_length= field->max_display_length(); - if (is_blob && octet_max_length != (uint32) 4294967295U) + if (is_blob && octet_max_length != (uint32) UINT_MAX32) octet_max_length /= field->charset()->mbmaxlen; longlong char_max_len= is_blob ? (longlong) octet_max_length / field->charset()->mbminlen : diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8c05d0fa02b..5fed57fbb0d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7368,7 +7368,7 @@ blob_length_by_type(enum_field_types type) case MYSQL_TYPE_MEDIUM_BLOB: return 16777215; case MYSQL_TYPE_LONG_BLOB: - return 4294967295U; + return (uint) UINT32_MAX; default: DBUG_ASSERT(0); // we should never go here return 0; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index a34619b5e36..659e5839585 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -31,10 +31,6 @@ static Type_handler_date type_handler_date; static Type_handler_timestamp type_handler_timestamp; static Type_handler_timestamp2 type_handler_timestamp2; static Type_handler_olddecimal type_handler_olddecimal; -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; Type_handler_null type_handler_null; @@ -54,6 +50,11 @@ Type_handler_time2 type_handler_time2; Type_handler_newdate type_handler_newdate; Type_handler_datetime2 type_handler_datetime2; +Type_handler_tiny_blob type_handler_tiny_blob; +Type_handler_medium_blob type_handler_medium_blob; +Type_handler_long_blob type_handler_long_blob; +Type_handler_blob type_handler_blob; + #ifdef HAVE_SPATIAL Type_handler_geometry type_handler_geometry; #endif @@ -80,9 +81,18 @@ bool Type_handler_data::init() m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_geometry, &type_handler_geometry) || + m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_tiny_blob, + &type_handler_long_blob) || m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_blob, &type_handler_long_blob) || + m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_medium_blob, + &type_handler_long_blob) || + m_type_aggregator_for_result.add(&type_handler_geometry, + &type_handler_long_blob, + &type_handler_long_blob) || m_type_aggregator_for_result.add(&type_handler_geometry, &type_handler_varchar, &type_handler_long_blob) || @@ -140,6 +150,19 @@ Type_handler::string_type_handler(uint max_octet_length) } +const Type_handler * +Type_handler::blob_type_handler(uint max_octet_length) +{ + if (max_octet_length <= 255) + return &type_handler_tiny_blob; + if (max_octet_length <= 65535) + return &type_handler_blob; + if (max_octet_length <= 16777215) + return &type_handler_medium_blob; + return &type_handler_long_blob; +} + + /** This method is used by: - Item_sum_hybrid, e.g. MAX(item), MIN(item). @@ -1152,6 +1175,423 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table, ((const Field_enum*) target)->typelib, target->charset()); } +/*************************************************************************/ +Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + Field *field= make_table_field(name, addr, attr, table); + if (field) + field->init(table); + return field; +} + + +Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_tiny(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_short::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_short(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_medium(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_long::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_long(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_longlong(addr.ptr, attr.max_length, + addr.null_ptr, addr.null_bit, + Field::NONE, name, + 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_float::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_float(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + attr.decimals, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_double::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_double(addr.ptr, attr.max_length, + addr.null_ptr, addr.null_bit, + Field::NONE, name, + attr.decimals, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field * +Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + /* + Currently make_table_field() is used for Item purpose only. + On Item level we have type_handler_newdecimal only. + Will be implemented when we reuse Type_handler::make_table_field() + in make_field() in field.cc, to open old tables with old decimal. + */ + DBUG_ASSERT(0); + return NULL; +} + + +Field * +Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + uint8 dec= attr.decimals; + uint8 intg= attr.decimal_precision() - dec; + uint32 len= attr.max_char_length(); + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= MY_MIN(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, attr.unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= MY_MAX(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + return new (table->in_use->mem_root) + Field_new_decimal(addr.ptr, len, addr.null_ptr, addr.null_bit, + Field::NONE, name, + dec, 0/*zerofill*/, attr.unsigned_flag); +} + + +Field *Type_handler_year::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_year(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_null::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_null(addr.ptr, attr.max_length, + Field::NONE, name, attr.collation.collation); +} + + +Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new_Field_timestamp(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, attr.decimals); +} + + +Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_timestampf(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, attr.decimals); +} + + +Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_newdate(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_date::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_date(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_time::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new_Field_time(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + + +{ + return new (table->in_use->mem_root) + Field_timef(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new_Field_datetime(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_datetimef(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); +} + + +Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_bit_as_char(addr.ptr, attr.max_length, + addr.null_ptr, addr.null_bit, + Field::NONE, name); +} + + +Field *Type_handler_string::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_string(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.collation.collation); +} + + +Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_varstring(addr.ptr, attr.max_length, + HA_VARCHAR_PACKLENGTH(attr.max_length), + addr.null_ptr, addr.null_bit, + Field::NONE, name, + table->s, attr.collation.collation); +} + + +Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 1, attr.collation.collation); +} + + +Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 2, attr.collation.collation); +} + + +Field * +Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 3, attr.collation.collation); +} + + +Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + return new (table->in_use->mem_root) + Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, + 4, attr.collation.collation); +} + + + +#ifdef HAVE_SPATIAL +Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + return new (table->in_use->mem_root) + Field_geom(addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, 4, + (Field::geometry_type) attr.uint_geometry_type(), + 0); +} +#endif + + +Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const +{ + /* + Will be implemented when we split Item_type_holder::make_field_by_type() + and/or reuse Type_handler::make_table_field() in make_field() in field.cc + */ + DBUG_ASSERT(0); + return 0; +} + + +Field *Type_handler_set::make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + +{ + /* + Will be implemented when we split Item_type_holder::make_field_by_type() + and/or reuse Type_handler::make_table_field() in make_field() in field.cc + */ + DBUG_ASSERT(0); + return 0; +} + /*************************************************************************/ uint32 Type_handler_decimal_result::max_display_length(const Item *item) const @@ -1440,6 +1880,17 @@ bool Type_handler_string_result:: } +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)) + return true; + func->set_handler(blob_type_handler(func->max_length)); + return false; +} + + bool Type_handler_date_common:: Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const diff --git a/sql/sql_type.h b/sql/sql_type.h index 0652e56da4f..0df54315763 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -314,6 +314,27 @@ public: }; +class Type_all_attributes: public Type_std_attributes +{ +public: + Type_all_attributes() + :Type_std_attributes() + { } + Type_all_attributes(const Type_all_attributes *other) + :Type_std_attributes(other) + { } + // Returns total number of decimal digits + virtual uint decimal_precision() const= 0; + /* + Field::geometry_type is not visible here. + Let's use an "uint" wrapper for now. Later when we move Field_geom + into a plugin, this method will be replaced to some generic + datatype indepented method. + */ + virtual uint uint_geometry_type() const= 0; +}; + + class Name: private LEX_CSTRING { public: @@ -327,6 +348,31 @@ public: }; +class Record_addr +{ +public: + uchar *ptr; // Position to field in record + /** + Byte where the @c NULL bit is stored inside a record. If this Field is a + @c NOT @c NULL field, this member is @c NULL. + */ + uchar *null_ptr; + uchar null_bit; // Bit used to test null bit + Record_addr(uchar *ptr_arg, + uchar *null_ptr_arg, + uchar null_bit_arg) + :ptr(ptr_arg), + null_ptr(null_ptr_arg), + null_bit(null_bit_arg) + { } + Record_addr(bool maybe_null) + :ptr(NULL), + null_ptr(maybe_null ? (uchar*) "" : 0), + null_bit(0) + { } +}; + + class Type_handler { protected: @@ -342,6 +388,7 @@ protected: bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const; public: + static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); static const Type_handler *get_handler_by_field_type(enum_field_types type); static const Type_handler *get_handler_by_real_type(enum_field_types type); @@ -431,6 +478,14 @@ public: virtual Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const= 0; + virtual Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const= 0; + Field *make_and_init_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; virtual void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const= 0; @@ -630,6 +685,14 @@ public: DBUG_ASSERT(0); return NULL; } + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const + { + DBUG_ASSERT(0); + return NULL; + } void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, Sort_param *param) const @@ -1179,6 +1242,10 @@ public: uint32 max_display_length(const Item *item) const { return 4; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1192,6 +1259,10 @@ public: uint32 max_display_length(const Item *item) const { return 6; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1208,6 +1279,10 @@ public: } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1221,6 +1296,10 @@ public: uint32 max_display_length(const Item *item) const { return 20; } Field *make_conversion_table_field(TABLE *TABLE, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1234,6 +1313,10 @@ public: uint32 max_display_length(const Item *item) const { return 8; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1247,6 +1330,10 @@ public: uint32 max_display_length(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1264,6 +1351,10 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1278,6 +1369,10 @@ public: Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1291,6 +1386,10 @@ public: uint32 max_display_length(const Item *item) const { return 53; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1321,6 +1420,10 @@ public: virtual ~Type_handler_time() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1331,6 +1434,10 @@ public: enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1367,6 +1474,10 @@ public: virtual ~Type_handler_date() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1376,6 +1487,10 @@ public: virtual ~Type_handler_newdate() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1402,6 +1517,10 @@ public: virtual ~Type_handler_datetime() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1412,6 +1531,10 @@ public: enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1438,6 +1561,10 @@ public: virtual ~Type_handler_timestamp() {} Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1448,6 +1575,10 @@ public: enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1460,6 +1591,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1472,6 +1607,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1486,6 +1625,10 @@ public: uint32 max_display_length(const Item *item) const { return 0; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1499,6 +1642,10 @@ public: bool is_param_long_data_type() const { return true; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1512,6 +1659,10 @@ public: bool is_param_long_data_type() const { return true; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1525,6 +1676,8 @@ public: return false; // Materialization does not work with BLOB columns } bool is_param_long_data_type() const { return true; } + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; }; @@ -1537,6 +1690,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1549,6 +1706,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1561,6 +1722,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1573,6 +1738,10 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1593,6 +1762,11 @@ public: } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; + bool is_traditional_type() const { return false; @@ -1629,6 +1803,10 @@ public: virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1642,6 +1820,10 @@ public: virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; + Field *make_table_field(const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE *table) const; }; @@ -1742,6 +1924,10 @@ extern Type_handler_time2 type_handler_time2; extern Type_handler_newdate type_handler_newdate; extern Type_handler_datetime2 type_handler_datetime2; +extern Type_handler_tiny_blob type_handler_tiny_blob; +extern Type_handler_blob type_handler_blob; +extern Type_handler_medium_blob type_handler_medium_blob; +extern Type_handler_long_blob type_handler_long_blob; class Type_aggregator { From 5f1544fef3c9aa97ec2bb9fd5625e1e7dce2c93a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 24 Apr 2017 16:08:28 +0400 Subject: [PATCH 03/20] A cleanup for MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler Fixing that the server tried to create the old decimal for: CREATE TABLE t2 AS SELECT old_decimal_field FROM t1 UNION SELECT bigint_field FROM t1; CREATE TABLE t2 AS SELECT old_decimal_field FROM t1 UNION SELECT mediumint_field FROM t1; CREATE TABLE t2 AS SELECT year FROM t1 UNION SELECT old_decimal_field FROM t1; CREATE TABLE t2 AS SELCT COALESCE(old_decimal_field) FROM t1; Solution: 1. field_types_merge_rules[][] had three MYSQL_TYPE_DECIMAL remainders. Fixing to MYSQL_TYPE_NEWDECIMAL, like it is done for all other type pairs. This fixes the above queries with UNION. 2. Convert MYSQL_TYPE_DECIMAL to MYSQL_TYPE_NEWDECIMAL in Item::tmp_table_field_from_field_type(). This fixed the above query with COALESCE. 3. Adding "new Field_decimal" into Type_handler_olddecimal::make_table_field(). In case if something goes wrong it will crash on assert only in debug builds, while create the old decimal in release. Note, this "new Field_decimal" will be needed later anyway, when we reuse Type_handler::make_table_field() in make_field() in field.cc. --- mysql-test/r/type_decimal.result | 49 ++++++++++++++++++++++++++++++++ mysql-test/t/type_decimal.test | 43 ++++++++++++++++++++++++++++ sql/field.cc | 4 +-- sql/item.cc | 3 ++ sql/sql_type.cc | 8 ++++-- 5 files changed, 103 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 0ead4ec9aa2..52ea0092ffa 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -1019,3 +1019,52 @@ cast('-0.0' as decimal(5,1)) < 0 # # End of 5.5 tests # +# +# Start of 10.3 tests +# +# +# MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler +# +# This creates the old DECIMAL. Will be fixed in MDEV-12574. +CREATE TABLE t1 AS SELECT MAX(a) FROM t1dec102; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `MAX(a)` decimal(10,2)/*old*/ DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT COALESCE(a) FROM t1dec102; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `COALESCE(a)` decimal(12,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a BIGINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(21,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a MEDIUMINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(12,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 (a YEAR); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1dec102; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` decimal(12,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +DROP TABLE t1dec102; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 777bb2f23e5..51fa3bb7461 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -612,3 +612,46 @@ select cast('-0.0' as decimal(5,1)) < 0; --echo # --echo # End of 5.5 tests --echo # + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler +--echo # + +let $MYSQLD_DATADIR= `select @@datadir`; + +--copy_file std_data/old_decimal/t1dec102.frm $MYSQLD_DATADIR/test/t1dec102.frm +--copy_file std_data/old_decimal/t1dec102.MYD $MYSQLD_DATADIR/test/t1dec102.MYD +--copy_file std_data/old_decimal/t1dec102.MYI $MYSQLD_DATADIR/test/t1dec102.MYI + +--echo # This creates the old DECIMAL. Will be fixed in MDEV-12574. +CREATE TABLE t1 AS SELECT MAX(a) FROM t1dec102; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT COALESCE(a) FROM t1dec102; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a BIGINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 (a MEDIUMINT); +CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 (a YEAR); +CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1dec102; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + +DROP TABLE t1dec102; diff --git a/sql/field.cc b/sql/field.cc index 91efcd52b0f..6f80646817c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -125,7 +125,7 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= //MYSQL_TYPE_NULL MYSQL_TYPE_TIMESTAMP MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR, //MYSQL_TYPE_LONGLONG MYSQL_TYPE_INT24 - MYSQL_TYPE_DECIMAL, MYSQL_TYPE_DECIMAL, + MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_NEWDECIMAL, //MYSQL_TYPE_DATE MYSQL_TYPE_TIME MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR, //MYSQL_TYPE_DATETIME MYSQL_TYPE_YEAR @@ -520,7 +520,7 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]= /* MYSQL_TYPE_YEAR -> */ { //MYSQL_TYPE_DECIMAL MYSQL_TYPE_TINY - MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_TINY, //MYSQL_TYPE_SHORT MYSQL_TYPE_LONG MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, //MYSQL_TYPE_FLOAT MYSQL_TYPE_DOUBLE diff --git a/sql/item.cc b/sql/item.cc index 307c299e410..b38dc90d9ad 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6284,6 +6284,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) Record_addr addr(maybe_null); switch (handler->field_type()) { + case MYSQL_TYPE_DECIMAL: + handler= &type_handler_newdecimal; + break; case MYSQL_TYPE_NULL: case MYSQL_TYPE_STRING: case MYSQL_TYPE_ENUM: diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 659e5839585..a6c2f3e5e23 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -1281,11 +1281,15 @@ Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name, /* Currently make_table_field() is used for Item purpose only. On Item level we have type_handler_newdecimal only. - Will be implemented when we reuse Type_handler::make_table_field() + For now we have DBUG_ASSERT(0). + It will be removed when we reuse Type_handler::make_table_field() in make_field() in field.cc, to open old tables with old decimal. */ DBUG_ASSERT(0); - return NULL; + return new (table->in_use->mem_root) + Field_decimal(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals, + 0/*zerofill*/,attr.unsigned_flag); } From 6cc40856eed0f47a6198dc73a0d2f5bd42ac62fc Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 25 Apr 2017 10:20:27 +0400 Subject: [PATCH 04/20] A safety patch for MDEV-9217 Split Item::tmp_table_field_from_field_type() into virtual methods in Type_handler During refactoring in Type_handler, it's safer to use new_Field_xxx in Type_handler_xxx2::make_table_field(), to avoid creations of wrong fields for fields of the TIME(0), DATETIME(0) and TIMESTAMP(0) types. This will be changed back to "new" when we finish refactoring and reuse Type_handler::make_table_field() in make_field() in field.cc. --- sql/sql_type.cc | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/sql/sql_type.cc b/sql/sql_type.cc index a6c2f3e5e23..be945dcf631 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -1381,9 +1381,13 @@ Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name, TABLE *table) const { - return new (table->in_use->mem_root) - Field_timestampf(addr.ptr, addr.null_ptr, addr.null_bit, - Field::NONE, name, table->s, attr.decimals); + /* + Will be changed to "new Field_timestampf" when we reuse + make_table_field() for make_field() purposes in field.cc. + */ + return new_Field_timestamp(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, table->s, attr.decimals); } @@ -1405,6 +1409,11 @@ Field *Type_handler_date::make_table_field(const LEX_CSTRING *name, TABLE *table) const { + /* + DBUG_ASSERT will be removed when we reuse make_table_field() + for make_field() in field.cc + */ + DBUG_ASSERT(0); return new (table->in_use->mem_root) Field_date(addr.ptr, addr.null_ptr, addr.null_bit, Field::NONE, name); @@ -1430,9 +1439,13 @@ Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name, { - return new (table->in_use->mem_root) - Field_timef(addr.ptr, addr.null_ptr, addr.null_bit, - Field::NONE, name, attr.decimals); + /* + Will be changed to "new Field_timef" when we reuse + make_table_field() for make_field() purposes in field.cc. + */ + return new_Field_time(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); } @@ -1453,9 +1466,13 @@ Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name, const Type_all_attributes &attr, TABLE *table) const { - return new (table->in_use->mem_root) - Field_datetimef(addr.ptr, addr.null_ptr, addr.null_bit, - Field::NONE, name, attr.decimals); + /* + Will be changed to "new Field_datetimef" when we reuse + make_table_field() for make_field() purposes in field.cc. + */ + return new_Field_datetime(table->in_use->mem_root, + addr.ptr, addr.null_ptr, addr.null_bit, + Field::NONE, name, attr.decimals); } From 57bcc70fdc5baddfb527589863da7ed7f17e64f7 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 25 Apr 2017 11:05:41 +0400 Subject: [PATCH 05/20] MDEV-12582 Wrong data type for CREATE..SELECT MAX(COALESCE(timestamp_column)) --- mysql-test/r/type_timestamp.result | 20 +++++++++++++++ mysql-test/t/type_timestamp.test | 16 ++++++++++++ sql/item_sum.cc | 40 ++---------------------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 8e0da59d247..cf4f6df4b04 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -992,5 +992,25 @@ a b DROP TABLE t1; SET @@timestamp=DEFAULT; # +# MDEV-12582 Wrong data type for CREATE..SELECT MAX(COALESCE(timestamp_column)) +# +CREATE TABLE t1 (a TIMESTAMP); +CREATE TABLE t2 AS SELECT +MAX(a), +COALESCE(a), +COALESCE(MAX(a)), +MAX(COALESCE(a)) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `MAX(a)` timestamp NULL DEFAULT NULL, + `COALESCE(a)` timestamp NULL DEFAULT NULL, + `COALESCE(MAX(a))` timestamp NULL DEFAULT NULL, + `MAX(COALESCE(a))` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 058d5687819..6d81a86331a 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -587,6 +587,22 @@ SELECT * FROM t1 WHERE TIME'10:20:30' BETWEEN a and b; DROP TABLE t1; SET @@timestamp=DEFAULT; +--echo # +--echo # MDEV-12582 Wrong data type for CREATE..SELECT MAX(COALESCE(timestamp_column)) +--echo # + +CREATE TABLE t1 (a TIMESTAMP); +CREATE TABLE t2 AS SELECT + MAX(a), + COALESCE(a), + COALESCE(MAX(a)), + MAX(COALESCE(a)) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 42e634b1caa..1eac5ed2593 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1202,51 +1202,15 @@ void Item_sum_hybrid::setup_hybrid(THD *thd, Item *item, Item *value_arg) Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table) { - Field *field; - MEM_ROOT *mem_root; - if (args[0]->type() == Item::FIELD_ITEM) { - field= ((Item_field*) args[0])->field; + Field *field= ((Item_field*) args[0])->field; if ((field= create_tmp_field_from_field(table->in_use, field, &name, table, NULL))) field->flags&= ~NOT_NULL_FLAG; return field; } - - /* - DATE/TIME fields have STRING_RESULT result types. - In order to preserve field type, it's needed to handle DATE/TIME - fields creations separately. - */ - mem_root= table->in_use->mem_root; - switch (args[0]->field_type()) { - case MYSQL_TYPE_DATE: - { - field= new (mem_root) - Field_newdate(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE, - &name); - break; - } - case MYSQL_TYPE_TIME: - { - field= new_Field_time(mem_root, 0, maybe_null ? (uchar*)"" : 0, 0, - Field::NONE, &name, decimals); - break; - } - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: - { - field= new_Field_datetime(mem_root, 0, maybe_null ? (uchar*)"" : 0, 0, - Field::NONE, &name, decimals); - break; - } - default: - return Item_sum::create_tmp_field(group, table); - } - if (field) - field->init(table); - return field; + return Item_sum::create_tmp_field(group, table); } From 2fd635409d6588d4c379af1a3a0f38f7dc2d839d Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 25 Apr 2017 14:22:07 +0400 Subject: [PATCH 06/20] MDEV-12426 Add Field::type_handler() + MDEV-12432 This is a joint patch for: - MDEV-12426 Add Field::type_handler() - MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case With the new type handler approach being added to Field, it was easier to fix MDEV-12432 rather than to reproduce the old ENUM/SET behavior. The patch does the following: 1. Adds Field::type_handler(), according to the task description. 2. Fixes the asymmetry between Fields and Items of ENUM and SET field types. Field_enum::cmp_type() returned INT_RESULT Item*::cmp_type() returned STRING_RESULT for ENUM and SET expressions This asymmetry was originally done for easier coding in the optimizer sources. However, in 10.1 we moved a lot of code to methods of the class Field: - test_if_equality_guarantees_uniqueness() - can_be_substituted_to_equal_item() - get_equal_const_item() - can_optimize_keypart_ref() - can_optimize_hash_join() - can_optimize_group_min_max() - can_optimize_range() - can_optimize_outer_join_table_elimination() As of 10.2 only a few lines of the code in opt_range.cc, field.cc and field.h still relayed on the fact that Field_enum::cmp_type() returns INT_RESULT: - Some asserts in field.cc - Field_year::get_copy_func() - Item_func_like::get_mm_leaf() - Item_bool_func::get_mm_leaf() These lines have been fixed. 3. Item_bool_func::get_mm_leaf() did not work well for ENUM/SET, see MDEV-12432. So the ENUM/SET code was rewritten, and the relevant code in Field_enum::store() and Field_set::store() was fixed to properly return errors to the caller. 4. The result of Field_decimal::result_type() was changed from REAL_RESULT to DECIMAL_RESULT. Data type aggregation (e.g. in COALESCE()) is now more precise for old DECIMAL, because Item::decimal_precision() now goes through the DECIMAL_RESULT branch. Earlier it went through the REAL_RESULT branch. --- mysql-test/r/type_decimal.result | 6 +- mysql-test/r/type_enum.result | 40 ++++++++- mysql-test/r/type_set.result | 36 +++++++++ mysql-test/t/type_enum.test | 21 ++++- mysql-test/t/type_set.test | 22 +++++ sql/field.cc | 22 +++-- sql/field.h | 135 ++++++++++++++++++------------- sql/item.cc | 20 ----- sql/item.h | 16 +++- sql/opt_range.cc | 38 ++++++--- sql/sql_type.cc | 53 +++++++----- sql/sql_type.h | 72 +++++++++++++---- 12 files changed, 345 insertions(+), 136 deletions(-) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 52ea0092ffa..2911e58fd88 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -1037,7 +1037,7 @@ CREATE TABLE t1 AS SELECT COALESCE(a) FROM t1dec102; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `COALESCE(a)` decimal(12,2) DEFAULT NULL + `COALESCE(a)` decimal(10,2) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 (a BIGINT); @@ -1054,7 +1054,7 @@ CREATE TABLE t2 AS SELECT a FROM t1dec102 UNION SELECT a FROM t1; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `a` decimal(12,2) DEFAULT NULL + `a` decimal(10,2) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; DROP TABLE t1; @@ -1063,7 +1063,7 @@ CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1dec102; SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( - `a` decimal(12,2) DEFAULT NULL + `a` decimal(10,2) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; DROP TABLE t1; diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index 6ad75339847..2a08a140087 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -1803,13 +1803,18 @@ id c1 + 0 c1 4 0 DROP TABLE t1; End of 4.1 tests -create table t1(f1 set('a','b'), index(f1)); +SET sql_mode=''; +create table t1(f1 enum('a','b'), index(f1)); insert into t1 values(''),(''),('a'),('b'); +Warnings: +Warning 1265 Data truncated for column 'f1' at row 1 +Warning 1265 Data truncated for column 'f1' at row 2 select * from t1 where f1=''; f1 drop table t1; +SET sql_mode=DEFAULT; CREATE TABLE t1 (c1 ENUM('a', '', 'b')); INSERT INTO t1 (c1) VALUES ('b'); INSERT INTO t1 (c1) VALUES (''); @@ -2219,3 +2224,36 @@ SELECT * FROM t1; a DROP TABLE t1; +# +# MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +# +CREATE TABLE t1 (a ENUM('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='100'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; diff --git a/mysql-test/r/type_set.result b/mysql-test/r/type_set.result index 742ee5a33e9..1258de317ec 100644 --- a/mysql-test/r/type_set.result +++ b/mysql-test/r/type_set.result @@ -316,3 +316,39 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# Start of 10.3 tests +# +# +# MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +# +CREATE TABLE t1 (a SET('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='100'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index 105da427219..d00cf66ccb0 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -179,10 +179,12 @@ DROP TABLE t1; # # Bug#28729: Field_enum wrongly reported an error while storing an empty string. # -create table t1(f1 set('a','b'), index(f1)); +SET sql_mode=''; +create table t1(f1 enum('a','b'), index(f1)); insert into t1 values(''),(''),('a'),('b'); select * from t1 where f1=''; drop table t1; +SET sql_mode=DEFAULT; # # Bug#29360: Confluence of the special 0 enum value with the normal empty string @@ -454,3 +456,20 @@ SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR ALTER TABLE t1 MODIFY a ENUM('2001','2002'); SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +--echo # + +CREATE TABLE t1 (a ENUM('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +EXPLAIN SELECT * FROM t1 WHERE a=100; +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +EXPLAIN SELECT * FROM t1 WHERE a='100'; +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +DROP TABLE t1; diff --git a/mysql-test/t/type_set.test b/mysql-test/t/type_set.test index 7a79cd12f70..8c26d5a4366 100644 --- a/mysql-test/t/type_set.test +++ b/mysql-test/t/type_set.test @@ -218,3 +218,25 @@ DROP TABLE t1; --echo # --echo # End of 10.1 tests --echo # + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case +--echo # + +CREATE TABLE t1 (a SET('a','b','c','1'),KEY(a)); +INSERT INTO t1 VALUES ('a'),('b'),('c'),('1'); +EXPLAIN SELECT * FROM t1 WHERE a='xx'; +EXPLAIN SELECT * FROM t1 WHERE a='99999999'; +EXPLAIN SELECT * FROM t1 WHERE a=100.1e0; +EXPLAIN SELECT * FROM t1 WHERE a=100; +EXPLAIN SELECT * FROM t1 WHERE a=100.1; +EXPLAIN SELECT * FROM t1 WHERE a='100'; +EXPLAIN SELECT * FROM t1 WHERE a='1x'; +EXPLAIN SELECT * FROM t1 WHERE a='1.0'; +EXPLAIN SELECT * FROM t1 WHERE a='1.1'; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 6f80646817c..13bef70e7b8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1256,14 +1256,14 @@ bool Field::can_optimize_group_min_max(const Item_bool_func *cond, /* - This covers all numeric types, ENUM, SET, BIT + This covers all numeric types, BIT */ bool Field::can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const { DBUG_ASSERT(cmp_type() != TIME_RESULT); // Handled in Field_temporal - DBUG_ASSERT(cmp_type() != STRING_RESULT); // Handled in Field_longstr + DBUG_ASSERT(cmp_type() != STRING_RESULT); // Handled in Field_str descendants return item->cmp_type() != TIME_RESULT; } @@ -8577,12 +8577,16 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { tmp=0; set_warning(WARN_DATA_TRUNCATED, 1); + err= 1; } - if (!get_thd()->count_cuted_fields) + if (!get_thd()->count_cuted_fields && !length) err= 0; } else + { set_warning(WARN_DATA_TRUNCATED, 1); + err= 1; + } } store_type((ulonglong) tmp); return err; @@ -8756,6 +8760,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { tmp=0; set_warning(WARN_DATA_TRUNCATED, 1); + err= 1; } } else if (got_warning) @@ -8994,12 +8999,17 @@ uint Field_num::is_equal(Create_field *new_field) } +bool Field_enum::can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const +{ + return item->cmp_type() != TIME_RESULT; +} + + bool Field_enum::can_optimize_keypart_ref(const Item_bool_func *cond, const Item *item) const { - DBUG_ASSERT(cmp_type() == INT_RESULT); - DBUG_ASSERT(result_type() == STRING_RESULT); - switch (item->cmp_type()) { case TIME_RESULT: diff --git a/sql/field.h b/sql/field.h index 5f5fd83b407..30a379af04e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -851,11 +851,13 @@ public: to be quoted when used in constructing an SQL query. */ virtual bool str_needs_quotes() { return FALSE; } - virtual Item_result result_type () const=0; - virtual Item_result cmp_type () const { return result_type(); } - virtual const Type_handler *cast_to_int_type_handler() const + Item_result result_type () const { - return Type_handler::get_handler_by_field_type(type()); + return type_handler()->result_type(); + } + Item_result cmp_type () const + { + return type_handler()->cmp_type(); } static bool type_can_have_key_part(enum_field_types); static enum_field_types field_type_merge(enum_field_types, enum_field_types); @@ -971,12 +973,15 @@ public: virtual bool zero_pack() const { return 1; } virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } virtual uint32 key_length() const { return pack_length(); } - virtual const Type_handler *type_handler() const + virtual const Type_handler *type_handler() const= 0; + virtual enum_field_types type() const { - return Type_handler::get_handler_by_field_type(type()); + return type_handler()->field_type(); + } + virtual enum_field_types real_type() const + { + return type_handler()->real_field_type(); } - virtual enum_field_types type() const =0; - virtual enum_field_types real_type() const { return type(); } virtual enum_field_types binlog_type() const { /* @@ -1593,7 +1598,6 @@ public: uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg, bool zero_arg, bool unsigned_arg); - enum Item_result result_type () const { return INT_RESULT; } enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } CHARSET_INFO *charset(void) const { return &my_charset_numeric; } @@ -1656,7 +1660,6 @@ public: Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, CHARSET_INFO *charset); - Item_result result_type () const { return STRING_RESULT; } uint decimals() const { return NOT_FIXED_DEC; } int save_in_field(Field *to) { return save_in_field_str(to); } bool memcpy_field_possible(const Field *from) const @@ -1764,7 +1767,6 @@ public: field_name_arg, dec_arg, zero_arg, unsigned_arg), not_fixed(dec_arg >= FLOATING_POINT_DECIMALS) {} - Item_result result_type () const { return REAL_RESULT; } Copy_func *get_copy_func(const Field *from) const { return do_field_real; @@ -1801,7 +1803,7 @@ public: unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} + const Type_handler *type_handler() const { return &type_handler_olddecimal; } enum ha_base_keytype key_type() const { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } Copy_func *get_copy_func(const Field *from) const @@ -1846,9 +1848,8 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint8 dec_arg, bool zero_arg, bool unsigned_arg); - enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} + const Type_handler *type_handler() const { return &type_handler_newdecimal; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } - Item_result result_type () const { return DECIMAL_RESULT; } Copy_func *get_copy_func(const Field *from) const { // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why? @@ -1912,7 +1913,7 @@ public: unireg_check_arg, field_name_arg, 0, zero_arg,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_TINY;} + const Type_handler *type_handler() const { return &type_handler_tiny; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -1962,7 +1963,7 @@ public: :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, 0, 0, unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_SHORT;} + const Type_handler *type_handler() const { return &type_handler_short; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} int store(const char *to,uint length,CHARSET_INFO *charset); @@ -1997,7 +1998,7 @@ public: unireg_check_arg, field_name_arg, 0, zero_arg,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_INT24;} + const Type_handler *type_handler() const { return &type_handler_int24; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2037,7 +2038,7 @@ public: :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg,0,0,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_LONG;} + const Type_handler *type_handler() const { return &type_handler_long; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2083,7 +2084,7 @@ public: :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg,0,0,unsigned_arg) {} - enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} + const Type_handler *type_handler() const { return &type_handler_longlong; } enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -2137,7 +2138,7 @@ public: if (dec_arg >= FLOATING_POINT_DECIMALS) dec_arg= NOT_FIXED_DEC; } - enum_field_types type() const { return MYSQL_TYPE_FLOAT;} + const Type_handler *type_handler() const { return &type_handler_float; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -2188,7 +2189,7 @@ public: if (dec_arg >= FLOATING_POINT_DECIMALS) dec_arg= NOT_FIXED_DEC; } - enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} + const Type_handler *type_handler() const { return &type_handler_double; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -2225,7 +2226,7 @@ public: :Field_str(ptr_arg, len_arg, null, 1, unireg_check_arg, field_name_arg, cs) {} - enum_field_types type() const { return MYSQL_TYPE_NULL;} + const Type_handler *type_handler() const { return &type_handler_null; } Copy_func *get_copy_func(const Field *from) const { return do_field_string; @@ -2275,7 +2276,6 @@ public: :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { flags|= BINARY_FLAG; } - Item_result result_type () const { return STRING_RESULT; } int store_hex_hybrid(const char *str, uint length) { return store(str, length, &my_charset_bin); @@ -2296,7 +2296,6 @@ public: CHARSET_INFO *charset(void) const { return &my_charset_numeric; } CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } bool binary() const { return true; } - enum Item_result cmp_type () const { return TIME_RESULT; } bool val_bool() { return val_real() != 0e0; } uint is_equal(Create_field *new_field); bool eq_def(const Field *field) const @@ -2373,7 +2372,7 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share); - enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} + const Type_handler *type_handler() const { return &type_handler_timestamp; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -2507,7 +2506,7 @@ public: Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, share, dec_arg) {} - enum_field_types real_type() const { return MYSQL_TYPE_TIMESTAMP2; } + const Type_handler *type_handler() const { return &type_handler_timestamp2; } enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; } uint32 pack_length() const { @@ -2538,14 +2537,19 @@ public: :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, 1, 1) {} - enum_field_types type() const { return MYSQL_TYPE_YEAR;} + const Type_handler *type_handler() const { return &type_handler_year; } Copy_func *get_copy_func(const Field *from) const { if (eq_def(from)) return get_identical_copy_func(); switch (from->cmp_type()) { case STRING_RESULT: + { + const Type_handler *handler= from->type_handler(); + if (handler == &type_handler_enum || handler == &type_handler_set) + return do_field_int; return do_field_string; + } case TIME_RESULT: return do_field_temporal; case DECIMAL_RESULT: @@ -2583,7 +2587,7 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg) :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DATE;} + const Type_handler *type_handler() const { return &type_handler_date; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) @@ -2619,8 +2623,7 @@ public: :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) {} - enum_field_types type() const { return MYSQL_TYPE_DATE;} - enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } + const Type_handler *type_handler() const { return &type_handler_newdate; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } double val_real(void); @@ -2658,7 +2661,7 @@ public: :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), curdays(0) {} - enum_field_types type() const { return MYSQL_TYPE_TIME;} + const Type_handler *type_handler() const { return &type_handler_time; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } Copy_func *get_copy_func(const Field *from) const { @@ -2770,7 +2773,7 @@ public: { DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); } - enum_field_types real_type() const { return MYSQL_TYPE_TIME2; } + const Type_handler *type_handler() const { return &type_handler_time2; } enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; } uint32 pack_length() const { @@ -2812,7 +2815,7 @@ public: unireg_check == TIMESTAMP_DNUN_FIELD) flags|= ON_UPDATE_NOW_FLAG; } - enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + const Type_handler *type_handler() const { return &type_handler_datetime; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } double val_real(void); longlong val_int(void); @@ -2929,7 +2932,7 @@ public: :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, dec_arg) {} - enum_field_types real_type() const { return MYSQL_TYPE_DATETIME2; } + const Type_handler *type_handler() const { return &type_handler_datetime2; } enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; } uint32 pack_length() const { @@ -3007,6 +3010,14 @@ class Field_string :public Field_longstr { public: Warn_filter_string(const THD *thd, const Field_string *field); }; + bool is_var_string() const + { + return can_alter_field_type && + orig_table && + (orig_table->s->db_create_options & HA_OPTION_PACK_RECORD) && + field_length >= 4 && + orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR; + } public: bool can_alter_field_type; Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, @@ -3023,13 +3034,11 @@ public: NONE, field_name_arg, cs), can_alter_field_type(1) {}; - enum_field_types type() const + const Type_handler *type_handler() const { - return ((can_alter_field_type && orig_table && - orig_table->s->db_create_options & HA_OPTION_PACK_RECORD && - field_length >= 4) && - orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ? - MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING); + if (is_var_string()) + return &type_handler_var_string; + return &type_handler_string; } enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } @@ -3071,7 +3080,6 @@ public: uint packed_col_length(const uchar *to, uint length); uint max_packed_col_length(uint max_length); uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_STRING; } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); @@ -3119,7 +3127,7 @@ public: share->varchar_fields++; } - enum_field_types type() const { return MYSQL_TYPE_VARCHAR; } + const Type_handler *type_handler() const { return &type_handler_varchar; } enum ha_base_keytype key_type() const; uint row_pack_length() const { return field_length; } bool zero_pack() const { return 0; } @@ -3163,7 +3171,6 @@ public: uint max_packed_col_length(uint max_length); uint32 data_length(); uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); @@ -3241,7 +3248,22 @@ public: return &type_handler_long_blob; } /* Note that the default copy constructor is used, in clone() */ - enum_field_types type() const { return MYSQL_TYPE_BLOB;} + enum_field_types type() const + { + /* + We cannot return type_handler()->field_type() here. + Some pieces of the code (e.g. in engines) rely on the fact + that Field::type(), Field::real_type() and Item_field::field_type() + return MYSQL_TYPE_BLOB for all blob variants. + We should eventually fix all such code pieces to expect + all BLOB type codes. + */ + return MYSQL_TYPE_BLOB; + } + enum_field_types real_type() const + { + return MYSQL_TYPE_BLOB; + } enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } Copy_func *get_copy_func(const Field *from) const @@ -3431,7 +3453,14 @@ public: { return &type_handler_geometry; } - enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } + enum_field_types type() const + { + return MYSQL_TYPE_GEOMETRY; + } + enum_field_types real_type() const + { + return MYSQL_TYPE_GEOMETRY; + } bool can_optimize_range(const Item_bool_func *cond, const Item *item, bool is_eq_func) const; @@ -3488,12 +3517,7 @@ public: flags|=ENUM_FLAG; } Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); - enum_field_types type() const { return MYSQL_TYPE_STRING; } - enum Item_result cmp_type () const { return INT_RESULT; } - const Type_handler *cast_to_int_type_handler() const - { - return &type_handler_longlong; - } + const Type_handler *type_handler() const { return &type_handler_enum; } enum ha_base_keytype key_type() const; Copy_func *get_copy_func(const Field *from) const { @@ -3534,7 +3558,6 @@ public: void store_type(ulonglong value); void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } uint pack_length_from_metadata(uint field_metadata) { return (field_metadata & 0x00ff); } uint row_pack_length() const { return pack_length(); } @@ -3564,6 +3587,9 @@ public: */ return false; } + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; private: int do_save_field_metadata(uchar *first_byte); uint is_equal(Create_field *new_field); @@ -3594,7 +3620,7 @@ public: String *val_str(String*,String *); void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } - enum_field_types real_type() const { return MYSQL_TYPE_SET; } + const Type_handler *type_handler() const { return &type_handler_set; } bool has_charset(void) const { return TRUE; } private: const String empty_set_string; @@ -3624,13 +3650,12 @@ public: Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg); - enum_field_types type() const { return MYSQL_TYPE_BIT; } + const Type_handler *type_handler() const { return &type_handler_bit; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) (field_length + 7) / 8; } uint32 max_data_length() const { return (field_length + 7) / 8; } uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } - Item_result result_type () const { return INT_RESULT; } int reset(void) { bzero(ptr, bytes_in_rec); if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits diff --git a/sql/item.cc b/sql/item.cc index b38dc90d9ad..6199aba12d5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5841,26 +5841,6 @@ error: } -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; - else if (type == MYSQL_TYPE_BLOB) - return field->type_handler(); - return Type_handler::get_handler_by_real_type(type); - -} - - /* @brief Mark virtual columns as used in a partitioning expression diff --git a/sql/item.h b/sql/item.h index 0d4dbf77d6d..28bc0283495 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2640,6 +2640,11 @@ public: table_map all_used_tables() const; const Type_handler *type_handler() const { + const Type_handler *handler= field->type_handler(); + // This special code for ENUM and SET should eventually be removed + if (handler == &type_handler_enum || + handler == &type_handler_set) + return &type_handler_string; return field->type_handler(); } enum Item_result result_type () const @@ -2648,13 +2653,18 @@ public: } const Type_handler *cast_to_int_type_handler() const { - return field->cast_to_int_type_handler(); + return field->type_handler()->cast_to_int_type_handler(); } enum_field_types field_type() const { return field->type(); } - const Type_handler *real_type_handler() const; + const Type_handler *real_type_handler() const + { + if (field->is_created_from_null_item) + return &type_handler_null; + return field->type_handler(); + } enum_monotonicity_info get_monotonicity_info() const { return MONOTONIC_STRICT_INCREASING; @@ -5859,8 +5869,6 @@ public: { return Type_handler_hybrid_field_type::type_handler(); } enum_field_types field_type() const { return Type_handler_hybrid_field_type::field_type(); } - enum_field_types real_field_type() const - { return Type_handler_hybrid_field_type::real_field_type(); } enum Item_result result_type () const { /* diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 881e6de6085..b7b06080121 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7926,7 +7926,9 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param, if (!(res= value->val_str(&tmp))) DBUG_RETURN(&null_element); - if (field->cmp_type() != STRING_RESULT) + if (field->cmp_type() != STRING_RESULT || + field->type_handler() == &type_handler_enum || + field->type_handler() == &type_handler_set) DBUG_RETURN(0); /* @@ -8022,19 +8024,31 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param, goto end; err= value->save_in_field_no_warnings(field, 1); - if (err == 2 && field->cmp_type() == STRING_RESULT) - { - if (type == EQ_FUNC || type == EQUAL_FUNC) - { - tree= new (alloc) SEL_ARG(field, 0, 0); - tree->type= SEL_ARG::IMPOSSIBLE; - } - else - tree= NULL; /* Cannot infer anything */ - goto end; - } if (err > 0) { + if (field->type_handler() == &type_handler_enum || + field->type_handler() == &type_handler_set) + { + if (type == EQ_FUNC || type == EQUAL_FUNC) + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + } + goto end; + } + + if (err == 2 && field->cmp_type() == STRING_RESULT) + { + if (type == EQ_FUNC || type == EQUAL_FUNC) + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + } + else + tree= NULL; /* Cannot infer anything */ + goto end; + } + if (field->cmp_type() != value->result_type()) { if ((type == EQ_FUNC || type == EQUAL_FUNC) && diff --git a/sql/sql_type.cc b/sql/sql_type.cc index be945dcf631..61521052444 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -21,35 +21,39 @@ #include "item.h" #include "log.h" -static Type_handler_tiny type_handler_tiny; -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_time type_handler_time; -static Type_handler_date type_handler_date; -static Type_handler_timestamp type_handler_timestamp; -static Type_handler_timestamp2 type_handler_timestamp2; -static Type_handler_olddecimal type_handler_olddecimal; - +Type_handler_row type_handler_row; Type_handler_null type_handler_null; -Type_handler_row type_handler_row; -Type_handler_string type_handler_string; -Type_handler_varchar type_handler_varchar; + +Type_handler_tiny type_handler_tiny; +Type_handler_short type_handler_short; +Type_handler_long type_handler_long; +Type_handler_int24 type_handler_int24; 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; +Type_handler_olddecimal type_handler_olddecimal; +Type_handler_newdecimal type_handler_newdecimal; + +Type_handler_year type_handler_year; +Type_handler_time type_handler_time; +Type_handler_date type_handler_date; +Type_handler_timestamp type_handler_timestamp; +Type_handler_timestamp2 type_handler_timestamp2; +Type_handler_datetime type_handler_datetime; Type_handler_time2 type_handler_time2; Type_handler_newdate type_handler_newdate; Type_handler_datetime2 type_handler_datetime2; +Type_handler_enum type_handler_enum; +Type_handler_set type_handler_set; + +Type_handler_string type_handler_string; +Type_handler_var_string type_handler_var_string; +Type_handler_varchar type_handler_varchar; + Type_handler_tiny_blob type_handler_tiny_blob; Type_handler_medium_blob type_handler_medium_blob; Type_handler_long_blob type_handler_long_blob; @@ -245,6 +249,7 @@ const Name Type_handler_null::m_name_null(C_STRING_WITH_LEN("null")); const Name Type_handler_string::m_name_char(C_STRING_WITH_LEN("char")), + Type_handler_var_string::m_name_var_string(C_STRING_WITH_LEN("varchar")), Type_handler_varchar::m_name_varchar(C_STRING_WITH_LEN("varchar")), Type_handler_tiny_blob::m_name_tinyblob(C_STRING_WITH_LEN("tinyblob")), Type_handler_medium_blob::m_name_mediumblob(C_STRING_WITH_LEN("mediumblob")), @@ -326,6 +331,18 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const return &type_handler_row; } +/***************************************************************************/ + +const Type_handler *Type_handler_enum::cast_to_int_type_handler() const +{ + return &type_handler_longlong; +} + + +const Type_handler *Type_handler_set::cast_to_int_type_handler() const +{ + return &type_handler_longlong; +} /***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 0df54315763..0d4230403f4 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -426,6 +426,10 @@ public: */ virtual bool is_param_long_data_type() const { return false; } virtual const Type_handler *type_handler_for_comparison() const= 0; + virtual const Type_handler *cast_to_int_type_handler() const + { + return this; + } virtual CHARSET_INFO *charset_for_protocol(const Item *item) const; virtual const Type_handler* type_handler_adjusted_to_max_octet_length(uint max_octet_length, @@ -1485,6 +1489,7 @@ class Type_handler_newdate: public Type_handler_date_common { public: virtual ~Type_handler_newdate() {} + enum_field_types real_field_type() const { return MYSQL_TYPE_NEWDATE; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -1649,6 +1654,18 @@ public: }; +/* Old varchar */ +class Type_handler_var_string: public Type_handler_string +{ + static const Name m_name_var_string; +public: + virtual ~Type_handler_var_string() {} + const Name name() const { return m_name_var_string; } + enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; } + enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; } +}; + + class Type_handler_varchar: public Type_handler_string_result { static const Name m_name_varchar; @@ -1799,8 +1816,9 @@ class Type_handler_enum: public Type_handler_string_result public: virtual ~Type_handler_enum() {} const Name name() const { return m_name_enum; } - enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -1816,8 +1834,9 @@ class Type_handler_set: public Type_handler_string_result public: virtual ~Type_handler_set() {} const Name name() const { return m_name_set; } - enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -1906,23 +1925,44 @@ public: }; -extern Type_handler_row type_handler_row; -extern Type_handler_null type_handler_null; -extern Type_handler_string type_handler_string; -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; +extern Type_handler_row type_handler_row; +extern Type_handler_null type_handler_null; -extern Type_handler_time2 type_handler_time2; +extern Type_handler_float type_handler_float; +extern Type_handler_double type_handler_double; + +extern Type_handler_bit type_handler_bit; + +extern Type_handler_enum type_handler_enum; +extern Type_handler_set type_handler_set; + +extern Type_handler_string type_handler_string; +extern Type_handler_var_string type_handler_var_string; +extern Type_handler_varchar type_handler_varchar; + +extern Type_handler_tiny_blob type_handler_tiny_blob; +extern Type_handler_medium_blob type_handler_medium_blob; +extern Type_handler_long_blob type_handler_long_blob; +extern Type_handler_blob type_handler_blob; + +extern Type_handler_tiny type_handler_tiny; +extern Type_handler_short type_handler_short; +extern Type_handler_int24 type_handler_int24; +extern Type_handler_long type_handler_long; +extern Type_handler_longlong type_handler_longlong; + +extern Type_handler_newdecimal type_handler_newdecimal; +extern Type_handler_olddecimal type_handler_olddecimal; + +extern Type_handler_year type_handler_year; extern Type_handler_newdate type_handler_newdate; +extern Type_handler_date type_handler_date; +extern Type_handler_time type_handler_time; +extern Type_handler_time2 type_handler_time2; +extern Type_handler_datetime type_handler_datetime; extern Type_handler_datetime2 type_handler_datetime2; +extern Type_handler_timestamp type_handler_timestamp; +extern Type_handler_timestamp2 type_handler_timestamp2; extern Type_handler_tiny_blob type_handler_tiny_blob; extern Type_handler_blob type_handler_blob; From 61a771df00c8d4266cc8f76c3e3e9d1565c7e2fa Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 26 Apr 2017 09:49:41 +0400 Subject: [PATCH 07/20] Moving a part of st_select_lex_unit::prepare() into a new method prepare_join() This is to simplify the logic inside st_select_lex_unit::prepare(), to implement data type aggregation for pluggable data types. --- sql/sql_lex.h | 3 ++ sql/sql_union.cc | 119 ++++++++++++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 91f9eb77db2..b90d3402afe 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -749,6 +749,9 @@ public: /* UNION methods */ bool prepare(THD *thd, select_result *result, ulong additional_options); + bool prepare_join(THD *thd, SELECT_LEX *sl, select_result *result, + ulong additional_options, + bool is_union_select); bool optimize(); bool exec(); bool exec_recursive(); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index d90b0c7aa68..ff455e680f7 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -636,6 +636,59 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, } +bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl, + select_result *tmp_result, + ulong additional_options, + bool is_union_select) +{ + DBUG_ENTER("st_select_lex_unit::prepare_join"); + bool can_skip_order_by; + sl->options|= SELECT_NO_UNLOCK; + JOIN *join= new JOIN(thd_arg, sl->item_list, + (sl->options | thd_arg->variables.option_bits | + additional_options), + tmp_result); + if (!join) + DBUG_RETURN(true); + + thd_arg->lex->current_select= sl; + + can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); + + saved_error= join->prepare(sl->table_list.first, + sl->with_wild, + sl->where, + (can_skip_order_by ? 0 : + sl->order_list.elements) + + sl->group_list.elements, + can_skip_order_by ? + NULL : sl->order_list.first, + can_skip_order_by, + sl->group_list.first, + sl->having, + (is_union_select ? NULL : + thd_arg->lex->proc_list.first), + sl, this); + + /* There are no * in the statement anymore (for PS) */ + sl->with_wild= 0; + last_procedure= join->procedure; + + if (saved_error || (saved_error= thd_arg->is_fatal_error)) + DBUG_RETURN(true); + /* + Remove all references from the select_lex_units to the subqueries that + are inside the ORDER BY clause. + */ + if (can_skip_order_by) + { + for (ORDER *ord= (ORDER *)sl->order_list.first; ord; ord= ord->next) + { + (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); + } + } + DBUG_RETURN(false); +} bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, @@ -747,15 +800,22 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, tmp_result= sel_result; sl->context.resolve_in_select_list= TRUE; + + if (!is_union_select && !is_recursive) + { + if (prepare_join(thd_arg, first_sl, tmp_result, additional_options, + is_union_select)) + goto err; + types= first_sl->item_list; + goto cont; + } for (;sl; sl= sl->next_select()) - { - bool can_skip_order_by; - sl->options|= SELECT_NO_UNLOCK; - JOIN *join= new JOIN(thd_arg, sl->item_list, - (sl->options | thd_arg->variables.option_bits | - additional_options), - tmp_result); + { + if (prepare_join(thd_arg, sl, tmp_result, additional_options, + is_union_select)) + goto err; + /* setup_tables_done_option should be set only for very first SELECT, because it protect from secont setup_tables call for select-like non @@ -763,53 +823,12 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, SELECT (for union it can be only INSERT ... SELECT). */ additional_options&= ~OPTION_SETUP_TABLES_DONE; - if (!join) - goto err; - - thd_arg->lex->current_select= sl; - - can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); - - saved_error= join->prepare(sl->table_list.first, - sl->with_wild, - sl->where, - (can_skip_order_by ? 0 : - sl->order_list.elements) + - sl->group_list.elements, - can_skip_order_by ? - NULL : sl->order_list.first, - can_skip_order_by, - sl->group_list.first, - sl->having, - (is_union_select ? NULL : - thd_arg->lex->proc_list.first), - sl, this); - - /* There are no * in the statement anymore (for PS) */ - sl->with_wild= 0; - last_procedure= join->procedure; - - if (saved_error || (saved_error= thd_arg->is_fatal_error)) - goto err; - /* - Remove all references from the select_lex_units to the subqueries that - are inside the ORDER BY clause. - */ - if (can_skip_order_by) - { - for (ORDER *ord= (ORDER *)sl->order_list.first; ord; ord= ord->next) - { - (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); - } - } /* Use items list of underlaid select for derived tables to preserve information about fields lengths and exact types */ - if (!is_union_select && !is_recursive) - types= first_sl->item_list; - else if (sl == first_sl) + if (sl == first_sl) { if (is_recursive) { @@ -846,6 +865,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, Item *type, *item_tmp; while ((type= tp++, item_tmp= it++)) { + DBUG_ASSERT(item_tmp->fixed); if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp)) DBUG_RETURN(TRUE); } @@ -878,6 +898,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } +cont: /* If the query is using select_union_direct, we have postponed preparation of the underlying select_result until column types From 852f2305b972d6b7e0160d1c6454807d346048b7 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 26 Apr 2017 10:37:05 +0400 Subject: [PATCH 08/20] Fixing a typo: UINT32_MAX -> UINT_MAX32 (introduced by the patch for MDEV-9217) Note, some platforms have definitions for UINT32_MAX, so compiled without problems on FC. --- sql/sql_table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5fed57fbb0d..76755a028ed 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7368,7 +7368,7 @@ blob_length_by_type(enum_field_types type) case MYSQL_TYPE_MEDIUM_BLOB: return 16777215; case MYSQL_TYPE_LONG_BLOB: - return (uint) UINT32_MAX; + return (uint) UINT_MAX32; default: DBUG_ASSERT(0); // we should never go here return 0; From b445c1ebb5d7012b3994b37a6a9a58c6585040af Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 26 Apr 2017 10:52:18 +0400 Subject: [PATCH 09/20] Fixing compilation failure on Windows: moving references to type_handler_xxx from field.h to field.cc --- sql/field.cc | 16 ++++++++++++++++ sql/field.h | 10 +--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 13bef70e7b8..fa3104f69fe 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8176,6 +8176,22 @@ void Field_blob::sort_string(uchar *to,uint length) } +/* + Return the data type handler, according to packlength. + Implemented in field.cc rather than in field.h + to avoid exporting type_handler_xxx with MYSQL_PLUGIN_IMPORT. +*/ +const Type_handler *Field_blob::type_handler() const +{ + switch (packlength) { + case 1: return &type_handler_tiny_blob; + case 2: return &type_handler_blob; + case 3: return &type_handler_medium_blob; + } + return &type_handler_long_blob; +} + + void Field_blob::sql_type(String &res) const { const char *str; diff --git a/sql/field.h b/sql/field.h index 30a379af04e..814f3b05811 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3238,15 +3238,7 @@ public: :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, &temp_lex_str, system_charset_info), packlength(packlength_arg) {} - const Type_handler *type_handler() const - { - switch (packlength) { - case 1: return &type_handler_tiny_blob; - case 2: return &type_handler_blob; - case 3: return &type_handler_medium_blob; - } - return &type_handler_long_blob; - } + const Type_handler *type_handler() const; /* Note that the default copy constructor is used, in clone() */ enum_field_types type() const { From 441349aa0659f07828af7c09164e142b8d565b3a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 27 Apr 2017 14:37:27 +0400 Subject: [PATCH 10/20] MDEV-12588 Add Type_handler::type_handler_for_tmp_table() and Type_handler::type_handler_for_union() 1. Implementing the task according to the description: a. Adding Type_handler::type_handler_for_tmp_table(). b. Adding Type_handler::type_handler_for_union_table. c. Adding helper methods Type_handler::varstring_type_handler(const Item*), Type_handler::blob_type_handler(const Item*) d. Removing Item::make_string_field() and Item_func_group_concat::make_string_field(). They are not needed any more. e. Simplifying Item::tmp_table_field_from_field_type() to just two lines. f. Renaming Item_type_holder::make_field_by_type() and implementing virtual Item_type_holder::create_tmp_field() instead. The new implementation is also as simple as two lines. g. Adding a new virtual method Type_all_attributes::get_typelib(), to access to TYPELIB definitions for ENUM and SET columns. h. Simplifying the code branch for TIME_RESULT, DECIMAL_RESULT, STRING_RESULT in Item::create_tmp_field(). It's now just one line. i. Implementing Type_handler_enum::make_table_field() and Type_handler_set::make_table_field(). 2. Code simplification in Field_str constructor calls. a. Changing the "CHARSET_INFO *cs" argument in constuctors for Field_str and its descendants to "const DTCollation &collation". This is to avoid two step initialization: - setting Field_str::derivation and Field_str::repertoire to the default values first - then resetting them using: set_derivation(item->derivation, item->repertoire). b. Removing Field::set_derivation() c. Adding a new constructor DTCollation(CHARSET_INFO *cs), for the old code compatibility. 3. Changes in test results As a side effect some test results have changed, because in the old version Item::make_string_field() converted TINYBLOB to VARCHAR(255). Now TINYBLOB is preserved. a. sp-row.result This query: CREATE TABLE t1 AS SELECT tinyblob_sp_variable; Now preserves TINYBLOB as the data type. Before the patch a VARCHAR(255) was created. b. gis-debug.result This is a debug test, to make sure that + and - operators are commutative and non-commutative correspondingly. The exact data type is not really important. (But anyway, it now chooses a better data type that fits the result) --- mysql-test/r/gis-debug.result | 14 +- mysql-test/r/sp-row.result | 8 +- .../suite/compat/oracle/r/sp-row.result | 8 +- sql/field.cc | 14 +- sql/field.h | 58 ++++---- sql/item.cc | 133 +----------------- sql/item.h | 26 +++- sql/item_sum.cc | 18 --- sql/item_sum.h | 3 - sql/sql_select.cc | 19 +-- sql/sql_type.cc | 87 +++++++++--- sql/sql_type.h | 65 +++++++++ 12 files changed, 207 insertions(+), 246 deletions(-) diff --git a/mysql-test/r/gis-debug.result b/mysql-test/r/gis-debug.result index 889ee5c9513..1516c3d5089 100644 --- a/mysql-test/r/gis-debug.result +++ b/mysql-test/r/gis-debug.result @@ -381,11 +381,11 @@ POINT(0,0) MOD '0' LIMIT 0; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `POINT(0,0)+'0'` longtext DEFAULT NULL, - `POINT(0,0)-'0'` longtext DEFAULT NULL, - `POINT(0,0)*'0'` longtext DEFAULT NULL, - `POINT(0,0)/'0'` longtext DEFAULT NULL, - `POINT(0,0) MOD '0'` longtext DEFAULT NULL + `POINT(0,0)+'0'` tinytext DEFAULT NULL, + `POINT(0,0)-'0'` tinytext DEFAULT NULL, + `POINT(0,0)*'0'` tinytext DEFAULT NULL, + `POINT(0,0)/'0'` tinytext DEFAULT NULL, + `POINT(0,0) MOD '0'` tinytext DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 AS SELECT @@ -394,8 +394,8 @@ CREATE TABLE t1 AS SELECT SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `'0'+POINT(0,0)` longtext DEFAULT NULL, - `'0'*POINT(0,0)` longtext DEFAULT NULL + `'0'+POINT(0,0)` tinytext DEFAULT NULL, + `'0'*POINT(0,0)` tinytext DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 AS SELECT '0'-POINT(0,0) LIMIT 0; diff --git a/mysql-test/r/sp-row.result b/mysql-test/r/sp-row.result index 687e6629b8d..1f33f11a519 100644 --- a/mysql-test/r/sp-row.result +++ b/mysql-test/r/sp-row.result @@ -2052,8 +2052,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `var` varchar(255) DEFAULT NULL, - `rec.var` varchar(255) DEFAULT NULL + `var` tinytext DEFAULT NULL, + `rec.var` tinytext DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; DROP PROCEDURE p1; @@ -2092,8 +2092,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `var` varchar(255) CHARACTER SET utf8 DEFAULT NULL, - `rec.var` varchar(255) CHARACTER SET utf8 DEFAULT NULL + `var` text CHARACTER SET utf8 DEFAULT NULL, + `rec.var` text CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; DROP PROCEDURE p1; diff --git a/mysql-test/suite/compat/oracle/r/sp-row.result b/mysql-test/suite/compat/oracle/r/sp-row.result index 5712bce3cee..6526b3e1ec3 100644 --- a/mysql-test/suite/compat/oracle/r/sp-row.result +++ b/mysql-test/suite/compat/oracle/r/sp-row.result @@ -2129,8 +2129,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE "t1" ( - "var" varchar(255) DEFAULT NULL, - "rec.var" varchar(255) DEFAULT NULL + "var" tinytext DEFAULT NULL, + "rec.var" tinytext DEFAULT NULL ) DROP TABLE t1; DROP PROCEDURE p1; @@ -2169,8 +2169,8 @@ CALL p1(); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE "t1" ( - "var" varchar(255) CHARACTER SET utf8 DEFAULT NULL, - "rec.var" varchar(255) CHARACTER SET utf8 DEFAULT NULL + "var" text CHARACTER SET utf8 DEFAULT NULL, + "rec.var" text CHARACTER SET utf8 DEFAULT NULL ) DROP TABLE t1; DROP PROCEDURE p1; diff --git a/sql/field.cc b/sql/field.cc index fa3104f69fe..8b4aac93a9c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2003,15 +2003,15 @@ bool Field_num::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *charset_arg) + const DTCollation &collation) :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg) { - field_charset= charset_arg; - if (charset_arg->state & MY_CS_BINSORT) + field_charset= collation.collation; + if (collation.collation->state & MY_CS_BINSORT) flags|=BINARY_FLAG; - field_derivation= DERIVATION_IMPLICIT; - field_repertoire= my_charset_repertoire(charset_arg); + field_derivation= collation.derivation; + field_repertoire= collation.repertoire; } @@ -7756,10 +7756,10 @@ Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, TABLE_SHARE *share, uint blob_pack_length, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length), null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, - cs), + collation), packlength(blob_pack_length) { DBUG_ASSERT(blob_pack_length <= 4); // Only pack lengths 1-4 supported currently diff --git a/sql/field.h b/sql/field.h index 814f3b05811..6a350642463 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1306,9 +1306,6 @@ public: virtual enum Derivation derivation(void) const { return DERIVATION_IMPLICIT; } virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } - virtual void set_derivation(enum Derivation derivation_arg, - uint repertoire_arg) - { } virtual int set_time() { return 1; } bool set_warning(Sql_condition::enum_warning_level, unsigned int code, int cuted_increment) const; @@ -1659,7 +1656,8 @@ public: const Item_equal *item_equal); Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, - const LEX_CSTRING *field_name_arg, CHARSET_INFO *charset); + const LEX_CSTRING *field_name_arg, + const DTCollation &collation); uint decimals() const { return NOT_FIXED_DEC; } int save_in_field(Field *to) { return save_in_field_str(to); } bool memcpy_field_possible(const Field *from) const @@ -1679,12 +1677,6 @@ public: uint repertoire(void) const { return field_repertoire; } CHARSET_INFO *charset(void) const { return field_charset; } enum Derivation derivation(void) const { return field_derivation; } - void set_derivation(enum Derivation derivation_arg, - uint repertoire_arg) - { - field_derivation= derivation_arg; - field_repertoire= repertoire_arg; - } bool binary() const { return field_charset == &my_charset_bin; } uint32 max_display_length() { return field_length; } friend class Create_field; @@ -1726,9 +1718,10 @@ protected: public: Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, - const LEX_CSTRING *field_name_arg, CHARSET_INFO *charset_arg) + const LEX_CSTRING *field_name_arg, + const DTCollation &collation) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, - field_name_arg, charset_arg) + field_name_arg, collation) {} int store_decimal(const my_decimal *d); @@ -2222,9 +2215,9 @@ class Field_null :public Field_str { public: Field_null(uchar *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_str(ptr_arg, len_arg, null, 1, - unireg_check_arg, field_name_arg, cs) + unireg_check_arg, field_name_arg, collation) {} const Type_handler *type_handler() const { return &type_handler_null; } Copy_func *get_copy_func(const Field *from) const @@ -3023,15 +3016,15 @@ public: Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, cs), + unireg_check_arg, field_name_arg, collation), can_alter_field_type(1) {}; Field_string(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), + NONE, field_name_arg, collation), can_alter_field_type(1) {}; const Type_handler *type_handler() const @@ -3110,18 +3103,18 @@ public: uint32 len_arg, uint length_bytes_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, CHARSET_INFO *cs) + TABLE_SHARE *share, const DTCollation &collation) :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, cs), + unireg_check_arg, field_name_arg, collation), length_bytes(length_bytes_arg) { share->varchar_fields++; } Field_varstring(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, CHARSET_INFO *cs) + TABLE_SHARE *share, const DTCollation &collation) :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), + NONE, field_name_arg, collation), length_bytes(len_arg < 256 ? 1 :2) { share->varchar_fields++; @@ -3210,20 +3203,21 @@ protected: public: Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, - TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs); + TABLE_SHARE *share, uint blob_pack_length, + const DTCollation &collation); Field_blob(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs) + const DTCollation &collation) :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs), + NONE, field_name_arg, collation), packlength(4) { flags|= BLOB_FLAG; } Field_blob(uint32 len_arg,bool maybe_null_arg, const LEX_CSTRING *field_name_arg, - CHARSET_INFO *cs, bool set_packlength) + const DTCollation &collation, bool set_packlength) :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, - NONE, field_name_arg, cs) + NONE, field_name_arg, collation) { flags|= BLOB_FLAG; packlength= 4; @@ -3501,9 +3495,9 @@ public: enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint packlength_arg, TYPELIB *typelib_arg, - CHARSET_INFO *charset_arg) + const DTCollation &collation) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, charset_arg), + unireg_check_arg, field_name_arg, collation), packlength(packlength_arg),typelib(typelib_arg) { flags|=ENUM_FLAG; @@ -3594,12 +3588,12 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg, uint32 packlength_arg, - TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) + TYPELIB *typelib_arg, const DTCollation &collation) :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, packlength_arg, - typelib_arg,charset_arg), - empty_set_string("", 0, charset_arg) + typelib_arg, collation), + empty_set_string("", 0, collation.collation) { flags=(flags & ~ENUM_FLAG) | SET_FLAG; } diff --git a/sql/item.cc b/sql/item.cc index 6199aba12d5..3ee8985c779 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6205,82 +6205,6 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs) } -/** - Create a field to hold a string value from an item. - - If too_big_for_varchar() create a blob @n - If max_length > 0 create a varchar @n - If max_length == 0 create a CHAR(0) - - @param table Table for which the field is created -*/ - -Field *Item::make_string_field(TABLE *table) -{ - Field *field; - MEM_ROOT *mem_root= table->in_use->mem_root; - DBUG_ASSERT(collation.collation); - /* - Note: the following check is repeated in - subquery_types_allow_materialization(): - */ - if (too_big_for_varchar()) - field= new (mem_root) - Field_blob(max_length, maybe_null, &name, - collation.collation, TRUE); - /* Item_type_holder holds the exact type, do not change it */ - else if (max_length > 0 && - (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) - field= new (mem_root) - Field_varstring(max_length, maybe_null, &name, table->s, - collation.collation); - else - field= new (mem_root) - Field_string(max_length, maybe_null, &name, collation.collation); - if (field) - field->init(table); - return field; -} - - -/** - Create a field based on field_type of argument. - - This is used to create a field for - - IFNULL(x,something) - - time functions - - prepared statement placeholders - - SP variables with data type references: DECLARE a t1.a%TYPE; - - @retval - NULL error - @retval - \# Created field -*/ - -Field *Item::tmp_table_field_from_field_type(TABLE *table) -{ - const Type_handler *handler= type_handler(); - Record_addr addr(maybe_null); - - switch (handler->field_type()) { - case MYSQL_TYPE_DECIMAL: - handler= &type_handler_newdecimal; - break; - case MYSQL_TYPE_NULL: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - return make_string_field(table); - default: - break; - } - return handler->make_and_init_table_field(&name, addr, *this, table); -} - - /* ARGSUSED */ void Item_field::make_field(THD *thd, Send_field *tmp_field) { @@ -10256,6 +10180,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) }; maybe_null|= item->maybe_null; get_full_info(item); + set_handler(Item_type_holder::type_handler()->type_handler_for_union(this)); /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ prev_decimal_int_part= decimal_int_part(); @@ -10266,62 +10191,6 @@ bool Item_type_holder::join_types(THD *thd, Item *item) } -/** - Make temporary table field according collected information about type - of UNION result. - - @param table temporary table for which we create fields - - @return - created field -*/ - -Field *Item_type_holder::make_field_by_type(TABLE *table) -{ - /* - The field functions defines a field to be not null if null_ptr is not 0 - */ - uchar *null_ptr= maybe_null ? (uchar*) "" : 0; - Field *field; - - 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, - Field::NONE, &name, - get_enum_pack_length(enum_set_typelib->count), - enum_set_typelib, collation.collation); - if (field) - field->init(table); - return field; - } - case MYSQL_TYPE_SET: - { - DBUG_ASSERT(enum_set_typelib); - field= new Field_set((uchar *) 0, max_length, null_ptr, 0, - Field::NONE, &name, - get_set_pack_length(enum_set_typelib->count), - enum_set_typelib, collation.collation); - if (field) - field->init(table); - return field; - } - case MYSQL_TYPE_NULL: - return make_string_field(table); - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - set_handler(Type_handler::blob_type_handler(max_length)); - break; - default: - break; - } - return tmp_table_field_from_field_type(table); -} - - /** Get full information from Item about enum/set fields to be able to create them later. diff --git a/sql/item.h b/sql/item.h index 28bc0283495..7200b69b7b5 100644 --- a/sql/item.h +++ b/sql/item.h @@ -536,8 +536,22 @@ protected: SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); - virtual Field *make_string_field(TABLE *table); - Field *tmp_table_field_from_field_type(TABLE *table); + /** + Create a field based on field_type of argument. + This is used to create a field for + - IFNULL(x,something) + - time functions + - prepared statement placeholders + - SP variables with data type references: DECLARE a TYPE OF t1.a; + @retval NULL error + @retval !NULL on success + */ + Field *tmp_table_field_from_field_type(TABLE *table) + { + const Type_handler *h= type_handler()->type_handler_for_tmp_table(this); + return h->make_and_init_table_field(&name, Record_addr(maybe_null), + *this, table); + } Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length); void push_note_converted_to_negative_complement(THD *thd); @@ -5891,12 +5905,18 @@ public: } enum Type type() const { return TYPE_HOLDER; } + TYPELIB *get_typelib() const { return enum_set_typelib; } double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); String *val_str(String*); bool join_types(THD *thd, Item *); - Field *make_field_by_type(TABLE *table); + Field *create_tmp_field(bool group, TABLE *table) + { + return Item_type_holder::type_handler()-> + make_and_init_table_field(&name, Record_addr(maybe_null), + *this, table); + } 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.cc b/sql/item_sum.cc index 1eac5ed2593..6d510253259 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3318,24 +3318,6 @@ void Item_func_group_concat::cleanup() } -Field *Item_func_group_concat::make_string_field(TABLE *table_arg) -{ - Field *field; - DBUG_ASSERT(collation.collation); - - if (too_big_for_varchar()) - field= new Field_blob(max_length, - maybe_null, &name, collation.collation, TRUE); - else - field= new Field_varstring(max_length, - maybe_null, &name, table_arg->s, collation.collation); - - if (field) - field->init(table_arg); - return field; -} - - Item *Item_func_group_concat::copy_or_same(THD* thd) { return new (thd->mem_root) Item_func_group_concat(thd, this); diff --git a/sql/item_sum.h b/sql/item_sum.h index 039ae0de1a8..33ee83f147b 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1636,9 +1636,6 @@ class Item_func_group_concat : public Item_sum friend int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), void* item_arg); -protected: - virtual Field *make_string_field(TABLE *table); - public: Item_func_group_concat(THD *thd, Name_resolution_context *context_arg, bool is_distinct, List *is_select, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3eecd9b2544..b3c427bf043 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15880,19 +15880,8 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) } case TIME_RESULT: case DECIMAL_RESULT: - new_field= tmp_table_field_from_field_type(table); - break; case STRING_RESULT: - DBUG_ASSERT(collation.collation); - /* - GEOMETRY fields have STRING_RESULT result type. - To preserve type they needed to be handled separately. - */ - if (field_type() == MYSQL_TYPE_GEOMETRY) - new_field= tmp_table_field_from_field_type(table); - else - new_field= make_string_field(table); - new_field->set_derivation(collation.derivation, collation.repertoire); + new_field= tmp_table_field_from_field_type(table); break; case ROW_RESULT: // This case should never be choosen @@ -16029,6 +16018,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, } switch (type) { + case Item::TYPE_HOLDER: case Item::SUM_FUNC_ITEM: { result= item->create_tmp_field(group, table); @@ -16158,11 +16148,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, return create_tmp_field_from_item(thd, item, table, (make_copy_field ? 0 : copy_func), modify_item); - case Item::TYPE_HOLDER: - result= ((Item_type_holder *)item)->make_field_by_type(table); - result->set_derivation(item->collation.derivation, - item->collation.repertoire); - return result; default: // Dosen't have to be stored return 0; } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 61521052444..9b4aa61cbdb 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -154,6 +154,17 @@ Type_handler::string_type_handler(uint max_octet_length) } +const Type_handler * +Type_handler::varstring_type_handler(const Item *item) +{ + if (!item->max_length) + return &type_handler_string; + if (item->too_big_for_varchar()) + return blob_type_handler(item->max_length); + return &type_handler_varchar; +} + + const Type_handler * Type_handler::blob_type_handler(uint max_octet_length) { @@ -167,6 +178,12 @@ Type_handler::blob_type_handler(uint max_octet_length) } +const Type_handler * +Type_handler::blob_type_handler(const Item *item) +{ + return blob_type_handler(item->max_length); +} + /** This method is used by: - Item_sum_hybrid, e.g. MAX(item), MIN(item). @@ -1514,7 +1531,7 @@ Field *Type_handler_string::make_table_field(const LEX_CSTRING *name, { return new (table->in_use->mem_root) Field_string(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, - Field::NONE, name, attr.collation.collation); + Field::NONE, name, attr.collation); } @@ -1529,7 +1546,7 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name, HA_VARCHAR_PACKLENGTH(attr.max_length), addr.null_ptr, addr.null_bit, Field::NONE, name, - table->s, attr.collation.collation); + table->s, attr.collation); } @@ -1542,7 +1559,7 @@ Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name, return new (table->in_use->mem_root) Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, Field::NONE, name, table->s, - 1, attr.collation.collation); + 1, attr.collation); } @@ -1555,7 +1572,7 @@ Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name, return new (table->in_use->mem_root) Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, Field::NONE, name, table->s, - 2, attr.collation.collation); + 2, attr.collation); } @@ -1569,7 +1586,7 @@ Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name, return new (table->in_use->mem_root) Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, Field::NONE, name, table->s, - 3, attr.collation.collation); + 3, attr.collation); } @@ -1582,7 +1599,7 @@ Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name, return new (table->in_use->mem_root) Field_blob(addr.ptr, addr.null_ptr, addr.null_bit, Field::NONE, name, table->s, - 4, attr.collation.collation); + 4, attr.collation); } @@ -1607,12 +1624,13 @@ Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name, const Type_all_attributes &attr, TABLE *table) const { - /* - Will be implemented when we split Item_type_holder::make_field_by_type() - and/or reuse Type_handler::make_table_field() in make_field() in field.cc - */ - DBUG_ASSERT(0); - return 0; + TYPELIB *typelib= attr.get_typelib(); + DBUG_ASSERT(typelib); + return new (table->in_use->mem_root) + Field_enum(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + get_enum_pack_length(typelib->count), typelib, + attr.collation); } @@ -1622,12 +1640,13 @@ Field *Type_handler_set::make_table_field(const LEX_CSTRING *name, TABLE *table) const { - /* - Will be implemented when we split Item_type_holder::make_field_by_type() - and/or reuse Type_handler::make_table_field() in make_field() in field.cc - */ - DBUG_ASSERT(0); - return 0; + TYPELIB *typelib= attr.get_typelib(); + DBUG_ASSERT(typelib); + return new (table->in_use->mem_root) + Field_set(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit, + Field::NONE, name, + get_enum_pack_length(typelib->count), typelib, + attr.collation); } /*************************************************************************/ @@ -3714,7 +3733,7 @@ bool Type_handler_string_result:: /* Materialization also is unable to work when create_tmp_table() will create a blob column because item->max_length is too big. - The following test is copied from Item::make_string_field(): + The following test is copied from varstring_type_handler(). */ !inner->too_big_for_varchar(); } @@ -3730,3 +3749,33 @@ bool Type_handler_temporal_result:: } /***************************************************************************/ + + +const Type_handler * +Type_handler_null::type_handler_for_tmp_table(const Item *item) const +{ + return &type_handler_string; +} + + +const Type_handler * +Type_handler_null::type_handler_for_union(const Item *item) const +{ + return &type_handler_string; +} + + +const Type_handler * +Type_handler_olddecimal::type_handler_for_tmp_table(const Item *item) const +{ + return &type_handler_newdecimal; +} + +const Type_handler * +Type_handler_olddecimal::type_handler_for_union(const Item *item) const +{ + return &type_handler_newdecimal; +} + + +/***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index 0d4230403f4..e3e86ae7204 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -130,6 +130,21 @@ public: derivation= DERIVATION_NONE; repertoire= MY_REPERTOIRE_UNICODE30; } + DTCollation(CHARSET_INFO *collation_arg) + { + /* + This constructor version is used in combination with Field constructors, + to pass "CHARSET_INFO" instead of the full DTCollation. + Therefore, derivation is set to DERIVATION_IMPLICIT, which is the + proper derivation for table fields. + We should eventually remove all code pieces that pass "CHARSET_INFO" + (e.g. in storage engine sources) and fix to pass the full DTCollation + instead. Then, this constructor can be removed. + */ + collation= collation_arg; + derivation= DERIVATION_IMPLICIT; + repertoire= my_charset_repertoire(collation_arg); + } DTCollation(CHARSET_INFO *collation_arg, Derivation derivation_arg) { collation= collation_arg; @@ -332,6 +347,7 @@ public: datatype indepented method. */ virtual uint uint_geometry_type() const= 0; + virtual TYPELIB *get_typelib() const { return NULL; } }; @@ -390,6 +406,15 @@ protected: public: static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); + /** + Return a string type handler for Item + If too_big_for_varchar() returns a BLOB variant, according to length. + If max_length > 0 create a VARCHAR(n) + If max_length == 0 create a CHAR(0) + @param item - the Item to get the handler to. + */ + static const Type_handler *varstring_type_handler(const Item *item); + static const Type_handler *blob_type_handler(const Item *item); static const Type_handler *get_handler_by_field_type(enum_field_types type); static const Type_handler *get_handler_by_real_type(enum_field_types type); static const Type_handler *get_handler_by_cmp_type(Item_result type); @@ -426,6 +451,14 @@ public: */ virtual bool is_param_long_data_type() const { return false; } virtual const Type_handler *type_handler_for_comparison() const= 0; + virtual const Type_handler *type_handler_for_tmp_table(const Item *) const + { + return this; + } + virtual const Type_handler *type_handler_for_union(const Item *) const + { + return this; + } virtual const Type_handler *cast_to_int_type_handler() const { return this; @@ -1594,6 +1627,8 @@ public: virtual ~Type_handler_olddecimal() {} const Name name() const { return m_name_decimal; } enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const; + const Type_handler *type_handler_for_union(const Item *item) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -1627,6 +1662,8 @@ public: const Name name() const { return m_name_null; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; } const Type_handler *type_handler_for_comparison() const; + const Type_handler *type_handler_for_tmp_table(const Item *item) const; + const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -1645,6 +1682,10 @@ public: const Name name() const { return m_name_char; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } bool is_param_long_data_type() const { return true; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return varstring_type_handler(item); + } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, @@ -1663,6 +1704,14 @@ public: const Name name() const { return m_name_var_string; } enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; } enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return varstring_type_handler(item); + } + const Type_handler *type_handler_for_union(const Item *item) const + { + return varstring_type_handler(item); + } }; @@ -1673,6 +1722,14 @@ public: virtual ~Type_handler_varchar() {} const Name name() const { return m_name_varchar; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return varstring_type_handler(item); + } + const Type_handler *type_handler_for_union(const Item *item) const + { + return varstring_type_handler(item); + } bool is_param_long_data_type() const { return true; } Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -1687,6 +1744,14 @@ class Type_handler_blob_common: public Type_handler_string_result { public: virtual ~Type_handler_blob_common() { } + const Type_handler *type_handler_for_tmp_table(const Item *item) const + { + return blob_type_handler(item); + } + const Type_handler *type_handler_for_union(const Item *item) const + { + return blob_type_handler(item); + } bool subquery_type_allows_materialization(const Item *inner, const Item *outer) const { From cfb4d9f9dcc6e6bac92785fb32779e157d52daee Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 27 Apr 2017 15:02:35 +0400 Subject: [PATCH 11/20] MDEV-12592 Illegal mix of collations with the HEX function Fixing repertoire for HEX() from MY_REPERTOIRE_EXTENDED to MY_REPERTOIRE_ASCII. --- mysql-test/r/func_str.result | 17 +++++++++++++++++ mysql-test/t/func_str.test | 20 ++++++++++++++++++++ sql/item_strfunc.h | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 4194a6359c6..8a1302c9b5c 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -4661,3 +4661,20 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# Start of 10.3 tests +# +# +# MDEV-12592 Illegal mix of collations with the HEX function +# +SET NAMES utf8; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1); +INSERT INTO t1 VALUES (0x09),('a'); +SELECT IF(a<' ',HEX(a),a) FROM t1 ORDER BY a; +IF(a<' ',HEX(a),a) +09 +a +DROP TABLE t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index bc5b112e949..b3f6b4faf49 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1806,3 +1806,23 @@ DROP TABLE t1; --echo # --echo # End of 10.1 tests --echo # + + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12592 Illegal mix of collations with the HEX function +--echo # + +SET NAMES utf8; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1); +INSERT INTO t1 VALUES (0x09),('a'); +SELECT IF(a<' ',HEX(a),a) FROM t1 ORDER BY a; +DROP TABLE t1; + + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 58bd6c99f80..6fdee625749 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1074,7 +1074,7 @@ public: } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); decimals=0; fix_char_length(args[0]->max_length * 2); m_arg0_type_handler= args[0]->type_handler(); From 9346939545a513abee09b2c65e27737a66cb1864 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 27 Apr 2017 15:40:16 +0400 Subject: [PATCH 12/20] MDEV-12601 Hybrid functions create a column of an impossible type DOUBLE(256,4) --- mysql-test/r/func_hybrid_type.result | 12 ++++++++++++ mysql-test/t/func_hybrid_type.test | 10 ++++++++++ sql/item_func.cc | 2 ++ 3 files changed, 24 insertions(+) diff --git a/mysql-test/r/func_hybrid_type.result b/mysql-test/r/func_hybrid_type.result index edb3a553492..dfc552cc58c 100644 --- a/mysql-test/r/func_hybrid_type.result +++ b/mysql-test/r/func_hybrid_type.result @@ -3500,5 +3500,17 @@ t2 CREATE TABLE `t2` ( DROP TABLE t2; DROP TABLE t1; # +# MDEV-12601 Hybrid functions create a column of an impossible type DOUBLE(256,4) +# +CREATE TABLE t1 (a DOUBLE(255,4),b DOUBLE(255,3)); +CREATE TABLE t2 AS SELECT COALESCE(a,b) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `COALESCE(a,b)` double(255,4) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# # End of 10.3 tests # diff --git a/mysql-test/t/func_hybrid_type.test b/mysql-test/t/func_hybrid_type.test index 2efbdbe0451..918320a68c5 100644 --- a/mysql-test/t/func_hybrid_type.test +++ b/mysql-test/t/func_hybrid_type.test @@ -500,6 +500,16 @@ SHOW CREATE TABLE t2; DROP TABLE t2; DROP TABLE t1; +--echo # +--echo # MDEV-12601 Hybrid functions create a column of an impossible type DOUBLE(256,4) +--echo # + +CREATE TABLE t1 (a DOUBLE(255,4),b DOUBLE(255,3)); +CREATE TABLE t2 AS SELECT COALESCE(a,b) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; + --echo # --echo # End of 10.3 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index 584d387f89c..5574ae7511e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -662,6 +662,8 @@ void Item_func::count_real_length(Item **items, uint nitems) else max_length= length; } + // Corner case: COALESCE(DOUBLE(255,4), DOUBLE(255,3)) -> FLOAT(255, 4) + set_if_smaller(max_length, MAX_FIELD_CHARLENGTH); } From a147eea62c7ad0462f1ee85e50c7628a734c33ae Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 27 Apr 2017 21:58:10 +0400 Subject: [PATCH 13/20] MDEV-12607 Hybrid functions create wrong VARBINARY length when mixing character and binary data --- mysql-test/r/ctype_utf8.result | 16 ++++++++++++++++ mysql-test/t/ctype_utf8.test | 12 ++++++++++++ sql/item_func.cc | 17 ++++++++++++++++- sql/item_func.h | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 573799ff6e5..f6a88d49579 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -11184,5 +11184,21 @@ SET NAMES utf8; CREATE TABLE t1 (a SET('a,bü')); ERROR 22007: Illegal set 'a,bü' value found during parsing # +# MDEV-12607 Hybrid functions create wrong VARBINARY length when mixing character and binary data +# +SET sql_mode=''; +SET NAMES utf8; +CREATE OR REPLACE TABLE t1 AS SELECT COALESCE('ßa',_binary 'a'); +SELECT * FROM t1; +COALESCE('ßa',_binary 'a') +ßa +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `COALESCE('ßa',_binary 'a')` varbinary(6) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +SET sql_mode=DEFAULT; +# # End of 10.3 tests # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 5e747bc4b3c..b191b27d367 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -2109,6 +2109,18 @@ SET NAMES utf8; --error ER_ILLEGAL_VALUE_FOR_TYPE CREATE TABLE t1 (a SET('a,bü')); +--echo # +--echo # MDEV-12607 Hybrid functions create wrong VARBINARY length when mixing character and binary data +--echo # +SET sql_mode=''; +SET NAMES utf8; +CREATE OR REPLACE TABLE t1 AS SELECT COALESCE('ßa',_binary 'a'); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +SET sql_mode=DEFAULT; + + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item_func.cc b/sql/item_func.cc index 5574ae7511e..0bdf708aecb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -632,6 +632,18 @@ void Item_func::count_only_length(Item **item, uint nitems) } +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. @@ -681,7 +693,10 @@ 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; - count_only_length(items, nitems); + 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; } diff --git a/sql/item_func.h b/sql/item_func.h index 4e93c93aec6..71fa904a707 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -43,6 +43,7 @@ protected: 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); From ea18b11235448a6416de5ce78792e24861a7a73e Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 28 Apr 2017 16:27:55 +0400 Subject: [PATCH 14/20] MDEV-12619 UNION creates excessive integer column types for integer literals --- mysql-test/r/gis.result | 60 +++++++++---------- mysql-test/r/metadata.result | 4 +- mysql-test/r/union.result | 32 +++++++++- .../innodb_gis/r/create_spatial_index.result | 2 +- mysql-test/t/union.test | 24 ++++++++ sql/item.h | 15 +++++ 6 files changed, 103 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 43de7d2e7d6..fdc0e1e6368 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -4030,65 +4030,65 @@ DROP TABLE t1; # CREATE TABLE t1 (a GEOMETRY); SELECT POINT(1,1) + 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '+' +ERROR HY000: Illegal parameter data types geometry and int for operation '+' SELECT POINT(1,1) - 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '-' +ERROR HY000: Illegal parameter data types geometry and int for operation '-' SELECT POINT(1,1) * 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '*' +ERROR HY000: Illegal parameter data types geometry and int for operation '*' SELECT POINT(1,1) / 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '/' +ERROR HY000: Illegal parameter data types geometry and int for operation '/' SELECT POINT(1,1) MOD 1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '%' +ERROR HY000: Illegal parameter data types geometry and int for operation '%' SELECT 1 + POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '+' +ERROR HY000: Illegal parameter data types int and geometry for operation '+' SELECT 1 - POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '-' +ERROR HY000: Illegal parameter data types int and geometry for operation '-' SELECT 1 * POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '*' +ERROR HY000: Illegal parameter data types int and geometry for operation '*' SELECT 1 / POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '/' +ERROR HY000: Illegal parameter data types int and geometry for operation '/' SELECT 1 MOD POINT(1,1); -ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' +ERROR HY000: Illegal parameter data types int and geometry for operation '%' SELECT a + 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '+' +ERROR HY000: Illegal parameter data types geometry and int for operation '+' SELECT a - 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '-' +ERROR HY000: Illegal parameter data types geometry and int for operation '-' SELECT a * 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '*' +ERROR HY000: Illegal parameter data types geometry and int for operation '*' SELECT a / 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '/' +ERROR HY000: Illegal parameter data types geometry and int for operation '/' SELECT a MOD 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '%' +ERROR HY000: Illegal parameter data types geometry and int for operation '%' SELECT 1 + a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '+' +ERROR HY000: Illegal parameter data types int and geometry for operation '+' SELECT 1 - a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '-' +ERROR HY000: Illegal parameter data types int and geometry for operation '-' SELECT 1 * a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '*' +ERROR HY000: Illegal parameter data types int and geometry for operation '*' SELECT 1 / a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '/' +ERROR HY000: Illegal parameter data types int and geometry for operation '/' SELECT 1 MOD a FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' +ERROR HY000: Illegal parameter data types int and geometry for operation '%' SELECT COALESCE(a) + 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '+' +ERROR HY000: Illegal parameter data types geometry and int for operation '+' SELECT COALESCE(a) - 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '-' +ERROR HY000: Illegal parameter data types geometry and int for operation '-' SELECT COALESCE(a) * 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '*' +ERROR HY000: Illegal parameter data types geometry and int for operation '*' SELECT COALESCE(a) / 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '/' +ERROR HY000: Illegal parameter data types geometry and int for operation '/' SELECT COALESCE(a) MOD 1 FROM t1; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '%' +ERROR HY000: Illegal parameter data types geometry and int for operation '%' SELECT 1 + COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '+' +ERROR HY000: Illegal parameter data types int and geometry for operation '+' SELECT 1 - COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '-' +ERROR HY000: Illegal parameter data types int and geometry for operation '-' SELECT 1 * COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '*' +ERROR HY000: Illegal parameter data types int and geometry for operation '*' SELECT 1 / COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '/' +ERROR HY000: Illegal parameter data types int and geometry for operation '/' SELECT 1 MOD COALESCE(a) FROM t1; -ERROR HY000: Illegal parameter data types bigint and geometry for operation '%' +ERROR HY000: Illegal parameter data types int and geometry for operation '%' DROP TABLE t1; # # MDEV-12514 Split Item_temporal_func::fix_length_and_dec() diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 3db3bcd450f..d31b2c5efe0 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -76,12 +76,12 @@ def aaa @arg00 @arg00 8 20 1 Y 32768 0 63 1 select 1 union select 1; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def 1 1 8 20 1 N 32769 0 63 +def 1 1 3 11 1 N 32769 0 63 1 1 select * from (select 1 union select 1) aaa; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def aaa 1 1 8 20 1 N 32769 0 63 +def aaa 1 1 3 11 1 N 32769 0 63 1 1 drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 807a194e773..9949defebf7 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -852,7 +852,7 @@ select * from t1; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `1` bigint(20) NOT NULL DEFAULT 0 + `1` int(11) NOT NULL DEFAULT 0 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 select _latin1"test" union select _latin2"testt" ; @@ -2178,3 +2178,33 @@ WHERE t1_2.b NOT IN ( SELECT 4 UNION ALL SELECT 5 ); a b a b 1 1 1 1 DROP TABLE t1; +# +# Start of 10.3 tests +# +# +# MDEV-12619 UNION creates excessive integer column types for integer literals +# +CREATE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(1) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT 1 UNION SELECT 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(11) NOT NULL DEFAULT 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(11) NOT NULL DEFAULT 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# End of 10.3 tests +# diff --git a/mysql-test/suite/innodb_gis/r/create_spatial_index.result b/mysql-test/suite/innodb_gis/r/create_spatial_index.result index 572e3ac0d14..9629fa03fef 100644 --- a/mysql-test/suite/innodb_gis/r/create_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/create_spatial_index.result @@ -1238,7 +1238,7 @@ Table Op Msg_type Msg_text test.tab check status OK DROP TABLE tab; CREATE TABLE tab(c1 POINT NOT NULL,CONSTRAINT tab_const check(c1 > 0) ) ENGINE=InnoDB; -ERROR HY000: Illegal parameter data types geometry and bigint for operation '>' +ERROR HY000: Illegal parameter data types geometry and int for operation '>' CREATE TABLE tab(c1 POINT NOT NULL,CONSTRAINT tab_const check(CAST(c1 AS BINARY) > 0) ) ENGINE=InnoDB; CREATE SPATIAL INDEX idx1 ON tab(c1) ; SHOW CREATE TABLE tab; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index fa07dc22dbb..04ab71588be 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -1523,3 +1523,27 @@ SELECT * FROM t1 t1_1 LEFT JOIN t1 t1_2 ON ( t1_2.b = t1_1.a ) WHERE t1_2.b NOT IN ( SELECT 4 UNION ALL SELECT 5 ); DROP TABLE t1; + +--echo # +--echo # Start of 10.3 tests +--echo # + +--echo # +--echo # MDEV-12619 UNION creates excessive integer column types for integer literals +--echo # + +CREATE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 AS SELECT 1 UNION SELECT 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 AS SELECT * FROM (SELECT 1 UNION SELECT 1) AS t0; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # End of 10.3 tests +--echo # diff --git a/sql/item.h b/sql/item.h index 7200b69b7b5..886292d394c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3207,6 +3207,17 @@ public: enum Type type() const { return INT_ITEM; } enum Item_result result_type () const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + const Type_handler *type_handler() const + { + // The same condition is repeated in Item::create_tmp_field() + if (max_length > MY_INT32_NUM_DECIMAL_DIGITS - 2) + return &type_handler_longlong; + return &type_handler_long; + } + Field *create_tmp_field(bool group, TABLE *table) + { return tmp_table_field_from_field_type(table); } + Field *create_field_for_create_select(TABLE *table) + { return tmp_table_field_from_field_type(table); } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } my_decimal *val_decimal(my_decimal *); @@ -3717,6 +3728,10 @@ public: unsigned_flag=1; } enum_field_types field_type() const { return int_field_type; } + const Type_handler *type_handler() const + { + return Type_handler::get_handler_by_field_type(int_field_type); + } }; From 7a19c59c003002b13aba27144c18a8a8560e7394 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sat, 29 Apr 2017 21:34:57 +0400 Subject: [PATCH 15/20] MDEV-9395 Add Type_handler::Item_decimal_scale() and Item_divisor_precision_increment() --- sql/field.h | 21 --------------------- sql/item.h | 10 ++-------- sql/sql_type.cc | 30 ++++++++++++++++++++++++++++++ sql/sql_type.h | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/sql/field.h b/sql/field.h index 6a350642463..5b7b08ec37a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -525,27 +525,6 @@ inline bool is_temporal_type(enum_field_types type) } -/** - Tests if field type is temporal and has time part, - i.e. represents TIME, DATETIME or TIMESTAMP types in SQL. - - @param type Field type, as returned by field->type(). - @retval true If field type is temporal type with time part. - @retval false If field type is not temporal type with time part. -*/ -inline bool is_temporal_type_with_time(enum_field_types type) -{ - switch (type) - { - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - return true; - default: - return false; - } -} - enum enum_vcol_info_type { VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, diff --git a/sql/item.h b/sql/item.h index 886292d394c..a6c3ac1b686 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1162,10 +1162,7 @@ public: */ uint decimal_scale() const { - return decimals < NOT_FIXED_DEC ? decimals : - is_temporal_type_with_time(field_type()) ? - TIME_SECOND_PART_DIGITS : - MY_MIN(max_length, DECIMAL_MAX_SCALE); + return type_handler()->Item_decimal_scale(this); } /* Returns how many digits a divisor adds into a division result. @@ -1186,10 +1183,7 @@ public: */ uint divisor_precision_increment() const { - return decimals < NOT_FIXED_DEC ? decimals : - is_temporal_type_with_time(field_type()) ? - TIME_SECOND_PART_DIGITS : - decimals; + return type_handler()->Item_divisor_precision_increment(this); } /** TIME or DATETIME precision of the item: 0..6 diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 9b4aa61cbdb..8245d0993be 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3696,6 +3696,36 @@ uint Type_handler_string_result::Item_temporal_precision(Item *item, /***************************************************************************/ +uint Type_handler::Item_decimal_scale(const Item *item) const +{ + return item->decimals < NOT_FIXED_DEC ? + item->decimals : + MY_MIN(item->max_length, DECIMAL_MAX_SCALE); +} + +uint Type_handler_temporal_result:: + Item_decimal_scale_with_seconds(const Item *item) const +{ + return item->decimals < NOT_FIXED_DEC ? + item->decimals : + TIME_SECOND_PART_DIGITS; +} + +uint Type_handler::Item_divisor_precision_increment(const Item *item) const +{ + return item->decimals; +} + +uint Type_handler_temporal_result:: + Item_divisor_precision_increment_with_seconds(const Item *item) const +{ + return item->decimals < NOT_FIXED_DEC ? + item->decimals : + TIME_SECOND_PART_DIGITS; +} + +/***************************************************************************/ + bool Type_handler_real_result:: subquery_type_allows_materialization(const Item *inner, const Item *outer) const diff --git a/sql/sql_type.h b/sql/sql_type.h index e3e86ae7204..abd8463ec17 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -479,6 +479,12 @@ public: } virtual uint Item_time_precision(Item *item) const; virtual uint Item_datetime_precision(Item *item) const; + virtual uint Item_decimal_scale(const Item *item) const; + /* + Returns how many digits a divisor adds into a division result. + See Item::divisor_precision_increment() in item.h for more comments. + */ + virtual uint Item_divisor_precision_increment(const Item *) const; /** Makes a temporary table Field to handle numeric aggregate functions, e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc. @@ -1110,6 +1116,9 @@ public: class Type_handler_temporal_result: public Type_handler { +protected: + uint Item_decimal_scale_with_seconds(const Item *item) const; + uint Item_divisor_precision_increment_with_seconds(const Item *) const; public: Item_result result_type() const { return STRING_RESULT; } Item_result cmp_type() const { return TIME_RESULT; } @@ -1441,6 +1450,14 @@ public: { return MYSQL_TIMESTAMP_TIME; } + uint Item_decimal_scale(const Item *item) const + { + return Item_decimal_scale_with_seconds(item); + } + uint Item_divisor_precision_increment(const Item *item) const + { + return Item_divisor_precision_increment_with_seconds(item); + } const Type_handler *type_handler_for_comparison() const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const; @@ -1543,6 +1560,14 @@ public: { return MYSQL_TIMESTAMP_DATETIME; } + uint Item_decimal_scale(const Item *item) const + { + return Item_decimal_scale_with_seconds(item); + } + uint Item_divisor_precision_increment(const Item *item) const + { + return Item_divisor_precision_increment_with_seconds(item); + } String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; @@ -1587,6 +1612,14 @@ public: { return MYSQL_TIMESTAMP_DATETIME; } + uint Item_decimal_scale(const Item *item) const + { + return Item_decimal_scale_with_seconds(item); + } + uint Item_divisor_precision_increment(const Item *item) const + { + return Item_divisor_precision_increment_with_seconds(item); + } String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, Item **items, uint nitems) const; From c67971a8a35a51822eb155181676ef4348cf6134 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sun, 30 Apr 2017 22:50:37 +0400 Subject: [PATCH 16/20] MDEV-12649 Add Type_handler::Item_save_in_value --- sql/item.cc | 2 +- sql/item.h | 49 ++-------------------------- sql/sql_type.cc | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_type.h | 11 +++++++ 4 files changed, 101 insertions(+), 48 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 3ee8985c779..8cb898e310f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3787,7 +3787,7 @@ bool Item_param::set_from_item(THD *thd, Item *item) } } struct st_value tmp; - if (!item->store(&tmp, 0)) + if (!item->save_in_value(&tmp)) { unsigned_flag= item->unsigned_flag; switch (item->cmp_type()) { diff --git a/sql/item.h b/sql/item.h index a6c3ac1b686..440905b51f6 100644 --- a/sql/item.h +++ b/sql/item.h @@ -676,54 +676,9 @@ public: */ virtual inline void quick_fix_field() { fixed= 1; } - bool store(struct st_value *value, ulonglong fuzzydate) + bool save_in_value(struct st_value *value) { - switch (cmp_type()) { - case INT_RESULT: - { - value->m_type= unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; - value->value.m_longlong= val_int(); - break; - } - case REAL_RESULT: - { - value->m_type= DYN_COL_DOUBLE; - value->value.m_double= val_real(); - break; - } - case DECIMAL_RESULT: - { - value->m_type= DYN_COL_DECIMAL; - my_decimal *dec= val_decimal(&value->m_decimal); - if (dec != &value->m_decimal && !null_value) - my_decimal2decimal(dec, &value->m_decimal); - break; - } - case STRING_RESULT: - { - value->m_type= DYN_COL_STRING; - String *str= val_str(&value->m_string); - if (str != &value->m_string && !null_value) - value->m_string.set(str->ptr(), str->length(), str->charset()); - break; - } - case TIME_RESULT: - { - value->m_type= DYN_COL_DATETIME; - get_date(&value->value.m_time, fuzzydate); - break; - } - case ROW_RESULT: - DBUG_ASSERT(false); - null_value= true; - break; - } - if (null_value) - { - value->m_type= DYN_COL_NULL; - return true; - } - return false; + return type_handler()->Item_save_in_value(this, value); } /* Function returns 1 on overflow and -1 on fatal errors */ diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 8245d0993be..ad9059ecd57 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3808,4 +3808,91 @@ Type_handler_olddecimal::type_handler_for_union(const Item *item) const } +/***************************************************************************/ + +bool Type_handler::check_null(const Item *item, st_value *value) const +{ + if (item->null_value) + { + value->m_type= DYN_COL_NULL; + return true; + } + return false; +} + + +bool Type_handler_null:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_NULL; + return true; +} + + +bool Type_handler_row:: + Item_save_in_value(Item *item, st_value *value) const +{ + DBUG_ASSERT(0); + value->m_type= DYN_COL_NULL; + return true; +} + + +bool Type_handler_int_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= item->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; + value->value.m_longlong= item->val_int(); + return check_null(item, value); +} + + +bool Type_handler_real_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DOUBLE; + value->value.m_double= item->val_real(); + return check_null(item, value); +} + + +bool Type_handler_decimal_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DECIMAL; + my_decimal *dec= item->val_decimal(&value->m_decimal); + if (dec != &value->m_decimal && !item->null_value) + my_decimal2decimal(dec, &value->m_decimal); + return check_null(item, value); +} + + +bool Type_handler_string_result:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_STRING; + String *str= item->val_str(&value->m_string); + if (str != &value->m_string && !item->null_value) + value->m_string.set(str->ptr(), str->length(), str->charset()); + return check_null(item, value); +} + + +bool Type_handler_temporal_with_date:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DATETIME; + item->get_date(&value->value.m_time, sql_mode_for_dates(current_thd)); + return check_null(item, value); +} + + +bool Type_handler_time_common:: + Item_save_in_value(Item *item, st_value *value) const +{ + value->m_type= DYN_COL_DATETIME; + item->get_time(&value->value.m_time); + return check_null(item, value); +} + /***************************************************************************/ diff --git a/sql/sql_type.h b/sql/sql_type.h index abd8463ec17..d9694c98cb8 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -63,6 +63,7 @@ class in_vector; class Type_std_attributes; class Sort_param; class Arg_comparator; +struct st_value; struct TABLE; struct SORT_FIELD_ATTR; @@ -403,6 +404,7 @@ protected: Item_func_or_sum_illegal_param(const char *name) const; bool Item_func_or_sum_illegal_param(const Item_func_or_sum *) const; + bool check_null(const Item *item, st_value *value) const; public: static const Type_handler *blob_type_handler(uint max_octet_length); static const Type_handler *string_type_handler(uint max_octet_length); @@ -537,6 +539,7 @@ public: SORT_FIELD_ATTR *attr) const= 0; virtual uint32 max_display_length(const Item *item) const= 0; + virtual bool Item_save_in_value(Item *item, st_value *value) const= 0; virtual int Item_save_in_field(Item *item, Field *field, bool no_conversions) const= 0; @@ -752,6 +755,7 @@ public: DBUG_ASSERT(0); return 0; } + bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const { DBUG_ASSERT(0); @@ -960,6 +964,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_save_in_value(Item *item, st_value *value) 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; @@ -1019,6 +1024,7 @@ public: const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; uint32 max_display_length(const Item *item) const; + bool Item_save_in_value(Item *item, st_value *value) 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; @@ -1074,6 +1080,7 @@ public: void sortlength(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *attr) const; + bool Item_save_in_value(Item *item, st_value *value) 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; @@ -1202,6 +1209,7 @@ public: { return Item_temporal_precision(item, false); } + bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const { @@ -1459,6 +1467,7 @@ public: return Item_divisor_precision_increment_with_seconds(item); } const Type_handler *type_handler_for_comparison() const; + bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const; bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, @@ -1500,6 +1509,7 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result public: virtual ~Type_handler_temporal_with_date() {} const Type_handler *type_handler_for_comparison() const; + bool Item_save_in_value(Item *item, st_value *value) const; int Item_save_in_field(Item *item, Field *field, bool no_conversions) 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; @@ -1698,6 +1708,7 @@ public: const Type_handler *type_handler_for_tmp_table(const Item *item) const; const Type_handler *type_handler_for_union(const Item *) const; uint32 max_display_length(const Item *item) const { return 0; } + bool Item_save_in_value(Item *item, st_value *value) const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; Field *make_table_field(const LEX_CSTRING *name, From 50b70e765bcdb361e98ec6a3a5fc51d92e899630 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 2 May 2017 07:49:06 +0400 Subject: [PATCH 17/20] 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); + } + }; From 85b73e2254359823515536075e7e20738a732ec1 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 2 May 2017 11:39:20 +0400 Subject: [PATCH 18/20] MDEV-12656 Crash in CREATE..SELECT..UNION with a ENUM column and NULL --- mysql-test/r/type_enum.result | 54 +++++++++++++++++++++++++++++++++++ mysql-test/t/type_enum.test | 45 +++++++++++++++++++++++++++++ sql/item.cc | 11 +++++-- sql/item.h | 15 +++++----- sql/sql_type.cc | 12 ++++++++ sql/sql_type.h | 6 ++++ 6 files changed, 133 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/type_enum.result b/mysql-test/r/type_enum.result index 2a08a140087..02d71c6bd9f 100644 --- a/mysql-test/r/type_enum.result +++ b/mysql-test/r/type_enum.result @@ -2225,6 +2225,9 @@ a DROP TABLE t1; # +# Start of 10.3 tests +# +# # MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case # CREATE TABLE t1 (a ENUM('a','b','c','1'),KEY(a)); @@ -2257,3 +2260,54 @@ EXPLAIN SELECT * FROM t1 WHERE a='1.1'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables DROP TABLE t1; +# +# MDEV-12656 Crash in CREATE..SELECT..UNION with a ENUM column and NULL +# +CREATE TABLE t1 (a ENUM('a')); +# non-UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT a FROM t1)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +# UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT a FROM t1 UNION SELECT NULL)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +# UNION + SP variable +CREATE PROCEDURE p1() +BEGIN +DECLARE va ENUM('a'); +CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +DROP TABLE t2; +END; +$$ +CALL p1(); +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT va FROM t1 UNION SELECT NULL)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP PROCEDURE p1; +# UNION + anchored SP variable +CREATE PROCEDURE p1() +BEGIN +DECLARE va TYPE OF t1.a; +CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +DROP TABLE t2; +END; +$$ +CALL p1(); +Table Create Table +t2 CREATE TABLE `t2` ( + `(SELECT va FROM t1 UNION SELECT NULL)` varchar(1) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/mysql-test/t/type_enum.test b/mysql-test/t/type_enum.test index d00cf66ccb0..a79335960bc 100644 --- a/mysql-test/t/type_enum.test +++ b/mysql-test/t/type_enum.test @@ -457,6 +457,10 @@ ALTER TABLE t1 MODIFY a ENUM('2001','2002'); SELECT * FROM t1; DROP TABLE t1; +--echo # +--echo # Start of 10.3 tests +--echo # + --echo # --echo # MDEV-12432 Range optimizer for ENUM and SET does not return "Impossible WHERE" in some case --echo # @@ -473,3 +477,44 @@ EXPLAIN SELECT * FROM t1 WHERE a='1x'; EXPLAIN SELECT * FROM t1 WHERE a='1.0'; EXPLAIN SELECT * FROM t1 WHERE a='1.1'; DROP TABLE t1; + +--echo # +--echo # MDEV-12656 Crash in CREATE..SELECT..UNION with a ENUM column and NULL +--echo # + +CREATE TABLE t1 (a ENUM('a')); +--echo # non-UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1); +SHOW CREATE TABLE t2; +DROP TABLE t2; +--echo # UNION + table column +CREATE TABLE t2 AS SELECT (SELECT a FROM t1 UNION SELECT NULL); +SHOW CREATE TABLE t2; +DROP TABLE t2; +--echo # UNION + SP variable +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE va ENUM('a'); + CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +--echo # UNION + anchored SP variable +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + DECLARE va TYPE OF t1.a; + CREATE TABLE t2 AS SELECT (SELECT va FROM t1 UNION SELECT NULL); + SHOW CREATE TABLE t2; + DROP TABLE t2; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/sql/item.cc b/sql/item.cc index c0c99dc22bb..416f889712a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10072,7 +10072,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) if (aggregate_for_result(item_type_handler)) { my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), - Item_type_holder::type_handler()->name().ptr(), + Item_type_holder::real_type_handler()->name().ptr(), item_type_handler->name().ptr(), "UNION"); DBUG_RETURN(true); @@ -10180,7 +10180,14 @@ bool Item_type_holder::join_types(THD *thd, Item *item) }; maybe_null|= item->maybe_null; get_full_info(item); - set_handler(Item_type_holder::type_handler()->type_handler_for_union(this)); + /* + Adjust data type for union, e.g.: + - convert type_handler_null to type_handler_string + - convert type_handler_olddecimal to type_handler_newdecimal + - adjust varchar/blob according to max_length + */ + set_handler(Item_type_holder:: + real_type_handler()->type_handler_for_union(this)); /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */ prev_decimal_int_part= decimal_int_part(); diff --git a/sql/item.h b/sql/item.h index 1123b4beb93..0e004571395 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2604,11 +2604,7 @@ public: const Type_handler *type_handler() const { const Type_handler *handler= field->type_handler(); - // This special code for ENUM and SET should eventually be removed - if (handler == &type_handler_enum || - handler == &type_handler_set) - return &type_handler_string; - return field->type_handler(); + return handler->type_handler_for_item_field(); } enum Item_result result_type () const { @@ -5792,7 +5788,10 @@ public: Item_type_holder(THD*, Item*); const Type_handler *type_handler() const - { return Type_handler_hybrid_field_type::type_handler(); } + { + const Type_handler *handler= Type_handler_hybrid_field_type::type_handler(); + return handler->type_handler_for_item_field(); + } enum_field_types field_type() const { return Type_handler_hybrid_field_type::field_type(); } enum Item_result result_type () const @@ -5813,7 +5812,7 @@ public: } const Type_handler *real_type_handler() const { - return Item_type_holder::type_handler(); + return Type_handler_hybrid_field_type::type_handler(); } enum Type type() const { return TYPE_HOLDER; } @@ -5825,7 +5824,7 @@ public: bool join_types(THD *thd, Item *); Field *create_tmp_field(bool group, TABLE *table) { - return Item_type_holder::type_handler()-> + return Item_type_holder::real_type_handler()-> make_and_init_table_field(&name, Record_addr(maybe_null), *this, table); } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 88ad5bd576c..23cfe20e5e6 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -470,12 +470,24 @@ const Type_handler *Type_handler_row::type_handler_for_comparison() const /***************************************************************************/ +const Type_handler *Type_handler_enum::type_handler_for_item_field() const +{ + return &type_handler_string; +} + + const Type_handler *Type_handler_enum::cast_to_int_type_handler() const { return &type_handler_longlong; } +const Type_handler *Type_handler_set::type_handler_for_item_field() const +{ + return &type_handler_string; +} + + const Type_handler *Type_handler_set::cast_to_int_type_handler() const { return &type_handler_longlong; diff --git a/sql/sql_type.h b/sql/sql_type.h index a1a2beeb1d1..c61142d0a7b 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -579,6 +579,10 @@ public: */ virtual bool is_param_long_data_type() const { return false; } virtual const Type_handler *type_handler_for_comparison() const= 0; + virtual const Type_handler *type_handler_for_item_field() const + { + return this; + } virtual const Type_handler *type_handler_for_tmp_table(const Item *) const { return this; @@ -2053,6 +2057,7 @@ public: const Name name() const { return m_name_enum; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; } + const Type_handler *type_handler_for_item_field() const; const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; @@ -2071,6 +2076,7 @@ public: const Name name() const { return m_name_set; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; } + const Type_handler *type_handler_for_item_field() const; const Type_handler *cast_to_int_type_handler() const; Field *make_conversion_table_field(TABLE *, uint metadata, const Field *target) const; From 07143a73935494056d187bd9da0a5097715d952c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 2 May 2017 12:58:25 +0400 Subject: [PATCH 19/20] MDEV-12659 Add THD::make_string_literal() --- sql/sql_class.cc | 20 ++++++++++++++++++++ sql/sql_class.h | 14 ++++++++++++++ sql/sql_yacc.yy | 22 +--------------------- sql/sql_yacc_ora.yy | 22 +--------------------- 4 files changed, 36 insertions(+), 42 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f61e1f0885e..8793dd9b409 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2352,6 +2352,26 @@ bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) } +Item_string *THD::make_string_literal(const char *str, size_t length, + uint repertoire) +{ + if (!charset_is_collation_connection && + (repertoire != MY_REPERTOIRE_ASCII || + !my_charset_is_ascii_based(variables.collation_connection))) + { + LEX_STRING to; + if (convert_string(&to, variables.collation_connection, + str, length, variables.character_set_client)) + return NULL; + str= to.str; + length= to.length; + } + return new (mem_root) Item_string(this, str, length, + variables.collation_connection, + DERIVATION_COERCIBLE, repertoire); +} + + /* Update some cache variables when character set changes */ diff --git a/sql/sql_class.h b/sql/sql_class.h index cc855c723e2..c1e80761235 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3423,6 +3423,20 @@ public: bool convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs); + /* + Create a string literal with optional client->connection conversion. + @param str - the string in the client character set + @param length - length of the string + @param repertoire - the repertoire of the string + */ + Item_string *make_string_literal(const char *str, size_t length, + uint repertoire); + Item_string *make_string_literal(const Lex_string_with_metadata_st &str) + { + uint repertoire= str.repertoire(variables.character_set_client); + return make_string_literal(str.str, str.length, repertoire); + } + void add_changed_table(TABLE *table); void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 59c045029f4..d8793c56405 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13712,27 +13712,7 @@ load_data_set_elem: text_literal: TEXT_STRING { - LEX_CSTRING tmp; - CHARSET_INFO *cs_con= thd->variables.collation_connection; - CHARSET_INFO *cs_cli= thd->variables.character_set_client; - uint repertoire= $1.repertoire(cs_cli); - if (thd->charset_is_collation_connection || - (repertoire == MY_REPERTOIRE_ASCII && - my_charset_is_ascii_based(cs_con))) - tmp= $1; - else - { - LEX_STRING to; - if (thd->convert_string(&to, cs_con, $1.str, $1.length, cs_cli)) - MYSQL_YYABORT; - tmp.str= to.str; - tmp.length= to.length; - } - $$= new (thd->mem_root) Item_string(thd, tmp.str, tmp.length, - cs_con, - DERIVATION_COERCIBLE, - repertoire); - if ($$ == NULL) + if (!($$= thd->make_string_literal($1))) MYSQL_YYABORT; } | NCHAR_STRING diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 77ced40ed5f..aaf3adcf974 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -13836,27 +13836,7 @@ load_data_set_elem: text_literal: TEXT_STRING { - LEX_CSTRING tmp; - CHARSET_INFO *cs_con= thd->variables.collation_connection; - CHARSET_INFO *cs_cli= thd->variables.character_set_client; - uint repertoire= $1.repertoire(cs_cli); - if (thd->charset_is_collation_connection || - (repertoire == MY_REPERTOIRE_ASCII && - my_charset_is_ascii_based(cs_con))) - tmp= $1; - else - { - LEX_STRING to; - if (thd->convert_string(&to, cs_con, $1.str, $1.length, cs_cli)) - MYSQL_YYABORT; - tmp.str= to.str; - tmp.length= to.length; - } - $$= new (thd->mem_root) Item_string(thd, tmp.str, tmp.length, - cs_con, - DERIVATION_COERCIBLE, - repertoire); - if ($$ == NULL) + if (!($$= thd->make_string_literal($1))) MYSQL_YYABORT; } | NCHAR_STRING From 746f794c4302d6dc376544cc66b132ff1e926313 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 2 May 2017 13:51:35 +0400 Subject: [PATCH 20/20] MDEV-12657 A few tests fail in build-bot on Windows after changing Field::field_name and Item::name to LEX_CSTRING --- sql/item.cc | 2 +- sql/partition_info.cc | 2 +- sql/sql_class.cc | 2 +- sql/sql_view.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 416f889712a..c145e69e88f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8762,7 +8762,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { - my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); + my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name.str); goto error; } diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ab4a1cc0360..322fc4e1e93 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1922,7 +1922,7 @@ void partition_info::report_part_expr_error(bool use_subpart_expr) !(type == HASH_PARTITION && list_of_fields)) { my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0), - item_field->name); + item_field->name.str); DBUG_VOID_RETURN; } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8793dd9b409..b586cd138de 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3134,7 +3134,7 @@ int select_export::send_data(List &items) ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER_THD(thd, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "string", printable_buff, - item->name, static_cast(row_count)); + item->name.str, static_cast(row_count)); } else if (copier.source_end_pos() < res->ptr() + res->length()) { diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 447d80b8b00..af597c48264 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -156,7 +156,7 @@ bool check_duplicate_names(THD *thd, List &item_list, bool gen_unique_view DBUG_RETURN(FALSE); err: - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + my_error(ER_DUP_FIELDNAME, MYF(0), item->name.str); DBUG_RETURN(TRUE); }