From: Date: July 4 2009 6:05am Subject: bzr commit into mysql-5.1-bugteam branch (davi:2994) Bug#45261 List-Archive: http://lists.mysql.com/commits/77958 X-Bug: 45261 Message-Id: <20090704040543.74904492043@skynet> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Boundary_(ID_55YIG8LGFxRIKZu4QusR2A)" --Boundary_(ID_55YIG8LGFxRIKZu4QusR2A) MIME-version: 1.0 Content-type: text/plain; CHARSET=US-ASCII Content-transfer-encoding: 7BIT Content-disposition: inline # At a local mysql-5.1-bugteam repository of davi 2994 Davi Arnaut 2009-07-04 Bug#45261: Crash, stored procedure + decimal The problem was that creating a DECIMAL column from decimal value could lead to a assertion as decimal values can have a higher precision than those attached to a table. The assert could be triggered by creating a table from a decimal with a large (> 30) scale. The solution is to ensure that truncation procedure is executed when deducing a DECIMAL column from a decimal value of higher precision. If the integer part is equal to or bigger than the maximum precision for the DECIMAL type (65), the integer part is truncated to fit and the fractional becomes zero. Otherwise, the fractional part is truncated to fit into the space left after the integer part is copied. This patch borrows code and ideas from Martin Hansson's patch. @ mysql-test/r/type_newdecimal.result Add test case result for Bug#45261 @ mysql-test/t/type_newdecimal.test Add test case for Bug#45261 @ sql/field.cc Added DBUG_ASSERT to ensure object's invariant is maintained. @ sql/field.h Explain member variable. @ sql/sql_select.cc Implement new truncation procedure. 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-04 04:05:37 +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,144 @@ Error 1264 Out of range value for column select cast(98.6 as decimal(2,0)); cast(98.6 as decimal(2,0)) 99 +# +# Bug#45261: Crash, stored procedure + decimal +# +CREATE TABLE t1 SELECT +/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 +AS c1; +Warnings: +Error 1292 Truncated incorrect DECIMAL value: '' +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ +AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,25) NO 0.0000000000000000000000000 +SELECT * FROM t1; +c1 +1000000000000000000000000000000000000001.1000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ +AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(31,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +1.100000000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ +AS c1; +DESC t1; +Field Type Null Key Default Extra +c1 decimal(31,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +1.100000000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ +AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(30,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +0.100000000000000000000000000000 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ +AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,20) NO 0.00000000000000000000 +SELECT * FROM t1; +c1 +123456789012345678901234567890123456789012345.12345678901234567890 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ +AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +12345678901234567890123456789012345678901234567890123456789012345 +DROP TABLE t1; +CREATE TABLE t1 SELECT +/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ +AS c1; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(65,0) NO 0 +SELECT * FROM t1; +c1 +99999999999999999999999999999999999999999999999999999999999999999 +DROP TABLE t1; +CREATE TABLE t1 SELECT +.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ +AS c1; +Warnings: +Note 1265 Data truncated for column 'c1' at row 1 +DESC t1; +Field Type Null Key Default Extra +c1 decimal(30,30) NO 0.000000000000000000000000000000 +SELECT * FROM t1; +c1 +0.123456789012345678901234567890 +DROP TABLE t1; === 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-04 04:05:37 +0000 @@ -1257,3 +1257,91 @@ 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)); + +--echo # +--echo # Bug#45261: Crash, stored procedure + decimal +--echo # + +CREATE TABLE t1 SELECT + /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + .100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + /* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 SELECT + .123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ + AS c1; +DESC t1; +SELECT * FROM t1; +DROP TABLE t1; === modified file 'sql/field.cc' --- a/sql/field.cc 2009-06-09 16:44:26 +0000 +++ b/sql/field.cc 2009-07-04 04:05:37 +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-04 04:05:37 +0000 @@ -608,6 +608,10 @@ 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-26 19:57:42 +0000 +++ b/sql/sql_select.cc 2009-07-04 04:05:37 +0000 @@ -9368,40 +9368,79 @@ static Field *create_tmp_field_from_item break; case DECIMAL_RESULT: { - uint8 dec= item->decimals; - uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; - uint32 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. - */ + The MySQL DECIMAL data type has a characteristic that needs to be + taken into account when deducing the type from a Item_decimal. - if (dec > 0) - { - signed int overflow; + But first, let's briefly recap what is the new MySQL DECIMAL type: - dec= min(dec, DECIMAL_MAX_SCALE); + The declaration syntax for a decimal is DECIMAL(M,D), where: - /* - 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 - */ + * M is the maximum number of digits (the precision). + It has a range of 1 to 65. + * D is the number of digits to the right of the decimal separator (the scale). + It has a range of 0 to 30 and must be no larger than M. - overflow= my_decimal_precision_to_length(intg + dec, dec, - item->unsigned_flag) - len; + D and M are used to determine the storage requirements for the integer + and fractional parts of each value. The integer part is to the left of + the decimal separator and to the right is the fractional part. Hence: - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - len -= item->decimals - dec; // corrected value fits + M is the number of digits for the integer and fractional part. + D is the number of digits for the fractional part. + + Consequently, M - D is the number of digits for the integer part. For + example, a DECIMAL(20,10) column has ten digits on either side of the + decimal separator. + + The characteristic that needs to be taken into account is that the + backing type for Item_decimal is a my_decimal that has a higher precision + (DECIMAL_MAX_POSSIBLE_PRECISION, see my_decimal.h) than DECIMAL. + + Drawing a comparison between my_decimal and DECIMAL: + + * M has a range of 1 to 81. + * D has a range of 0 to 72. + + The difference in range is that the fractional part must always be on + on a group boundary, leaving one group for the integer part. Since each + group is 9 (DIG_PER_DEC1) digits and there are 9 (DECIMAL_BUFF_LENGTH) + groups, the fractional part is limited to 72 digits. + + Although the backing type for a DECIMAL is also my_decimal, every time + a my_decimal is stored in a DECIMAL field, the precision and scale are + explicitly capped at 65 (DECIMAL_MAX_PRECISION) and 30 (DECIMAL_MAX_SCALE) + digits, following my_decimal truncation procedure (FIX_INTG_FRAC_ERROR). + */ + + uint8 scale= item->decimals; + uint8 precision= ((Item_decimal *) item)->decimal_precision(); + + /* + Employ a procedure along the lines of the my_decimal truncation process: + - If the integer part is equal to or bigger than the maximum precision: + Truncate integer part to fit and the fractional becomes zero. + - Otherwise: + Truncate fractional part to fit. + */ + + uint intg= precision - scale; + + if (intg >= DECIMAL_MAX_PRECISION) + { + intg= DECIMAL_MAX_PRECISION; + scale= 0; + } + else + { + uint room= min(DECIMAL_MAX_PRECISION - intg, DECIMAL_MAX_SCALE); + if (scale > room) + scale= room; } - new_field= new Field_new_decimal(len, maybe_null, item->name, - dec, item->unsigned_flag); + uint len= my_decimal_precision_to_length(intg + scale, scale, + item->unsigned_flag); + new_field= new Field_new_decimal(len, maybe_null, item->name, scale, + item->unsigned_flag); break; } case ROW_RESULT: --Boundary_(ID_55YIG8LGFxRIKZu4QusR2A) MIME-version: 1.0 Content-type: text/bzr-bundle; CHARSET=US-ASCII; name="bzr/davi.arnaut@stripped" Content-transfer-encoding: 7BIT Content-disposition: inline; filename="bzr/davi.arnaut@stripped" # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: davi.arnaut@stripped # target_branch: file:///home/davi/bzr/work/45261-5.1/ # testament_sha1: 2bf5ba8551bc697495d851baa37ffe08a9f914b4 # timestamp: 2009-07-04 01:05:43 -0300 # base_revision_id: joro@stripped # # Begin bundle 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 --Boundary_(ID_55YIG8LGFxRIKZu4QusR2A)--