Bug #75210 | Using rand() in UPSERT may result in wrong result | ||
---|---|---|---|
Submitted: | 15 Dec 2014 6:10 | Modified: | 13 Jan 2016 9:24 |
Reporter: | Calvin Sun | Email Updates: | |
Status: | Not a Bug | Impact on me: | |
Category: | MySQL Server: DML | Severity: | S1 (Critical) |
Version: | 5.5, 5.6, 5.6.22, 5.7.9, 5.5.48, 5.6.29 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[15 Dec 2014 6:10]
Calvin Sun
[15 Dec 2014 8:05]
MySQL Verification Team
Hello Calvin, Thank you for the report and test case. Thanks, Umesh
[13 Jan 2016 9:24]
Sreeharsha Ramanavarapu
The user's case is: create table t1 (col1 bigint, col2 tinyint, primary key(col1, col2)); mysql> insert into t1 values (12345678901234567, 1); Query OK, 1 row affected (0.01 sec) mysql> insert into t1 values (12345678901234567, 1) ON DUPLICATE KEY UPDATE col1 = if(false, RAND()*1000, col1); Query OK, 2 rows affected (0.00 sec) mysql> select * from t1; +-------------------+------+ | col1 | col2 | +-------------------+------+ | 12345678901234568 | 1 | +-------------------+------+ 1 row in set (0.00 sec) His complaint is : "I never intended for the last digit to be 8..." What is happening internally: The use of the RAND function function here converts the whole if condition into a double. Since double trumps bigint, we first convert col1 to double, losing precision, which is not regained when converting back to bigint again on the assignment. Why does double lose precision? A double can't accurately hold values greater than 2^53. See https://en.wikipedia.org/wiki/Double-precision_floating-point_format "Between 2^52=4,503,599,627,370,496 and 253=9,007,199,254,740,992 the representable numbers are exactly the integers. For the next range, from 2^53 to 2^54, everything is multiplied by 2, so the representable numbers are the even ones, etc." So is there a bug? No. See sql-1992 standard section 4.6: "If least significant digits are lost, implementation-defined rounding or truncating occurs with no exception condition being raised." Any workarounds? Casting to decimal always helps. Since there is no loss of precision for longlong. insert into t1 values (12345678901234567, 1) ON DUPLICATE KEY UPDATE col1= if(false, CAST(RAND()*1000 AS DECIMAL(20)), col1); Action: I will be closing this as not a bug, after mentioning the workaround. Closed as not a bug.