From: Date: May 12 2008 6:59am Subject: bk commit into 5.1 tree (holyfoot:1.2582) BUG#36025 List-Archive: http://lists.mysql.com/commits/46612 X-Bug: 36025 Message-Id: <20080512045902.72CDA2C380A5@hfmain.localdomain> Below is the list of changes that have just been committed into a local 5.1 repository of holyfoot. When holyfoot 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, 2008-05-12 09:58:57+05:00, holyfoot@stripped +4 -0 Bug #36025 func_1._storedproc test failing on Windows. Float types are of limited precision (15 digits for DOUBLE for example), so if the string representation has more than 15 digits, the precision of the initial string will be lost. Which is worse, different sprintf() versions can produce slightly different result on these data (what caused this bug). As we implement homegrovn double->string conversion in 6.0, this bug will disappear there. Still i'd propose this patch. Here we store the initial string representation of a 'float' value and use it to produce decimal if it's necessary. That way, we won't lost the precision up to 60 digits. mysql-test/r/type_newdecimal.result@stripped, 2008-05-12 09:58:54+05:00, holyfoot@stripped +3 -0 Bug #36025 func_1._storedproc test failing on Windows test result mysql-test/t/type_newdecimal.test@stripped, 2008-05-12 09:58:54+05:00, holyfoot@stripped +7 -0 Bug #36025 func_1._storedproc test failing on Windows test case sql/item.cc@stripped, 2008-05-12 09:58:54+05:00, holyfoot@stripped +10 -1 Bug #36025 func_1._storedproc test failing on Windows. Store string representation of the double in the 'value_str' member. Then use this string to create decimal result rather than the 'value' itself. sql/item.h@stripped, 2008-05-12 09:58:54+05:00, holyfoot@stripped +10 -3 Bug #36025 func_1._storedproc test failing on Windows. Item_float::value_str member added to store string representation of the number diff -Nrup a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result --- a/mysql-test/r/type_newdecimal.result 2007-11-17 22:42:14 +04:00 +++ b/mysql-test/r/type_newdecimal.result 2008-05-12 09:58:54 +05:00 @@ -1557,3 +1557,6 @@ Error 1264 Out of range value for column select cast(98.6 as decimal(2,0)); cast(98.6 as decimal(2,0)) 99 +select cast(0.123456789098765432101234567890987654321e+29 as decimal(60,30)); +cast(0.123456789098765432101234567890987654321e+29 as decimal(60,30)) +12345678909876543210123456789.098765432100000000000000000000 diff -Nrup a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test --- a/mysql-test/t/type_newdecimal.test 2007-11-17 22:12:34 +04:00 +++ b/mysql-test/t/type_newdecimal.test 2008-05-12 09:58:54 +05:00 @@ -1238,3 +1238,10 @@ 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 #36025 funcs_1._storedproc Test failing on Windows +# here we check that float->decimal conversion doesn't lose +# precision + +select cast(0.123456789098765432101234567890987654321e+29 as decimal(60,30)); diff -Nrup a/sql/item.cc b/sql/item.cc --- a/sql/item.cc 2008-04-23 18:10:18 +05:00 +++ b/sql/item.cc 2008-05-12 09:58:54 +05:00 @@ -2335,7 +2335,13 @@ my_decimal *Item_float::val_decimal(my_d { // following assert is redundant, because fixed=1 assigned in constructor DBUG_ASSERT(fixed == 1); - double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); + if (value_str) + { + char *str_end= value_str + value_str_length; + str2my_decimal(E_DEC_FATAL_ERROR, value_str, decimal_value, &str_end); + } + else + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); return (decimal_value); } @@ -4928,6 +4934,8 @@ Item_float::Item_float(const char *str_a { int error; char *end_not_used; + value_str= sql_strmake(str_arg, length); + value_str_length= length; value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used, &error); if (error) @@ -4938,6 +4946,7 @@ Item_float::Item_float(const char *str_a */ DBUG_ASSERT(str_arg[length] == 0); my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", (char*) str_arg); + value_str= NULL; } presentation= name=(char*) str_arg; decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); diff -Nrup a/sql/item.h b/sql/item.h --- a/sql/item.h 2008-03-12 12:21:09 +04:00 +++ b/sql/item.h 2008-05-12 09:58:54 +05:00 @@ -1786,17 +1786,19 @@ class Item_float :public Item_num char *presentation; public: double value; + char *value_str; + int value_str_length; // Item_real() :value(0) {} Item_float(const char *str_arg, uint length); Item_float(const char *str,double val_arg,uint decimal_par,uint length) - :value(val_arg) + :value(val_arg), value_str(NULL) { presentation= name=(char*) str; decimals=(uint8) decimal_par; max_length=length; fixed= 1; } - Item_float(double value_par, uint decimal_par) :presentation(0), value(value_par) + Item_float(double value_par, uint decimal_par) :presentation(0), value(value_par), value_str(NULL) { decimals= (uint8) decimal_par; fixed= 1; @@ -1822,7 +1824,12 @@ public: my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } Item *clone_item() - { return new Item_float(name, value, decimals, max_length); } + { + Item_float *clone= new Item_float(name, value, decimals, max_length); + clone->value_str= value_str; + clone->value_str_length= value_str_length; + return clone; + } Item_num *neg() { value= -value; return this; } virtual void print(String *str, enum_query_type query_type); bool eq(const Item *, bool binary_cmp) const;