← Back to team overview

maria-developers team mailing list archive

MDEV-5450 Assertion ... mysql_type_to_time_type(cached_field_type) == ltime.time_type' fails ...

 

Hi Sergei,

Please review a patch for mdev-5450.

Thanks.
=== modified file 'mysql-test/r/func_time.result'
--- mysql-test/r/func_time.result	2013-12-19 08:39:40 +0000
+++ mysql-test/r/func_time.result	2014-01-31 12:58:42 +0000
@@ -2382,3 +2382,60 @@ Catalog	Database	Table	Table_alias	Colum
 def					DATE_ADD('2011-01-02 12:13:14', INTERVAL 1 MINUTE)	254	19	19	Y	0	0	8
 DATE_ADD('2011-01-02 12:13:14', INTERVAL 1 MINUTE)
 2011-01-02 12:14:14
+#
+# MDEV-5450 Assertion `cached_field_ type == MYSQL_TYPE_STRING || ltime.time_type == MYSQL_TIMESTAMP_NONE || mysql_type_to_time_type(cached_field_type) == ltime.time_type' fails with IF, ISNULL, ADDDATE
+#
+CREATE TABLE t1 (a DATETIME, b DATE);
+INSERT INTO t1 VALUES (NULL, '2012-12-21');
+SELECT IF(1,ADDDATE(IFNULL(a,b),0),1) FROM t1;
+IF(1,ADDDATE(IFNULL(a,b),0),1)
+2012-12-21 00:00:00
+SELECT CAST(ADDDATE(IFNULL(a,b),0) AS CHAR) FROM t1;
+CAST(ADDDATE(IFNULL(a,b),0) AS CHAR)
+2012-12-21 00:00:00
+SELECT CAST(ADDDATE(COALESCE(a,b),0) AS CHAR) FROM t1;
+CAST(ADDDATE(COALESCE(a,b),0) AS CHAR)
+2012-12-21 00:00:00
+SELECT CAST(ADDDATE(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+CAST(ADDDATE(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR)
+2012-12-21 00:00:00
+SELECT IF(1,ADDTIME(IFNULL(a,b),0),1) FROM t1;
+IF(1,ADDTIME(IFNULL(a,b),0),1)
+2012-12-21 00:00:00
+SELECT CAST(ADDTIME(IFNULL(a,b),0) AS CHAR) FROM t1;
+CAST(ADDTIME(IFNULL(a,b),0) AS CHAR)
+2012-12-21 00:00:00
+SELECT CAST(ADDTIME(COALESCE(a,b),0) AS CHAR) FROM t1;
+CAST(ADDTIME(COALESCE(a,b),0) AS CHAR)
+2012-12-21 00:00:00
+SELECT CAST(ADDTIME(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+CAST(ADDTIME(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR)
+2012-12-21 00:00:00
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME, b TIME);
+INSERT INTO t1 VALUES (NULL, '00:20:12');
+SELECT IF(1,ADDDATE(IFNULL(a,b),0),1) FROM t1;
+IF(1,ADDDATE(IFNULL(a,b),0),1)
+0000-00-00 00:20:12
+SELECT CAST(ADDDATE(IFNULL(a,b),0) AS CHAR) FROM t1;
+CAST(ADDDATE(IFNULL(a,b),0) AS CHAR)
+0000-00-00 00:20:12
+SELECT CAST(ADDDATE(COALESCE(a,b),0) AS CHAR) FROM t1;
+CAST(ADDDATE(COALESCE(a,b),0) AS CHAR)
+0000-00-00 00:20:12
+SELECT CAST(ADDDATE(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+CAST(ADDDATE(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR)
+0000-00-00 00:20:12
+SELECT IF(1,ADDTIME(IFNULL(a,b),0),1) FROM t1;
+IF(1,ADDTIME(IFNULL(a,b),0),1)
+NULL
+SELECT CAST(ADDTIME(IFNULL(a,b),0) AS CHAR) FROM t1;
+CAST(ADDTIME(IFNULL(a,b),0) AS CHAR)
+NULL
+SELECT CAST(ADDTIME(COALESCE(a,b),0) AS CHAR) FROM t1;
+CAST(ADDTIME(COALESCE(a,b),0) AS CHAR)
+NULL
+SELECT CAST(ADDTIME(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+CAST(ADDTIME(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR)
+NULL
+DROP TABLE t1;

=== modified file 'mysql-test/t/func_time.test'
--- mysql-test/t/func_time.test	2013-12-19 08:39:40 +0000
+++ mysql-test/t/func_time.test	2014-01-31 12:55:44 +0000
@@ -1457,3 +1457,31 @@ SELECT EXTRACT(DAY FROM TIME('1 02:00:00
 --enable_metadata
 SELECT DATE_ADD('2011-01-02 12:13:14', INTERVAL 1 MINUTE);
 --disable_metadata
+
+--echo #
+--echo # MDEV-5450 Assertion `cached_field_ type == MYSQL_TYPE_STRING || ltime.time_type == MYSQL_TIMESTAMP_NONE || mysql_type_to_time_type(cached_field_type) == ltime.time_type' fails with IF, ISNULL, ADDDATE
+--echo #
+
+CREATE TABLE t1 (a DATETIME, b DATE);
+INSERT INTO t1 VALUES (NULL, '2012-12-21');
+SELECT IF(1,ADDDATE(IFNULL(a,b),0),1) FROM t1;
+SELECT CAST(ADDDATE(IFNULL(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDDATE(COALESCE(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDDATE(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+SELECT IF(1,ADDTIME(IFNULL(a,b),0),1) FROM t1;
+SELECT CAST(ADDTIME(IFNULL(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDTIME(COALESCE(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDTIME(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DATETIME, b TIME);
+INSERT INTO t1 VALUES (NULL, '00:20:12');
+SELECT IF(1,ADDDATE(IFNULL(a,b),0),1) FROM t1;
+SELECT CAST(ADDDATE(IFNULL(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDDATE(COALESCE(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDDATE(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+SELECT IF(1,ADDTIME(IFNULL(a,b),0),1) FROM t1;
+SELECT CAST(ADDTIME(IFNULL(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDTIME(COALESCE(a,b),0) AS CHAR) FROM t1;
+SELECT CAST(ADDTIME(CASE WHEN 0 THEN a ELSE b END,0) AS CHAR) FROM t1;
+DROP TABLE t1;

=== modified file 'sql/item_timefunc.cc'
--- sql/item_timefunc.cc	2013-12-16 12:02:21 +0000
+++ sql/item_timefunc.cc	2014-01-31 12:35:17 +0000
@@ -1480,12 +1480,42 @@ String *Item_temporal_func::val_str(Stri
 }
 
 
+bool Item_temporal_hybrid_func::fix_temporal_type(MYSQL_TIME *ltime)
+{
+  if (ltime->time_type < 0) /* MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_ERROR */
+    return false;
+  switch (field_type())
+  {
+  case MYSQL_TYPE_TIME:
+    ltime->year= ltime->month= ltime->day= 0;
+    ltime->time_type= MYSQL_TIMESTAMP_TIME;
+    return false;
+  case MYSQL_TYPE_DATETIME:
+  case MYSQL_TYPE_TIMESTAMP:
+    ltime->neg= 0;
+    ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
+    return false;
+  case MYSQL_TYPE_DATE:
+    ltime->neg= 0;
+    ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
+    ltime->time_type= MYSQL_TIMESTAMP_DATE;
+    return false;
+  case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
+    return false;
+  default:
+    DBUG_ASSERT(0);
+    return true;
+  }
+  return false;
+}
+
+
 String *Item_temporal_hybrid_func::val_str_ascii(String *str)
 {
   DBUG_ASSERT(fixed == 1);
   MYSQL_TIME ltime;
 
-  if (get_date(&ltime, 0) ||
+  if (get_date(&ltime, 0) || fix_temporal_type(&ltime) ||
       (null_value= my_TIME_to_str(&ltime, str, decimals)))
     return (String *) 0;
 
@@ -2599,16 +2629,18 @@ bool Item_func_add_time::get_date(MYSQL_
   longlong seconds;
   int l_sign= sign, was_cut= 0;
 
-  if (is_date)                        // TIMESTAMP function
+  if (cached_field_type == MYSQL_TYPE_DATETIME)
   {
+    // TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP
     if (get_arg0_date(&l_time1, 0) || 
         args[1]->get_time(&l_time2) ||
         l_time1.time_type == MYSQL_TIMESTAMP_TIME || 
         l_time2.time_type != MYSQL_TIMESTAMP_TIME)
       return (null_value= 1);
   }
-  else                                // ADDTIME function
+  else
   {
+    // ADDTIME function AND the first argument is TIME
     if (args[0]->get_time(&l_time1) || 
         args[1]->get_time(&l_time2) ||
         l_time2.time_type == MYSQL_TIMESTAMP_DATETIME)

=== modified file 'sql/item_timefunc.h'
--- sql/item_timefunc.h	2013-12-16 12:02:21 +0000
+++ sql/item_timefunc.h	2014-01-31 12:13:19 +0000
@@ -542,6 +542,11 @@ class Item_temporal_hybrid_func: public
            collation.collation : &my_charset_bin;
   }
   /**
+    Fix the returned timestamp to match field_type(),
+    which is important for val_str().
+  */
+  bool fix_temporal_type(MYSQL_TIME *ltime);
+  /**
     Return string value in ASCII character set.
   */
   String *val_str_ascii(String *str);


Follow ups