Commit 4172d5e9 authored by Tor Didriksen's avatar Tor Didriksen

Bug#13359121 LARGE NUMBERS, /STRINGS/DTOA.C:662

Bug#12985021 SIMPLE QUERY WITH DECIMAL NUMBERS TAKE AN

When parsing the fractional part of a string which
is to be converted to double, we can stop after a few digits:
the extra digits will not contribute to the actual result anyways.


mysql-test/r/func_str.result:
  New tests.
mysql-test/t/func_str.test:
  New tests.
strings/dtoa.c:
  The problem was s2b() multiplying and adding hundreds-of-thousands
  of ever smaller fractions.
parent c7964159
...@@ -2826,5 +2826,41 @@ SELECT ((0xf3) * (rpad(1.0,2048,1)) << (0xcc)); ...@@ -2826,5 +2826,41 @@ SELECT ((0xf3) * (rpad(1.0,2048,1)) << (0xcc));
((0xf3) * (rpad(1.0,2048,1)) << (0xcc)) ((0xf3) * (rpad(1.0,2048,1)) << (0xcc))
0 0
# #
# Bug#13359121 LARGE NUMBERS, /STRINGS/DTOA.C:662:
# BALLOC: ASSERTION `K <= 15' FAILED.
# Bug#12985021 SIMPLE QUERY WITH DECIMAL NUMBERS TAKE AN
# EXTRAORDINARY LONG TIME TO EXECUTE
SELECT @tmp_max:= @@global.max_allowed_packet;
@tmp_max:= @@global.max_allowed_packet
1048576
SET @@global.max_allowed_packet=1024*1024*1024;
SELECT @@global.max_allowed_packet;
@@global.max_allowed_packet
1073741824
do
format(rpad('111111111.1',
1111111,
'999999999999999999999999999999999999999999'),0,'be_BY')
;
DO
round(
concat( (
coalesce( (
linefromwkb('2147483648',
-b'1111111111111111111111111111111111111111111')),
( convert('[.DC2.]',decimal(30,30)) ),
bit_count('')
) ),
( lpad( ( elt('01','}:K5')),
sha1('P'),
( ( select '-9223372036854775808.1' > all (select '')))
)
)
)
);
Warnings:
Warning 1292 Truncated incorrect DECIMAL value: '[.DC2.]'
SET @@global.max_allowed_packet:= @tmp_max;
#
# End of 5.5 tests # End of 5.5 tests
# #
...@@ -1459,6 +1459,45 @@ SELECT stddev_samp(rpad(1.0,2048,1)); ...@@ -1459,6 +1459,45 @@ SELECT stddev_samp(rpad(1.0,2048,1));
SELECT ((127.1) not in ((rpad(1.0,2048,1)),(''),(-1.1))); SELECT ((127.1) not in ((rpad(1.0,2048,1)),(''),(-1.1)));
SELECT ((0xf3) * (rpad(1.0,2048,1)) << (0xcc)); SELECT ((0xf3) * (rpad(1.0,2048,1)) << (0xcc));
--echo #
--echo # Bug#13359121 LARGE NUMBERS, /STRINGS/DTOA.C:662:
--echo # BALLOC: ASSERTION `K <= 15' FAILED.
--echo # Bug#12985021 SIMPLE QUERY WITH DECIMAL NUMBERS TAKE AN
--echo # EXTRAORDINARY LONG TIME TO EXECUTE
SELECT @tmp_max:= @@global.max_allowed_packet;
SET @@global.max_allowed_packet=1024*1024*1024;
# switching connection to allow the new max_allowed_packet take effect
--connect (newconn, localhost, root,,)
SELECT @@global.max_allowed_packet;
do
format(rpad('111111111.1',
1111111,
'999999999999999999999999999999999999999999'),0,'be_BY')
;
DO
round(
concat( (
coalesce( (
linefromwkb('2147483648',
-b'1111111111111111111111111111111111111111111')),
( convert('[.DC2.]',decimal(30,30)) ),
bit_count('')
) ),
( lpad( ( elt('01','}:K5')),
sha1('P'),
( ( select '-9223372036854775808.1' > all (select '')))
)
)
)
);
--connection default
SET @@global.max_allowed_packet:= @tmp_max;
--disconnect newconn
--echo # --echo #
--echo # End of 5.5 tests --echo # End of 5.5 tests
......
...@@ -783,7 +783,20 @@ static Bigint *multadd(Bigint *b, int m, int a, Stack_alloc *alloc) ...@@ -783,7 +783,20 @@ static Bigint *multadd(Bigint *b, int m, int a, Stack_alloc *alloc)
return b; return b;
} }
/**
Converts a string to Bigint.
Now we have nd0 digits, starting at s, followed by a
decimal point, followed by nd-nd0 digits.
Unless nd0 == nd, in which case we have a number of the form:
".xxxxxx" or "xxxxxx."
@param s Input string, already partially parsed by my_strtod_int().
@param nd0 Number of digits before decimal point.
@param nd Total number of digits.
@param y9 Pre-computed value of the first nine digits.
@param alloc Stack allocator for Bigints.
*/
static Bigint *s2b(const char *s, int nd0, int nd, ULong y9, Stack_alloc *alloc) static Bigint *s2b(const char *s, int nd0, int nd, ULong y9, Stack_alloc *alloc)
{ {
Bigint *b; Bigint *b;
...@@ -803,10 +816,11 @@ static Bigint *s2b(const char *s, int nd0, int nd, ULong y9, Stack_alloc *alloc) ...@@ -803,10 +816,11 @@ static Bigint *s2b(const char *s, int nd0, int nd, ULong y9, Stack_alloc *alloc)
do do
b= multadd(b, 10, *s++ - '0', alloc); b= multadd(b, 10, *s++ - '0', alloc);
while (++i < nd0); while (++i < nd0);
s++; s++; /* skip '.' */
} }
else else
s+= 10; s+= 10;
/* now do the fractional part */
for(; i < nd; i++) for(; i < nd; i++)
b= multadd(b, 10, *s++ - '0', alloc); b= multadd(b, 10, *s++ - '0', alloc);
return b; return b;
...@@ -1416,6 +1430,14 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s ...@@ -1416,6 +1430,14 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s
for (; s < end && c >= '0' && c <= '9'; c = *++s) for (; s < end && c >= '0' && c <= '9'; c = *++s)
{ {
have_dig: have_dig:
/*
Here we are parsing the fractional part.
We can stop counting digits after a while: the extra digits
will not contribute to the actual result produced by s2b().
We have to continue scanning, in case there is an exponent part.
*/
if (nd < 2 * DBL_DIG)
{
nz++; nz++;
if (c-= '0') if (c-= '0')
{ {
...@@ -1433,6 +1455,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s ...@@ -1433,6 +1455,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s
} }
} }
} }
}
dig_done: dig_done:
e= 0; e= 0;
if (s < end && (c == 'e' || c == 'E')) if (s < end && (c == 'e' || c == 'E'))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment