diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-12-08 19:39:23 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-12-10 19:25:12 +0400 |
commit | 34eb98387f8f46a80fb053081dbe20d415f23b39 (patch) | |
tree | 674bfd44acc89e741c26d788e614aa95a69c9936 /sql/item_cmpfunc.cc | |
parent | 5b3db87134bb0af2f04027c42971e560fbbf04ab (diff) | |
download | mariadb-git-34eb98387f8f46a80fb053081dbe20d415f23b39.tar.gz |
MDEV-13995 MAX(timestamp) returns a wrong result near DST change
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 624d0f062cc..4cd63042558 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -567,6 +567,18 @@ bool Arg_comparator::set_cmp_func_datetime() } +bool Arg_comparator::set_cmp_func_native() +{ + THD *thd= current_thd; + m_compare_collation= &my_charset_numeric; + func= is_owner_equal_func() ? &Arg_comparator::compare_e_native : + &Arg_comparator::compare_native; + a= cache_converted_constant(thd, a, &a_cache, compare_type_handler()); + b= cache_converted_constant(thd, b, &b_cache, compare_type_handler()); + return false; +} + + bool Arg_comparator::set_cmp_func_int() { THD *thd= current_thd; @@ -770,6 +782,39 @@ int Arg_comparator::compare_e_string() } +int Arg_comparator::compare_native() +{ + THD *thd= current_thd; + if (!(*a)->val_native_with_conversion(thd, &m_native1, + compare_type_handler())) + { + if (!(*b)->val_native_with_conversion(thd, &m_native2, + compare_type_handler())) + { + if (set_null) + owner->null_value= 0; + return compare_type_handler()->cmp_native(m_native1, m_native2); + } + } + if (set_null) + owner->null_value= 1; + return -1; +} + + +int Arg_comparator::compare_e_native() +{ + THD *thd= current_thd; + bool res1= (*a)->val_native_with_conversion(thd, &m_native1, + compare_type_handler()); + bool res2= (*b)->val_native_with_conversion(thd, &m_native2, + compare_type_handler()); + if (res1 || res2) + return MY_TEST(res1 == res2); + return MY_TEST(compare_type_handler()->cmp_native(m_native1, m_native2) == 0); +} + + int Arg_comparator::compare_real() { /* @@ -2121,6 +2166,29 @@ longlong Item_func_between::val_int_cmp_time() } +longlong Item_func_between::val_int_cmp_native() +{ + THD *thd= current_thd; + const Type_handler *h= m_comparator.type_handler(); + NativeBuffer<STRING_BUFFER_USUAL_SIZE> value, a, b; + if (val_native_with_conversion_from_item(thd, args[0], &value, h)) + return 0; + bool ra= args[1]->val_native_with_conversion(thd, &a, h); + bool rb= args[2]->val_native_with_conversion(thd, &b, h); + if (!ra && !rb) + return (longlong) + ((h->cmp_native(value, a) >= 0 && + h->cmp_native(value, b) <= 0) != negated); + if (ra && rb) + null_value= true; + else if (ra) + null_value= h->cmp_native(value, b) <= 0; + else + null_value= h->cmp_native(value, a) >= 0; + return (longlong) (!null_value && negated); +} + + longlong Item_func_between::val_int_cmp_string() { String *value,*a,*b; @@ -2306,6 +2374,15 @@ Item_func_ifnull::str_op(String *str) } +bool Item_func_ifnull::native_op(THD *thd, Native *to) +{ + DBUG_ASSERT(fixed == 1); + if (!val_native_with_conversion_from_item(thd, args[0], to, type_handler())) + return false; + return val_native_with_conversion_from_item(thd, args[1], to, type_handler()); +} + + bool Item_func_ifnull::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { DBUG_ASSERT(fixed == 1); @@ -2829,6 +2906,16 @@ Item_func_nullif::time_op(THD *thd, MYSQL_TIME *ltime) bool +Item_func_nullif::native_op(THD *thd, Native *to) +{ + DBUG_ASSERT(fixed == 1); + if (!compare()) + return (null_value= true); + return val_native_with_conversion_from_item(thd, args[2], to, type_handler()); +} + + +bool Item_func_nullif::is_null() { return (null_value= (!compare() ? 1 : args[2]->is_null())); @@ -3002,6 +3089,16 @@ bool Item_func_case::time_op(THD *thd, MYSQL_TIME *ltime) } +bool Item_func_case::native_op(THD *thd, Native *to) +{ + DBUG_ASSERT(fixed == 1); + Item *item= find_item(); + if (!item) + return (null_value= true); + return val_native_with_conversion_from_item(thd, item, to, type_handler()); +} + + bool Item_func_case::fix_fields(THD *thd, Item **ref) { bool res= Item_func::fix_fields(thd, ref); @@ -3360,6 +3457,18 @@ bool Item_func_coalesce::time_op(THD *thd, MYSQL_TIME *ltime) } +bool Item_func_coalesce::native_op(THD *thd, Native *to) +{ + DBUG_ASSERT(fixed == 1); + for (uint i= 0; i < arg_count; i++) + { + if (!val_native_with_conversion_from_item(thd, args[i], to, type_handler())) + return false; + } + return (null_value= true); +} + + my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); @@ -3637,6 +3746,53 @@ Item *in_longlong::create_item(THD *thd) } +static int cmp_timestamp(void *cmp_arg, + Timestamp_or_zero_datetime *a, + Timestamp_or_zero_datetime *b) +{ + return a->cmp(*b); +} + + +in_timestamp::in_timestamp(THD *thd, uint elements) + :in_vector(thd, elements, sizeof(Value), (qsort2_cmp) cmp_timestamp, 0) +{} + + +void in_timestamp::set(uint pos, Item *item) +{ + Timestamp_or_zero_datetime *buff= &((Timestamp_or_zero_datetime *) base)[pos]; + Timestamp_or_zero_datetime_native_null native(current_thd, item, true); + if (native.is_null()) + *buff= Timestamp_or_zero_datetime(); + else + *buff= Timestamp_or_zero_datetime(native); +} + + +uchar *in_timestamp::get_value(Item *item) +{ + Timestamp_or_zero_datetime_native_null native(current_thd, item, true); + if (native.is_null()) + return 0; + tmp= Timestamp_or_zero_datetime(native); + return (uchar*) &tmp; +} + + +Item *in_timestamp::create_item(THD *thd) +{ + return new (thd->mem_root) Item_timestamp_literal(thd); +} + + +void in_timestamp::value_to_item(uint pos, Item *item) +{ + const Timestamp_or_zero_datetime &buff= (((Timestamp_or_zero_datetime*) base)[pos]); + static_cast<Item_timestamp_literal*>(item)->set_value(buff); +} + + void in_datetime::set(uint pos,Item *item) { struct packed_longlong *buff= &((packed_longlong*) base)[pos]; @@ -4044,6 +4200,49 @@ cmp_item *cmp_item_time::make_same() } +void cmp_item_timestamp::store_value(Item *item) +{ + item->val_native_with_conversion(current_thd, &m_native, + &type_handler_timestamp2); + m_null_value= item->null_value; +} + + +int cmp_item_timestamp::cmp_not_null(const Value *val) +{ + /* + This method will be implemented when we add this syntax: + SELECT TIMESTAMP WITH LOCAL TIME ZONE '2001-01-01 10:20:30' + For now TIMESTAMP is compared to non-TIMESTAMP using DATETIME. + */ + DBUG_ASSERT(0); + return 0; +} + + +int cmp_item_timestamp::cmp(Item *arg) +{ + THD *thd= current_thd; + Timestamp_or_zero_datetime_native_null tmp(thd, arg, true); + return m_null_value || tmp.is_null() ? UNKNOWN : + type_handler_timestamp2.cmp_native(m_native, tmp) != 0; +} + + +int cmp_item_timestamp::compare(cmp_item *arg) +{ + cmp_item_timestamp *tmp= static_cast<cmp_item_timestamp*>(arg); + return type_handler_timestamp2.cmp_native(m_native, tmp->m_native); +} + + +cmp_item* cmp_item_timestamp::make_same() +{ + return new cmp_item_timestamp(); +} + + + bool Item_func_in::count_sargable_conds(void *arg) { ((SELECT_LEX*) arg)->cond_count++; |