Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
5.5(EOL), 10.0(EOL), 10.1(EOL), 10.2(EOL), 10.3(EOL), 10.4(EOL), 10.5
-
None
Description
CREATE OR REPLACE TABLE t1 (a BIGINT UNSIGNED, b DOUBLE, c DECIMAL(30,0)); |
INSERT INTO t1 VALUES(18446744073709551615,18446744073709551615,18446744073709551615); |
SELECT a, b, c, a << 0, b << 0, c << 0 FROM t1\G |
MariaDB [test]> SELECT a, b, c, a << 0, b << 0, c << 0 FROM t1\G
|
*************************** 1. row ***************************
|
a: 18446744073709551615
|
b: 1.8446744073709552e19
|
c: 18446744073709551615
|
a << 0: 18446744073709551615
|
b << 0: 9223372036854775807
|
c << 0: 9223372036854775807
|
Notice, the result for `b << 0` and `c << 0` is wrong. It should be 18446744073709551615.
The problem happens because Field_double::val_int() and Field_new_decimal::val_int() truncate to max signed bigint value.
It's not easy to fix this in the current code base.
It seems we need to change this Field and Item method:
virtual longlong val_int(); |
to:
virtual Longlong_hybrid to_longlong_hybrid(); |
so the underlying Field or Item can return the entire range -9223372036854775808 .. 18446744073709551615, i.e. from the minimum possible SIGNED value to maximum possible UNSIGNED value.
Unexpected truncation is also repeatable in this script:
+----------------------------------------------------------------+
| CAST(CAST(18446744073709551615 AS UNSIGNED) AS DECIMAL(32))<<0 |
+----------------------------------------------------------------+
| 9223372036854775807 |
+----------------------------------------------------------------+
1 row in set, 1 warning (0.000 sec)
And in this script:
+-----------------------------------------------------------+
| CAST(CAST(18446744073709551615 AS UNSIGNED) AS DOUBLE)<<0 |
+-----------------------------------------------------------+
| 9223372036854775807 |
+-----------------------------------------------------------+
1 row in set (0.000 sec)
Note, there is a inconsistency: