[MCOL-4610] TreeNode::getUintVal() looses precision for narrow decimal Created: 2021-03-15  Updated: 2021-03-30  Resolved: 2021-03-30

Status: Closed
Project: MariaDB ColumnStore
Component/s: PrimProc
Affects Version/s: 5.5.1, 5.6.1, 6.1.1
Fix Version/s: 6.1.1

Type: Bug Priority: Major
Reporter: Alexander Barkov Assignee: Alexander Barkov
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Blocks
blocks MCOL-4361 Replace pow(10.0, (double)scale) expr... Closed
Relates
relates to MCOL-4650 TreeNode::getIntVal() looses precisio... Closed
Sprint: 2021-5

 Description   

The code for the DECIMAL data type in TreeNode::getUintVal() performs calculations in double format. This approach looses precision for huge numbers.

        case CalpontSystemCatalog::DECIMAL:
        case CalpontSystemCatalog::UDECIMAL:
        {
            return (uint64_t)(fResult.decimalVal.value / pow((double)10, fResult.decimalVal.scale));
        }

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a DECIMAL(18,0)) ENGINE=ColumnStore;
INSERT INTO t1 VALUES (9999999999999999);
INSERT INTO t1 VALUES (99999999999999998);
INSERT INTO t1 VALUES (999999999999999997);
SELECT a, CAST(a DIV 1 AS UNSIGNED) FROM t1;

+--------------------+---------------------------+
| a                  | CAST(a DIV 1 AS UNSIGNED) |
+--------------------+---------------------------+
|   9999999999999999 |         10000000000000000 |
|  99999999999999998 |        100000000000000000 |
| 999999999999999997 |       1000000000000000000 |
+--------------------+---------------------------+

Looks wrong. Values in the first and the second columns are expected to be equal.

Note:

  • the problem is repeatable for narrow decimal in 5.5 and 5.6
  • the problem is not repeatable for wide decimal in 5.6:

    DROP TABLE IF EXISTS t1;
    CREATE TABLE t1 (a DECIMAL(30,0)) ENGINE=ColumnStore;
    INSERT INTO t1 VALUES (9999999999999999);
    INSERT INTO t1 VALUES (99999999999999998);
    INSERT INTO t1 VALUES (999999999999999997);
    SELECT a, CAST(a DIV 1 AS UNSIGNED) FROM t1;
    

    +--------------------+---------------------------+
    | a                  | CAST(a DIV 1 AS UNSIGNED) |
    +--------------------+---------------------------+
    |   9999999999999999 |          9999999999999999 |
    |  99999999999999998 |         99999999999999998 |
    | 999999999999999997 |        999999999999999997 |
    +--------------------+---------------------------+
    



 Comments   
Comment by Alexander Barkov [ 2021-03-17 ]

The same problem is in this code: double is used to perform INT an result operation:

int64_t Func_div::getIntVal(rowgroup::Row& row,
                            FunctionParm& parm,
                            bool& isNull,
                            CalpontSystemCatalog::ColType& op_ct)
{
    double val1 = parm[0]->data()->getDoubleVal(row, isNull);
    double val2 = parm[1]->data()->getDoubleVal(row, isNull);

Generated at Thu Feb 08 02:51:39 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.