List:Commits« Previous MessageNext Message »
From:Martin Hansson Date:July 3 2009 12:00pm
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-03
      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 taking into accunt the truncation during calculation, 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/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/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-03 12:00:48 +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-03 12:00:48 +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-03 12:00:48 +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-03 12:00:48 +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/sql_select.cc'
--- a/sql/sql_select.cc	2009-06-07 20:40:53 +0000
+++ b/sql/sql_select.cc	2009-07-03 12:00:48 +0000
@@ -9379,8 +9379,6 @@ static Field *create_tmp_field_from_item
 
     if (dec > 0)
     {
-      signed int overflow;
-
       dec= min(dec, DECIMAL_MAX_SCALE);
 
       /*
@@ -9390,15 +9388,19 @@ static Field *create_tmp_field_from_item
         +1: for decimal point
       */
 
-      overflow= my_decimal_precision_to_length(intg + dec, dec,
-                                               item->unsigned_flag) - len;
-
-      if (overflow > 0)
-        dec= max(0, dec - overflow);            // too long, discard fract
-      else
-        len -= item->decimals - dec;            // corrected value fits
+      /* Maximum length. Automatically truncated to avoid overflow. */
+      len= my_decimal_precision_to_length(intg + dec, dec, item->unsigned_flag);
+      DBUG_ASSERT(len <= item->max_length);
+      if (intg >= item->max_length - (item->unsigned_flag ? 0 : 1))
+        dec= 0;
+      /* Get the maximum number of decimal digits that can be stored. */
+      uint new_precision=
+        my_decimal_length_to_precision(len, dec, item->unsigned_flag);
+      uint new_scale= new_precision - min(intg, len - (item->unsigned_flag ? 0 : 1));
+      /* Throw out decimals if necessary. */
+      if (dec > new_precision - intg)
+        dec= new_precision - intg;
     }
-
     new_field= new Field_new_decimal(len, maybe_null, item->name,
                                      dec, item->unsigned_flag);
     break;


Attachment: [text/bzr-bundle] bzr/martin.hansson@sun.com-20090703120048-mruymubpbhsq5f3v.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#45261Martin Hansson3 Jul