diff options
-rw-r--r-- | mysql-test/r/type_decimal.result | 8 | ||||
-rw-r--r-- | mysql-test/t/type_decimal.test | 13 | ||||
-rw-r--r-- | sql/my_decimal.cc | 43 |
3 files changed, 51 insertions, 13 deletions
diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index efac8cbe580..fa7bf91b113 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -683,6 +683,7 @@ select * from t1; a b 123.12345 123.1 drop table t1; +End of 4.1 tests CREATE TABLE t1 (EMPNUM CHAR(3) NOT NULL, HOURS DECIMAL(5)); @@ -799,3 +800,10 @@ SELECT ROUND(qty,3), dps, ROUND(qty,dps) FROM t1; ROUND(qty,3) dps ROUND(qty,dps) 1.133 3 1.133 DROP TABLE t1; +create table t1 (f1 decimal(6,6),f2 decimal(6,6) zerofill); +insert into t1 values (-0.123456,0.123456); +select group_concat(f1),group_concat(f2) from t1; +group_concat(f1) group_concat(f2) +-0.123456 0.123456 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 5538f19f5f9..458583fca81 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -278,7 +278,7 @@ update t1 set b=a; select * from t1; drop table t1; -# End of 4.1 tests +--echo End of 4.1 tests # # Test for BUG#8397: decimal type in subselects (Item_cache_decimal) @@ -408,3 +408,14 @@ INSERT INTO t1 VALUES (1.1325,3); SELECT ROUND(qty,3), dps, ROUND(qty,dps) FROM t1; DROP TABLE t1; + +# +# Bug #31227: memory overrun with decimal (6,6) and zerofill and group_concat +# valgrind will complain about this (the group_concat(f2)) on unpatched mysqld. +# +create table t1 (f1 decimal(6,6),f2 decimal(6,6) zerofill); +insert into t1 values (-0.123456,0.123456); +select group_concat(f1),group_concat(f2) from t1; +drop table t1; + +--echo End of 5.0 tests diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 1f0ebf32795..54cef6abdb5 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -68,24 +68,43 @@ int decimal_operation_results(int result) } -/* - Converting decimal to string - - SYNOPSIS - my_decimal2string() - - return - E_DEC_OK - E_DEC_TRUNCATED - E_DEC_OVERFLOW - E_DEC_OOM +/** + @brief Converting decimal to string + + @details Convert given my_decimal to String; allocate buffer as needed. + + @param[in] mask what problems to warn on (mask of E_DEC_* values) + @param[in] d the decimal to print + @param[in] fixed_prec overall number of digits if ZEROFILL, 0 otherwise + @param[in] fixed_dec number of decimal places (if fixed_prec != 0) + @param[in] filler what char to pad with (ZEROFILL et al.) + @param[out] *str where to store the resulting string + + @return error coce + @retval E_DEC_OK + @retval E_DEC_TRUNCATED + @retval E_DEC_OVERFLOW + @retval E_DEC_OOM */ int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec, uint fixed_dec, char filler, String *str) { - int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d)); + /* + Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a + holds true iff the type is also ZEROFILL, which in turn implies + UNSIGNED. Hence the buffer for a ZEROFILLed value is the length + the user requested, plus one for a possible decimal point, plus + one if the user only wanted decimal places, but we force a leading + zero on them. Because the type is implicitly UNSIGNED, we do not + need to reserve a character for the sign. For all other cases, + fixed_prec will be 0, and my_decimal_string_length() will be called + instead to calculate the required size of the buffer. + */ + int length= (fixed_prec + ? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1) + : my_decimal_string_length(d)); int result; if (str->alloc(length)) return check_result(mask, E_DEC_OOM); |