summaryrefslogtreecommitdiff
path: root/strings/decimal.c
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2021-02-05 19:50:05 +0400
committerAlexander Barkov <bar@mariadb.com>2021-02-08 16:19:45 +0400
commitafc5bac49d48b6fd13def25409642104b988de28 (patch)
tree8fce436ad2cd41c073a89647d01162c57a108281 /strings/decimal.c
parent739abf5195765914fad6f759f4b08e2a09a6006a (diff)
downloadmariadb-git-afc5bac49d48b6fd13def25409642104b988de28.tar.gz
MDEV-24790 CAST('0e1111111111' AS DECIMAL(38,0)) returns a wrong result
Diffstat (limited to 'strings/decimal.c')
-rw-r--r--strings/decimal.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/strings/decimal.c b/strings/decimal.c
index 2dd7c960a3e..9d18a9ce52a 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -921,20 +921,75 @@ internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed)
if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E'))
{
int str_error;
- longlong exponent= my_strtoll10(endp+1, (char**) &end_of_string,
+ const char *end_of_exponent= end_of_string;
+ longlong exponent= my_strtoll10(endp+1, (char**) &end_of_exponent,
&str_error);
- if (end_of_string != endp +1) /* If at least one digit */
+ if (end_of_exponent != endp +1) /* If at least one digit */
{
- *end= (char*) end_of_string;
+ *end= (char*) end_of_exponent;
if (str_error > 0)
{
+ if (str_error == MY_ERRNO_ERANGE)
+ {
+ /*
+ Exponent is:
+ - a huge positive number that does not fit into ulonglong
+ - a huge negative number that does not fit into longlong
+ Skip all remaining digits.
+ */
+ for ( ; end_of_exponent < end_of_string &&
+ my_isdigit(&my_charset_latin1, *end_of_exponent)
+ ; end_of_exponent++)
+ { }
+ *end= (char*) end_of_exponent;
+ if (exponent == ~0)
+ {
+ if (!decimal_is_zero(to))
+ {
+ /*
+ Non-zero mantissa and a huge positive exponent that
+ does not fit into ulonglong, e.g.:
+ 1e111111111111111111111
+ */
+ error= E_DEC_OVERFLOW;
+ }
+ else
+ {
+ /*
+ Zero mantissa and a huge positive exponent that
+ does not fit into ulonglong, e.g.:
+ 0e111111111111111111111
+ Return zero without warnings.
+ */
+ }
+ }
+ else
+ {
+ /*
+ Huge negative exponent that does not fit into longlong, e.g.
+ 1e-111111111111111111111
+ 0e-111111111111111111111
+ Return zero without warnings.
+ */
+ }
+ goto fatal_error;
+ }
+
+ /*
+ Some other error, e.g. MY_ERRNO_EDOM
+ */
error= E_DEC_BAD_NUM;
goto fatal_error;
}
if (exponent > INT_MAX/2 || (str_error == 0 && exponent < 0))
{
- error= E_DEC_OVERFLOW;
+ /*
+ The exponent fits into ulonglong, but it's still huge, e.g.
+ 1e1111111111
+ */
+ if (!decimal_is_zero(to))
+ error= E_DEC_OVERFLOW;
goto fatal_error;
}
if (exponent < INT_MIN/2 && error != E_DEC_OVERFLOW)