List:Commits« Previous MessageNext Message »
From:Chad MILLER Date:August 15 2008 7:46pm
Subject:bzr commit into mysql-5.0 branch (chad:2664) Bug#36270
View as plain text  
#At file:///home/cmiller/work/mysqlbzr/mysql-5.0-bugteam/

 2664 Chad MILLER	2008-08-15
      Bug#36270: incorrect calculation result - works in 4.1 but not in 5.0 or 5.1
      
      When the fractional part in a multiplication of DECIMALs
      overflowed, we truncated the first operand rather than the
      longest. Now truncating least significant places instead
      for more precise multiplications.
      
      (Queuing at demand of Trudy/Davi.)
modified:
  mysql-test/r/type_newdecimal.result
  mysql-test/t/type_newdecimal.test
  strings/decimal.c

per-file messages:
  mysql-test/r/type_newdecimal.result
    show that if we need to truncate the scale of an operand, we pick the
    right one (that is, we discard the least significant decimal places)
  mysql-test/t/type_newdecimal.test
    show that if we need to truncate the scale of an operand, we pick the
    right one (that is, we discard the least significant decimal places)
  strings/decimal.c
    when needing to disregard fractional parts, pick the least
    significant ones
=== modified file 'mysql-test/r/type_newdecimal.result'
--- a/mysql-test/r/type_newdecimal.result	2007-11-17 18:05:31 +0000
+++ b/mysql-test/r/type_newdecimal.result	2008-08-15 19:46:21 +0000
@@ -1519,4 +1519,9 @@ SELECT f1 FROM t1;
 f1
 99999999999999999999999999999.999999999999999999999999999999
 DROP TABLE t1;
+select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
+1.01500000 * 1.01500000 * 0.99500000);
+(1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
+1.01500000 * 1.01500000 * 0.99500000)
+0.812988073953673124592306939480
 End of 5.0 tests

=== modified file 'mysql-test/t/type_newdecimal.test'
--- a/mysql-test/t/type_newdecimal.test	2007-11-17 18:05:31 +0000
+++ b/mysql-test/t/type_newdecimal.test	2008-08-15 19:46:21 +0000
@@ -1216,4 +1216,13 @@ DESC t1;
 SELECT f1 FROM t1;
 DROP TABLE t1;
 
+#
+# Bug #36270: incorrect calculation result - works in 4.1 but not in 5.0 or 5.1
+#
+
+# show that if we need to truncate the scale of an operand, we pick the
+# right one (that is, we discard the least significant decimal places)
+select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
+        1.01500000 * 1.01500000 * 0.99500000);
+
 --echo End of 5.0 tests

=== modified file 'strings/decimal.c'
--- a/strings/decimal.c	2008-01-14 15:16:36 +0000
+++ b/strings/decimal.c	2008-08-15 19:46:21 +0000
@@ -1999,18 +1999,18 @@ int decimal_mul(decimal_t *from1, decima
 
   sanity(to);
 
-  i=intg0;
+  i=intg0;                                       /* save 'ideal' values */
   j=frac0;
-  FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error);
+  FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error);  /* bound size */
   to->sign=from1->sign != from2->sign;
-  to->frac=from1->frac+from2->frac;
+  to->frac=from1->frac+from2->frac;              /* store size in digits */
   to->intg=intg0*DIG_PER_DEC1;
 
   if (unlikely(error))
   {
     set_if_smaller(to->frac, frac0*DIG_PER_DEC1);
     set_if_smaller(to->intg, intg0*DIG_PER_DEC1);
-    if (unlikely(i > intg0))
+    if (unlikely(i > intg0))                     /* bounded integer-part */
     {
       i-=intg0;
       j=i >> 1;
@@ -2018,12 +2018,20 @@ int decimal_mul(decimal_t *from1, decima
       intg2-=i-j;
       frac1=frac2=0; /* frac0 is already 0 here */
     }
-    else
+    else                                         /* bounded fract part */
     {
       j-=frac0;
       i=j >> 1;
-      frac1-= i;
-      frac2-=j-i;
+      if (frac1 <= frac2)
+      {
+        frac1-= i;
+        frac2-=j-i;
+      }
+      else
+      {
+        frac2-= i;
+        frac1-=j-i;
+      }
     }
   }
   start0=to->buf+intg0+frac0-1;

Thread
bzr commit into mysql-5.0 branch (chad:2664) Bug#36270Chad MILLER15 Aug