List:Commits« Previous MessageNext Message »
From:Alexey Kopytov Date:November 21 2007 6:44am
Subject:bk commit into 5.0 tree (kaa:1.2527) BUG#26788
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of kaa. When kaa 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, 2007-11-21 09:44:35+03:00, kaa@polly.(none) +3 -0
  Fix for bug #26788 "mysqld (debug) aborts when inserting specific
  numbers into char fields".
  
  Rewrote the code that determines what 'precision' argument should be
  passed to sprintf() to fit the string representation of the input number
  into the field.
  We get finer control over conversion by pre-calculating the exponent, so
  we are able to determine which conversion format, 'e' or 'f', will be
  used by sprintf().

  mysql-test/r/insert.result@stripped, 2007-11-21 09:44:30+03:00, kaa@polly.(none) +66 -0
    Added test cases for bug #26788 and bug #31152.

  mysql-test/t/insert.test@stripped, 2007-11-21 09:44:30+03:00, kaa@polly.(none) +56 -0
    Added test cases for bug #26788 and bug #31152.

  sql/field.cc@stripped, 2007-11-21 09:44:30+03:00, kaa@polly.(none) +46 -14
    Rewrote the code that determines what 'precision' argument should be
    passed to sprintf() to fit the string representation of the input number
    into the field.
    We get finer control over conversion by pre-calculating the exponent, so
    we are able to determine which conversion format, 'e' or 'f', will be
    used by sprintf().

diff -Nrup a/mysql-test/r/insert.result b/mysql-test/r/insert.result
--- a/mysql-test/r/insert.result	2007-05-30 16:04:02 +04:00
+++ b/mysql-test/r/insert.result	2007-11-21 09:44:30 +03:00
@@ -461,4 +461,70 @@ i
 2
 2
 DROP TABLE t1, t2;
+CREATE TABLE t1 (
+a char(20) NOT NULL,
+b char(7) DEFAULT NULL,
+c char(4) DEFAULT NULL
+);
+INSERT INTO t1(a,b,c) VALUES (9.999999e+0, 9.999999e+0, 9.999e+0);
+INSERT INTO t1(a,b,c) VALUES (1.225e-05, 1.225e-05, 1.225e-05);
+Warnings:
+Warning	1265	Data truncated for column 'c' at row 1
+INSERT INTO t1(a,b) VALUES (1.225e-04, 1.225e-04);
+INSERT INTO t1(a,b) VALUES (1.225e-01, 1.225e-01);
+INSERT INTO t1(a,b) VALUES (1.225877e-01, 1.225877e-01);
+INSERT INTO t1(a,b) VALUES (1.225e+01, 1.225e+01);
+INSERT INTO t1(a,b,c) VALUES (1.225e+01, 1.225e+01, 1.225e+01);
+INSERT INTO t1(a,b) VALUES (1.225e+05, 1.225e+05);
+INSERT INTO t1(a,b) VALUES (1.225e+10, 1.225e+10);
+INSERT INTO t1(a,b) VALUES (1.225e+15, 1.225e+15);
+INSERT INTO t1(a,b) VALUES (5000000e+0, 5000000e+0);
+INSERT INTO t1(a,b) VALUES (1.25e+78, 1.25e+78);
+INSERT INTO t1(a,b) VALUES (1.25e-94, 1.25e-94);
+INSERT INTO t1(a,b) VALUES (1.25e+203, 1.25e+203);
+INSERT INTO t1(a,b) VALUES (1.25e-175, 1.25e-175);
+INSERT INTO t1(a,c) VALUES (1.225e+0, 1.225e+0);
+INSERT INTO t1(a,c) VALUES (1.37e+0, 1.37e+0);
+INSERT INTO t1(a,c) VALUES (-1.37e+0, -1.37e+0);
+Warnings:
+Warning	1265	Data truncated for column 'c' at row 1
+INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3);
+Warnings:
+Warning	1265	Data truncated for column 'c' at row 1
+INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2);
+Warnings:
+Warning	1265	Data truncated for column 'c' at row 1
+INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0);
+INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0);
+Warnings:
+Warning	1265	Data truncated for column 'c' at row 1
+SELECT * FROM t1;
+a	b	c
+9.999999000000000748	10	10
+1.225e-05	1.2e-05	1e-0
+0.0001225	0.00012	NULL
+0.122499999999999998	0.1225	NULL
+0.122587699999999994	0.12259	NULL
+12.25	12.25	NULL
+12.25	12.25	12.2
+122500	122500	NULL
+12250000000	1.2e+10	NULL
+1225000000000000	1.2e+15	NULL
+5000000	5000000	NULL
+1.25e+78	1.2e+78	NULL
+1.25e-94	1.2e-94	NULL
+1.25e+203	1e+203	NULL
+1.25e-175	1e-175	NULL
+1.225000000000000089	NULL	1.23
+1.370000000000000107	NULL	1.37
+-1.37	NULL	-1.3
+0.00187	NULL	0.00
+-0.0187	NULL	-0.0
+5000	NULL	5000
+-5000	NULL	-500
+DROP TABLE t1;
+CREATE TABLE t (a CHAR(10),b INT);
+INSERT INTO t VALUES (),(),();
+INSERT INTO t(a) SELECT rand() FROM t;
+DROP TABLE t;
 End of 5.0 tests.
diff -Nrup a/mysql-test/t/insert.test b/mysql-test/t/insert.test
--- a/mysql-test/t/insert.test	2007-05-16 09:51:03 +04:00
+++ b/mysql-test/t/insert.test	2007-11-21 09:44:30 +03:00
@@ -353,5 +353,61 @@ SELECT * FROM t2;
 
 DROP TABLE t1, t2;
 
+#
+# Bug #26788: mysqld (debug) aborts when inserting specific numbers into char
+#             fields
+#
+
+CREATE TABLE t1 (
+  a char(20) NOT NULL,
+  b char(7) DEFAULT NULL,
+  c char(4) DEFAULT NULL
+);
+
+INSERT INTO t1(a,b,c) VALUES (9.999999e+0, 9.999999e+0, 9.999e+0);
+INSERT INTO t1(a,b,c) VALUES (1.225e-05, 1.225e-05, 1.225e-05);
+INSERT INTO t1(a,b) VALUES (1.225e-04, 1.225e-04);
+INSERT INTO t1(a,b) VALUES (1.225e-01, 1.225e-01);
+INSERT INTO t1(a,b) VALUES (1.225877e-01, 1.225877e-01);
+INSERT INTO t1(a,b) VALUES (1.225e+01, 1.225e+01);
+INSERT INTO t1(a,b,c) VALUES (1.225e+01, 1.225e+01, 1.225e+01);
+INSERT INTO t1(a,b) VALUES (1.225e+05, 1.225e+05);
+INSERT INTO t1(a,b) VALUES (1.225e+10, 1.225e+10);
+INSERT INTO t1(a,b) VALUES (1.225e+15, 1.225e+15);
+INSERT INTO t1(a,b) VALUES (5000000e+0, 5000000e+0);
+INSERT INTO t1(a,b) VALUES (1.25e+78, 1.25e+78);
+INSERT INTO t1(a,b) VALUES (1.25e-94, 1.25e-94);
+INSERT INTO t1(a,b) VALUES (1.25e+203, 1.25e+203);
+INSERT INTO t1(a,b) VALUES (1.25e-175, 1.25e-175);
+INSERT INTO t1(a,c) VALUES (1.225e+0, 1.225e+0);
+INSERT INTO t1(a,c) VALUES (1.37e+0, 1.37e+0);
+INSERT INTO t1(a,c) VALUES (-1.37e+0, -1.37e+0);
+INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3);
+INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2);
+INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0);
+INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0);
+
+# Expected result is "1.225e-05", but windows returns "1.225e-005"
+# Expected result is "1.2e-05", but windows returns "1e-005"
+# Expected result is "1.2e+10", but windows returns "1e+010"
+# Expected result is "1.2e+15", but windows returns "1e+015"
+# Expected result is "1.25e+78", but windows returns "1.25e+078"
+# Expected result is "1.2e+78", but windows returns "1e+078"
+# Expected result is "1.25e-94", but windows returns "1.25e-094"
+# Expected result is "1.2e-94", but windows returns "1e-094"
+--replace_result 1.225e-005 1.225e-05 1e-005 1.2e-05 1e+010 1.2e+10 1e+015 1.2e+15 1.25e+078 1.25e+78 1e+078 1.2e+78 1.25e-094 1.25e-94 1e-094 1.2e-94
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+#
+# Bug #31152: assertion in Field_str::store(double)
+#
+
+CREATE TABLE t (a CHAR(10),b INT);
+INSERT INTO t VALUES (),(),();
+INSERT INTO t(a) SELECT rand() FROM t;
+DROP TABLE t;
+
 --echo End of 5.0 tests.
 
diff -Nrup a/sql/field.cc b/sql/field.cc
--- a/sql/field.cc	2007-08-06 15:57:26 +04:00
+++ b/sql/field.cc	2007-11-21 09:44:30 +03:00
@@ -5907,24 +5907,56 @@ int Field_str::store(double nr)
 {
   char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
   uint length;
-  bool use_scientific_notation= TRUE;
   uint local_char_length= field_length / charset()->mbmaxlen;
-  /*
-    Check fabs(nr) against longest value that can be stored in field,
-    which depends on whether the value is < 1 or not, and negative or not
-  */
   double anr= fabs(nr);
   int neg= (nr < 0.0) ? 1 : 0;
-  if (local_char_length > 4 && local_char_length < 32 &&
-      (anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */
-                 : anr < log_10[local_char_length-neg]-1))
-    use_scientific_notation= FALSE;
+  uint max_length;
+  int exp;
+  uint digits;
+  uint i;
+
+  /* Calculate the exponent from the 'e'-format conversion */
+  if (anr < 1.0 && anr > 0)
+  {
+    for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100);
+    for (; anr < 1e-10; exp-= 10, anr*= 1e10);
+    for (i= 1; anr < 1 / log_10[i]; exp--, i++);
+    exp--;
+  }
+  else
+  {
+    for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100);
+    for (; anr > 1e10; exp+= 10, anr/= 1e10);
+    for (i= 1; anr > log_10[i]; exp++, i++);
+  }
+
+  max_length= local_char_length - neg;
+
+  /*
+    Since in sprintf("%g") precision means the number of significant digits,
+    calculate the maximum number of significant digits if the 'f'-format
+    would be used (+1 for decimal point if the number has a fractional part).
+  */
+  digits= max(0, (int) max_length - (nr != trunc(nr)));
+  /*
+    If the exponent is negative, decrease digits by the number of leading zeros
+    after the decimal point that do not count as significant digits.
+  */
+  if (exp < 0)
+    digits= max(0, (int) digits + exp);
+  /*
+    'e'-format is used only if the exponent is less than -4 or greater than or
+    equal to the precision. In this case we need to adjust the number of
+    significant digits to take "e+NN" + decimal point into account (hence -5).
+    We also have to reserve one additional character if abs(exp) >= 100.
+    Windows always zero-pads the exponent to 3 digits.
+  */
+  if (exp >= (int) digits || exp < -4)
+    digits= max(0, (int) (max_length - 5 -
+                          IF_WIN(1, (exp >= 100 || exp <= -100))));
+  
+  length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr));
 
-  length= (uint) my_sprintf(buff, (buff, "%-.*g",
-                                   (use_scientific_notation ?
-                                    max(0, (int)local_char_length-neg-5) :
-                                    local_char_length),
-                                   nr));
   /*
     +1 below is because "precision" in %g above means the
     max. number of significant digits, not the output width.
Thread
bk commit into 5.0 tree (kaa:1.2527) BUG#26788Alexey Kopytov21 Nov