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#24907 | Tatjana A Nuernberg | 17 Nov |