mirror of
https://github.com/MariaDB/server.git
synced 2026-04-20 15:25:33 +02:00
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.
This commit is contained in:
parent
b431da6214
commit
368ac9f03e
5 changed files with 39 additions and 5 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1127,7 +1127,12 @@ longlong number_to_datetime(longlong nr, MYSQL_TIME *time_res,
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
19
sql/item.cc
19
sql/item.cc
|
|
@ -7493,9 +7493,19 @@ void Item_cache_datetime::store(Item *item, longlong val_arg)
|
|||
}
|
||||
|
||||
|
||||
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(String *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(String *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_decimal(my_decimal *decimal_val)
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue