From 340a90fc8d76db7ecefb38c8b2afae489efb785a Mon Sep 17 00:00:00 2001 From: Gagan Goel Date: Tue, 7 Dec 2021 16:09:34 -0500 Subject: [PATCH] MCOL-4874 Crossengine JOIN involving a ColumnStore table and a wide decimal column in a non-ColumnStore table throws an exception. ROW::getSignedNullValue() method does not support wide decimal fields yet. To fix this exception, we remove the call to this method from CrossEngineStep::setField(). --- dbcon/joblist/crossenginestep.cpp | 62 +++++++++++-------- dbcon/joblist/crossenginestep.h | 5 +- .../columnstore/bugfixes/mcol-4874.result | 23 +++++++ .../columnstore/bugfixes/mcol-4874.test | 57 +++++++++++++++++ 4 files changed, 118 insertions(+), 29 deletions(-) create mode 100644 mysql-test/columnstore/bugfixes/mcol-4874.result create mode 100644 mysql-test/columnstore/bugfixes/mcol-4874.test diff --git a/dbcon/joblist/crossenginestep.cpp b/dbcon/joblist/crossenginestep.cpp index 0929d5b94..1722c89d8 100644 --- a/dbcon/joblist/crossenginestep.cpp +++ b/dbcon/joblist/crossenginestep.cpp @@ -195,10 +195,17 @@ void CrossEngineStep::setField(int i, const char* value, unsigned long length, M ct.colDataType = colType; ct.colWidth = row.getColumnWidth(i); - if (colType == CalpontSystemCatalog::DECIMAL) + if (colType == CalpontSystemCatalog::DECIMAL || + colType == CalpontSystemCatalog::UDECIMAL) { ct.scale = field->decimals; ct.precision = field->length; + + if (ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + row.setInt128Field(convertValueNum(value, ct), i); + return; + } } else { @@ -206,7 +213,7 @@ void CrossEngineStep::setField(int i, const char* value, unsigned long length, M ct.precision = row.getPrecision(i); } - row.setIntField(convertValueNum(value, ct, row.getSignedNullValue(i)), i); + row.setIntField(convertValueNum(value, ct), i); } } @@ -229,29 +236,21 @@ inline void CrossEngineStep::addRow(RGData& data) // simplified version of convertValueNum() in jlf_execplantojoblist.cpp. -int64_t CrossEngineStep::convertValueNum( - const char* str, const CalpontSystemCatalog::ColType& ct, int64_t nullValue) +template +T CrossEngineStep::convertValueNum( + const char* str, const CalpontSystemCatalog::ColType& ct) { - // return value - int64_t rv = nullValue; - - // null value - if (str == NULL) - return rv; - - // convertColumnData(execplan::CalpontSystemCatalog::ColType colType, - // const std::string& dataOrig, - // bool& pushWarning, - // bool nulFlag, - // bool noRoundup ) + T rv = 0; bool pushWarning = false; - boost::any anyVal = ct.convertColumnData(str, pushWarning, fTimeZone, false, true, false); + bool nullFlag = (str == NULL); + boost::any anyVal = ct.convertColumnData((nullFlag ? "" : str), pushWarning, fTimeZone, nullFlag, true, false); // Out of range values are treated as NULL as discussed during design review. if (pushWarning) - return rv; + { + anyVal = ct.getNullValueForType(); + } - // non-null value switch (ct.colDataType) { case CalpontSystemCatalog::BIT: @@ -259,7 +258,11 @@ int64_t CrossEngineStep::convertValueNum( break; case CalpontSystemCatalog::TINYINT: +#if BOOST_VERSION >= 105200 rv = boost::any_cast(anyVal); +#else + rv = boost::any_cast(anyVal); +#endif break; case CalpontSystemCatalog::UTINYINT: @@ -285,7 +288,11 @@ int64_t CrossEngineStep::convertValueNum( case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: +#ifdef _MSC_VER + rv = boost::any_cast(anyVal); +#else rv = boost::any_cast(anyVal); +#endif break; case CalpontSystemCatalog::BIGINT: @@ -359,20 +366,21 @@ int64_t CrossEngineStep::convertValueNum( case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: - if (ct.colWidth == CalpontSystemCatalog::ONE_BYTE) - rv = boost::any_cast(anyVal); - else if (ct.colWidth == CalpontSystemCatalog::TWO_BYTE) - rv = boost::any_cast(anyVal); - else if (ct.colWidth == CalpontSystemCatalog::FOUR_BYTE) + if (LIKELY(ct.colWidth == datatypes::MAXDECIMALWIDTH)) + rv = boost::any_cast(anyVal); + else if (ct.colWidth == execplan::CalpontSystemCatalog::EIGHT_BYTE) + rv = boost::any_cast(anyVal); + else if (ct.colWidth == execplan::CalpontSystemCatalog::FOUR_BYTE) #ifdef _MSC_VER rv = boost::any_cast(anyVal); #else rv = boost::any_cast(anyVal); #endif - else - rv = boost::any_cast(anyVal); - + else if (ct.colWidth == execplan::CalpontSystemCatalog::TWO_BYTE) + rv = boost::any_cast(anyVal); + else if (ct.colWidth == execplan::CalpontSystemCatalog::ONE_BYTE) + rv = boost::any_cast(anyVal); break; default: diff --git a/dbcon/joblist/crossenginestep.h b/dbcon/joblist/crossenginestep.h index 15b2f6df2..bce3ee048 100644 --- a/dbcon/joblist/crossenginestep.h +++ b/dbcon/joblist/crossenginestep.h @@ -165,8 +165,9 @@ protected: virtual void setField(int, const char*, unsigned long, MYSQL_FIELD*, rowgroup::Row&); inline void addRow(rowgroup::RGData&); //inline void addRow(boost::shared_array&); - virtual int64_t convertValueNum( - const char*, const execplan::CalpontSystemCatalog::ColType&, int64_t); + template + T convertValueNum( + const char*, const execplan::CalpontSystemCatalog::ColType&); virtual void formatMiniStats(); virtual void printCalTrace(); diff --git a/mysql-test/columnstore/bugfixes/mcol-4874.result b/mysql-test/columnstore/bugfixes/mcol-4874.result new file mode 100644 index 000000000..66128a203 --- /dev/null +++ b/mysql-test/columnstore/bugfixes/mcol-4874.result @@ -0,0 +1,23 @@ +DROP DATABASE IF EXISTS `mcol_4874`; +CREATE DATABASE `mcol_4874`; +USE `mcol_4874`; +CREATE USER IF NOT EXISTS'cejuser'@'localhost' IDENTIFIED BY 'Vagrant1|0000001'; +GRANT ALL PRIVILEGES ON *.* TO 'cejuser'@'localhost'; +FLUSH PRIVILEGES; +CREATE TABLE cs1 (a1 INT, b1 BIGINT, c1 INT)ENGINE=COLUMNSTORE; +CREATE TABLE i1 (a2 INT, b2 DECIMAL(37,0), c2 INT); +INSERT INTO cs1 VALUES (1, 11, 10), (1, 0, 11); +INSERT INTO i1 VALUES (1, 11, 100), (1, 0, 11), (1, 12, 101); +SELECT * FROM +( +SELECT a1 AS col1, COUNT(DISTINCT(IF((b1 <> 0), c1, NULL))) FROM cs1 group by col1 +) as t1 +JOIN +( +SELECT a2 AS col1, COUNT(DISTINCT(IF((b2 <> 0), c2, NULL))) FROM i1 GROUP BY col1 +) as t2 +USING (col1); +col1 COUNT(DISTINCT(IF((b1 <> 0), c1, NULL))) COUNT(DISTINCT(IF((b2 <> 0), c2, NULL))) +1 1 2 +DROP USER 'cejuser'@'localhost'; +DROP DATABASE `mcol_4874`; diff --git a/mysql-test/columnstore/bugfixes/mcol-4874.test b/mysql-test/columnstore/bugfixes/mcol-4874.test new file mode 100644 index 000000000..eae680c97 --- /dev/null +++ b/mysql-test/columnstore/bugfixes/mcol-4874.test @@ -0,0 +1,57 @@ +# +# MCOL-4874 Crossengine JOIN involving a ColumnStore table and a +# wide decimal column in a non-ColumnStore table throws an exception. +# + +-- source include/have_innodb.inc +-- source ../include/have_columnstore.inc + +if (!$MASTER_MYPORT) +{ + # Running with --extern + let $MASTER_MYPORT=`SELECT @@port`; +} + +--disable_warnings +DROP DATABASE IF EXISTS `mcol_4874`; +--enable_warnings +CREATE DATABASE `mcol_4874`; +USE `mcol_4874`; + +# +# Enable cross engine join +# Configure user and password in Columnstore.xml file +# +--exec $MCS_MCSSETCONFIG CrossEngineSupport User 'cejuser' +--exec $MCS_MCSSETCONFIG CrossEngineSupport Password 'Vagrant1|0000001' +--exec $MCS_MCSSETCONFIG CrossEngineSupport Port $MASTER_MYPORT +# +# Create corresponding in the server +# +--disable_warnings +CREATE USER IF NOT EXISTS'cejuser'@'localhost' IDENTIFIED BY 'Vagrant1|0000001'; +--enable_warnings +GRANT ALL PRIVILEGES ON *.* TO 'cejuser'@'localhost'; +FLUSH PRIVILEGES; + +CREATE TABLE cs1 (a1 INT, b1 BIGINT, c1 INT)ENGINE=COLUMNSTORE; + +CREATE TABLE i1 (a2 INT, b2 DECIMAL(37,0), c2 INT); + +INSERT INTO cs1 VALUES (1, 11, 10), (1, 0, 11); + +INSERT INTO i1 VALUES (1, 11, 100), (1, 0, 11), (1, 12, 101); + +SELECT * FROM +( + SELECT a1 AS col1, COUNT(DISTINCT(IF((b1 <> 0), c1, NULL))) FROM cs1 group by col1 +) as t1 +JOIN +( + SELECT a2 AS col1, COUNT(DISTINCT(IF((b2 <> 0), c2, NULL))) FROM i1 GROUP BY col1 +) as t2 +USING (col1); + +# Cleanup +DROP USER 'cejuser'@'localhost'; +DROP DATABASE `mcol_4874`;