diff options
author | unknown <kaa@polly.local> | 2006-10-12 12:36:13 +0400 |
---|---|---|
committer | unknown <kaa@polly.local> | 2006-10-12 12:36:13 +0400 |
commit | 131d8b8645f0f5628cd62f5c0b1a3457f9f63307 (patch) | |
tree | 4763f87f5b35217d4afe850ab88ba2dfc0974778 | |
parent | 1f816053d2f531062c5449fc4cea71c2c41792d6 (diff) | |
parent | 45af97ad1d06f1ef66d9f4dad53b6cc255e781a2 (diff) | |
download | mariadb-git-131d8b8645f0f5628cd62f5c0b1a3457f9f63307.tar.gz |
Merge polly.local:/tmp/maint/bug11655/my51-bug11655
into polly.local:/home/kaa/src/maint/m51-new-maint--07OGx
include/my_time.h:
Auto merged
mysql-test/t/func_time.test:
Auto merged
sql/field.cc:
Auto merged
sql/item_timefunc.cc:
Auto merged
sql/time.cc:
Auto merged
mysql-test/r/func_time.result:
Manually merged
-rw-r--r-- | include/my_time.h | 14 | ||||
-rw-r--r-- | mysql-test/r/func_sapdb.result | 15 | ||||
-rw-r--r-- | mysql-test/r/func_time.result | 91 | ||||
-rw-r--r-- | mysql-test/t/func_time.test | 41 | ||||
-rw-r--r-- | sql-common/my_time.c | 90 | ||||
-rw-r--r-- | sql/field.cc | 35 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 228 | ||||
-rw-r--r-- | sql/time.cc | 6 |
8 files changed, 427 insertions, 93 deletions
diff --git a/include/my_time.h b/include/my_time.h index cb8684efdb1..069cecc7b14 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -57,6 +57,16 @@ typedef long my_time_t; #define TIME_NO_ZERO_DATE (TIME_NO_ZERO_IN_DATE*2) #define TIME_INVALID_DATES (TIME_NO_ZERO_DATE*2) +#define MYSQL_TIME_WARN_TRUNCATED 1 +#define MYSQL_TIME_WARN_OUT_OF_RANGE 2 + +/* Limits for the TIME data type */ +#define TIME_MAX_HOUR 838 +#define TIME_MAX_MINUTE 59 +#define TIME_MAX_SECOND 59 +#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + \ + TIME_MAX_SECOND) + enum enum_mysql_timestamp_type str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, uint flags, int *was_cut); @@ -69,7 +79,9 @@ ulonglong TIME_to_ulonglong(const MYSQL_TIME *time); my_bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time, - int *was_cut); + int *warning); + +int check_time_range(struct st_mysql_time *time, int *warning); long calc_daynr(uint year,uint month,uint day); uint calc_days_in_year(uint year); diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index 7e9bba9710c..29ceb6ecaa4 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -107,7 +107,9 @@ subtime("02:01:01.999999", "01:01:01.999999") 01:00:00.000000 select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002") -8807:59:59.999999 +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '8807:59:59.999999' select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") 46:58:57.999999 @@ -219,13 +221,16 @@ SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq, TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test; ttt qqq eee rrr -744:00:00 NULL NULL NULL -26305:01:02 22:58:58 -22:58:58 NULL --26305:01:02 -22:58:58 22:58:58 NULL +838:59:59 22:58:58 -22:58:58 NULL +-838:59:59 -22:58:58 22:58:58 NULL NULL 26:02:02 -26:02:02 NULL 00:00:00 -26:02:02 26:02:02 NULL NULL NULL NULL NULL NULL NULL NULL NULL 00:00:00 -24:00:00 24:00:00 NULL +Warnings: +Warning 1292 Truncated incorrect time value: '26305:01:02' +Warning 1292 Truncated incorrect time value: '-26305:01:02' drop table t1, test; select addtime("-01:01:01.01", "-23:59:59.1") as a; a @@ -235,7 +240,9 @@ a 10000 select microsecond(19971231235959.01) as a; a -10000 +0 +Warnings: +Warning 1292 Truncated incorrect time value: '19971231235959.01' select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; a 1997-12-31 00:00:10.090000 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 93158750b89..7cafd641dd6 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -339,7 +339,9 @@ extract(DAY_MINUTE FROM "02 10:11:12") 21011 select extract(DAY_SECOND FROM "225 10:11:12"); extract(DAY_SECOND FROM "225 10:11:12") -225101112 +8385959 +Warnings: +Warning 1292 Truncated incorrect time value: '225 10:11:12' select extract(HOUR FROM "1999-01-02 10:11:12"); extract(HOUR FROM "1999-01-02 10:11:12") 10 @@ -902,6 +904,93 @@ fmtddate field2 Sep-4 12:00AM abcd DROP TABLE testBug8868; SET NAMES DEFAULT; +SELECT SEC_TO_TIME(3300000); +SEC_TO_TIME(3300000) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '3300000' +SELECT SEC_TO_TIME(3300000)+0; +SEC_TO_TIME(3300000)+0 +8385959.000000 +Warnings: +Warning 1292 Truncated incorrect time value: '3300000' +SELECT SEC_TO_TIME(3600 * 4294967296); +SEC_TO_TIME(3600 * 4294967296) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '15461882265600' +SELECT TIME_TO_SEC('916:40:00'); +TIME_TO_SEC('916:40:00') +3020399 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT ADDTIME('500:00:00', '416:40:00'); +ADDTIME('500:00:00', '416:40:00') +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT ADDTIME('916:40:00', '416:40:00'); +ADDTIME('916:40:00', '416:40:00') +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +Warning 1292 Truncated incorrect time value: '1255:39:59' +SELECT SUBTIME('916:40:00', '416:40:00'); +SUBTIME('916:40:00', '416:40:00') +422:19:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT SUBTIME('-916:40:00', '416:40:00'); +SUBTIME('-916:40:00', '416:40:00') +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '-916:40:00' +Warning 1292 Truncated incorrect time value: '-1255:39:59' +SELECT MAKETIME(916,0,0); +MAKETIME(916,0,0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:00:00' +SELECT MAKETIME(4294967296, 0, 0); +MAKETIME(4294967296, 0, 0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '4294967296:00:00' +SELECT MAKETIME(-4294967296, 0, 0); +MAKETIME(-4294967296, 0, 0) +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '-4294967296:00:00' +SELECT MAKETIME(0, 4294967296, 0); +MAKETIME(0, 4294967296, 0) +NULL +SELECT MAKETIME(0, 0, 4294967296); +MAKETIME(0, 0, 4294967296) +NULL +SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); +MAKETIME(CAST(-1 AS UNSIGNED), 0, 0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '18446744073709551615:00:00' +SELECT EXTRACT(HOUR FROM '100000:02:03'); +EXTRACT(HOUR FROM '100000:02:03') +838 +Warnings: +Warning 1292 Truncated incorrect time value: '100000:02:03' +CREATE TABLE t1(f1 TIME); +INSERT INTO t1 VALUES('916:00:00 a'); +Warnings: +Warning 1265 Data truncated for column 'f1' at row 1 +Warning 1264 Out of range value adjusted for column 'f1' at row 1 +SELECT * FROM t1; +f1 +838:59:59 +DROP TABLE t1; +SELECT SEC_TO_TIME(CAST(-1 AS UNSIGNED)); +SEC_TO_TIME(CAST(-1 AS UNSIGNED)) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '18446744073709551615' (select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H) union (select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H); diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index d49a4fed9d2..a0b0a929b6a 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -466,6 +466,47 @@ SET NAMES DEFAULT; # +# Bug #11655: Wrong time is returning from nested selects - maximum time exists +# +# check if SEC_TO_TIME() handles out-of-range values correctly +SELECT SEC_TO_TIME(3300000); +SELECT SEC_TO_TIME(3300000)+0; +SELECT SEC_TO_TIME(3600 * 4294967296); + +# check if TIME_TO_SEC() handles out-of-range values correctly +SELECT TIME_TO_SEC('916:40:00'); + +# check if ADDTIME() handles out-of-range values correctly +SELECT ADDTIME('500:00:00', '416:40:00'); +SELECT ADDTIME('916:40:00', '416:40:00'); + +# check if SUBTIME() handles out-of-range values correctly +SELECT SUBTIME('916:40:00', '416:40:00'); +SELECT SUBTIME('-916:40:00', '416:40:00'); + +# check if MAKETIME() handles out-of-range values correctly +SELECT MAKETIME(916,0,0); +SELECT MAKETIME(4294967296, 0, 0); +SELECT MAKETIME(-4294967296, 0, 0); +SELECT MAKETIME(0, 4294967296, 0); +SELECT MAKETIME(0, 0, 4294967296); +SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); + +# check if EXTRACT() handles out-of-range values correctly +SELECT EXTRACT(HOUR FROM '100000:02:03'); + +# check if we get proper warnings if both input string truncation +# and out-of-range value occur +CREATE TABLE t1(f1 TIME); +INSERT INTO t1 VALUES('916:00:00 a'); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #20927: sec_to_time treats big unsigned as signed +# +# check if SEC_TO_TIME() handles BIGINT UNSIGNED values correctly +SELECT SEC_TO_TIME(CAST(-1 AS UNSIGNED)); # Bug #19844 time_format in Union truncates values # diff --git a/sql-common/my_time.c b/sql-common/my_time.c index b4cfe041529..29de0504468 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -465,8 +465,10 @@ err: There may be an optional [.second_part] after seconds length Length of str l_time Store result here - was_cut Set to 1 if value was cut during conversion or to 0 - otherwise. + warning Set MYSQL_TIME_WARN_TRUNCATED flag if the input string + was cut during conversion, and/or + MYSQL_TIME_WARN_OUT_OF_RANGE flag, if the value is + out of range. NOTES Because of the extra days argument, this function can only @@ -478,15 +480,16 @@ err: */ my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, - int *was_cut) + int *warning) { - long date[5],value; + ulong date[5]; + ulonglong value; const char *end=str+length, *end_of_days; my_bool found_days,found_hours; uint state; l_time->neg=0; - *was_cut= 0; + *warning= 0; for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') @@ -501,13 +504,16 @@ my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, /* Check first if this is a full TIMESTAMP */ if (length >= 12) { /* Probably full timestamp */ + int was_cut; enum enum_mysql_timestamp_type res= str_to_datetime(str, length, l_time, - (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), was_cut); + (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut); if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR) + { + if (was_cut) + *warning|= MYSQL_TIME_WARN_TRUNCATED; return res == MYSQL_TIMESTAMP_ERROR; - /* We need to restore was_cut flag since str_to_datetime can modify it */ - *was_cut= 0; + } } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ @@ -587,7 +593,7 @@ fractional: if (field_length > 0) value*= (long) log_10_int[field_length]; else if (field_length < 0) - *was_cut= 1; + *warning|= MYSQL_TIME_WARN_TRUNCATED; date[4]=value; } else @@ -601,10 +607,7 @@ fractional: ((str[1] == '-' || str[1] == '+') && (end - str) > 2 && my_isdigit(&my_charset_latin1, str[2])))) - { - *was_cut= 1; return 1; - } if (internal_format_positions[7] != 255) { @@ -623,12 +626,12 @@ fractional: } } - /* Some simple checks */ - if (date[2] >= 60 || date[3] >= 60) - { - *was_cut= 1; + /* Integer overflow checks */ + if (date[0] > UINT_MAX || date[1] > UINT_MAX || + date[2] > UINT_MAX || date[3] > UINT_MAX || + date[4] > UINT_MAX) return 1; - } + l_time->year= 0; /* For protocol::store_time */ l_time->month= 0; l_time->day= date[0]; @@ -638,6 +641,10 @@ fractional: l_time->second_part= date[4]; l_time->time_type= MYSQL_TIMESTAMP_TIME; + /* Check if the value is valid and fits into TIME range */ + if (check_time_range(l_time, warning)) + return 1; + /* Check if there is garbage at end of the TIME specification */ if (str != end) { @@ -645,7 +652,7 @@ fractional: { if (!my_isspace(&my_charset_latin1,*str)) { - *was_cut= 1; + *warning|= MYSQL_TIME_WARN_TRUNCATED; break; } } while (++str != end); @@ -655,6 +662,47 @@ fractional: /* + Check 'time' value to lie in the TIME range + + SYNOPSIS: + check_time_range() + time pointer to TIME value + warning set MYSQL_TIME_WARN_OUT_OF_RANGE flag if the value is out of range + + DESCRIPTION + If the time value lies outside of the range [-838:59:59, 838:59:59], + set it to the closest endpoint of the range and set + MYSQL_TIME_WARN_OUT_OF_RANGE flag in the 'warning' variable. + + RETURN + 0 time value is valid, but was possibly truncated + 1 time value is invalid +*/ + +int check_time_range(struct st_mysql_time *time, int *warning) +{ + longlong hour; + + if (time->minute >= 60 || time->second >= 60) + return 1; + + hour= time->hour + (24*time->day); + if (hour <= TIME_MAX_HOUR && + (hour != TIME_MAX_HOUR || time->minute != TIME_MAX_MINUTE || + time->second != TIME_MAX_SECOND || !time->second_part)) + return 0; + + time->day= 0; + time->hour= TIME_MAX_HOUR; + time->minute= TIME_MAX_MINUTE; + time->second= TIME_MAX_SECOND; + time->second_part= 0; + *warning|= MYSQL_TIME_WARN_OUT_OF_RANGE; + return 0; +} + + +/* Prepare offset of system time zone from UTC for my_system_gmt_sec() func. SYNOPSIS @@ -840,7 +888,7 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type) int my_time_to_str(const MYSQL_TIME *l_time, char *to) { uint extra_hours= 0; - return my_sprintf(to, (to, "%s%02d:%02d:%02d", + return my_sprintf(to, (to, "%s%02u:%02u:%02u", (l_time->neg ? "-" : ""), extra_hours+ l_time->hour, l_time->minute, @@ -849,7 +897,7 @@ int my_time_to_str(const MYSQL_TIME *l_time, char *to) int my_date_to_str(const MYSQL_TIME *l_time, char *to) { - return my_sprintf(to, (to, "%04d-%02d-%02d", + return my_sprintf(to, (to, "%04u-%02u-%02u", l_time->year, l_time->month, l_time->day)); @@ -857,7 +905,7 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to) int my_datetime_to_str(const MYSQL_TIME *l_time, char *to) { - return my_sprintf(to, (to, "%04d-%02d-%02d %02d:%02d:%02d", + return my_sprintf(to, (to, "%04u-%02u-%02u %02u:%02u:%02u", l_time->year, l_time->month, l_time->day, diff --git a/sql/field.cc b/sql/field.cc index 09e919d872a..122a44305f2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4875,9 +4875,10 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) { TIME ltime; long tmp; - int error; + int error= 0; + int warning; - if (str_to_time(from, len, <ime, &error)) + if (str_to_time(from, len, <ime, &warning)) { tmp=0L; error= 2; @@ -4886,29 +4887,27 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) } else { - if (error) + if (warning & MYSQL_TIME_WARN_TRUNCATED) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, from, len, MYSQL_TIMESTAMP_TIME, 1); - - if (ltime.month) - ltime.day=0; - tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second); - if (tmp > 8385959) + if (warning & MYSQL_TIME_WARN_OUT_OF_RANGE) { - tmp=8385959; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, from, len, MYSQL_TIMESTAMP_TIME, !error); error= 1; } + if (ltime.month) + ltime.day=0; + tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second); if (error > 1) error= 2; } if (ltime.neg) tmp= -tmp; - error |= Field_time::store((longlong) tmp, FALSE); + int3store(ptr,tmp); return error; } @@ -4928,16 +4927,16 @@ int Field_time::store(double nr) ASSERT_COLUMN_MARKED_FOR_WRITE; long tmp; int error= 0; - if (nr > 8385959.0) + if (nr > (double)TIME_MAX_VALUE) { - tmp=8385959L; + tmp= TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME); error= 1; } - else if (nr < -8385959.0) + else if (nr < (double)-TIME_MAX_VALUE) { - tmp= -8385959L; + tmp= -TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME); error= 1; @@ -4966,17 +4965,17 @@ int Field_time::store(longlong nr, bool unsigned_val) ASSERT_COLUMN_MARKED_FOR_WRITE; long tmp; int error= 0; - if (nr < (longlong) -8385959L && !unsigned_val) + if (nr < (longlong) -TIME_MAX_VALUE && !unsigned_val) { - tmp= -8385959L; + tmp= -TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); error= 1; } - else if (nr > (longlong) 8385959 || nr < 0 && unsigned_val) + else if (nr > (longlong) TIME_MAX_VALUE || nr < 0 && unsigned_val) { - tmp=8385959L; + tmp= TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 064db11b65f..f378e5037dc 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -96,6 +96,125 @@ static bool make_datetime(date_time_format_types format, TIME *ltime, /* + Wrapper over make_datetime() with validation of the input TIME value + + NOTE + see make_datetime() for more information + + RETURN + 1 if there was an error during converion + 0 otherwise +*/ + +static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime, + String *str) +{ + int warning= 0; + bool rc; + + if (make_datetime(format, ltime, str)) + return 1; + if (check_time_range(ltime, &warning)) + return 1; + if (!warning) + return 0; + + make_truncated_value_warning(current_thd, str->ptr(), str->length(), + MYSQL_TIMESTAMP_TIME, NullS); + return make_datetime(format, ltime, str); +} + + +/* + Wrapper over make_time() with validation of the input TIME value + + NOTE + see make_time() for more info + + RETURN + 1 if there was an error during conversion + 0 otherwise +*/ + +static bool make_time_with_warn(const DATE_TIME_FORMAT *format, + TIME *l_time, String *str) +{ + int warning= 0; + make_time(format, l_time, str); + if (check_time_range(l_time, &warning)) + return 1; + if (warning) + { + make_truncated_value_warning(current_thd, str->ptr(), str->length(), + MYSQL_TIMESTAMP_TIME, NullS); + make_time(format, l_time, str); + } + + return 0; +} + + +/* + Convert seconds to TIME value with overflow checking + + SYNOPSIS: + sec_to_time() + seconds number of seconds + unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise + ltime output TIME value + + DESCRIPTION + If the 'seconds' argument is inside TIME data range, convert it to a + corresponding value. + Otherwise, truncate the resulting value to the nearest endpoint, and + produce a warning message. + + RETURN + 1 if the value was truncated during conversion + 0 otherwise +*/ + +static bool sec_to_time(longlong seconds, bool unsigned_flag, TIME *ltime) +{ + uint sec; + + bzero((char *)ltime, sizeof(*ltime)); + + if (seconds < 0) + { + if (unsigned_flag) + goto overflow; + ltime->neg= 1; + if (seconds < -3020399) + goto overflow; + seconds= -seconds; + } + else if (seconds > 3020399) + goto overflow; + + sec= (uint) ((ulonglong) seconds % 3600); + ltime->hour= (uint) (seconds/3600); + ltime->minute= sec/60; + ltime->second= sec % 60; + + return 0; + +overflow: + ltime->hour= TIME_MAX_HOUR; + ltime->minute= TIME_MAX_MINUTE; + ltime->second= TIME_MAX_SECOND; + + char buf[22]; + int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10) + - buf); + make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME, + NullS); + + return 1; +} + + +/* Date formats corresponding to compound %r and %T conversion specifiers Note: We should init at least first element of "positions" array @@ -1546,8 +1665,6 @@ int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions) String *Item_func_sec_to_time::val_str(String *str) { DBUG_ASSERT(fixed == 1); - longlong seconds=(longlong) args[0]->val_int(); - uint sec; TIME ltime; if ((null_value=args[0]->null_value) || str->alloc(19)) @@ -1556,19 +1673,8 @@ String *Item_func_sec_to_time::val_str(String *str) return (String*) 0; } - ltime.neg= 0; - if (seconds < 0) - { - seconds= -seconds; - ltime.neg= 1; - } - - sec= (uint) ((ulonglong) seconds % 3600); - ltime.day= 0; - ltime.hour= (uint) (seconds/3600); - ltime.minute= sec/60; - ltime.second= sec % 60; - + sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; } @@ -1577,16 +1683,15 @@ String *Item_func_sec_to_time::val_str(String *str) longlong Item_func_sec_to_time::val_int() { DBUG_ASSERT(fixed == 1); - longlong seconds=args[0]->val_int(); - longlong sign=1; + TIME ltime; + if ((null_value=args[0]->null_value)) return 0; - if (seconds < 0) - { - seconds= -seconds; - sign= -1; - } - return sign*((seconds / 3600)*10000+((seconds/60) % 60)*100+ (seconds % 60)); + + sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + + return (ltime.neg ? -1 : 1) * + ((ltime.hour)*10000 + ltime.minute*100 + ltime.second); } @@ -2575,7 +2680,9 @@ String *Item_func_add_time::val_str(String *str) } if (l_time1.neg != l_time2.neg) l_sign= -l_sign; - + + bzero((char *)&l_time3, sizeof(l_time3)); + l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign, &seconds, µseconds); @@ -2604,9 +2711,9 @@ String *Item_func_add_time::val_str(String *str) } l_time3.hour+= days*24; - if (!make_datetime(l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY, - &l_time3, str)) + if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2661,6 +2768,8 @@ String *Item_func_timediff::val_str(String *str) if (l_time1.neg != l_time2.neg) l_sign= -l_sign; + bzero((char *)&l_time3, sizeof(l_time3)); + l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign, &seconds, µseconds); @@ -2674,9 +2783,9 @@ String *Item_func_timediff::val_str(String *str) calc_time_from_sec(&l_time3, (long) seconds, microseconds); - if (!make_datetime(l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY, - &l_time3, str)) + if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2694,29 +2803,58 @@ String *Item_func_maketime::val_str(String *str) { DBUG_ASSERT(fixed == 1); TIME ltime; + bool overflow= 0; - long hour= (long) args[0]->val_int(); - long minute= (long) args[1]->val_int(); - long second= (long) args[2]->val_int(); + longlong hour= args[0]->val_int(); + longlong minute= args[1]->val_int(); + longlong second= args[2]->val_int(); if ((null_value=(args[0]->null_value || - args[1]->null_value || - args[2]->null_value || - minute > 59 || minute < 0 || - second > 59 || second < 0 || - str->alloc(19)))) + args[1]->null_value || + args[2]->null_value || + minute < 0 || minute > 59 || + second < 0 || second > 59 || + str->alloc(19)))) return 0; + bzero((char *)<ime, sizeof(ltime)); ltime.neg= 0; + + /* Check for integer overflows */ if (hour < 0) { - ltime.neg= 1; - hour= -hour; + if (args[0]->unsigned_flag) + overflow= 1; + else + ltime.neg= 1; + } + if (-hour > UINT_MAX || hour > UINT_MAX) + overflow= 1; + + if (!overflow) + { + ltime.hour= (uint) ((hour < 0 ? -hour : hour)); + ltime.minute= (uint) minute; + ltime.second= (uint) second; + } + else + { + ltime.hour= TIME_MAX_HOUR; + ltime.minute= TIME_MAX_MINUTE; + ltime.second= TIME_MAX_SECOND; + char buf[28]; + char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10); + int len = (int)(ptr - buf) + + my_sprintf(ptr, (ptr, ":%02u:%02u", (uint)minute, (uint)second)); + make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME, + NullS); + } + + if (make_time_with_warn((DATE_TIME_FORMAT *) 0, <ime, str)) + { + null_value= 1; + return 0; } - ltime.hour= (ulong) hour; - ltime.minute= (ulong) minute; - ltime.second= (ulong) second; - make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; } @@ -3060,7 +3198,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) goto null_date; null_value= 0; - bzero((char*) ltime, sizeof(ltime)); + bzero((char*) ltime, sizeof(*ltime)); date_time_format.format.str= (char*) format->ptr(); date_time_format.format.length= format->length(); if (extract_date_time(&date_time_format, val->ptr(), val->length(), diff --git a/sql/time.cc b/sql/time.cc index 467dbc684a5..25a1995dd01 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -289,9 +289,9 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *in_dst_time_gap) bool str_to_time_with_warn(const char *str, uint length, TIME *l_time) { - int was_cut; - bool ret_val= str_to_time(str, length, l_time, &was_cut); - if (was_cut) + int warning; + bool ret_val= str_to_time(str, length, l_time, &warning); + if (ret_val || warning) make_truncated_value_warning(current_thd, str, length, MYSQL_TIMESTAMP_TIME, NullS); return ret_val; |