summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <kaa@polly.local>2006-10-12 12:36:13 +0400
committerunknown <kaa@polly.local>2006-10-12 12:36:13 +0400
commit131d8b8645f0f5628cd62f5c0b1a3457f9f63307 (patch)
tree4763f87f5b35217d4afe850ab88ba2dfc0974778
parent1f816053d2f531062c5449fc4cea71c2c41792d6 (diff)
parent45af97ad1d06f1ef66d9f4dad53b6cc255e781a2 (diff)
downloadmariadb-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.h14
-rw-r--r--mysql-test/r/func_sapdb.result15
-rw-r--r--mysql-test/r/func_time.result91
-rw-r--r--mysql-test/t/func_time.test41
-rw-r--r--sql-common/my_time.c90
-rw-r--r--sql/field.cc35
-rw-r--r--sql/item_timefunc.cc228
-rw-r--r--sql/time.cc6
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, &ltime, &error))
+ if (str_to_time(from, len, &ltime, &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, &ltime);
+
make_time((DATE_TIME_FORMAT *) 0, &ltime, 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, &ltime);
+
+ 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, &microseconds);
@@ -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, &microseconds);
@@ -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 *)&ltime, 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, &ltime, str))
+ {
+ null_value= 1;
+ return 0;
}
- ltime.hour= (ulong) hour;
- ltime.minute= (ulong) minute;
- ltime.second= (ulong) second;
- make_time((DATE_TIME_FORMAT *) 0, &ltime, 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;