List:Commits« Previous MessageNext Message »
From:Martin Hansson Date:June 29 2009 8:20am
Subject:bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#45261
View as plain text  
#At file:///data0/martin/bzr/bug45261/5.1bt-gca-commit/ based on revid:davi.arnaut@stripped

 2936 Martin Hansson	2009-06-29
      Bug#45261: Crash, stored procedure + decimal
      
      The truncation procedure for creating field for DECIMAL typed columns
      calculated overflow using a function that automatically truncated field
      length to avoid overflow, and this was caught much later than the actual
      error. 
      Fixed by creating a new function for field length calculation that does not
      truncate, and by adding and assertion in constructor for DECIMAL type
      column objects.
     @ mysql-test/r/type_newdecimal.result
        Bug#45261:
        
        - Wrong test result turned correct.
        - Test result.
     @ mysql-test/t/type_newdecimal.test
        Bug#45261: Test case.
     @ sql/field.cc
        Bug#45261: Added DBUG_ASSERT to ensure object's invariant is maintained.
     @ sql/field.h
        Bug#45261: Added comment to explain what member is for.
     @ sql/my_decimal.h
        Bug#45261: Created non-truncating overload of my_decimal_precision_to_length()
     @ sql/sql_select.cc
        Bug#45261: Fix: Using new non-truncating function.

    modified:
      mysql-test/r/type_newdecimal.result
      mysql-test/t/type_newdecimal.test
      sql/field.cc
      sql/field.h
      sql/my_decimal.h
      sql/sql_select.cc
=== modified file 'mysql-test/r/type_newdecimal.result'
--- a/mysql-test/r/type_newdecimal.result	2008-11-18 09:52:03 +0000
+++ b/mysql-test/r/type_newdecimal.result	2009-06-29 08:20:19 +0000
@@ -1521,13 +1521,13 @@ f1
 DROP TABLE t1;
 CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1;
 Warnings:
-Warning	1264	Out of range value for column 'f1' at row 1
+Note	1265	Data truncated for column 'f1' at row 1
 DESC t1;
 Field	Type	Null	Key	Default	Extra
-f1	decimal(59,30)	NO		0.000000000000000000000000000000	
+f1	decimal(65,20)	NO		0.00000000000000000000	
 SELECT f1 FROM t1;
 f1
-99999999999999999999999999999.999999999999999999999999999999
+123451234512345123451234512345123451234512345.67890678906789067891
 DROP TABLE t1;
 select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
 1.01500000 * 1.01500000 * 0.99500000);
@@ -1577,3 +1577,47 @@ Error	1264	Out of range value for column
 select cast(98.6 as decimal(2,0));
 cast(98.6 as decimal(2,0))
 99
+CREATE TABLE t1 SELECT 
+123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345
+AS a;
+Warnings:
+Note	1265	Data truncated for column 'a' at row 1
+SELECT a FROM t1;
+a
+123456789012345678901234567890123456789012345.12345678901234567890
+DESC t1;
+Field	Type	Null	Key	Default	Extra
+a	decimal(65,20)	NO		0.00000000000000000000	
+CREATE TABLE t2 SELECT 
+12345678901234567890123456789012345678901234567890123456789012345.1
+AS a;
+Warnings:
+Note	1265	Data truncated for column 'a' at row 1
+SELECT a FROM t2;
+a
+12345678901234567890123456789012345678901234567890123456789012345
+DESC t2;
+Field	Type	Null	Key	Default	Extra
+a	decimal(65,0)	NO		0	
+CREATE TABLE t3 SELECT 
+123456789012345678901234567890123456789012345678901234567890123456.1
+AS a;
+Warnings:
+Warning	1264	Out of range value for column 'a' at row 1
+SELECT a FROM t3;
+a
+99999999999999999999999999999999999999999999999999999999999999999
+DESC t3;
+Field	Type	Null	Key	Default	Extra
+a	decimal(65,0)	NO		0	
+CREATE TABLE t4 
+SELECT .123456789012345678901234567890123456789012345678901234567890123456 AS a;
+Warnings:
+Note	1265	Data truncated for column 'a' at row 1
+SELECT a FROM t4;
+a
+0.123456789012345678901234567890
+DESC t4;
+Field	Type	Null	Key	Default	Extra
+a	decimal(30,30)	NO		0.000000000000000000000000000000	
+DROP TABLE t1, t2, t3, t4;

=== modified file 'mysql-test/t/type_newdecimal.test'
--- a/mysql-test/t/type_newdecimal.test	2008-11-17 15:43:10 +0000
+++ b/mysql-test/t/type_newdecimal.test	2009-06-29 08:20:19 +0000
@@ -1257,3 +1257,31 @@ select cast(-3.4 as decimal(2,1));
 select cast(99.6 as decimal(2,0));
 select cast(-13.4 as decimal(2,1));
 select cast(98.6 as decimal(2,0));
+#
+# Bug#45261 Crash, stored procedure + decimal
+#
+
+CREATE TABLE t1 SELECT 
+123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345
+AS a;
+SELECT a FROM t1;
+DESC t1;
+
+CREATE TABLE t2 SELECT 
+12345678901234567890123456789012345678901234567890123456789012345.1
+AS a;
+SELECT a FROM t2;
+DESC t2;
+
+CREATE TABLE t3 SELECT 
+123456789012345678901234567890123456789012345678901234567890123456.1
+AS a;
+SELECT a FROM t3;
+DESC t3;
+
+CREATE TABLE t4 
+SELECT .123456789012345678901234567890123456789012345678901234567890123456 AS a;
+SELECT a FROM t4;
+DESC t4;
+
+DROP TABLE t1, t2, t3, t4;

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2009-06-09 16:44:26 +0000
+++ b/sql/field.cc	2009-06-29 08:20:19 +0000
@@ -2473,7 +2473,6 @@ Field_new_decimal::Field_new_decimal(uch
   bin_size= my_decimal_get_binary_size(precision, dec);
 }
 
-
 Field_new_decimal::Field_new_decimal(uint32 len_arg,
                                      bool maybe_null_arg,
                                      const char *name,
@@ -2485,6 +2484,7 @@ Field_new_decimal::Field_new_decimal(uin
 {
   precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
   set_if_smaller(precision, DECIMAL_MAX_PRECISION);
+  DBUG_ASSERT(precision >= dec);
   DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
               (dec <= DECIMAL_MAX_SCALE));
   bin_size= my_decimal_get_binary_size(precision, dec);

=== modified file 'sql/field.h'
--- a/sql/field.h	2009-06-09 16:44:26 +0000
+++ b/sql/field.h	2009-06-29 08:20:19 +0000
@@ -608,6 +608,11 @@ protected:
 
 class Field_num :public Field {
 public:
+
+  /**
+     The scale of the Field's value, i.e. the number of digits to the right
+     of the decimal point.
+  */
   const uint8 dec;
   bool zerofill,unsigned_flag;	// Purify cannot handle bit fields
   Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,

=== modified file 'sql/my_decimal.h'
--- a/sql/my_decimal.h	2008-05-20 07:38:17 +0000
+++ b/sql/my_decimal.h	2009-06-29 08:20:19 +0000
@@ -184,18 +184,25 @@ inline uint my_decimal_length_to_precisi
 }
 
 inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
-                                             bool unsigned_flag)
+                                             bool unsigned_flag, bool truncate)
 {
   /*
     When precision is 0 it means that original length was also 0. Thus
     unsigned_flag is ignored in this case.
   */
   DBUG_ASSERT(precision || !scale);
-  set_if_smaller(precision, DECIMAL_MAX_PRECISION);
+  if (truncate)
+    set_if_smaller(precision, DECIMAL_MAX_PRECISION);
   return (uint32)(precision + (scale>0 ? 1:0) +
                   (unsigned_flag || !precision ? 0:1));
 }
 
+inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
+                                             bool unsigned_flag)
+{
+  return my_decimal_precision_to_length(precision, scale, unsigned_flag, TRUE);
+}
+
 inline
 int my_decimal_string_length(const my_decimal *d)
 {

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-06-07 20:40:53 +0000
+++ b/sql/sql_select.cc	2009-06-29 08:20:19 +0000
@@ -9389,14 +9389,16 @@ static Field *create_tmp_field_from_item
         bad and of course throws a truncation warning.
         +1: for decimal point
       */
-
-      overflow= my_decimal_precision_to_length(intg + dec, dec,
-                                               item->unsigned_flag) - len;
+      const int required_length= 
+        my_decimal_precision_to_length(intg + dec, dec, 
+                                       item->unsigned_flag, FALSE);
+      overflow= required_length - len;
 
       if (overflow > 0)
         dec= max(0, dec - overflow);            // too long, discard fract
       else
-        len -= item->decimals - dec;            // corrected value fits
+        /* Corrected value fits. */
+        len= required_length;
     }
 
     new_field= new Field_new_decimal(len, maybe_null, item->name,


Attachment: [text/bzr-bundle] bzr/martin.hansson@sun.com-20090629082019-bldj5u24fwgvu4a2.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#45261Martin Hansson29 Jun
  • Re: bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936)Bug#45261Alexey Botchkov2 Jul