summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/type_newdecimal.result20
-rw-r--r--mysql-test/t/type_newdecimal.test21
-rw-r--r--sql/sql_select.cc38
3 files changed, 76 insertions, 3 deletions
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 75d9582a23c..b53b49bd0dd 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -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 --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index 5a631b6163e..cb7e0c4163a 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -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 --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1d11f23d854..8227d09fe85 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8960,9 +8960,43 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
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