summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Didriksen <tor.didriksen@oracle.com>2012-03-14 13:25:14 +0100
committerTor Didriksen <tor.didriksen@oracle.com>2012-03-14 13:25:14 +0100
commitc8f4e2793dffe2b044d510baa36ce23dcddeac62 (patch)
tree89a4ce6fd8cf69097195b200cbdef6b91bd37489
parentbedf97c93aa8665cef5e8d0865eecb56ac2b4d26 (diff)
downloadmariadb-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.result9
-rw-r--r--mysql-test/t/subselect.test10
-rw-r--r--sql/item.cc27
-rw-r--r--sql/item_timefunc.cc2
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(),
+ &ltime,
+ TIME_DATETIME_ONLY,
+ &was_cut);
+ if (tt != MYSQL_TIMESTAMP_DATETIME || was_cut)
+ null_value= true;
+ else
+ my_datetime_to_str(&ltime, 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(&ltime,1))
+ if (get_arg0_date(&ltime, TIME_FUZZY_DATE))
{
null_value= 1;
return 0;