diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index cd60996e590..0b71f9522e2 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1726,7 +1726,7 @@ select 1 from t1 where 1 < some (select cast(a as datetime) from t1); 1 1 Warnings: -Warning 1292 Truncated incorrect DOUBLE value: '2001-01-01 00:01:00' +Warning 1292 Incorrect datetime value: '1' drop table t1; SET timestamp=DEFAULT; select time('10:10:10') > 10; diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index a05ba88d175..155e9535a0a 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -1096,5 +1096,48 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (coalesce(`test`.`t1`.`a`) = TIMESTAMP'2001-01-01 00:00:00') DROP TABLE t1; # +# MDEV-8875 Wrong metadata for MAX(CAST(time_column AS DATETIME)) +# +SET timestamp=UNIX_TIMESTAMP('2015-01-01 00:00:00'); +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('00:00:00'),('00:01:00'); +SELECT MAX(CAST(a AS DATETIME)) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def MAX(CAST(a AS DATETIME)) 12 19 19 Y 128 0 63 +MAX(CAST(a AS DATETIME)) +2015-01-01 00:01:00 +CREATE TABLE t2 AS SELECT MAX(CAST(a AS DATETIME)) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `MAX(CAST(a AS DATETIME))` datetime DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +SET timestamp=DEFAULT; +# +# MDEV-8860 Wrong result for WHERE 2016 < SOME (SELECT CAST(time_column AS DATETIME) FROM t1) +# +SET timestamp=UNIX_TIMESTAMP('2015-01-01 00:00:00'); +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('00:00:00'),('00:01:00'); +SELECT 1 FROM t1 WHERE 2016 > SOME (SELECT CAST(a AS DATETIME) FROM t1); +1 +Warnings: +Warning 1292 Incorrect datetime value: '2016' +SELECT * FROM t1 WHERE 2016 > CAST(a AS DATETIME); +a +Warnings: +Warning 1292 Incorrect datetime value: '2016' +SELECT 1 FROM t1 WHERE 20160101 > SOME (SELECT CAST(a AS DATETIME) FROM t1); +1 +1 +1 +SELECT * FROM t1 WHERE 20160101 > CAST(a AS DATETIME); +a +00:00:00 +00:01:00 +DROP TABLE t1; +# # End of 10.1 tests # diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 9d049d0c6e7..444ab02d223 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -663,6 +663,35 @@ INSERT INTO t1 VALUES ('2001-01-01 00:00:00'),('2001-01-02 00:00:00'); EXPLAIN EXTENDED SELECT * FROM t1 WHERE COALESCE(a)=TIMESTAMP'2001-01-01 00:00:00' AND COALESCE(a)>=TIMESTAMP'2001-01-01 00:00:00'; DROP TABLE t1; +--echo # +--echo # MDEV-8875 Wrong metadata for MAX(CAST(time_column AS DATETIME)) +--echo # +SET timestamp=UNIX_TIMESTAMP('2015-01-01 00:00:00'); +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('00:00:00'),('00:01:00'); +--disable_ps_protocol +--enable_metadata +SELECT MAX(CAST(a AS DATETIME)) FROM t1; +--disable_metadata +--enable_ps_protocol +CREATE TABLE t2 AS SELECT MAX(CAST(a AS DATETIME)) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; +SET timestamp=DEFAULT; + +--echo # +--echo # MDEV-8860 Wrong result for WHERE 2016 < SOME (SELECT CAST(time_column AS DATETIME) FROM t1) +--echo # +SET timestamp=UNIX_TIMESTAMP('2015-01-01 00:00:00'); +CREATE TABLE t1 (a TIME); +INSERT INTO t1 VALUES ('00:00:00'),('00:01:00'); +SELECT 1 FROM t1 WHERE 2016 > SOME (SELECT CAST(a AS DATETIME) FROM t1); +SELECT * FROM t1 WHERE 2016 > CAST(a AS DATETIME); +SELECT 1 FROM t1 WHERE 20160101 > SOME (SELECT CAST(a AS DATETIME) FROM t1); +SELECT * FROM t1 WHERE 20160101 > CAST(a AS DATETIME); +DROP TABLE t1; + --echo # --echo # End of 10.1 tests --echo # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index a52c4d783f2..4cbbc274526 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1190,7 +1190,15 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) decimals=item->decimals; with_subselect= args[0]->with_subselect; - switch (hybrid_type= item->result_type()) { + Item *item2= item->real_item(); + if (item2->type() == Item::FIELD_ITEM) + set_handler_by_field_type(((Item_field*) item2)->field->type()); + else if (item->cmp_type() == TIME_RESULT) + set_handler_by_field_type(item2->field_type()); + else + set_handler_by_result_type(item2->result_type()); + + switch (Item_sum_hybrid::result_type()) { case INT_RESULT: case DECIMAL_RESULT: case STRING_RESULT: @@ -1210,11 +1218,6 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) result_field=0; null_value=1; fix_length_and_dec(); - item= item->real_item(); - if (item->type() == Item::FIELD_ITEM) - hybrid_field_type= ((Item_field*) item)->field->type(); - else - hybrid_field_type= Item::field_type(); if (check_sum_func(thd, ref)) return TRUE; @@ -2235,7 +2238,7 @@ void Item_sum_num::reset_field() void Item_sum_hybrid::reset_field() { - switch(hybrid_type) { + switch(Item_sum_hybrid::result_type()) { case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; @@ -2507,7 +2510,7 @@ Item *Item_sum_avg::result_item(THD *thd, Field *field) void Item_sum_hybrid::update_field() { - switch (hybrid_type) { + switch (Item_sum_hybrid::result_type()) { case STRING_RESULT: min_max_update_str_field(); break; diff --git a/sql/item_sum.h b/sql/item_sum.h index 01a580d03cb..2cf6c7fbe39 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1027,26 +1027,26 @@ class Item_sum_std :public Item_sum_variance // This class is a string or number function depending on num_func class Arg_comparator; class Item_cache; -class Item_sum_hybrid :public Item_sum +class Item_sum_hybrid :public Item_sum, public Type_handler_hybrid_field_type { protected: Item_cache *value, *arg_cache; Arg_comparator *cmp; - Item_result hybrid_type; - enum_field_types hybrid_field_type; int cmp_sign; bool was_values; // Set if we have found at least one row (for max/min only) bool was_null_value; public: Item_sum_hybrid(THD *thd, Item *item_par,int sign): - Item_sum(thd, item_par), value(0), arg_cache(0), cmp(0), - hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG), + Item_sum(thd, item_par), + Type_handler_hybrid_field_type(MYSQL_TYPE_LONGLONG), + value(0), arg_cache(0), cmp(0), cmp_sign(sign), was_values(TRUE) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) - :Item_sum(thd, item), value(item->value), arg_cache(0), - hybrid_type(item->hybrid_type), hybrid_field_type(item->hybrid_field_type), + :Item_sum(thd, item), + Type_handler_hybrid_field_type(item), + value(item->value), arg_cache(0), cmp_sign(item->cmp_sign), was_values(item->was_values) { } bool fix_fields(THD *, Item **); @@ -1058,8 +1058,12 @@ protected: void reset_field(); String *val_str(String *); bool keep_field_type(void) const { return 1; } - enum Item_result result_type () const { return hybrid_type; } - enum enum_field_types field_type() const { return hybrid_field_type; } + enum Item_result result_type () const + { return Type_handler_hybrid_field_type::result_type(); } + enum Item_result cmp_type () const + { return Type_handler_hybrid_field_type::cmp_type(); } + enum enum_field_types field_type() const + { return Type_handler_hybrid_field_type::field_type(); } void update_field(); void min_max_update_str_field(); void min_max_update_real_field(); diff --git a/sql/sql_type.h b/sql/sql_type.h index 13ddf4a83f8..5ad259db88b 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -270,6 +270,12 @@ class Type_handler_hybrid_field_type: public Type_handler const Type_handler *get_handler_by_field_type(enum_field_types type) const; public: Type_handler_hybrid_field_type(); + Type_handler_hybrid_field_type(enum_field_types type) + :m_type_handler(get_handler_by_field_type(type)) + { } + Type_handler_hybrid_field_type(const Type_handler_hybrid_field_type *other) + :m_type_handler(other->m_type_handler) + { } enum_field_types field_type() const { return m_type_handler->field_type(); } Item_result result_type() const { return m_type_handler->result_type(); } Item_result cmp_type() const { return m_type_handler->cmp_type(); }