Commit 0e80f5a6 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-23105 Cast number string with many leading zeros to decimal gives unexpected result

Skip leading zeros when converting a string to decimal_t.
parent a09a06d5
...@@ -2342,6 +2342,50 @@ t1 CREATE TABLE `t1` ( ...@@ -2342,6 +2342,50 @@ t1 CREATE TABLE `t1` (
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-23105 Cast number string with many leading zeros to decimal gives unexpected result
#
SELECT CAST(0000000000000000000000000000000000000000000000000000000000000000000000000000000020.01 AS DECIMAL(15,2)) as val;
val
20.01
SET sql_mode='';
CREATE TABLE t1 (a TEXT);
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.0'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.9'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.99'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.994'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.995'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.999'));
CREATE TABLE t2 (a TEXT, d DECIMAL(15,2));
INSERT IGNORE INTO t2 (a,d) SELECT a, a FROM t1;
Warnings:
Note 1265 Data truncated for column 'd' at row 5
Note 1265 Data truncated for column 'd' at row 6
Note 1265 Data truncated for column 'd' at row 7
INSERT IGNORE INTO t2 (a,d) SELECT CONCAT('-',a), CONCAT('-',a) FROM t1;
Warnings:
Note 1265 Data truncated for column 'd' at row 5
Note 1265 Data truncated for column 'd' at row 6
Note 1265 Data truncated for column 'd' at row 7
SELECT d, a FROM t2 ORDER BY d,a;
d a
-2.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.995
-2.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.999
-1.99 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.99
-1.99 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.994
-1.90 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.9
-1.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
-1.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.0
1.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
1.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.0
1.90 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.9
1.99 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.99
1.99 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.994
2.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.995
2.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.999
DROP TABLE t1, t2;
SET sql_mode=DEFAULT;
#
# End of 10.1 tests # End of 10.1 tests
# #
# #
......
...@@ -1821,6 +1821,28 @@ CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001e0); ...@@ -1821,6 +1821,28 @@ CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001e0);
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-23105 Cast number string with many leading zeros to decimal gives unexpected result
--echo #
SELECT CAST(0000000000000000000000000000000000000000000000000000000000000000000000000000000020.01 AS DECIMAL(15,2)) as val;
SET sql_mode='';
CREATE TABLE t1 (a TEXT);
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.0'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.9'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.99'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.994'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.995'));
INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.999'));
CREATE TABLE t2 (a TEXT, d DECIMAL(15,2));
INSERT IGNORE INTO t2 (a,d) SELECT a, a FROM t1;
INSERT IGNORE INTO t2 (a,d) SELECT CONCAT('-',a), CONCAT('-',a) FROM t1;
SELECT d, a FROM t2 ORDER BY d,a;
DROP TABLE t1, t2;
SET sql_mode=DEFAULT;
--echo # --echo #
--echo # End of 10.1 tests --echo # End of 10.1 tests
--echo # --echo #
......
...@@ -812,6 +812,24 @@ internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed) ...@@ -812,6 +812,24 @@ internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed)
while (s < end_of_string && my_isdigit(&my_charset_latin1, *s)) while (s < end_of_string && my_isdigit(&my_charset_latin1, *s))
s++; s++;
intg= (int) (s-s1); intg= (int) (s-s1);
/*
If the integer part is long enough and it has multiple leading zeros,
let's trim them, so this expression can return 1 without overflowing:
CAST(CONCAT(REPEAT('0',90),'1') AS DECIMAL(10))
*/
if (intg > DIG_PER_DEC1 && s1[0] == '0' && s1[1] == '0')
{
/*
Keep at least one digit, to avoid an empty string.
So we trim '0000' to '0' rather than to ''.
Otherwise the below code (converting digits to to->buf)
would fail on a fatal error.
*/
const char *iend= s - 1;
for ( ; s1 < iend && *s1 == '0'; s1++)
{ }
intg= (int) (s-s1);
}
if (s < end_of_string && *s=='.') if (s < end_of_string && *s=='.')
{ {
endp= s+1; endp= s+1;
......
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