#At file:///work/bzrroot/57278-bug-5.5-bugfixing/ based on revid:marc.alff@stripped
3098 Evgeny Potemkin 2010-11-04
Bug#57278: Crash on min/max + with date out of range.
MySQL officially supports DATE values starting from 1000-01-01. This is
enforced for int values, but not for string values, thus one
could easily insert '0001-01-01' value. Int values are checked by
number_to_datetime function and Item_cache_datetime::val_str uses it
to fill MYSQL_TIME struct out of cached int value. This leads to the
scenario where Item_cache_datetime caches a non-null datetime value and when
it tries to convert it from int to string number_to_datetime function
treats the value as out-of-range and returns an error and
Item_cache_datetime::val_str returns NULL for a non-null value. Due to this
inconsistency server crashes.
Now number_to_datetime allows DATE values below 1000-01-01 if the
TIME_FUZZY_DATE flag is set. Better NULL handling for Item_cache_datetime.
Added the Item_cache_datetime::store function to reset str_value_cached flag
when an item is stored.
@ mysql-test/r/type_date.result
Added a test case for the bug#57278.
@ mysql-test/t/type_date.test
Added a test case for the bug#57278.
@ sql-common/my_time.c
Bug#57278: Crash on min/max + with date out of range.
Now number_to_datetime allows DATE values below 1000-01-01 if the
TIME_FUZZY_DATE flag is set.
@ sql/item.cc
Bug#57278: Crash on min/max + with date out of range.
Item_cache_datetime::val_str now better handles
null_value.
modified:
mysql-test/r/type_date.result
mysql-test/t/type_date.test
sql-common/my_time.c
sql/item.cc
sql/item.h
=== modified file 'mysql-test/r/type_date.result'
--- a/mysql-test/r/type_date.result 2010-03-20 20:23:42 +0000
+++ b/mysql-test/r/type_date.result 2010-11-04 13:18:27 +0000
@@ -318,4 +318,12 @@ f1 date YES NULL
f2 date YES NULL
DROP TABLE t1;
#
+#
+# Bug#57278: Crash on min/max + with date out of range.
+#
+set @a=(select min(makedate('111','1'))) ;
+select @a;
+@a
+0111-01-01
+#
End of 6.0 tests
=== modified file 'mysql-test/t/type_date.test'
--- a/mysql-test/t/type_date.test 2010-03-20 20:23:42 +0000
+++ b/mysql-test/t/type_date.test 2010-11-04 13:18:27 +0000
@@ -284,4 +284,12 @@ DROP TABLE t1;
--echo #
+--echo #
+--echo # Bug#57278: Crash on min/max + with date out of range.
+--echo #
+set @a=(select min(makedate('111','1'))) ;
+select @a;
+--echo #
+
+
--echo End of 6.0 tests
=== modified file 'sql-common/my_time.c'
--- a/sql-common/my_time.c 2010-07-09 12:28:51 +0000
+++ b/sql-common/my_time.c 2010-11-04 13:18:27 +0000
@@ -1127,7 +1127,12 @@ longlong number_to_datetime(longlong nr,
nr= (nr+19000000L)*1000000L; /* YYMMDD, year: 1970-1999 */
goto ok;
}
- if (nr < 10000101L)
+ /*
+ Though officially we support DATE values from 1000-01-01 only, one can
+ easily insert a value like 1-1-1. So, for consistency reasons such dates
+ are allowed when TIME_FUZZY_DATE is set.
+ */
+ if (nr < 10000101L && !(flags & TIME_FUZZY_DATE))
goto err;
if (nr <= 99991231L)
{
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2010-10-08 14:06:31 +0000
+++ b/sql/item.cc 2010-11-04 13:18:27 +0000
@@ -7493,9 +7493,19 @@ void Item_cache_datetime::store(Item *it
}
+void Item_cache_datetime::store(Item *item)
+{
+ Item_cache::store(item);
+ str_value_cached= FALSE;
+}
+
String *Item_cache_datetime::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
+
+ if ((value_cached || str_value_cached) && null_value)
+ return NULL;
+
if (!str_value_cached)
{
/*
@@ -7509,6 +7519,8 @@ String *Item_cache_datetime::val_str(Str
if (value_cached)
{
MYSQL_TIME ltime;
+ /* Return NULL in case of OOM/conversion error. */
+ null_value= TRUE;
if (str_value.alloc(MAX_DATE_STRING_REP_LENGTH))
return NULL;
if (cached_field_type == MYSQL_TYPE_TIME)
@@ -7531,13 +7543,14 @@ String *Item_cache_datetime::val_str(Str
{
int was_cut;
longlong res;
- res= number_to_datetime(val_int(), <ime, TIME_FUZZY_DATE, &was_cut);
+ res= number_to_datetime(int_value, <ime, TIME_FUZZY_DATE, &was_cut);
if (res == -1)
return NULL;
}
str_value.length(my_TIME_to_str(<ime,
const_cast<char*>(str_value.ptr())));
str_value_cached= TRUE;
+ null_value= FALSE;
}
else if (!cache_value())
return NULL;
@@ -7558,7 +7571,7 @@ my_decimal *Item_cache_datetime::val_dec
double Item_cache_datetime::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value_int())
+ if ((!value_cached && !cache_value_int()) || null_value)
return 0.0;
return (double) int_value;
}
@@ -7566,7 +7579,7 @@ double Item_cache_datetime::val_real()
longlong Item_cache_datetime::val_int()
{
DBUG_ASSERT(fixed == 1);
- if (!value_cached && !cache_value_int())
+ if ((!value_cached && !cache_value_int()) || null_value)
return 0;
return int_value;
}
=== modified file 'sql/item.h'
--- a/sql/item.h 2010-08-19 11:55:35 +0000
+++ b/sql/item.h 2010-11-04 13:18:27 +0000
@@ -3451,8 +3451,8 @@ public:
cmp_context= STRING_RESULT;
}
- virtual void store(Item *item) { Item_cache::store(item); }
void store(Item *item, longlong val_arg);
+ void store(Item *item);
double val_real();
longlong val_int();
String* val_str(String *str);
Attachment: [text/bzr-bundle] bzr/epotemkin@mysql.com-20101104131827-dbhpx3mqhwg6rovr.bundle
| Thread |
|---|
| • bzr commit into mysql-5.5-bugteam branch (epotemkin:3098) Bug#57278 | Evgeny Potemkin | 4 Nov |