List:Commits« Previous MessageNext Message »
From:Gleb Shchepa Date:December 12 2008 11:22am
Subject:bzr push into mysql-5.0-bugteam branch (gshchepa:2746 to 2747)
Bug#40761
View as plain text  
 2747 Gleb Shchepa	2008-12-12
      rollback of bug #40761 fix
modified:
  mysql-test/r/func_if.result
  mysql-test/t/func_if.test
  sql/item_cmpfunc.cc
  sql/item_cmpfunc.h
  sql/item_func.cc
  sql/item_func.h

 2746 Gleb Shchepa	2008-12-12
      Bug #40761: Assert on sum function on
                  IF(..., CAST(longtext AS UNSIGNED), signed_val)
                  (was: LEFT JOIN on inline view crashes server)
      
      Select from a LONGTEXT column wrapped with an expression
      like "IF(..., CAST(longtext_column AS UNSIGNED), smth_signed)"
      failed an assertion or crashed the server. IFNULL function was
      affected too.
      
      LONGTEXT column item has a maximum length of 32^2-1 bytes,
      at the same time this is a maximum possible length of any
      MySQL item. CAST(longtext_column AS UNSIGNED) returns some
      unsigned numeric result of length 32^2-1, so the result of
      IF/IFNULL function of this number and some other signed number
      will have text length of (32^2-1)+1=32^2 (one byte for the
      minus sign) - there is integer overflow, and the length is
      equal to zero. That caused assert/crash.
      
      The bug has been fixed by the same solution as in the CASE
      function implementation.
modified:
  mysql-test/r/func_if.result
  mysql-test/t/func_if.test
  sql/item_cmpfunc.cc
  sql/item_cmpfunc.h
  sql/item_func.cc
  sql/item_func.h

=== modified file 'mysql-test/r/func_if.result'
--- a/mysql-test/r/func_if.result	2008-12-11 20:57:32 +0000
+++ b/mysql-test/r/func_if.result	2008-12-12 10:59:10 +0000
@@ -176,13 +176,4 @@ IF((ROUND(t1.a,2)=1), 2,
 IF((ROUND(t1.a,2)=1), 2,
 IF((R
 DROP TABLE t1;
-CREATE TABLE t1 (c LONGTEXT);
-INSERT INTO t1 VALUES(1), (2), (3), (4), ('12345678901234567890');
-SELECT * FROM (SELECT MAX(IF(1, CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
-MAX(IF(1, CAST(c AS UNSIGNED), 0))
-12345678901234567890
-SELECT * FROM (SELECT MAX(IFNULL(CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
-MAX(IFNULL(CAST(c AS UNSIGNED), 0))
-12345678901234567890
-DROP TABLE t1;
 End of 5.0 tests

=== modified file 'mysql-test/t/func_if.test'
--- a/mysql-test/t/func_if.test	2008-12-11 20:57:32 +0000
+++ b/mysql-test/t/func_if.test	2008-12-12 10:59:10 +0000
@@ -150,17 +150,4 @@ FROM t1;
 
 DROP TABLE t1;
 
-#
-# Bug #40761: Assert on sum func on IF(..., CAST(longtext AS UNSIGNED), signed)
-#             (was: LEFT JOIN on inline view crashes server)
-#
-
-CREATE TABLE t1 (c LONGTEXT);
-INSERT INTO t1 VALUES(1), (2), (3), (4), ('12345678901234567890');
-
-SELECT * FROM (SELECT MAX(IF(1, CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
-SELECT * FROM (SELECT MAX(IFNULL(CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
-
-DROP TABLE t1;
-
 --echo End of 5.0 tests

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2008-12-11 20:57:32 +0000
+++ b/sql/item_cmpfunc.cc	2008-12-12 10:59:10 +0000
@@ -2069,23 +2069,21 @@ Item_func_ifnull::fix_length_and_dec()
 {
   agg_result_type(&hybrid_type, args, 2);
   maybe_null=args[1]->maybe_null;
+  decimals= max(args[0]->decimals, args[1]->decimals);
+  unsigned_flag= args[0]->unsigned_flag && args[1]->unsigned_flag;
 
   if (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT) 
   {
-    max_length= 0;
-    decimals= 0;
-    unsigned_flag= TRUE;
-    agg_num_lengths(args[0]);
-    agg_num_lengths(args[1]);
-    max_length= my_decimal_precision_to_length(max_length + decimals, decimals,
-                                               unsigned_flag);
+    int len0= args[0]->max_length - args[0]->decimals
+      - (args[0]->unsigned_flag ? 0 : 1);
+
+    int len1= args[1]->max_length - args[1]->decimals
+      - (args[1]->unsigned_flag ? 0 : 1);
+
+    max_length= max(len0, len1) + decimals + (unsigned_flag ? 0 : 1);
   }
   else
-  {
     max_length= max(args[0]->max_length, args[1]->max_length);
-    decimals= max(args[0]->decimals, args[1]->decimals);
-    unsigned_flag=args[0]->unsigned_flag && args[1]->unsigned_flag;
-  }
 
   switch (hybrid_type) {
   case STRING_RESULT:
@@ -2240,6 +2238,8 @@ void
 Item_func_if::fix_length_and_dec()
 {
   maybe_null=args[1]->maybe_null || args[2]->maybe_null;
+  decimals= max(args[1]->decimals, args[2]->decimals);
+  unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
 
   enum Item_result arg1_type=args[1]->result_type();
   enum Item_result arg2_type=args[2]->result_type();
@@ -2276,20 +2276,16 @@ Item_func_if::fix_length_and_dec()
   if ((cached_result_type == DECIMAL_RESULT )
       || (cached_result_type == INT_RESULT))
   {
-    max_length= 0;
-    decimals= 0;
-    unsigned_flag= TRUE;
-    agg_num_lengths(args[1]);
-    agg_num_lengths(args[2]);
-    max_length= my_decimal_precision_to_length(max_length + decimals, decimals,
-                                               unsigned_flag);
+    int len1= args[1]->max_length - args[1]->decimals
+      - (args[1]->unsigned_flag ? 0 : 1);
+
+    int len2= args[2]->max_length - args[2]->decimals
+      - (args[2]->unsigned_flag ? 0 : 1);
+
+    max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
   }
   else
-  {
     max_length= max(args[1]->max_length, args[2]->max_length);
-    decimals= max(args[1]->decimals, args[2]->decimals);
-    unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
-  }
 }
 
 
@@ -2637,6 +2633,16 @@ void Item_func_case::agg_str_lengths(Ite
 }
 
 
+void Item_func_case::agg_num_lengths(Item *arg)
+{
+  uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals,
+                                           arg->unsigned_flag) - arg->decimals;
+  set_if_bigger(max_length, len); 
+  set_if_bigger(decimals, arg->decimals);
+  unsigned_flag= unsigned_flag && arg->unsigned_flag; 
+}
+
+
 void Item_func_case::fix_length_and_dec()
 {
   Item **agg;

=== modified file 'sql/item_cmpfunc.h'
--- a/sql/item_cmpfunc.h	2008-12-11 20:57:32 +0000
+++ b/sql/item_cmpfunc.h	2008-12-12 10:59:10 +0000
@@ -759,6 +759,7 @@ public:
   Item *find_item(String *str);
   CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
   void agg_str_lengths(Item *arg);
+  void agg_num_lengths(Item *arg);
 };
 
 

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2008-12-11 20:57:32 +0000
+++ b/sql/item_func.cc	2008-12-12 10:59:10 +0000
@@ -5668,13 +5668,3 @@ void Item_func_sp::update_used_tables()
     const_item_cache= FALSE;
   }
 }
-
-
-void Item_func::agg_num_lengths(Item *arg)
-{
-  uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals,
-                                           arg->unsigned_flag) - arg->decimals;
-  set_if_bigger(max_length, len); 
-  set_if_bigger(decimals, arg->decimals);
-  unsigned_flag= unsigned_flag && arg->unsigned_flag; 
-}

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2008-12-11 20:57:32 +0000
+++ b/sql/item_func.h	2008-12-12 10:59:10 +0000
@@ -193,8 +193,6 @@ public:
                      void * arg, traverse_order order);
   bool is_expensive_processor(byte *arg);
   virtual bool is_expensive() { return 0; }
-protected:
-  void agg_num_lengths(Item *arg);
 };
 
 

Thread
bzr push into mysql-5.0-bugteam branch (gshchepa:2746 to 2747)Bug#40761Gleb Shchepa12 Dec