diff options
author | Tor Didriksen <tor.didriksen@oracle.com> | 2012-03-14 13:25:14 +0100 |
---|---|---|
committer | Tor Didriksen <tor.didriksen@oracle.com> | 2012-03-14 13:25:14 +0100 |
commit | c8f4e2793dffe2b044d510baa36ce23dcddeac62 (patch) | |
tree | 89a4ce6fd8cf69097195b200cbdef6b91bd37489 | |
parent | bedf97c93aa8665cef5e8d0865eecb56ac2b4d26 (diff) | |
download | mariadb-git-c8f4e2793dffe2b044d510baa36ce23dcddeac62.tar.gz |
Bug#13721076 CRASH WITH TIME TYPE/TIMESTAMP() AND WARNINGS IN SUBQUERY
The table contains one time value: '00:00:32'
This value is converted to timestamp by a subquery.
In convert_constant_item we call (*item)->is_null()
which triggers execution of the Item_singlerow_subselect subquery,
and the string "0000-00-00 00:00:32" is cached
by Item_cache_datetime.
We continue execution and call update_null_value, which calls val_int()
on the cached item, which converts the time value to ((longlong) 32)
Then we continue to do (*item)->save_in_field()
which ends up in Item_cache_datetime::val_str() which fails,
since (32 < 101) in number_to_datetime, and val_str() returns NULL.
Item_singlerow_subselect::val_str isnt prepared for this:
if exec() succeeds, and return !null_value, then val_str()
*must* succeed.
Solution: refuse to cache strings like "0000-00-00 00:00:32"
in Item_cache_datetime::cache_value, and return NULL instead.
This is similar to the solution for
Bug#11766860 - 60085: CRASH IN ITEM::SAVE_IN_FIELD() WITH TIME DATA TYPE
This patch is for 5.5 only.
The issue is not present after WL#946, since a time value
will be converted to a proper timestamp, with the current date
rather than "0000-00-00"
-rw-r--r-- | mysql-test/r/subselect.result | 9 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 10 | ||||
-rw-r--r-- | sql/item.cc | 27 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 2 |
4 files changed, 47 insertions, 1 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 37741b79695..a2011f46ac8 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5113,3 +5113,12 @@ SELECT 1 FROM 1) FROM t1) AS e; ERROR 21000: Operand should contain 1 column(s) DROP TABLE t1; +# +# Bug#13721076 CRASH WITH TIME TYPE/TIMESTAMP() AND WARNINGS IN SUBQUERY +# +CREATE TABLE t1(a TIME NOT NULL); +INSERT INTO t1 VALUES ('00:00:32'); +SELECT 1 FROM t1 WHERE a > +(SELECT timestamp(a) AS a FROM t1); +1 +DROP TABLE t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index f3be94ebb94..088915b2590 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4067,4 +4067,14 @@ SELECT 1 FROM DROP TABLE t1; +--echo # +--echo # Bug#13721076 CRASH WITH TIME TYPE/TIMESTAMP() AND WARNINGS IN SUBQUERY +--echo # + +CREATE TABLE t1(a TIME NOT NULL); +INSERT INTO t1 VALUES ('00:00:32'); +SELECT 1 FROM t1 WHERE a > +(SELECT timestamp(a) AS a FROM t1); + +DROP TABLE t1; diff --git a/sql/item.cc b/sql/item.cc index 45ce1cac961..22b5adc4597 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7647,6 +7647,33 @@ bool Item_cache_datetime::cache_value() str_value.copy(*res); null_value= example->null_value; unsigned_flag= example->unsigned_flag; + + if (!null_value) + { + switch(field_type()) + { + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + { + MYSQL_TIME ltime; + int was_cut; + const timestamp_type tt= + str_to_datetime(str_value.charset(), + str_value.ptr(), + str_value.length(), + <ime, + TIME_DATETIME_ONLY, + &was_cut); + if (tt != MYSQL_TIMESTAMP_DATETIME || was_cut) + null_value= true; + else + my_datetime_to_str(<ime, const_cast<char*>(str_value.ptr())); + } + default: + {} + } + } + return TRUE; } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ddb00874b62..6fc85a01668 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2694,7 +2694,7 @@ longlong Item_datetime_typecast::val_int() { DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; - if (get_arg0_date(<ime,1)) + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) { null_value= 1; return 0; |