diff options
author | unknown <dlenev@brandersnatch.localdomain> | 2005-01-15 20:02:46 +0300 |
---|---|---|
committer | unknown <dlenev@brandersnatch.localdomain> | 2005-01-15 20:02:46 +0300 |
commit | 9e60778daeeead4a9470ecdf7c2d008635c197a8 (patch) | |
tree | 495065916f2afa9d80b2bed614e60acfc6fdad75 | |
parent | 6ead860060ebeae29f46d6c89f0bf7a45e748819 (diff) | |
download | mariadb-git-9e60778daeeead4a9470ecdf7c2d008635c197a8.tar.gz |
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).
-rw-r--r-- | mysql-test/r/func_sapdb.result | 6 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 79 |
2 files changed, 38 insertions, 47 deletions
diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index a2918e71d68..6556d2be6ad 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -107,7 +107,7 @@ timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") 46:58:57.999999 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") --23:59:59.999999 +-24:00:00.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") NULL @@ -116,7 +116,7 @@ timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001") -00:00:00.000001 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") --00:00:01.999999 +-00:00:00.000001 select maketime(10,11,12); maketime(10,11,12) 10:11:12 @@ -188,7 +188,7 @@ f8 date YES NULL f9 time YES NULL select * from t1; 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); insert into test values ('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 2d0e5d7632f..0c1cd3cbad3 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2441,36 +2441,37 @@ void Item_func_add_time::print(String *str) /* + Calculate difference between two datetime values as seconds + microseconds. + SYNOPSIS calc_time_diff() - l_time1 TIME/DATE/DATETIME value - l_time2 TIME/DATE/DATETIME value - l_sign Can be 1 (operation of addition) - or -1 (substraction) - seconds_out Returns count of seconds bitween - l_time1 and l_time2 - microseconds_out Returns count of microseconds bitween - l_time1 and l_time2. - - DESCRIPTION - Calculates difference in seconds(seconds_out) - and microseconds(microseconds_out) - bitween two TIME/DATE/DATETIME values. + l_time1 - TIME/DATE/DATETIME value + l_time2 - TIME/DATE/DATETIME value + l_sign - 1 absolute values are substracted, + -1 absolute values are added. + seconds_out - Out parameter where difference between + l_time1 and l_time2 in seconds is stored. + microseconds_out- Out parameter where microsecond part of difference + between l_time1 and l_time2 is stored. + + NOTE + This function calculates difference between l_time1 and l_time2 absolute + values. So one should set l_sign and correct result if he want to take + signs into account (i.e. for TIME values). RETURN VALUES - Rertuns sign of difference. + Returns sign of difference. 1 means negative result 0 means positive result */ -bool calc_time_diff(TIME *l_time1,TIME *l_time2, int l_sign, - longlong *seconds_out, long *microseconds_out) +static bool calc_time_diff(TIME *l_time1, TIME *l_time2, int l_sign, + longlong *seconds_out, long *microseconds_out) { long days; bool neg; - longlong seconds= *seconds_out; - long microseconds= *microseconds_out; + longlong microseconds; /* 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, (uint) l_time2->month, (uint) l_time2->day)); - microseconds= l_time1->second_part - l_sign*l_time2->second_part; - seconds= ((longlong) days*86400L + l_time1->hour*3600L + - l_time1->minute*60L + l_time1->second + microseconds/1000000L - - (longlong)l_sign*(l_time2->hour*3600L+l_time2->minute*60L+l_time2->second)); + microseconds= ((longlong)days*86400L + + l_time1->hour*3600L + l_time1->minute*60L + l_time1->second - + (longlong)l_sign*(l_time2->hour*3600L + l_time2->minute*60L + + l_time2->second))*1000000L + + l_time1->second_part - l_sign*l_time2->second_part; neg= 0; - if (seconds < 0) - { - seconds= -seconds; - neg= 1; - } - else if (seconds == 0 && microseconds < 0) + if (microseconds < 0) { microseconds= -microseconds; neg= 1; } - if (microseconds < 0) - { - microseconds+= 1000000L; - seconds--; - } - *seconds_out= seconds; - *microseconds_out= microseconds; + *seconds_out= microseconds/1000000L; + *microseconds_out= (long) (microseconds%1000000L); return neg; } @@ -2544,9 +2536,10 @@ String *Item_func_timediff::val_str(String *str) /* For MYSQL_TIMESTAMP_TIME only: 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 calc_time_from_sec(&l_time3, (long) seconds, microseconds); @@ -2712,13 +2705,11 @@ longlong Item_func_timestamp_diff::val_int() case INTERVAL_SECOND: return seconds*neg; case INTERVAL_MICROSECOND: - { - longlong max_sec= LONGLONG_MAX/1000000; - if (max_sec > seconds || - max_sec == seconds && LONGLONG_MAX%1000000 >= microseconds) - return (longlong) (seconds*1000000L+microseconds)*neg; - goto null_date; - } + /* + In MySQL difference between any two valid datetime values + in microseconds fits into longlong. + */ + return (seconds*1000000L+microseconds)*neg; default: break; } |