summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/type_date.result8
-rw-r--r--mysql-test/t/type_date.test8
-rw-r--r--sql-common/my_time.c7
-rw-r--r--sql/item.cc19
-rw-r--r--sql/item.h2
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(), &ltime, TIME_FUZZY_DATE, &was_cut);
+ res= number_to_datetime(int_value, &ltime, TIME_FUZZY_DATE, &was_cut);
if (res == -1)
return NULL;
}
str_value.length(my_TIME_to_str(&ltime,
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);