List:Commits« Previous MessageNext Message »
From:Tatjana A Nuernberg Date:November 17 2007 7:05pm
Subject:bk commit into 5.0 tree (tnurnberg:1.2530) BUG#24907
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of tnurnberg. When tnurnberg does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-11-17 19:05:31+01:00, tnurnberg@stripped +3 -0
  Bug#24907: unpredictable (display) precission, if input precission increases
  
  Server failed in assert() when we tried to create a DECIMAL() temp field
  with a scale of more than the allowed 30. Now we limit the scale to the
  allowed maximum. A truncation warning is thrown as necessary.

  mysql-test/r/type_newdecimal.result@stripped, 2007-11-17 19:05:29+01:00, tnurnberg@stripped
+20 -0
    Show that out of range DECIMAL temp fields will no longer
    stop the server with an assert. 

  mysql-test/t/type_newdecimal.test@stripped, 2007-11-17 19:05:29+01:00, tnurnberg@stripped
+20 -1
    Show that out of range DECIMAL temp fields will no longer
    stop the server with an assert. 

  sql/sql_select.cc@stripped, 2007-11-17 19:05:29+01:00, tnurnberg@stripped +36 -2
    When creating DECIMAL() temp field, ascertain we stay within allowed
    limits. If not, truncate and warn.

diff -Nrup a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
--- a/mysql-test/r/type_newdecimal.result	2007-07-08 00:45:20 +02:00
+++ b/mysql-test/r/type_newdecimal.result	2007-11-17 19:05:29 +01:00
@@ -1499,4 +1499,24 @@ SELECT 1 FROM t1 GROUP BY @b := @a, @b;
 1
 1
 DROP TABLE t1;
+CREATE TABLE t1 SELECT 0.123456789012345678901234567890123456 AS f1;
+Warnings:
+Note	1265	Data truncated for column 'f1' at row 1
+DESC t1;
+Field	Type	Null	Key	Default	Extra
+f1	decimal(31,30)	NO		0.000000000000000000000000000000	
+SELECT f1 FROM t1;
+f1
+0.123456789012345678901234567890
+DROP TABLE t1;
+CREATE TABLE t1 SELECT
123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890
AS f1;
+Warnings:
+Warning	1264	Out of range value adjusted for column 'f1' at row 1
+DESC t1;
+Field	Type	Null	Key	Default	Extra
+f1	decimal(59,30)	NO		0.000000000000000000000000000000	
+SELECT f1 FROM t1;
+f1
+99999999999999999999999999999.999999999999999999999999999999
+DROP TABLE t1;
 End of 5.0 tests
diff -Nrup a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
--- a/mysql-test/t/type_newdecimal.test	2007-07-08 00:45:20 +02:00
+++ b/mysql-test/t/type_newdecimal.test	2007-11-17 19:05:29 +01:00
@@ -1195,6 +1195,25 @@ SELECT 1 FROM t1 GROUP BY @b := @a, @b;
 
 DROP TABLE t1;
 
---echo End of 5.0 tests
+#
+# Bug #24907: unpredictable (display) precission, if input precission
+#             increases
+#
+
+# As per 10.1.1. Overview of Numeric Types, type (new) DECIMAL has a
+# maxmimum precision of 30 places after the decimal point. Show that
+# temp field creation beyond that works and throws a truncation warning.
+# DECIMAL(37,36) should be adjusted to DECIMAL(31,30).
+CREATE TABLE t1 SELECT 0.123456789012345678901234567890123456 AS f1;
+DESC t1;
+SELECT f1 FROM t1;
+DROP TABLE t1;
 
+# too many decimal places, AND too many digits altogether (90 = 45+45).
+# should preserve integers (65 = 45+20)
+CREATE TABLE t1 SELECT
123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890
AS f1;
+DESC t1;
+SELECT f1 FROM t1;
+DROP TABLE t1;
 
+--echo End of 5.0 tests
diff -Nrup a/sql/sql_select.cc b/sql/sql_select.cc
--- a/sql/sql_select.cc	2007-09-24 11:33:23 +02:00
+++ b/sql/sql_select.cc	2007-11-17 19:05:29 +01:00
@@ -8960,9 +8960,43 @@ static Field *create_tmp_field_from_item
     new_field->set_derivation(item->collation.derivation);
     break;
   case DECIMAL_RESULT:
-    new_field= new Field_new_decimal(item->max_length, maybe_null, item->name,
-                                     table, item->decimals, item->unsigned_flag);
+  {
+    uint8 dec= item->decimals;
+    uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec;
+    uint8 len= item->max_length;
+
+    /*
+      Trying to put too many digits overall in a DECIMAL(prec,dec)
+      will always throw a warning. We must limit dec to
+      DECIMAL_MAX_SCALE however to prevent an assert() later.
+    */
+
+    if (dec > 0)
+    {
+      signed int overflow;
+
+      dec= min(dec, DECIMAL_MAX_SCALE);
+
+      /*
+        If the value still overflows the field with the corrected dec,
+        we'll throw out decimals rather than integers. This is still
+        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;
+
+      if (overflow > 0)
+        dec= max(0, dec - overflow);            // too long, discard fract
+      else
+        len -= item->decimals - dec;            // corrected value fits
+    }
+
+    new_field= new Field_new_decimal(len, maybe_null, item->name,
+                                     table, dec, item->unsigned_flag);
     break;
+  }
   case ROW_RESULT:
   default:
     // This case should never be choosen
Thread
bk commit into 5.0 tree (tnurnberg:1.2530) BUG#24907Tatjana A Nuernberg17 Nov