Commit ae0c6a94 authored by Tatiana A. Nurnberg's avatar Tatiana A. Nurnberg
Browse files

Bug#37553: MySql Error Compare TimeDiff & Time

We pretended that TIMEDIFF() would always return positive results;
this gave strange results in comparisons of the TIMEDIFF(low,hi)<TIME(0)
type that rendered a negative result, but still gave false in comparison.
We also inadvertantly dropped the sign when converting times to
decimal.

CAST(time AS DECIMAL) handles signs of the times correctly.
TIMEDIFF() marked up as signed. Time/date comparison code switched to
signed for clarity.
parent 03a27c45
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -256,3 +256,15 @@ a
select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f");
str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f")
2003-01-02 10:11:12.001200
select timediff('2008-09-29 20:10:10','2008-09-30 20:10:10'),time('00:00:00');
timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')	time('00:00:00')
-24:00:00	00:00:00
select timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')>time('00:00:00');
timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')>time('00:00:00')
0
select timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')<time('00:00:00');
timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')<time('00:00:00')
1
SELECT CAST(time('-73:42:12') AS DECIMAL);
CAST(time('-73:42:12') AS DECIMAL)
-734212
+17 −0
Original line number Diff line number Diff line
@@ -135,3 +135,20 @@ select str_to_date("2003-01-02 10:11:12.0012", "%Y-%m-%d %H:%i:%S.%f");
--enable_ps_protocol

# End of 4.1 tests



#
# Bug#37553: MySql Error Compare TimeDiff & Time
#

# calculations involving negative time values ignored sign
select timediff('2008-09-29 20:10:10','2008-09-30 20:10:10'),time('00:00:00');
select timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')>time('00:00:00');
select timediff('2008-09-29 20:10:10','2008-09-30 20:10:10')<time('00:00:00');

# show that conversion to DECIMAL no longer drops sign
SELECT CAST(time('-73:42:12') AS DECIMAL);


# End of 5.0 tests
+7 −7
Original line number Diff line number Diff line
@@ -745,11 +745,11 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
    obtained value
*/

ulonglong
longlong
get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
               Item *warn_item, bool *is_null)
{
  ulonglong value;
  longlong value;
  Item *item= **item_arg;
  MYSQL_TIME ltime;

@@ -761,7 +761,7 @@ get_time_value(THD *thd, Item ***item_arg, Item **cache_arg,
  else
  {
    *is_null= item->get_time(&ltime);
    value= !*is_null ? TIME_to_ulonglong_datetime(&ltime) : 0;
    value= !*is_null ? (longlong) TIME_to_ulonglong_datetime(&ltime) : 0;
  }
  /*
    Do not cache GET_USER_VAR() function as its const_item() may return TRUE
@@ -886,11 +886,11 @@ void Arg_comparator::set_datetime_cmp_func(Item **a1, Item **b1)
    obtained value
*/

ulonglong
longlong
get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
                   Item *warn_item, bool *is_null)
{
  ulonglong value= 0;
  longlong value= 0;
  String buf, *str= 0;
  Item *item= **item_arg;

@@ -925,7 +925,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
    enum_field_types f_type= warn_item->field_type();
    timestamp_type t_type= f_type ==
      MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME;
    value= get_date_from_str(thd, str, t_type, warn_item->name, &error);
    value= (longlong) get_date_from_str(thd, str, t_type, warn_item->name, &error);
    /*
      If str did not contain a valid date according to the current
      SQL_MODE, get_date_from_str() has already thrown a warning,
@@ -979,7 +979,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
int Arg_comparator::compare_datetime()
{
  bool a_is_null, b_is_null;
  ulonglong a_value, b_value;
  longlong a_value, b_value;

  /* Get DATE/DATETIME/TIME value of the 'a' item. */
  a_value= (*get_value_func)(thd, &a, &a_cache, *b, &a_is_null);
+3 −3
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ class Arg_comparator: public Sql_alloc
  bool is_nulls_eq;                // TRUE <=> compare for the EQUAL_FUNC
  enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE,
                            CMP_DATE_WITH_STR, CMP_STR_WITH_DATE };
  ulonglong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
  longlong (*get_value_func)(THD *thd, Item ***item_arg, Item **cache_arg,
                             Item *warn_item, bool *is_null);
public:
  DTCollation cmp_collation;
@@ -1028,7 +1028,7 @@ class cmp_item_int :public cmp_item
*/
class cmp_item_datetime :public cmp_item
{
  ulonglong value;
  longlong value;
public:
  THD *thd;
  /* Item used for issuing warnings. */
+1 −1
Original line number Diff line number Diff line
@@ -2283,7 +2283,7 @@ uint Item_func_min_max::cmp_datetimes(ulonglong *value)
  {
    Item **arg= args + i;
    bool is_null;
    ulonglong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
    longlong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null);
    if ((null_value= args[i]->null_value))
      return 0;
    if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
Loading