Skip to content

Commit e823023

Browse files
Tor Didriksenholyfoot
authored andcommitted
Bug#18411494 WRONG COMPARSION ON BIG DECIMAL VALUES
Problem: integer literals may be converted to floats for comparison with decimal data. If the integers are large, we may lose precision, and give wrong results. Fix: for <non-const decimal expression> <cmp> <const string expression> or <const string expression> <cmp> <non-const decimal expression> we override the compare_type chosen by item_cmp_type(), and do comparison as decimal rather than float. (cherry picked from commit mysql/mysql-server@1cf3489 and edited by Johannes Weißl <jargon@molb.org>)
1 parent 68d632b commit e823023

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

mysql-test/r/type_newdecimal.result

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,3 +2243,42 @@ DROP TABLE t1;
22432243
#
22442244
# End of 10.1 tests
22452245
#
2246+
#
2247+
# Bug#18408499 UNSIGNED BIGINT HIGH VALUES
2248+
# WRONG NUMERICAL COMPARISON RESULTS
2249+
#
2250+
CREATE TABLE t1(value DECIMAL(24,0) NOT NULL);
2251+
INSERT INTO t1(value)
2252+
VALUES('100000000000000000000001'),
2253+
('100000000000000000000002'),
2254+
('100000000000000000000003');
2255+
SELECT * FROM t1 WHERE value = '100000000000000000000002';
2256+
value
2257+
100000000000000000000002
2258+
SELECT * FROM t1 WHERE '100000000000000000000002' = value;
2259+
value
2260+
100000000000000000000002
2261+
SELECT * FROM t1 WHERE value + 0 = '100000000000000000000002';
2262+
value
2263+
100000000000000000000002
2264+
SELECT * FROM t1 WHERE value = 100000000000000000000002;
2265+
value
2266+
100000000000000000000002
2267+
SELECT * FROM t1 WHERE value + 0 = 100000000000000000000002;
2268+
value
2269+
100000000000000000000002
2270+
PREPARE stmt FROM 'SELECT * FROM t1 WHERE value = ?';
2271+
set @a="100000000000000000000002";
2272+
EXECUTE stmt using @a;
2273+
value
2274+
100000000000000000000002
2275+
set @a=100000000000000000000002;
2276+
EXECUTE stmt using @a;
2277+
value
2278+
100000000000000000000002
2279+
DEALLOCATE PREPARE stmt;
2280+
ALTER TABLE t1 ADD INDEX value (value);
2281+
SELECT * FROM t1 WHERE value = '100000000000000000000002';
2282+
value
2283+
100000000000000000000002
2284+
DROP TABLE t1;

mysql-test/t/type_newdecimal.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,3 +1738,30 @@ DROP TABLE t1;
17381738
--echo #
17391739
--echo # End of 10.1 tests
17401740
--echo #
1741+
1742+
--echo #
1743+
--echo # Bug#18408499 UNSIGNED BIGINT HIGH VALUES
1744+
--echo # WRONG NUMERICAL COMPARISON RESULTS
1745+
--echo #
1746+
1747+
CREATE TABLE t1(value DECIMAL(24,0) NOT NULL);
1748+
INSERT INTO t1(value)
1749+
VALUES('100000000000000000000001'),
1750+
('100000000000000000000002'),
1751+
('100000000000000000000003');
1752+
SELECT * FROM t1 WHERE value = '100000000000000000000002';
1753+
SELECT * FROM t1 WHERE '100000000000000000000002' = value;
1754+
SELECT * FROM t1 WHERE value + 0 = '100000000000000000000002';
1755+
SELECT * FROM t1 WHERE value = 100000000000000000000002;
1756+
SELECT * FROM t1 WHERE value + 0 = 100000000000000000000002;
1757+
1758+
PREPARE stmt FROM 'SELECT * FROM t1 WHERE value = ?';
1759+
set @a="100000000000000000000002";
1760+
EXECUTE stmt using @a;
1761+
set @a=100000000000000000000002;
1762+
EXECUTE stmt using @a;
1763+
DEALLOCATE PREPARE stmt;
1764+
1765+
ALTER TABLE t1 ADD INDEX value (value);
1766+
SELECT * FROM t1 WHERE value = '100000000000000000000002';
1767+
DROP TABLE t1;

sql/item_cmpfunc.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,22 @@ int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg,
655655
return 0;
656656
}
657657

658+
if (m_compare_type == REAL_RESULT &&
659+
(((*a)->result_type() == DECIMAL_RESULT && !(*a)->const_item() &&
660+
(*b)->result_type() == STRING_RESULT && (*b)->const_item()) ||
661+
((*b)->result_type() == DECIMAL_RESULT && !(*b)->const_item() &&
662+
(*a)->result_type() == STRING_RESULT && (*a)->const_item())))
663+
{
664+
/*
665+
<non-const decimal expression> <cmp> <const string expression>
666+
or
667+
<const string expression> <cmp> <non-const decimal expression>
668+
669+
Do comparison as decimal rather than float, in order not to lose precision.
670+
*/
671+
m_compare_type= DECIMAL_RESULT;
672+
}
673+
658674
if (m_compare_type == INT_RESULT &&
659675
(*a)->field_type() == MYSQL_TYPE_YEAR &&
660676
(*b)->field_type() == MYSQL_TYPE_YEAR)

0 commit comments

Comments
 (0)