List:Commits« Previous MessageNext Message »
From:Martin Hansson Date:July 2 2009 12:15pm
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-07-02
      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 an 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 version 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-07-02 12:15:13 +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-07-02 12:15:13 +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-07-02 12:15:13 +0000
@@ -2485,6 +2485,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-07-02 12:15:13 +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-07-02 12:15:13 +0000
@@ -183,6 +183,19 @@ inline uint my_decimal_length_to_precisi
                  (unsigned_flag || !length ? 0:1));
 }
 
+inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, 
+                                                           uint8 scale,
+                                                           bool unsigned_flag)
+{
+  /*
+    When precision is 0 it means that original length was also 0. Thus
+    unsigned_flag is ignored in this case.
+  */
+  DBUG_ASSERT(precision || !scale);
+  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)
 {

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-06-07 20:40:53 +0000
+++ b/sql/sql_select.cc	2009-07-02 12:15:13 +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_no_truncation(intg + dec, dec, 
+                                                     item->unsigned_flag);
+      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-20090702121513-6kyue6c73dvh40nt.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#45261Martin Hansson2 Jul