Commit 26e0d1e4 authored by unknown's avatar unknown

Porting fix for bug #7586 "TIMEDIFF for sec+microsec not working properly"

to 5.0 tree (since it was lost during last merge).


mysql-test/r/func_sapdb.result:
  Updated test result after fixing bug #7586 "TIMEDIFF for sec+microsec not
  working properly" in 5.0 tree.
sql/item_timefunc.cc:
  calc_time_diff():
    Use simplier and less error-prone implementation. Now we are counting
    difference between time values in microseconds and then convert it to
    seconds + microseconds value (instead of using seconds and taking
    difference in "second_part"s into account).
parent 9d983231
...@@ -107,7 +107,7 @@ timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") ...@@ -107,7 +107,7 @@ timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002")
46:58:57.999999 46:58:57.999999
select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002");
timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002")
-23:59:59.999999 -24:00:00.000001
select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); select timediff("1997-12-31 23:59:59.000001","23:59:59.000001");
timediff("1997-12-31 23:59:59.000001","23:59:59.000001") timediff("1997-12-31 23:59:59.000001","23:59:59.000001")
NULL NULL
...@@ -116,7 +116,7 @@ timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001") ...@@ -116,7 +116,7 @@ timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001")
-00:00:00.000001 -00:00:00.000001
select timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50"); select timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50");
timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50") timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50")
-00:00:01.999999 -00:00:00.000001
select maketime(10,11,12); select maketime(10,11,12);
maketime(10,11,12) maketime(10,11,12)
10:11:12 10:11:12
...@@ -188,7 +188,7 @@ f8 date YES NULL ...@@ -188,7 +188,7 @@ f8 date YES NULL
f9 time YES NULL f9 time YES NULL
select * from t1; select * from t1;
f1 f2 f3 f4 f5 f6 f7 f8 f9 f1 f2 f3 f4 f5 f6 f7 f8 f9
1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -23:59:59 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59 1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -24:00:00 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59
create table test(t1 datetime, t2 time, t3 time, t4 datetime); create table test(t1 datetime, t2 time, t3 time, t4 datetime);
insert into test values insert into test values
('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), ('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'),
......
...@@ -2441,36 +2441,37 @@ void Item_func_add_time::print(String *str) ...@@ -2441,36 +2441,37 @@ void Item_func_add_time::print(String *str)
/* /*
Calculate difference between two datetime values as seconds + microseconds.
SYNOPSIS SYNOPSIS
calc_time_diff() calc_time_diff()
l_time1 TIME/DATE/DATETIME value l_time1 - TIME/DATE/DATETIME value
l_time2 TIME/DATE/DATETIME value l_time2 - TIME/DATE/DATETIME value
l_sign Can be 1 (operation of addition) l_sign - 1 absolute values are substracted,
or -1 (substraction) -1 absolute values are added.
seconds_out Returns count of seconds bitween seconds_out - Out parameter where difference between
l_time1 and l_time2 l_time1 and l_time2 in seconds is stored.
microseconds_out Returns count of microseconds bitween microseconds_out- Out parameter where microsecond part of difference
l_time1 and l_time2. between l_time1 and l_time2 is stored.
DESCRIPTION NOTE
Calculates difference in seconds(seconds_out) This function calculates difference between l_time1 and l_time2 absolute
and microseconds(microseconds_out) values. So one should set l_sign and correct result if he want to take
bitween two TIME/DATE/DATETIME values. signs into account (i.e. for TIME values).
RETURN VALUES RETURN VALUES
Rertuns sign of difference. Returns sign of difference.
1 means negative result 1 means negative result
0 means positive result 0 means positive result
*/ */
bool calc_time_diff(TIME *l_time1,TIME *l_time2, int l_sign, static bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign,
longlong *seconds_out, long *microseconds_out) longlong *seconds_out, long *microseconds_out)
{ {
long days; long days;
bool neg; bool neg;
longlong seconds= *seconds_out; longlong microseconds;
long microseconds= *microseconds_out;
/* /*
We suppose that if first argument is MYSQL_TIMESTAMP_TIME We suppose that if first argument is MYSQL_TIMESTAMP_TIME
...@@ -2487,29 +2488,20 @@ bool calc_time_diff(TIME *l_time1,TIME *l_time2, int l_sign, ...@@ -2487,29 +2488,20 @@ bool calc_time_diff(TIME *l_time1,TIME *l_time2, int l_sign,
(uint) l_time2->month, (uint) l_time2->month,
(uint) l_time2->day)); (uint) l_time2->day));
microseconds= l_time1->second_part - l_sign*l_time2->second_part; microseconds= ((longlong)days*86400L +
seconds= ((longlong) days*86400L + l_time1->hour*3600L + l_time1->hour*3600L + l_time1->minute*60L + l_time1->second -
l_time1->minute*60L + l_time1->second + microseconds/1000000L - (longlong)l_sign*(l_time2->hour*3600L + l_time2->minute*60L +
(longlong)l_sign*(l_time2->hour*3600L+l_time2->minute*60L+l_time2->second)); l_time2->second))*1000000L +
l_time1->second_part - l_sign*l_time2->second_part;
neg= 0; neg= 0;
if (seconds < 0) if (microseconds < 0)
{
seconds= -seconds;
neg= 1;
}
else if (seconds == 0 && microseconds < 0)
{ {
microseconds= -microseconds; microseconds= -microseconds;
neg= 1; neg= 1;
} }
if (microseconds < 0) *seconds_out= microseconds/1000000L;
{ *microseconds_out= (long) (microseconds%1000000L);
microseconds+= 1000000L;
seconds--;
}
*seconds_out= seconds;
*microseconds_out= microseconds;
return neg; return neg;
} }
...@@ -2544,9 +2536,10 @@ String *Item_func_timediff::val_str(String *str) ...@@ -2544,9 +2536,10 @@ String *Item_func_timediff::val_str(String *str)
/* /*
For MYSQL_TIMESTAMP_TIME only: For MYSQL_TIMESTAMP_TIME only:
If both argumets are negative values and diff between them If both argumets are negative values and diff between them
is negative we need to swap sign as result should be positive. is non-zero we need to swap sign to get proper result.
*/ */
if ((l_time2.neg == l_time1.neg) && l_time1.neg) if ((l_time2.neg == l_time1.neg) && l_time1.neg &&
(seconds || microseconds))
l_time3.neg= 1-l_time3.neg; // Swap sign of result l_time3.neg= 1-l_time3.neg; // Swap sign of result
calc_time_from_sec(&l_time3, (long) seconds, microseconds); calc_time_from_sec(&l_time3, (long) seconds, microseconds);
...@@ -2712,13 +2705,11 @@ longlong Item_func_timestamp_diff::val_int() ...@@ -2712,13 +2705,11 @@ longlong Item_func_timestamp_diff::val_int()
case INTERVAL_SECOND: case INTERVAL_SECOND:
return seconds*neg; return seconds*neg;
case INTERVAL_MICROSECOND: case INTERVAL_MICROSECOND:
{ /*
longlong max_sec= LONGLONG_MAX/1000000; In MySQL difference between any two valid datetime values
if (max_sec > seconds || in microseconds fits into longlong.
max_sec == seconds && LONGLONG_MAX%1000000 >= microseconds) */
return (longlong) (seconds*1000000L+microseconds)*neg; return (seconds*1000000L+microseconds)*neg;
goto null_date;
}
default: default:
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment