List:Commits« Previous MessageNext Message »
From:Evgeny Potemkin Date:November 4 2010 1:18pm
Subject:bzr commit into mysql-5.5-bugteam branch (epotemkin:3098) Bug#57278
View as plain text  
#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(), &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_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#57278Evgeny Potemkin4 Nov