Commit 0ed3eb41 authored by unknown's avatar unknown

Fix for bug #7458 "Microseconds are gobbled from the string result of

STR_TO_DATE() function if there is another format specifier after %f 
in format string". Also small cleanup of STR_TO_DATE() implementation.
(After review version.)


mysql-test/r/date_formats.result:
  Added test for small bug in STR_TO_DATE() implementation which caused
  microseconds to be gobbled from string result of this function, if
  there was another specifier after %f in format string.
mysql-test/t/date_formats.test:
  Added test for small bug in STR_TO_DATE() implementation which caused
  microseconds to be gobbled from string result of this function, if
  there was another specifier after %f in format string.
sql/item_timefunc.cc:
  Small cleanup of str_to_date() implementation.
    Renamed check_result_type() to less ambigous get_date_time_result_type()
    and made it static. Also added handling of %X,%x,%V,%v to this function.
    Fixed small bug in it which caused microseconds to be gobbled if there
    was some other specifiers after %f.
    Cleaned up comments a bit.
parent cb6007ce
...@@ -296,6 +296,9 @@ Tuesday 52 2001 %W %V %X 00:00:00 ...@@ -296,6 +296,9 @@ Tuesday 52 2001 %W %V %X 00:00:00
15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00 15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00
15-01-20 %d-%m-%y 00:00:00 15-01-20 %d-%m-%y 00:00:00
15-2001-1 %d-%Y-%c 00:00:00 15-2001-1 %d-%Y-%c 00:00:00
select concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d'));
concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d'))
2003-01-02 08:11:02.123456
truncate table t1; truncate table t1;
insert into t1 values insert into t1 values
('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'), ('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'),
......
...@@ -166,6 +166,8 @@ select date,format,cast(str_to_date(date, format) as datetime) as datetime from ...@@ -166,6 +166,8 @@ select date,format,cast(str_to_date(date, format) as datetime) as datetime from
select date,format,DATE(str_to_date(date, format)) as date2 from t1; select date,format,DATE(str_to_date(date, format)) as date2 from t1;
select date,format,TIME(str_to_date(date, format)) as time from t1; select date,format,TIME(str_to_date(date, format)) as time from t1;
select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1; select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1;
# Test small bug in %f handling
select concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d'));
# Test wrong dates or converion specifiers # Test wrong dates or converion specifiers
......
...@@ -149,6 +149,9 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0, ...@@ -149,6 +149,9 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
conversion specifiers that can be used in such sub-patterns is limited. conversion specifiers that can be used in such sub-patterns is limited.
Also most of checks are skipped in this case. Also most of checks are skipped in this case.
If one adds new format specifiers to this function he should also
consider adding them to get_date_time_result_type() function.
RETURN RETURN
0 ok 0 ok
1 error 1 error
...@@ -2595,25 +2598,31 @@ void Item_func_get_format::print(String *str) ...@@ -2595,25 +2598,31 @@ void Item_func_get_format::print(String *str)
/* /*
check_result_type(s, l) returns DATE/TIME type Get type of datetime value (DATE/TIME/...) which will be produced
according to format string according to format string.
s: DATE/TIME format string SYNOPSIS
l: length of s get_date_time_result_type()
Result: date_time_format_types value: format - format string
DATE_TIME_MICROSECOND, DATE_TIME, length - length of format string
TIME_MICROSECOND, TIME_ONLY
NOTE
We don't process day format's characters('D', 'd', 'e') We don't process day format's characters('D', 'd', 'e') because day
because day may be a member of all date/time types. may be a member of all date/time types.
If only day format's character and no time part present
the result type is MYSQL_TYPE_DATE Format specifiers supported by this function should be in sync with
specifiers supported by extract_date_time() function.
RETURN VALUE
One of date_time_format_types values:
DATE_TIME_MICROSECOND, DATE_TIME, DATE_ONLY, TIME_MICROSECOND, TIME_ONLY
*/ */
date_time_format_types check_result_type(const char *format, uint length) static date_time_format_types
get_date_time_result_type(const char *format, uint length)
{ {
const char *time_part_frms= "HISThiklrs"; const char *time_part_frms= "HISThiklrs";
const char *date_part_frms= "MUYWabcjmuyw"; const char *date_part_frms= "MVUXYWabcjmvuxyw";
bool date_part_used= 0, time_part_used= 0, frac_second_used= 0; bool date_part_used= 0, time_part_used= 0, frac_second_used= 0;
const char *val= format; const char *val= format;
...@@ -2624,22 +2633,30 @@ date_time_format_types check_result_type(const char *format, uint length) ...@@ -2624,22 +2633,30 @@ date_time_format_types check_result_type(const char *format, uint length)
if (*val == '%' && val+1 != end) if (*val == '%' && val+1 != end)
{ {
val++; val++;
if ((frac_second_used= (*val == 'f')) || if (*val == 'f')
(!time_part_used && strchr(time_part_frms, *val))) frac_second_used= time_part_used= 1;
else if (!time_part_used && strchr(time_part_frms, *val))
time_part_used= 1; time_part_used= 1;
else if (!date_part_used && strchr(date_part_frms, *val)) else if (!date_part_used && strchr(date_part_frms, *val))
date_part_used= 1; date_part_used= 1;
if (time_part_used && date_part_used && frac_second_used) if (date_part_used && frac_second_used)
{
/*
frac_second_used implies time_part_used, and thus we already
have all types of date-time components and can end our search.
*/
return DATE_TIME_MICROSECOND; return DATE_TIME_MICROSECOND;
}
} }
} }
/* We don't have all three types of date-time components */
if (frac_second_used)
return TIME_MICROSECOND;
if (time_part_used) if (time_part_used)
{ {
if (date_part_used) if (date_part_used)
return DATE_TIME; return DATE_TIME;
if (frac_second_used)
return TIME_MICROSECOND;
return TIME_ONLY; return TIME_ONLY;
} }
return DATE_ONLY; return DATE_ONLY;
...@@ -2670,7 +2687,8 @@ void Item_func_str_to_date::fix_length_and_dec() ...@@ -2670,7 +2687,8 @@ void Item_func_str_to_date::fix_length_and_dec()
if ((const_item= args[1]->const_item())) if ((const_item= args[1]->const_item()))
{ {
format= args[1]->val_str(&format_str); format= args[1]->val_str(&format_str);
cached_format_type= check_result_type(format->ptr(), format->length()); cached_format_type= get_date_time_result_type(format->ptr(),
format->length());
switch (cached_format_type) { switch (cached_format_type) {
case DATE_ONLY: case DATE_ONLY:
cached_timestamp_type= MYSQL_TIMESTAMP_DATE; cached_timestamp_type= MYSQL_TIMESTAMP_DATE;
......
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