summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-12-12 10:39:06 +0400
committerAlexander Barkov <bar@mariadb.com>2018-12-12 10:39:06 +0400
commitc353b2a8fc10e16107ee6c7e26877f4243d4eaef (patch)
tree6bb3d15613d83be28e8720f25ba4072bdbe0582f /sql
parent4abb8216a054e14afbeb81e8529e02bab6fa14ac (diff)
downloadmariadb-git-c353b2a8fc10e16107ee6c7e26877f4243d4eaef.tar.gz
--echo #
--echo # MDEV-17979 Assertion `0' failed in Item::val_native upon SELECT with timestamp, NULLIF, GROUP BY --echo #
Diffstat (limited to 'sql')
-rw-r--r--sql/item.h56
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_type.cc16
-rw-r--r--sql/sql_type.h8
4 files changed, 81 insertions, 1 deletions
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<Item_copy_timestamp>(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;