Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
5.6.1, 6.1.1
-
None
-
2021-5
Description
DROP TABLE IF EXISTS t1; |
CREATE TABLE t1 (d1 DOUBLE, d2 DOUBLE NOT NULL) ENGINE=ColumnStore; |
INSERT INTO t1 VALUES (9.2233720368547758e+18, 9.2233720368547758e+18); |
INSERT INTO t1 VALUES (18446744073709551614,18446744073709551614); |
SELECT d1, CAST(d1 AS SIGNED), CAST(d2 AS SIGNED) FROM t1; |
+-----------------------+---------------------+---------------------+
|
| d1 | CAST(d1 AS SIGNED) | CAST(d2 AS SIGNED) |
|
+-----------------------+---------------------+---------------------+
|
| 9.223372036854776e18 | NULL | 0 |
|
| 1.8446744073709552e19 | 9223372036854775807 | 9223372036854775807 |
|
+-----------------------+---------------------+---------------------+
|
Notice:
- the value 9.2233720368547758e+18 was erroneously converted to NULL and 0
- a huger value 8446744073709552e19 was correctly converted to 9223372036854775807
The expected result is:
DROP TABLE IF EXISTS t1; |
CREATE TABLE t1 (d1 DOUBLE, d2 DOUBLE NOT NULL) ENGINE=InnoDB; |
INSERT INTO t1 VALUES (9.2233720368547758e+18, 9.2233720368547758e+18); |
INSERT INTO t1 VALUES (18446744073709551614,18446744073709551614); |
SELECT d1, CAST(d1 AS SIGNED), CAST(d2 AS SIGNED) FROM t1; |
+-----------------------+---------------------+---------------------+
|
| d1 | CAST(d1 AS SIGNED) | CAST(d2 AS SIGNED) |
|
+-----------------------+---------------------+---------------------+
|
| 9.223372036854776e18 | 9223372036854775807 | 9223372036854775807 |
|
| 1.8446744073709552e19 | 9223372036854775807 | 9223372036854775807 |
|
+-----------------------+---------------------+---------------------+
|
The problem happens in this piece of the code in Func_cast_signed::getIntVal() in func_cast.cpp:
case execplan::CalpontSystemCatalog::FLOAT: |
case execplan::CalpontSystemCatalog::UFLOAT: |
case execplan::CalpontSystemCatalog::DOUBLE: |
case execplan::CalpontSystemCatalog::UDOUBLE: |
{
|
double value = parm[0]->data()->getDoubleVal(row, isNull); |
|
if (value > 0) |
value += 0.5;
|
else if (value < 0) |
value -= 0.5;
|
|
int64_t ret = (int64_t) value;
|
|
if (value > (double) numeric_limits<int64_t>::max()) |
ret = numeric_limits<int64_t>::max();
|
else if (value < (double) (numeric_limits<int64_t>::min() + 2)) |
ret = numeric_limits<int64_t>::min() + 2; // IDB min for bigint |
|
return ret; |
}
|
Let's print variable values after this statement:
int64_t ret = (int64_t) value;
|
(gdb) p value
|
$25 = 9.2233720368547758e+18
|
(gdb) p ret
|
$26 = -9223372036854775808
|
Notice, ret is wrong. The code should check for the int64_t range before casting double to int64_t.