From c353b2a8fc10e16107ee6c7e26877f4243d4eaef Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 12 Dec 2018 10:39:06 +0400 Subject: --echo # --echo # MDEV-17979 Assertion `0' failed in Item::val_native upon SELECT with timestamp, NULLIF, GROUP BY --echo # --- sql/item.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 2 +- sql/sql_type.cc | 16 ++++++++++++++++ sql/sql_type.h | 8 ++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 5d0f2cd43f5..9c53f731f6e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -6021,6 +6021,62 @@ public: }; +/** + We need a separate class Item_copy_timestamp because + TIMESTAMP->string->TIMESTAMP conversion is not round trip safe + near the DST change, e.g. '2010-10-31 02:25:26' can mean: + - my_time_t(1288477526) - summer time in Moscow + - my_time_t(1288481126) - winter time in Moscow, one hour later +*/ +class Item_copy_timestamp: public Item_copy +{ + Timestamp_or_zero_datetime m_value; +public: + Item_copy_timestamp(THD *thd, Item *arg): Item_copy(thd, arg) { } + const Type_handler *type_handler() const { return &type_handler_timestamp2; } + void copy() + { + Timestamp_or_zero_datetime_native_null tmp(current_thd, item, false); + null_value= tmp.is_null(); + m_value= tmp.is_null() ? Timestamp_or_zero_datetime() : + Timestamp_or_zero_datetime(tmp); + } + int save_in_field(Field *field, bool no_conversions) + { + Timestamp_or_zero_datetime_native native(m_value, decimals); + return native.save_in_field(field, decimals); + } + longlong val_int() + { + return m_value.to_datetime(current_thd).to_longlong(); + } + double val_real() + { + return m_value.to_datetime(current_thd).to_double(); + } + String *val_str(String *to) + { + return m_value.to_datetime(current_thd).to_string(to, decimals); + } + my_decimal *val_decimal(my_decimal *to) + { + return m_value.to_datetime(current_thd).to_decimal(to); + } + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + { + bool res= m_value.to_TIME(thd, ltime, fuzzydate); + DBUG_ASSERT(!res); + return res; + } + bool val_native(THD *thd, Native *to) + { + return m_value.to_native(to, decimals); + } + Item *get_copy(THD *thd) + { return get_item_copy(thd, this); } +}; + + /* Cached_item_XXX objects are not exactly caches. They do the following: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f99e60020c3..4b15cba1597 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -23907,7 +23907,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, on how the value is to be used: In some cases this may be an argument in a group function, like: IF(ISNULL(col),0,COUNT(*)) */ - if (!(pos=new (thd->mem_root) Item_copy_string(thd, pos))) + if (!(pos= pos->type_handler()->create_item_copy(thd, pos))) goto err; if (i < border) // HAVING, ORDER and GROUP BY { diff --git a/sql/sql_type.cc b/sql/sql_type.cc index e415aacce75..168f66d4c99 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3764,6 +3764,22 @@ Type_handler_date_common::Item_get_cache(THD *thd, const Item *item) const return new (thd->mem_root) Item_cache_date(thd); } + +/*************************************************************************/ + +Item_copy * +Type_handler::create_item_copy(THD *thd, Item *item) const +{ + return new (thd->mem_root) Item_copy_string(thd, item); +} + + +Item_copy * +Type_handler_timestamp_common::create_item_copy(THD *thd, Item *item) const +{ + return new (thd->mem_root) Item_copy_timestamp(thd, item); +} + /*************************************************************************/ bool Type_handler_int_result:: diff --git a/sql/sql_type.h b/sql/sql_type.h index 925dc25d7e7..abd574a4475 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -35,6 +35,7 @@ class Item_const; class Item_literal; class Item_param; class Item_cache; +class Item_copy; class Item_func_or_sum; class Item_sum_hybrid; class Item_sum_sum; @@ -3470,6 +3471,7 @@ public: DBUG_ASSERT(0); return NULL; } + virtual Item_copy *create_item_copy(THD *thd, Item *item) const; virtual int cmp_native(const Native &a, const Native &b) const { DBUG_ASSERT(0); @@ -3771,6 +3773,11 @@ public: } Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; + Item_copy *create_item_copy(THD *thd, Item *item) const + { + DBUG_ASSERT(0); + return NULL; + } bool set_comparator_func(Arg_comparator *cmp) const; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, @@ -5411,6 +5418,7 @@ public: int Item_save_in_field(Item *item, Field *field, bool no_conversions) const; String *print_item_value(THD *thd, Item *item, String *str) const; Item_cache *Item_get_cache(THD *thd, const Item *item) const; + Item_copy *create_item_copy(THD *thd, Item *item) const; String *Item_func_min_max_val_str(Item_func_min_max *, String *) const; double Item_func_min_max_val_real(Item_func_min_max *) const; longlong Item_func_min_max_val_int(Item_func_min_max *) const; -- cgit v1.2.1