#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 14:32:53 +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 14:32:53 +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 14:32:53 +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 14:32:53 +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 14:32:53 +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,18 @@ 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);
+ if (intg >= DECIMAL_MAX_PRECISION)
+ 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_scale)
+ dec= new_scale;
}
-
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-20090703143253-6lm5gmkypf6grnrn.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#45261 | Martin Hansson | 3 Jul |