summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatiana A. Nurnberg <azundris@mysql.com>2008-11-26 09:28:17 +0100
committerTatiana A. Nurnberg <azundris@mysql.com>2008-11-26 09:28:17 +0100
commitd096079d330f77eebd3c3abef04236a9a4a08d7b (patch)
tree89fc8f73a3e600368596aa2d7d21302f2ee7f34b
parentdf8a5474f8a904b4e254e446fd6ea61a94c98e2a (diff)
downloadmariadb-git-d096079d330f77eebd3c3abef04236a9a4a08d7b.tar.gz
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. mysql-test/r/func_sapdb.result: show that time-related comparisons work with negative time values now. show that converting time to DECIMAL no longer drops sign. mysql-test/t/func_sapdb.test: show that time-related comparisons work with negative time values now. show that converting time to DECIMAL no longer drops sign. sql/item_cmpfunc.cc: signed returns sql/item_cmpfunc.h: signed now (time/date < > =) sql/item_func.cc: signed now sql/item_timefunc.h: Functions such as TIMEDIFF() return signed results! The file-comments pretended we were doing that all along, anyway... sql/my_decimal.cc: heed sign when converting time to my_decimal; times may actually be negative! Needed for SELECT CAST(time('-73:42:12') AS DECIMAL); sql/mysql_priv.h: using signed for dates and times now
-rw-r--r--mysql-test/r/func_sapdb.result12
-rw-r--r--mysql-test/t/func_sapdb.test17
-rw-r--r--sql/item_cmpfunc.cc14
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_timefunc.h1
-rw-r--r--sql/my_decimal.cc2
-rw-r--r--sql/mysql_priv.h4
8 files changed, 44 insertions, 14 deletions
diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result
index 4db0416bdce..a06d7004908 100644
--- a/mysql-test/r/func_sapdb.result
+++ b/mysql-test/r/func_sapdb.result
@@ -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
diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test
index 5db6db70e8f..f37ee0c39f0 100644
--- a/mysql-test/t/func_sapdb.test
+++ b/mysql-test/t/func_sapdb.test
@@ -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
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 4bfae376acc..3b1d18b4252 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -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);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1bd60ff37d9..db831c7030c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -42,8 +42,8 @@ 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,
- Item *warn_item, bool *is_null);
+ 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 @@ public:
*/
class cmp_item_datetime :public cmp_item
{
- ulonglong value;
+ longlong value;
public:
THD *thd;
/* Item used for issuing warnings. */
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 45aa8e9bea0..8295bd41334 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -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)
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 7960c03d2e5..81a6c3e98bd 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -408,6 +408,7 @@ public:
{
return save_time_in_field(field);
}
+ bool result_as_longlong() { return TRUE; }
};
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 31a5b09370a..a235edbd73c 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -216,7 +216,7 @@ my_decimal *date2my_decimal(MYSQL_TIME *ltime, my_decimal *dec)
date = (ltime->year*100L + ltime->month)*100L + ltime->day;
if (ltime->time_type > MYSQL_TIMESTAMP_DATE)
date= ((date*100L + ltime->hour)*100L+ ltime->minute)*100L + ltime->second;
- if (int2my_decimal(E_DEC_FATAL_ERROR, date, FALSE, dec))
+ if (int2my_decimal(E_DEC_FATAL_ERROR, ltime->neg ? -date : date, FALSE, dec))
return dec;
if (ltime->second_part)
{
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 1568f042b7e..d112c2b2f39 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1556,8 +1556,8 @@ void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
String *str);
-ulonglong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
- Item *warn_item, bool *is_null);
+longlong get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
+ Item *warn_item, bool *is_null);
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(byte *,uint,char,char);