Bug #21564557: INCONSISTENT OUTPUT FROM 5.5 AND 5.6

               UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%M"

Issue:
-----
When an invalid date is supplied to the UNIX_TIMESTAMP
function from STR_TO_DATE, no check is performed before
converting it to a timestamp value.

SOLUTION:
---------
Add the check_date function and only if it succeeds,
proceed to the timestamp conversion.

No warning will be returned for dates having zero in
month/date, since partial dates are allowed. UNIX_TIMESTAMP
will return only a zero for such values.

The problem has been handled in 5.6+ with WL#946.
parent 1ec594dd
...@@ -1672,3 +1672,34 @@ insert into t1 values ('00:00:00'),('00:01:00'); ...@@ -1672,3 +1672,34 @@ insert into t1 values ('00:00:00'),('00:01:00');
select 1 from t1 where 1 < some (select cast(a as datetime) from t1); select 1 from t1 where 1 < some (select cast(a as datetime) from t1);
1 1
drop table t1; drop table t1;
#
# Bug #21564557: INCONSISTENT OUTPUT FROM 5.5 AND 5.6
# UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%M"
#
SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m"));
UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m"))
0
SELECT UNIX_TIMESTAMP('2015-06-00');
UNIX_TIMESTAMP('2015-06-00')
0
SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s'));
UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s'))
0
set sql_mode= 'TRADITIONAL';
SELECT @@sql_mode;
@@sql_mode
STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m"));
UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m"))
NULL
Warnings:
Warning 1411 Incorrect datetime value: '201506' for function str_to_date
SELECT UNIX_TIMESTAMP('2015-06-00');
UNIX_TIMESTAMP('2015-06-00')
0
SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s'));
UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s'))
NULL
Warnings:
Warning 1411 Incorrect datetime value: '0000-00-00 10:30:30' for function str_to_date
set sql_mode= default;
...@@ -1026,3 +1026,21 @@ create table t1(a time); ...@@ -1026,3 +1026,21 @@ create table t1(a time);
insert into t1 values ('00:00:00'),('00:01:00'); insert into t1 values ('00:00:00'),('00:01:00');
select 1 from t1 where 1 < some (select cast(a as datetime) from t1); select 1 from t1 where 1 < some (select cast(a as datetime) from t1);
drop table t1; drop table t1;
--echo #
--echo # Bug #21564557: INCONSISTENT OUTPUT FROM 5.5 AND 5.6
--echo # UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%M"
--echo #
SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m"));
SELECT UNIX_TIMESTAMP('2015-06-00');
SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s'));
set sql_mode= 'TRADITIONAL';
SELECT @@sql_mode;
SELECT UNIX_TIMESTAMP(STR_TO_DATE('201506', "%Y%m"));
SELECT UNIX_TIMESTAMP('2015-06-00');
SELECT UNIX_TIMESTAMP(STR_TO_DATE('0000-00-00 10:30:30', '%Y-%m-%d %h:%i:%s'));
set sql_mode= default;
/* /*
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -1378,7 +1378,7 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp) ...@@ -1378,7 +1378,7 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
longlong Item_func_unix_timestamp::val_int() longlong Item_func_unix_timestamp::val_int()
{ {
MYSQL_TIME ltime; MYSQL_TIME ltime;
my_bool not_used; my_bool not_used= 0;
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (arg_count == 0) if (arg_count == 0)
...@@ -1390,7 +1390,7 @@ longlong Item_func_unix_timestamp::val_int() ...@@ -1390,7 +1390,7 @@ longlong Item_func_unix_timestamp::val_int()
return ((Field_timestamp*) field)->get_timestamp(&null_value); return ((Field_timestamp*) field)->get_timestamp(&null_value);
} }
if (get_arg0_date(&ltime, 0)) if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
{ {
/* /*
We have to set null_value again because get_arg0_date will also set it We have to set null_value again because get_arg0_date will also set it
...@@ -1401,6 +1401,10 @@ longlong Item_func_unix_timestamp::val_int() ...@@ -1401,6 +1401,10 @@ longlong Item_func_unix_timestamp::val_int()
return 0; return 0;
} }
int dummy= 0;
if (check_date(&ltime, non_zero_date(&ltime), TIME_NO_ZERO_IN_DATE, &dummy))
return 0;
return (longlong) TIME_to_timestamp(current_thd, &ltime, &not_used); return (longlong) TIME_to_timestamp(current_thd, &ltime, &not_used);
} }
...@@ -3482,6 +3486,7 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date) ...@@ -3482,6 +3486,7 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val; String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
fuzzy_date|= sql_mode;
val= args[0]->val_str(&val_string); val= args[0]->val_str(&val_string);
format= args[1]->val_str(&format_str); format= args[1]->val_str(&format_str);
if (args[0]->null_value || args[1]->null_value) if (args[0]->null_value || args[1]->null_value)
......
/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -91,6 +91,11 @@ inline bool parse_date_time_format(timestamp_type format_type, ...@@ -91,6 +91,11 @@ inline bool parse_date_time_format(timestamp_type format_type,
date_time_format); date_time_format);
} }
static inline bool
non_zero_date(const MYSQL_TIME *ltime)
{
return ltime->year || ltime->month || ltime->day;
}
extern DATE_TIME_FORMAT global_date_format; extern DATE_TIME_FORMAT global_date_format;
extern DATE_TIME_FORMAT global_datetime_format; extern DATE_TIME_FORMAT global_datetime_format;
......
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