From 2fd635409d6588d4c379af1a3a0f38f7dc2d839d Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 25 Apr 2017 14:22:07 +0400 Subject: [PATCH] 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;