Commit 69432395 authored by Tatiana A. Nurnberg's avatar Tatiana A. Nurnberg

Bug#42146 - DATETIME fractional seconds parse error

Bug#38435 - LONG Microseconds cause MySQL to fail a CAST to DATETIME or DATE

Parsing of optional microsecond part in datetime did not
fail gracefully when field width was larger than the allowed
six places.

Now handles up to the correct six places, and disregards
any extra digits without messing up what we've already got.

mysql-test/r/type_datetime.result:
  show graceful handling of overly long microsecond parts
  (correct truncation).
mysql-test/t/type_datetime.test:
  show graceful handling of overly long microsecond parts
  (correct truncation).
sql-common/my_time.c:
  Special case for time-parsing: for microsecond part,
  leading zeroes are actually meaningful! Also, don't
  break the entire date on more than the allowed six
  digits in microsecond part, just truncate the extra
  digits.
parent 461cad77
...@@ -619,3 +619,22 @@ ERROR 42000: Invalid default value for 'da' ...@@ -619,3 +619,22 @@ ERROR 42000: Invalid default value for 'da'
create table t1 (t time default '916:00:00 a'); create table t1 (t time default '916:00:00 a');
ERROR 42000: Invalid default value for 't' ERROR 42000: Invalid default value for 't'
set @@sql_mode= @org_mode; set @@sql_mode= @org_mode;
SELECT CAST(CAST('2006-08-10 10:11:12.0123450' AS DATETIME) AS DECIMAL(30,7));
CAST(CAST('2006-08-10 10:11:12.0123450' AS DATETIME) AS DECIMAL(30,7))
20060810101112.0123450
Warnings:
Warning 1292 Truncated incorrect datetime value: '2006-08-10 10:11:12.0123450'
SELECT CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.0123450' AS DATETIME) AS DECIMAL(30,7));
CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.0123450' AS DATETIME) AS DECIMAL(30,7))
20060810101112.0123450
Warnings:
Warning 1292 Truncated incorrect datetime value: '00000002006-000008-0000010 000010:0000011:00000012.0123450'
SELECT CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.012345' AS DATETIME) AS DECIMAL(30,7));
CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.012345' AS DATETIME) AS DECIMAL(30,7))
20060810101112.0123450
SELECT CAST(CAST('2008-07-29T10:42:51.1234567' AS DateTime) AS DECIMAL(30,7));
CAST(CAST('2008-07-29T10:42:51.1234567' AS DateTime) AS DECIMAL(30,7))
20080729104251.1234560
Warnings:
Warning 1292 Truncated incorrect datetime value: '2008-07-29T10:42:51.1234567'
End of 5.1 tests
...@@ -427,3 +427,22 @@ create table t1 (da date default '1962-03-32 23:33:34', dt datetime default '196 ...@@ -427,3 +427,22 @@ create table t1 (da date default '1962-03-32 23:33:34', dt datetime default '196
--error 1067 --error 1067
create table t1 (t time default '916:00:00 a'); create table t1 (t time default '916:00:00 a');
set @@sql_mode= @org_mode; set @@sql_mode= @org_mode;
#
# Bug #42146 - DATETIME fractional seconds parse error
#
# show we trucate microseconds from the right -- special case: leftmost is 0
SELECT CAST(CAST('2006-08-10 10:11:12.0123450' AS DATETIME) AS DECIMAL(30,7));
# show that we ignore leading zeroes for all other fields
SELECT CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.0123450' AS DATETIME) AS DECIMAL(30,7));
# once more with feeling (but no warnings)
SELECT CAST(CAST('00000002006-000008-0000010 000010:0000011:00000012.012345' AS DATETIME) AS DECIMAL(30,7));
#
# Bug #38435 - LONG Microseconds cause MySQL to fail a CAST to DATETIME or DATE
#
# show we truncate microseconds from the right
SELECT CAST(CAST('2008-07-29T10:42:51.1234567' AS DateTime) AS DECIMAL(30,7));
--echo End of 5.1 tests
...@@ -264,8 +264,19 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, ...@@ -264,8 +264,19 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
{ {
const char *start= str; const char *start= str;
ulong tmp_value= (uint) (uchar) (*str++ - '0'); ulong tmp_value= (uint) (uchar) (*str++ - '0');
/*
Internal format means no delimiters; every field has a fixed
width. Otherwise, we scan until we find a delimiter and discard
leading zeroes -- except for the microsecond part, where leading
zeroes are significant, and where we never process more than six
digits.
*/
my_bool scan_until_delim= !is_internal_format &&
((i != format_position[6]));
while (str != end && my_isdigit(&my_charset_latin1,str[0]) && while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
(!is_internal_format || --field_length)) (scan_until_delim || --field_length))
{ {
tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0'); tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0');
str++; str++;
......
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