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;