From 9f41f574daaf19d668b702b8bb005e9e917725bf Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 6 Apr 2021 08:15:18 +0400 Subject: [PATCH] MCOL-4668 PERIOD_DIFF(dec_or_double1,dec_or_double2) is not as in InnoDB --- mtr/basic/r/func_period_diff.result | 40 +++++++ mtr/basic/t/func_period_diff.test | 43 +++++++ utils/funcexp/func_period_diff.cpp | 173 ++++++++-------------------- 3 files changed, 129 insertions(+), 127 deletions(-) create mode 100644 mtr/basic/r/func_period_diff.result create mode 100644 mtr/basic/t/func_period_diff.test diff --git a/mtr/basic/r/func_period_diff.result b/mtr/basic/r/func_period_diff.result new file mode 100644 index 000000000..047e99c9f --- /dev/null +++ b/mtr/basic/r/func_period_diff.result @@ -0,0 +1,40 @@ +# +# MCOL-4668 PERIOD_DIFF(dec_or_double1,dec_or_double2) is not as in InnoDB +# +# Narrow decimal rounding +CREATE TABLE t1 (a DECIMAL(18,1)); +INSERT INTO t1 VALUES (200101.9); +SELECT PERIOD_DIFF(a, 200101) FROM t1; +PERIOD_DIFF(a, 200101) +1 +DROP TABLE t1; +# Wide decimal rounding +CREATE TABLE t1 (a DECIMAL(30,1)); +INSERT INTO t1 VALUES (200101.9); +SELECT PERIOD_DIFF(a, 200101) FROM t1; +PERIOD_DIFF(a, 200101) +1 +DROP TABLE t1; +# Huge narrow decimal +CREATE TABLE t1 (a DECIMAL(18,0)); +INSERT INTO t1 VALUES (999999999999999999); +SELECT a, PERIOD_DIFF(200101,a) FROM t1; +a PERIOD_DIFF(200101,a) +999999999999999999 24012 +DROP TABLE t1; +# Huge wide decimal +CREATE TABLE t1 (a DECIMAL(30,0)); +INSERT INTO t1 VALUES (9223372036854775807); +SELECT a, PERIOD_DIFF(200101,a) FROM t1; +a PERIOD_DIFF(200101,a) +9223372036854775807 24012 +DROP TABLE t1; +# Huge double +CREATE TABLE t1 (a DOUBLE); +INSERT INTO t1 VALUES (9223372036854775807.0-1000); +INSERT INTO t1 VALUES (9223372036854775807.0+1000); +SELECT a, PERIOD_DIFF(200101,a) FROM t1 ORDER BY 2; +a PERIOD_DIFF(200101,a) +9.223372036854775e18 24012 +9.223372036854776e18 24012 +DROP TABLE t1; diff --git a/mtr/basic/t/func_period_diff.test b/mtr/basic/t/func_period_diff.test new file mode 100644 index 000000000..f02a371f0 --- /dev/null +++ b/mtr/basic/t/func_period_diff.test @@ -0,0 +1,43 @@ +--source ../include/have_columnstore.inc +--source ../include/combinations.myisam-columnstore.inc + + +--echo # +--echo # MCOL-4668 PERIOD_DIFF(dec_or_double1,dec_or_double2) is not as in InnoDB +--echo # + +--echo # Narrow decimal rounding + +CREATE TABLE t1 (a DECIMAL(18,1)); +INSERT INTO t1 VALUES (200101.9); +SELECT PERIOD_DIFF(a, 200101) FROM t1; +DROP TABLE t1; + +--echo # Wide decimal rounding + +CREATE TABLE t1 (a DECIMAL(30,1)); +INSERT INTO t1 VALUES (200101.9); +SELECT PERIOD_DIFF(a, 200101) FROM t1; +DROP TABLE t1; + +--echo # Huge narrow decimal + +CREATE TABLE t1 (a DECIMAL(18,0)); +INSERT INTO t1 VALUES (999999999999999999); +SELECT a, PERIOD_DIFF(200101,a) FROM t1; +DROP TABLE t1; + +--echo # Huge wide decimal + +CREATE TABLE t1 (a DECIMAL(30,0)); +INSERT INTO t1 VALUES (9223372036854775807); +SELECT a, PERIOD_DIFF(200101,a) FROM t1; +DROP TABLE t1; + +--echo # Huge double + +CREATE TABLE t1 (a DOUBLE); +INSERT INTO t1 VALUES (9223372036854775807.0-1000); +INSERT INTO t1 VALUES (9223372036854775807.0+1000); +SELECT a, PERIOD_DIFF(200101,a) FROM t1 ORDER BY 2; +DROP TABLE t1; diff --git a/utils/funcexp/func_period_diff.cpp b/utils/funcexp/func_period_diff.cpp index 3f344fd8f..dcf922494 100644 --- a/utils/funcexp/func_period_diff.cpp +++ b/utils/funcexp/func_period_diff.cpp @@ -38,11 +38,11 @@ namespace funcexp { #define YY_PART_YEAR 70 -inline int64_t convert_period_to_month(int64_t period) +inline uint64_t convert_period_to_month(uint64_t period) { - int64_t a, b; + uint64_t a, b; - if (period == 0) + if (period == 0 || period > 999912) return 0L; if ((a = period / 100) < YY_PART_YEAR) @@ -55,144 +55,63 @@ inline int64_t convert_period_to_month(int64_t period) } +int64_t getArgSInt64Val(rowgroup::Row& row, TreeNode *exp, bool& isNull) +{ + switch (exp->resultType().colDataType) + { + case execplan::CalpontSystemCatalog::BIGINT: + case execplan::CalpontSystemCatalog::INT: + case execplan::CalpontSystemCatalog::MEDINT: + case execplan::CalpontSystemCatalog::TINYINT: + case execplan::CalpontSystemCatalog::SMALLINT: + case execplan::CalpontSystemCatalog::DATE: + case execplan::CalpontSystemCatalog::DATETIME: + case execplan::CalpontSystemCatalog::TIMESTAMP: + return exp->getIntVal(row, isNull); + + case execplan::CalpontSystemCatalog::DECIMAL: + case execplan::CalpontSystemCatalog::UDECIMAL: + { + IDB_Decimal d = exp->getDecimalVal(row, isNull); + return d.toSInt64Round(); + } + + case execplan::CalpontSystemCatalog::VARCHAR: + case execplan::CalpontSystemCatalog::CHAR: + case execplan::CalpontSystemCatalog::TEXT: + return atoi(exp->getStrVal(row, isNull).c_str()); + + case execplan::CalpontSystemCatalog::DOUBLE: + case execplan::CalpontSystemCatalog::FLOAT: + { + datatypes::TDouble d(exp->getDoubleVal(row, isNull)); + return d.toMCSSInt64Round(); + } + + default: + isNull = true; + } + return 0; +} + + CalpontSystemCatalog::ColType Func_period_diff::operationType( FunctionParm& fp, CalpontSystemCatalog::ColType& resultType ) { return resultType; } + int64_t Func_period_diff::getIntVal(rowgroup::Row& row, FunctionParm& parm, bool& isNull, CalpontSystemCatalog::ColType& op_ct) { - int64_t period1 = 0; - - switch (parm[0]->data()->resultType().colDataType) - { - case execplan::CalpontSystemCatalog::BIGINT: - case execplan::CalpontSystemCatalog::INT: - case execplan::CalpontSystemCatalog::MEDINT: - case execplan::CalpontSystemCatalog::TINYINT: - case execplan::CalpontSystemCatalog::SMALLINT: - case execplan::CalpontSystemCatalog::DATE: - case execplan::CalpontSystemCatalog::DATETIME: - case execplan::CalpontSystemCatalog::TIMESTAMP: - { - period1 = parm[0]->data()->getIntVal(row, isNull); - break; - } - - case execplan::CalpontSystemCatalog::DECIMAL: - case execplan::CalpontSystemCatalog::UDECIMAL: - { - IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - - if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) - { - int128_t scaleDivisor; - datatypes::getScaleDivisor(scaleDivisor, d.scale); - int128_t tmpval = d.s128Value / scaleDivisor; - - if (tmpval > static_cast(INT64_MAX)) - tmpval = INT64_MAX; - else if (tmpval < static_cast(INT64_MIN)) - tmpval = INT64_MIN; - - period1 = tmpval; - } - else - { - period1 = d.value / pow(10.0, d.scale); - } - break; - } - - case execplan::CalpontSystemCatalog::VARCHAR: - case execplan::CalpontSystemCatalog::CHAR: - case execplan::CalpontSystemCatalog::TEXT: - { - period1 = atoi(parm[0]->data()->getStrVal(row, isNull).c_str()); - break; - } - - case execplan::CalpontSystemCatalog::DOUBLE: - case execplan::CalpontSystemCatalog::FLOAT: - { - period1 = (int64_t) parm[0]->data()->getDoubleVal(row, isNull); - break; - } - - default: - { - isNull = true; - } - } + uint64_t period1 = (uint64_t) getArgSInt64Val(row, parm[0]->data(), isNull); if (isNull) return 0; - int64_t period2 = 0; - - switch (parm[1]->data()->resultType().colDataType) - { - case execplan::CalpontSystemCatalog::BIGINT: - case execplan::CalpontSystemCatalog::INT: - case execplan::CalpontSystemCatalog::MEDINT: - case execplan::CalpontSystemCatalog::TINYINT: - case execplan::CalpontSystemCatalog::SMALLINT: - case execplan::CalpontSystemCatalog::DATE: - case execplan::CalpontSystemCatalog::DATETIME: - case execplan::CalpontSystemCatalog::TIMESTAMP: - { - period2 = parm[1]->data()->getIntVal(row, isNull); - break; - } - - case execplan::CalpontSystemCatalog::DECIMAL: - case execplan::CalpontSystemCatalog::UDECIMAL: - { - IDB_Decimal d = parm[1]->data()->getDecimalVal(row, isNull); - - if (parm[1]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) - { - int128_t scaleDivisor; - datatypes::getScaleDivisor(scaleDivisor, d.scale); - int128_t tmpval = d.s128Value / scaleDivisor; - - if (tmpval > static_cast(INT64_MAX)) - tmpval = INT64_MAX; - else if (tmpval < static_cast(INT64_MIN)) - tmpval = INT64_MIN; - - period2 = tmpval; - } - else - { - period2 = d.value / pow(10.0, d.scale); - } - break; - } - - case execplan::CalpontSystemCatalog::VARCHAR: - case execplan::CalpontSystemCatalog::CHAR: - case execplan::CalpontSystemCatalog::TEXT: - { - period2 = atoi(parm[1]->data()->getStrVal(row, isNull).c_str()); - break; - } - - case execplan::CalpontSystemCatalog::DOUBLE: - case execplan::CalpontSystemCatalog::FLOAT: - { - period2 = (int64_t) parm[1]->data()->getDoubleVal(row, isNull); - break; - } - - default: - { - isNull = true; - } - } + uint64_t period2 = (uint64_t) getArgSInt64Val(row, parm[1]->data(), isNull); if (isNull) return 0;