diff options
-rw-r--r-- | mysql-test/r/type_date.result | 8 | ||||
-rw-r--r-- | mysql-test/t/type_date.test | 8 | ||||
-rw-r--r-- | sql-common/my_time.c | 7 | ||||
-rw-r--r-- | sql/item.cc | 19 | ||||
-rw-r--r-- | sql/item.h | 2 |
5 files changed, 39 insertions, 5 deletions
diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index bb441099b98..41345be5b8d 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -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 diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index 11f2b68804a..6dec86dacab 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -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 diff --git a/sql-common/my_time.c b/sql-common/my_time.c index ac6c2ace890..38384600fc1 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -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) { diff --git a/sql/item.cc b/sql/item.cc index b166f3e645f..7efbdf162a7 100644 --- a/sql/item.cc +++ b/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; } diff --git a/sql/item.h b/sql/item.h index 8e8199ecac8..b46f78853b7 100644 --- a/sql/item.h +++ b/sql/item.h @@ -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); |