From 95d075a0e5b9b4276c53f888c8090113a8adfbf4 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 13 Feb 2018 20:37:31 +0400 Subject: [PATCH] MDEV-15293 CAST(AS TIME) returns bad results for LAST_VALUE(),NAME_CONST(),SP variable --- mysql-test/r/type_time.result | 42 +++++++++ mysql-test/t/type_time.test | 36 ++++++++ sql/item.cc | 156 +++++++++++++++++++++------------- sql/item.h | 67 ++++++++++++++- sql/item_func.cc | 16 ++++ sql/item_func.h | 22 +++++ sql/item_row.h | 5 ++ sql/item_strfunc.h | 2 + sql/item_subselect.h | 2 + sql/item_sum.h | 16 ++++ sql/item_timefunc.h | 8 ++ sql/item_windowfunc.cc | 11 +++ sql/item_windowfunc.h | 24 ++++++ sql/procedure.h | 4 + sql/sql_type.cc | 57 ++++++++++++- sql/sql_type.h | 14 +++ 16 files changed, 420 insertions(+), 62 deletions(-) diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result index d875254056a..c08575776e9 100644 --- a/mysql-test/r/type_time.result +++ b/mysql-test/r/type_time.result @@ -1487,3 +1487,45 @@ lt_minus200_implicit 200 lt_minus200_explictit 200 lt_plus200_implicit 10 lt_plus200_explicit 10 +# +# MDEV-15293 CAST(AS TIME) returns bad results for LAST_VALUE(),NAME_CONST(),SP variable +# +SELECT CAST(DATE'2001-01-01' AS TIME); +CAST(DATE'2001-01-01' AS TIME) +00:00:00 +SELECT CAST(LAST_VALUE(DATE'2001-01-01') AS TIME); +CAST(LAST_VALUE(DATE'2001-01-01') AS TIME) +00:00:00 +SELECT CAST(NAME_CONST('name',DATE'2001-01-01') AS TIME); +CAST(NAME_CONST('name',DATE'2001-01-01') AS TIME) +00:00:00 +BEGIN NOT ATOMIC +DECLARE a DATE DEFAULT '2001-01-01'; +SELECT CAST(a AS TIME); +END; +$$ +CAST(a AS TIME) +00:00:00 +CREATE OR REPLACE TABLE t1 (dt DATE,country VARCHAR(10), amount INT); +INSERT INTO t1 VALUES ('2000-01-01','DE',102); +SELECT +dt, country, amount, +FIRST_VALUE(dt) OVER () AS first, +MINUTE(FIRST_VALUE(dt) OVER ()) AS m_first, +LAST_VALUE(dt) OVER () AS last, +MINUTE(LAST_VALUE(dt) OVER ()) AS m_last +FROM t1 +ORDER BY country, dt; +dt country amount first m_first last m_last +2000-01-01 DE 102 2000-01-01 0 2000-01-01 0 +SELECT +dt, country, amount, +FIRST_VALUE(dt) OVER () AS first, +CAST(FIRST_VALUE(dt) OVER () AS TIME) AS t_first, +LAST_VALUE(dt) OVER () AS last, +CAST(LAST_VALUE(dt) OVER () AS TIME) AS t_last +FROM t1 +ORDER BY country, dt; +dt country amount first t_first last t_last +2000-01-01 DE 102 2000-01-01 00:00:00 2000-01-01 00:00:00 +DROP TABLE t1; diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test index 87eab381479..4bb4e5c4267 100644 --- a/mysql-test/t/type_time.test +++ b/mysql-test/t/type_time.test @@ -866,3 +866,39 @@ SELECT HOUR(LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('200:20:20'))) AS lt_plus200_explicit; --horizontal_results + + +--echo # +--echo # MDEV-15293 CAST(AS TIME) returns bad results for LAST_VALUE(),NAME_CONST(),SP variable +--echo # + +SELECT CAST(DATE'2001-01-01' AS TIME); +SELECT CAST(LAST_VALUE(DATE'2001-01-01') AS TIME); +SELECT CAST(NAME_CONST('name',DATE'2001-01-01') AS TIME); +DELIMITER $$; +BEGIN NOT ATOMIC + DECLARE a DATE DEFAULT '2001-01-01'; + SELECT CAST(a AS TIME); +END; +$$ +DELIMITER ;$$ + +CREATE OR REPLACE TABLE t1 (dt DATE,country VARCHAR(10), amount INT); +INSERT INTO t1 VALUES ('2000-01-01','DE',102); +SELECT + dt, country, amount, + FIRST_VALUE(dt) OVER () AS first, + MINUTE(FIRST_VALUE(dt) OVER ()) AS m_first, + LAST_VALUE(dt) OVER () AS last, + MINUTE(LAST_VALUE(dt) OVER ()) AS m_last +FROM t1 +ORDER BY country, dt; +SELECT + dt, country, amount, + FIRST_VALUE(dt) OVER () AS first, + CAST(FIRST_VALUE(dt) OVER () AS TIME) AS t_first, + LAST_VALUE(dt) OVER () AS last, + CAST(LAST_VALUE(dt) OVER () AS TIME) AS t_last +FROM t1 +ORDER BY country, dt; +DROP TABLE t1; diff --git a/sql/item.cc b/sql/item.cc index 7f1adf7d7c5..e05ba7d6389 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1454,67 +1454,73 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) As a extra convenience the time structure is reset on error or NULL values! */ -bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate) { - if (field_type() == MYSQL_TYPE_TIME) - fuzzydate|= TIME_TIME_ONLY; + longlong value= val_int(); + bool neg= !unsigned_flag && value < 0; + if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value, + ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} - switch (result_type()) { - case INT_RESULT: - { - longlong value= val_int(); - bool neg= !unsigned_flag && value < 0; - if (field_type() == MYSQL_TYPE_YEAR) - { - if (max_length == 2) - { - if (value < 70) - value+= 2000; - else if (value <= 1900) - value+= 1900; - } - value*= 10000; /* make it YYYYMMHH */ - } - if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value, - ltime, fuzzydate, - field_name_or_null())) - goto err; - break; - } - case REAL_RESULT: - { - double value= val_real(); - if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, - field_name_or_null())) - goto err; - break; - } - case DECIMAL_RESULT: - { - my_decimal value, *res; - if (!(res= val_decimal(&value)) || - decimal_to_datetime_with_warn(res, ltime, fuzzydate, - field_name_or_null())) - goto err; - break; - } - case STRING_RESULT: - { - char buff[40]; - String tmp(buff,sizeof(buff), &my_charset_bin),*res; - if (!(res=val_str(&tmp)) || - str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(), - ltime, fuzzydate)) - goto err; - break; - } - default: - DBUG_ASSERT(0); - } - return null_value= 0; +bool Item::get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + longlong value= val_int(); + DBUG_ASSERT(unsigned_flag || value >= 0); + if (max_length == 2) + { + if (value < 70) + value+= 2000; + else if (value <= 1900) + value+= 1900; + } + value*= 10000; /* make it YYYYMMHH */ + if (null_value || int_to_datetime_with_warn(false, value, + ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} -err: + +bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + double value= val_real(); + if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} + + +bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + my_decimal value, *res; + if (!(res= val_decimal(&value)) || + decimal_to_datetime_with_warn(res, ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} + + +bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + char buff[40]; + String tmp(buff,sizeof(buff), &my_charset_bin),*res; + if (!(res=val_str(&tmp)) || + str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(), + ltime, fuzzydate)) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} + + +bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ /* if the item was not null and convertion failed, we return a zero date if allowed, otherwise - null. @@ -1536,7 +1542,7 @@ err: */ ltime->time_type= MYSQL_TIMESTAMP_TIME; } - return null_value|= !(fuzzydate & TIME_FUZZY_DATES); + return !(fuzzydate & TIME_FUZZY_DATES); } bool Item::get_seconds(ulonglong *sec, ulong *sec_part) @@ -1780,6 +1786,16 @@ my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value) } +bool Item_sp_variable::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + bool val= it->get_date(ltime, fuzzydate); + null_value= it->null_value; + return val; +} + + bool Item_sp_variable::is_null() { return this_item()->is_null(); @@ -2125,6 +2141,13 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value) return val; } +bool Item_name_const::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed); + bool rc= value_item->get_date(ltime, fuzzydate); + null_value= value_item->null_value; + return rc; +} bool Item_name_const::is_null() { @@ -3731,6 +3754,15 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value) } +bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + make_zero_date(ltime, fuzzydate); + return (null_value= true); +} + + Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) { return this; @@ -4201,7 +4233,7 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate) *res= value.time; return 0; } - return Item::get_date(res, fuzzydate); + return type_handler()->Item_get_date(this, res, fuzzydate); } @@ -10191,6 +10223,12 @@ String *Item_type_holder::val_str(String*) return 0; } +bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(0); // should never be called + return true; +} + void Item_result_field::cleanup() { DBUG_ENTER("Item_result_field::cleanup()"); diff --git a/sql/item.h b/sql/item.h index 2f962469002..77aa6eb901e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -672,6 +672,12 @@ protected: DBUG_ASSERT(fixed == 1); return (null_value= item->get_date_with_conversion(ltime, fuzzydate)); } + /* + This method is used if the item was not null but convertion to + TIME/DATE/DATETIME failed. We return a zero date if allowed, + otherwise - null. + */ + bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate); public: /* @@ -1350,7 +1356,12 @@ public: void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, Item **ref, uint flags); - virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)= 0; + bool get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY | TIME_INVALID_DATES); } // Get date with automatic TIME->DATETIME conversion @@ -2306,6 +2317,7 @@ public: longlong val_int(); String *val_str(String *sp); my_decimal *val_decimal(my_decimal *decimal_value); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool is_null(); public: @@ -2568,6 +2580,7 @@ public: longlong val_int(); String *val_str(String *sp); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool is_null(); virtual void print(String *str, enum_query_type query_type); @@ -2604,6 +2617,10 @@ public: Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool check_partition_func_processor(void *int_arg) { return FALSE;} + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; #define NO_CACHED_FIELD_INDEX ((uint)(-1)) @@ -2725,6 +2742,10 @@ public: longlong val_int() { return field->val_int(); } String *val_str(String *str) { return field->val_str(str); } my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return field->get_date(ltime, fuzzydate); + } void make_field(THD *thd, Send_field *tmp_field); const Type_handler *type_handler() const { @@ -3025,6 +3046,7 @@ public: longlong val_int(); String *val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); bool send(Protocol *protocol, st_value *buffer); @@ -3735,6 +3757,10 @@ public: return (String*) &str_value; } my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_string(ltime, fuzzydate); + } int save_in_field(Field *field, bool no_conversions); const Type_handler *type_handler() const { return &type_handler_varchar; } bool basic_const_item() const { return 1; } @@ -4022,6 +4048,10 @@ public: str_value.bin_eq(&((Item_hex_constant*)item)->str_value); } String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -5324,6 +5354,8 @@ public: my_decimal *val_decimal(my_decimal *); double val_real(); longlong val_int(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_string(ltime, fuzzydate); } void copy(); int save_in_field(Field *field, bool no_conversions); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -5349,6 +5381,8 @@ public: { return null_value ? 0 : cached_value; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } virtual void copy(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } @@ -5391,6 +5425,10 @@ public: { return (longlong) rint(val_real()); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_real(ltime, fuzzydate); + } void copy() { cached_value= item->val_real(); @@ -5416,6 +5454,10 @@ public: } double val_real(); longlong val_int(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_decimal(ltime, fuzzydate); + } void copy(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } @@ -5909,6 +5951,8 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } bool cache_value(); int save_in_field(Field *field, bool no_conversions); Item *convert_to_basic_const_item(THD *thd); @@ -5917,6 +5961,15 @@ public: }; +class Item_cache_year: public Item_cache_int +{ +public: + Item_cache_year(THD *thd): Item_cache_int(thd, &type_handler_year) { } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_year(ltime, fuzzydate); } +}; + + class Item_cache_temporal: public Item_cache_int { protected: @@ -5984,6 +6037,8 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_real(ltime, fuzzydate); } bool cache_value(); Item *convert_to_basic_const_item(THD *thd); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -6002,6 +6057,8 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_decimal(ltime, fuzzydate); } bool cache_value(); Item *convert_to_basic_const_item(THD *thd); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -6028,6 +6085,8 @@ public: longlong val_int(); String* val_str(String *); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_string(ltime, fuzzydate); } CHARSET_INFO *charset() const { return value->charset(); }; int save_in_field(Field *field, bool no_conversions); bool cache_value(); @@ -6108,6 +6167,11 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + illegal_method_call((const char*)"val_decimal"); + return true; + } uint cols() const { return item_count; } Item *element_index(uint i) { return values[i]; } @@ -6186,6 +6250,7 @@ public: longlong val_int(); my_decimal *val_decimal(my_decimal *); String *val_str(String*); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); Field *create_tmp_field(bool group, TABLE *table) { return Item_type_holder::real_type_handler()-> diff --git a/sql/item_func.cc b/sql/item_func.cc index 9d3f1dd5606..bea57d6c938 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5551,6 +5551,13 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) } +bool Item_user_var_as_out_param::get_date(MYSQL_TIME *ltime, ulonglong fuzzy) +{ + DBUG_ASSERT(0); + return true; +} + + void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) { str->append('@'); @@ -6784,6 +6791,15 @@ my_decimal *Item_func_last_value::val_decimal(my_decimal *decimal_value) } +bool Item_func_last_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + evaluate_sideeffects(); + bool tmp= last_value->get_date(ltime, fuzzydate); + null_value= last_value->null_value; + return tmp; +} + + void Item_func_last_value::fix_length_and_dec() { last_value= args[arg_count -1]; diff --git a/sql/item_func.h b/sql/item_func.h index 8399123594f..adc5c238abd 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -386,6 +386,8 @@ public: my_decimal *val_decimal(my_decimal *decimal_value); longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) rint(val_real()); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_real(ltime, fuzzydate); } const Type_handler *type_handler() const { return &type_handler_double; } void fix_length_and_dec() { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } @@ -755,6 +757,8 @@ public: { collation.set_numeric(); } double val_real(); String *val_str(String*str); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } const Type_handler *type_handler() const= 0; void fix_length_and_dec() {} }; @@ -948,6 +952,8 @@ public: double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal*); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_decimal(ltime, fuzzydate); } const Type_handler *type_handler() const { return &type_handler_newdecimal; } void fix_length_and_dec_generic() {} void fix_length_and_dec() @@ -1591,6 +1597,10 @@ public: longlong val_int() { return args[0]->val_int(); } String *val_str(String *str) { return args[0]->val_str(str); } my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return args[0]->get_date(ltime, fuzzydate); + } const char *func_name() const { return "rollup_const"; } bool const_item() const { return 0; } const Type_handler *type_handler() const { return args[0]->type_handler(); } @@ -2033,6 +2043,10 @@ public: { return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -2330,6 +2344,8 @@ public: Field *create_field_for_create_select(TABLE *table) { return create_table_field_from_handler(table); } bool check_vcol_func_processor(void *arg); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return type_handler()->Item_get_date(this, ltime, fuzzydate); } }; @@ -2473,6 +2489,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); @@ -2520,6 +2537,10 @@ public: String* val_str(String*); my_decimal *val_decimal(my_decimal *dec_buf) { return val_decimal_from_real(dec_buf); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } /* TODO: fix to support views */ const char *func_name() const { return "get_system_var"; } /** @@ -2971,6 +2992,7 @@ public: longlong val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); void fix_length_and_dec(); const char *func_name() const { return "last_value"; } const Type_handler *type_handler() const { return last_value->type_handler(); } diff --git a/sql/item_row.h b/sql/item_row.h index 206a8ed83c5..83f6ba9c5b7 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -82,6 +82,11 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + illegal_method_call((const char*)"get_date"); + return true; + } bool fix_fields(THD *thd, Item **ref); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void cleanup(); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 2b7cc1a3aa1..a357c03bda5 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -62,6 +62,8 @@ public: longlong val_int(); double val_real(); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_string(ltime, fuzzydate); } const Type_handler *type_handler() const { return string_type_handler(); } void left_right_max_length(); bool fix_fields(THD *thd, Item **ref); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 812352e4c4f..fdb980efc80 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -400,6 +400,8 @@ public: String *val_str(String*); my_decimal *val_decimal(my_decimal *); bool val_bool(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); void print(String *str, enum_query_type query_type); diff --git a/sql/item_sum.h b/sql/item_sum.h index 0cb5be391a2..1f7d89e8a17 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -732,6 +732,10 @@ public: longlong val_int() { return val_int_from_real(); /* Real as default */ } String *val_str(String*str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } void reset_field(); }; @@ -1227,6 +1231,10 @@ public: { return mark_unsupported_function(name.str, arg, VCOL_IMPOSSIBLE); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -1376,6 +1384,10 @@ public: void update_field() {}; void cleanup(); virtual void print(String *str, enum_query_type query_type); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -1661,6 +1673,10 @@ public: { return val_decimal_from_string(decimal_value); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_string(ltime, fuzzydate); + } String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index f94a0d385f7..085c14ba3da 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -181,6 +181,10 @@ public: str->set(nr, collation.collation); return str; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_int(ltime, fuzzydate); + } const char *func_name() const { return "month"; } const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() @@ -441,6 +445,10 @@ public: { return (odbc_type ? "dayofweek" : "weekday"); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() { diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 45688b87730..6b703d5244f 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -344,6 +344,17 @@ Item_sum_hybrid_simple::val_str(String *str) return retval; } +bool Item_sum_hybrid_simple::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + bool retval= value->get_date(ltime, fuzzydate); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == true); + return retval; +} + Field *Item_sum_hybrid_simple::create_tmp_field(bool group, TABLE *table) { DBUG_ASSERT(0); diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index 9fe95ed6cee..717958d479c 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -303,6 +303,7 @@ class Item_sum_hybrid_simple : public Item_sum, my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } void update_field(); @@ -938,6 +939,29 @@ public: return res; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + bool res; + if (force_return_blank) + { + null_value= true; + res= true; + } + else if (read_value_from_result_field) + { + if ((null_value= result_field->is_null())) + res= true; + else + res= result_field->get_date(ltime, fuzzydate); + } + else + { + res= window_func()->get_date(ltime, fuzzydate); + null_value= window_func()->null_value; + } + return res; + } + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags); diff --git a/sql/procedure.h b/sql/procedure.h index a1c9b95f20b..23e5751a008 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -59,6 +59,10 @@ public: DBUG_ASSERT(0); // impossible return mark_unsupported_function("proc", arg, VCOL_IMPOSSIBLE); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 4b4f7a9ca70..ac9d19594fd 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -2651,6 +2651,12 @@ Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const return new (thd->mem_root) Item_cache_int(thd, item->type_handler()); } +Item_cache * +Type_handler_year::Item_get_cache(THD *thd, const Item *item) const +{ + return new (thd->mem_root) Item_cache_year(thd); +} + Item_cache * Type_handler_real_result::Item_get_cache(THD *thd, const Item *item) const { @@ -3175,6 +3181,53 @@ bool Type_handler_string_result::Item_val_bool(Item *item) const } +/*************************************************************************/ + +bool Type_handler_int_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_int(ltime, fuzzydate); +} + + +bool Type_handler_year::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_year(ltime, fuzzydate); +} + + +bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_real(ltime, fuzzydate); +} + + +bool Type_handler_decimal_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_decimal(ltime, fuzzydate); +} + + +bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_string(ltime, fuzzydate); +} + + +bool Type_handler_temporal_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + DBUG_ASSERT(0); // Temporal type items must implement native get_date() + item->null_value= true; + set_zero_time(ltime, mysql_timestamp_type()); + return true; +} + + /*************************************************************************/ longlong Type_handler_real_result:: @@ -3892,7 +3945,7 @@ bool Type_handler_string_result:: ::get_date() can be called for non-temporal values, for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09")) */ - return func->Item::get_date(ltime, fuzzydate); + return func->get_date_from_string(ltime, fuzzydate); } @@ -3900,7 +3953,7 @@ bool Type_handler_numeric:: Item_func_min_max_get_date(Item_func_min_max *func, MYSQL_TIME *ltime, ulonglong fuzzydate) const { - return func->Item::get_date(ltime, fuzzydate); + return Item_get_date(func, ltime, fuzzydate); } diff --git a/sql/sql_type.h b/sql/sql_type.h index 92695bc4072..f4482c6fbdd 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1026,6 +1026,8 @@ public: bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0; virtual bool Item_val_bool(Item *item) const= 0; + virtual bool Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const= 0; virtual longlong Item_val_int_signed_typecast(Item *item) const= 0; virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0; @@ -1286,6 +1288,11 @@ public: DBUG_ASSERT(0); return false; } + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const + { + DBUG_ASSERT(0); + return true; + } longlong Item_val_int_signed_typecast(Item *item) const { DBUG_ASSERT(0); @@ -1492,6 +1499,7 @@ public: bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1570,6 +1578,7 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1638,6 +1647,7 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1708,6 +1718,7 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1821,6 +1832,7 @@ public: bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -2063,6 +2075,8 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Item_cache *Item_get_cache(THD *thd, const Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; };