diff --git a/dbcon/joblist/joblisttypes.h b/dbcon/joblist/joblisttypes.h index cfd3a72e8..ccdf13228 100644 --- a/dbcon/joblist/joblisttypes.h +++ b/dbcon/joblist/joblisttypes.h @@ -83,8 +83,11 @@ const uint16_t NULL_UINT16 = USMALLINTNULL; const uint32_t NULL_UINT32 = UINTNULL; const uint64_t NULL_UINT64 = UBIGINTNULL; -const uint64_t BINARYEMPTYROW = UBIGINTEMPTYROW; -const uint64_t BINARYNULL = UBIGINTNULL; +const uint64_t BINARYNULLVALUELOW = 0ULL; +const uint64_t BINARYNULLVALUEHIGH = 0x8000000000000000ULL; +const uint64_t BINARYEMPTYVALUELOW = 1ULL; +const uint64_t BINARYEMPTYVALUEHIGH = 0x8000000000000000ULL; +const uint64_t BINARYEMPTYROW = 0ULL; const std::string CPNULLSTRMARK("_CpNuLl_"); const std::string CPSTRNOTFOUND("_CpNoTf_"); diff --git a/dbcon/mysql/ha_mcs_impl.cpp b/dbcon/mysql/ha_mcs_impl.cpp index ea23b3f44..135c5edd9 100644 --- a/dbcon/mysql/ha_mcs_impl.cpp +++ b/dbcon/mysql/ha_mcs_impl.cpp @@ -805,36 +805,21 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, bool h case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { - // WIP MCOL-641 - if (row.getPrecision(s) > 18) + if (colType.colWidth == 16) { // unset null bit first // Might be redundant if ((*f)->null_ptr) *(*f)->null_ptr &= ~(*f)->null_bit; - uint128_t* udec; int128_t* dec; - // We won't have more than 38 digits + sign + dp - // Make this precision based - char buf[41]; + // We won't have more than [+-][0][.] + up to 38 digits + char buf[utils::MAXLENGTH16BYTES]; - // This C-style cast doesn't look appropriate. - // Is there a way to use decltype instead of if? - if (colType.colDataType == CalpontSystemCatalog::DECIMAL) - { - dec = row.getBinaryField(s); - dataconvert::DataConvert::decimalToString(dec, - (unsigned)colType.scale, buf, - sizeof(buf), colType.colDataType); - } - else - { - udec = row.getBinaryField(s); - dataconvert::DataConvert::decimalToString(udec, - (unsigned)colType.scale, buf, - sizeof(buf), colType.colDataType); - } + dec = row.getBinaryField(s); + dataconvert::DataConvert::decimalToString(dec, + (unsigned)colType.scale, buf, + sizeof(buf), colType.colDataType); Field_new_decimal* f2 = (Field_new_decimal*)*f; f2->store(buf, strlen(buf), f2->charset()); diff --git a/primitives/linux-port/column.cpp b/primitives/linux-port/column.cpp index 463764cd0..b8acd52d9 100644 --- a/primitives/linux-port/column.cpp +++ b/primitives/linux-port/column.cpp @@ -40,6 +40,7 @@ using namespace boost; #include "stats.h" #include "primproc.h" #include "dataconvert.h" +#include "widedecimalutils.h" using namespace logging; using namespace dbbc; using namespace primitives; @@ -277,16 +278,17 @@ template<> inline bool isEmptyVal<32>(uint8_t type, const uint8_t* ival) // For BINARY { const uint64_t* val = reinterpret_cast(ival); - return ((val[0] == joblist::BINARYEMPTYROW) && (val[1] == joblist::BINARYEMPTYROW) - && (val[2] == joblist::BINARYEMPTYROW) && (val[3] == joblist::BINARYEMPTYROW)); + return ((val[0] == joblist::BINARYEMPTYVALUELOW) + && (val[1] == joblist::BINARYNULLVALUELOW) + && (val[2] == joblist::BINARYNULLVALUELOW) + && (val[3] == joblist::BINARYEMPTYVALUEHIGH)); } template<> inline bool isEmptyVal<16>(uint8_t type, const uint8_t* ival) // For BINARY { - const uint64_t* val = reinterpret_cast(ival); - return ((val[0] == joblist::BINARYEMPTYROW) && (val[1] == joblist::BINARYEMPTYROW)); - + const int128_t* val = reinterpret_cast(ival); + return utils::isWideDecimalEmptyValue (*val); } template<> @@ -410,19 +412,22 @@ inline bool isEmptyVal<1>(uint8_t type, const uint8_t* ival) template inline bool isNullVal(uint8_t type, const uint8_t* val8); +// WIP This method only works for wide DECIMAL so far. template<> inline bool isNullVal<16>(uint8_t type, const uint8_t* ival) // For BINARY { - const uint64_t* val = reinterpret_cast(ival); - return ((val[0] == joblist::BINARYNULL) && (val[1] == joblist::BINARYEMPTYROW)); + const int128_t* val = reinterpret_cast(ival); + return utils::isWideDecimalNullValue (*val); } template<> inline bool isNullVal<32>(uint8_t type, const uint8_t* ival) // For BINARY { const uint64_t* val = reinterpret_cast(ival); - return ((val[0] == joblist::BINARYNULL) && (val[1] == joblist::BINARYEMPTYROW) - && (val[2] == joblist::BINARYEMPTYROW) && (val[3] == joblist::BINARYEMPTYROW)); + return ((val[0] == joblist::BINARYNULLVALUELOW) + && (val[1] == joblist::BINARYNULLVALUELOW) + && (val[2] == joblist::BINARYNULLVALUELOW) + && (val[3] == joblist::BINARYNULLVALUEHIGH)); } template<> diff --git a/primitives/primproc/columncommand.cpp b/primitives/primproc/columncommand.cpp index d2145807c..8a50fd3e0 100644 --- a/primitives/primproc/columncommand.cpp +++ b/primitives/primproc/columncommand.cpp @@ -40,6 +40,7 @@ using namespace std; #include "primitiveserver.h" #include "primproc.h" #include "stats.h" +#include "widedecimalutils.h" using namespace messageqcpp; using namespace rowgroup; @@ -1062,9 +1063,8 @@ const uint64_t ColumnCommand::getEmptyRowValue( const CSCDataType dataType, cons void ColumnCommand::getEmptyRowValue(const CSCDataType dataType, const int width, messageqcpp::ByteStream::hexbyte* space) const { - uint64_t *ptr = reinterpret_cast(space); - ptr[0] = joblist::BINARYEMPTYROW; - ptr[1] = joblist::BINARYEMPTYROW; + int128_t *val = reinterpret_cast(space); + utils::setWideDecimalEMptyValue(*val); } void ColumnCommand::getLBIDList(uint32_t loopCount, vector* lbids) diff --git a/utils/common/columnwidth.h b/utils/common/columnwidth.h index b16086494..7d5865514 100644 --- a/utils/common/columnwidth.h +++ b/utils/common/columnwidth.h @@ -18,11 +18,12 @@ #ifndef UTILS_COLWIDTH_H #define UTILS_COLWIDTH_H -#define MAXLEGACYWIDTH 8 -#define MAXCOLUMNWIDTH 16 namespace utils { + const uint8_t MAXLEGACYWIDTH = 8ULL; + const uint8_t MAXCOLUMNWIDTH = 16ULL; + inline bool isWide(uint8_t width) { return width > MAXLEGACYWIDTH; diff --git a/utils/common/nullvaluemanip.cpp b/utils/common/nullvaluemanip.cpp index 63b0c8693..adb8e108d 100644 --- a/utils/common/nullvaluemanip.cpp +++ b/utils/common/nullvaluemanip.cpp @@ -127,7 +127,7 @@ uint64_t getNullValue(CalpontSystemCatalog::ColDataType t, uint32_t colWidth) return joblist::UBIGINTNULL; case CalpontSystemCatalog::BINARY: - return joblist::BINARYNULL; + return joblist::BINARYNULLVALUELOW; case CalpontSystemCatalog::VARBINARY: default: @@ -201,7 +201,6 @@ int64_t getSignedNullValue(CalpontSystemCatalog::ColDataType t, uint32_t colWidt default: throw logic_error("getSignedNullValue() Can't return the NULL string"); } - break; } @@ -219,8 +218,14 @@ int64_t getSignedNullValue(CalpontSystemCatalog::ColDataType t, uint32_t colWidt case 4 : return (int64_t) ((int32_t) joblist::INTNULL); - default: + case 8: return joblist::BIGINTNULL; + + default: + ostringstream os; + os << "getSignedNullValue(): got bad column width (" << t << + "). Width=" << colWidth << endl; + throw logic_error(os.str()); } break; @@ -243,7 +248,7 @@ int64_t getSignedNullValue(CalpontSystemCatalog::ColDataType t, uint32_t colWidt return (int64_t)joblist::LONGDOUBLENULL; case CalpontSystemCatalog::BINARY: - return (int64_t)joblist::BINARYNULL; + return (int64_t)joblist::BINARYNULLVALUELOW; case CalpontSystemCatalog::VARBINARY: default: diff --git a/utils/common/widedecimalutils.h b/utils/common/widedecimalutils.h index be0c742d9..67302f2bd 100644 --- a/utils/common/widedecimalutils.h +++ b/utils/common/widedecimalutils.h @@ -18,30 +18,58 @@ #ifndef WIDE_DECIMAL_UTILS_H #define WIDE_DECIMAL_UTILS_H -namespace utils -{ - using int128_t = __int128; using uint128_t = unsigned __int128; -const uint64_t BINARYNULLVALUELOW = 0ULL; -const uint64_t BINARYNULLVALUEHIGH = 0x8000000000000000ULL; -const uint64_t BINARYEMPTYVALUELOW = 1ULL; -const uint64_t BINARYEMPTYVALUEHIGH = 0x8000000000000000ULL; +namespace utils +{ + const uint64_t BINARYNULLVALUELOW = 0ULL; + const uint64_t BINARYNULLVALUEHIGH = 0x8000000000000000ULL; + const uint64_t BINARYEMPTYVALUELOW = 1ULL; + const uint64_t BINARYEMPTYVALUEHIGH = 0x8000000000000000ULL; + const uint8_t MAXLENGTH16BYTES = 42; - inline bool isWideDecimalNullValue(const int128_t val) + inline bool isWideDecimalNullValue(const int128_t& val) { const uint64_t* ptr = reinterpret_cast(&val); return (ptr[0] == BINARYNULLVALUELOW && ptr[1] == BINARYNULLVALUEHIGH); } - inline bool isWideDecimalEmptyValue(const int128_t val) + inline bool isWideDecimalEmptyValue(const int128_t& val) { const uint64_t* ptr = reinterpret_cast(&val); return (ptr[0] == BINARYEMPTYVALUELOW && ptr[1] == BINARYEMPTYVALUEHIGH); } - inline void int128Max(int128_t& val) + inline void setWideDecimalNullValue(int128_t& val) + { + uint64_t* ptr = reinterpret_cast(&val); + ptr[0] = BINARYNULLVALUELOW; + ptr[1] = BINARYNULLVALUEHIGH; + } + + inline void setWideDecimalEMptyValue(int128_t& val) + { + uint64_t* ptr = reinterpret_cast(&val); + ptr[0] = BINARYEMPTYVALUELOW; + ptr[1] = BINARYEMPTYVALUEHIGH; + } + + inline void setWideDecimalNullValue(int128_t* val) + { + uint64_t* ptr = reinterpret_cast(val); + ptr[0] = BINARYNULLVALUELOW; + ptr[1] = BINARYNULLVALUEHIGH; + } + + inline void setWideDecimalEMptyValue(int128_t* val) + { + uint64_t* ptr = reinterpret_cast(val); + ptr[0] = BINARYEMPTYVALUELOW; + ptr[1] = BINARYEMPTYVALUEHIGH; + } + + inline void int128Max(int128_t& val) { uint64_t* ptr = reinterpret_cast(&val); ptr[0] = 0xFFFFFFFFFFFFFFFF; @@ -61,7 +89,6 @@ const uint64_t BINARYEMPTYVALUEHIGH = 0x8000000000000000ULL; ptr[0] = 0xFFFFFFFFFFFFFFFF; ptr[1] = 0xFFFFFFFFFFFFFFFF; } - } #endif // WIDE_DECIMAL_UTILS_H diff --git a/utils/dataconvert/dataconvert.cpp b/utils/dataconvert/dataconvert.cpp index beaf5a7dd..42f4295fa 100644 --- a/utils/dataconvert/dataconvert.cpp +++ b/utils/dataconvert/dataconvert.cpp @@ -102,6 +102,29 @@ const string columnstore_big_precision[20] = "99999999999999999999999999999999999999" }; +const uint64_t columnstore_pow_10[20] = +{ + 1ULL, + 10ULL, + 100ULL, + 1000ULL, + 10000ULL, + 100000ULL, + 1000000ULL, + 10000000ULL, + 100000000ULL, + 1000000000ULL, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; template bool from_string(T& t, const std::string& s, std::ios_base & (*f)(std::ios_base&)) { @@ -1226,32 +1249,37 @@ bool stringToTimestampStruct(const string& data, TimeStamp& timeStamp, const str } -// WIP MCOL-641 -template -size_t DataConvert::writeIntPart(T* dec, char* p, +size_t DataConvert::writeIntPart(int128_t* dec, char* p, const uint16_t buflen, - const uint8_t scale) //don't need this + const uint8_t scale) { - T intPart = *dec; + int128_t intPart = *dec; if (scale) { - //TODO Use dictionary to produce divisor - // instead of a loop - for (size_t i = 0; i < scale; i++) - intPart /= 10; + uint8_t maxPowOf10 = sizeof(columnstore_pow_10)/sizeof(columnstore_pow_10[0])-1; + switch (scale/maxPowOf10) + { + case(2): + intPart /= columnstore_pow_10[maxPowOf10]; + intPart /= columnstore_pow_10[maxPowOf10]; + break; + case(1): + intPart /= columnstore_pow_10[maxPowOf10]; + case(0): + intPart /= columnstore_pow_10[scale%maxPowOf10]; + } } - // optimize for less then uint64_t values uint64_t div = 10000000000000000000ULL; - T high = intPart; - T low; + int128_t high = intPart; + int128_t low; low = high % div; high /= div; - T mid; + int128_t mid; mid = high % div; high /= div; - // pod[0] is high 8 byte, pod[1] is low + // pod[0] is low 8 byte, pod[1] is high uint64_t* high_pod = reinterpret_cast(&high); uint64_t* mid_pod = reinterpret_cast(&mid); uint64_t* low_pod = reinterpret_cast(&low); @@ -1287,17 +1315,29 @@ size_t DataConvert::writeIntPart(T* dec, char* p, return p-original_p; } -template -size_t DataConvert::writeFractionalPart(T* dec, char* p, +size_t DataConvert::writeFractionalPart(int128_t* dec, char* p, const uint16_t buflen, const uint8_t scale) { - //TODO Use dictionary instead of multiplication. - T scaleDivisor = 10; - for (size_t i = 1; i < scale; i++) - scaleDivisor *= 10; + int128_t scaleDivisor = 1; + + uint8_t maxPowOf10 = sizeof(columnstore_pow_10)/sizeof(columnstore_pow_10[0])-1; + switch (scale/maxPowOf10) + { + case(2): + scaleDivisor *= columnstore_pow_10[maxPowOf10]; + scaleDivisor *= columnstore_pow_10[maxPowOf10]; + break; + case(1): + scaleDivisor *= columnstore_pow_10[maxPowOf10]; + case(0): + scaleDivisor *= columnstore_pow_10[scale%maxPowOf10]; + } + + //for (size_t i = 1; i < scale; i++) + // scaleDivisor *= 10; - T fractionalPart = *dec % scaleDivisor; + int128_t fractionalPart = *dec % scaleDivisor; // divide by the base untill we have non-zero quotinent size_t written = 0; scaleDivisor /= 10; @@ -1319,38 +1359,24 @@ size_t DataConvert::writeFractionalPart(T* dec, char* p, return scale; } -template -void DataConvert::toString(T* dec, uint8_t scale, +void DataConvert::toString(int128_t* dec, uint8_t scale, char *p, unsigned int buflen) { char* original_p = p; size_t written = 0; - // Early return for NULL value - int128_t sign = 0; - // WIP use constants here - // WIP Treat both magics here - uint64_t* signPod = reinterpret_cast(&sign); - signPod[1] = utils::BINARYNULLVALUEHIGH; - - if (*dec == sign) + // Raise exception on NULL and EMPTY value + if (utils::isWideDecimalNullValue(*dec) || utils::isWideDecimalEmptyValue(*dec)) { - *p++ = '0'; - if (scale) - { - *p++ = '.'; - while (scale-- > 0) - *p++ = '0'; - } - return; + throw QueryDataExcept("toString() char buffer overflow.", formatErr); } - if (*dec < static_cast(0)) + if (*dec < static_cast(0)) { *p++ = '-'; *dec *= -1; } - written = writeIntPart(dec, p, buflen, scale); + written = writeIntPart(dec, p, buflen, scale); p += written; if (scale) @@ -1365,10 +1391,6 @@ void DataConvert::toString(T* dec, uint8_t scale, } } -template -void DataConvert::toString(int128_t* dec, uint8_t scale, - char *p, unsigned int buflen); - // WIP MCOL-641 void atoi128(const std::string& arg, int128_t& res) { @@ -1397,25 +1419,14 @@ void atoi128(const std::string& arg, uint128_t& res) } } -// WIP MCOL-641 -// Doesn't work for -0.042 -template -void DataConvert::decimalToString(T* valuePtr, +void DataConvert::decimalToString(int128_t* valuePtr, uint8_t scale, char* buf, unsigned int buflen, cscDataType colDataType) // We don't need the last one { - - toString(valuePtr, scale, buf, buflen); + toString(valuePtr, scale, buf, buflen); } -// Explicit instantiation -template -void DataConvert::decimalToString(int128_t* value, uint8_t scale, - char* buf, unsigned int buflen, cscDataType colDataType); -template -void DataConvert::decimalToString(uint128_t* value, uint8_t scale, - char* buf, unsigned int buflen, cscDataType colDataType); boost::any DataConvert::convertColumnData(const CalpontSystemCatalog::ColType& colType, diff --git a/utils/dataconvert/dataconvert.h b/utils/dataconvert/dataconvert.h index 78e3b8639..822d36e52 100644 --- a/utils/dataconvert/dataconvert.h +++ b/utils/dataconvert/dataconvert.h @@ -1041,17 +1041,13 @@ public: EXPORT static bool isNullData(execplan::ColumnResult* cr, int rownum, execplan::CalpontSystemCatalog::ColType colType); static inline std::string decimalToString(int64_t value, uint8_t scale, cscDataType colDataType); static inline void decimalToString(int64_t value, uint8_t scale, char* buf, unsigned int buflen, cscDataType colDataType); - template - EXPORT static void decimalToString(T* value, uint8_t scale, char* buf, unsigned int buflen, cscDataType colDataType); + static void decimalToString(int128_t* value, uint8_t scale, char* buf, unsigned int buflen, cscDataType colDataType); - template - static void toString(T* dec, uint8_t scale, char* p, unsigned int buflen); - template - static size_t writeIntPart(T* dec, char* p, const uint16_t buflen, + static void toString(int128_t* dec, uint8_t scale, char* p, unsigned int buflen); + static size_t writeIntPart(int128_t* dec, char* p, const uint16_t buflen, + const uint8_t scale); + static size_t writeFractionalPart(int128_t* dec, char* p, const uint16_t buflen, const uint8_t scale); - template - static size_t writeFractionalPart(T* dec, char* p, - const uint16_t buflen, const uint8_t scale); static inline void int128Max(int128_t& i) { diff --git a/utils/funcexp/funcexp.cpp b/utils/funcexp/funcexp.cpp index 854fbd8ed..d20382d30 100644 --- a/utils/funcexp/funcexp.cpp +++ b/utils/funcexp/funcexp.cpp @@ -477,11 +477,11 @@ void FuncExp::evaluate(rowgroup::Row& row, std::vector& expressi { // WIP make this a separate function w and w/o overflow check if (expression[i]->resultType().colDataType == execplan::CalpontSystemCatalog::DECIMAL) - row.setBinaryField_offset(reinterpret_cast(&val.__v.__s128), + row.setBinaryField_offset(&val.__v.__s128, expression[i]->resultType().colWidth, row.getOffset(expression[i]->outputIndex())); else - row.setBinaryField_offset(reinterpret_cast(&val.__v.__u128), + row.setBinaryField_offset(&val.__v.__u128, expression[i]->resultType().colWidth, row.getOffset(expression[i]->outputIndex())); } diff --git a/utils/rowgroup/rowaggregation.cpp b/utils/rowgroup/rowaggregation.cpp index da216c177..ce52b8d2e 100755 --- a/utils/rowgroup/rowaggregation.cpp +++ b/utils/rowgroup/rowaggregation.cpp @@ -53,6 +53,7 @@ #include "vlarray.h" #include "collation.h" +#include "widedecimalutils.h" //..comment out NDEBUG to enable assertions, uncomment NDEBUG to disable //#define NDEBUG @@ -222,19 +223,8 @@ inline string getStringNullValue() return joblist::CPNULLSTRMARK; } -inline uint64_t getBinaryNullValue() -{ - return joblist::BINARYNULL; } -inline uint64_t getBinaryEmptyValue() -{ - return joblist::BINARYEMPTYROW; -} - -} - - namespace rowgroup { const std::string typeStr(""); @@ -1176,14 +1166,11 @@ void RowAggregation::makeAggFieldsNull(Row& row) } else { - // WIP This is only 1st part of the value - uint64_t nullValue = getBinaryNullValue(); - uint64_t emptyValue = getBinaryEmptyValue(); + int128_t nullValue = 0; + utils::setWideDecimalNullValue(nullValue); uint32_t offset = row.getOffset(colOut); row.setBinaryField_offset(&nullValue, sizeof(nullValue), offset); - row.setBinaryField_offset(&emptyValue, sizeof(nullValue), - offset+sizeof(nullValue)); } break; } diff --git a/utils/rowgroup/rowgroup-tests.cpp b/utils/rowgroup/rowgroup-tests.cpp index a18f8d38b..8fbbe22fc 100644 --- a/utils/rowgroup/rowgroup-tests.cpp +++ b/utils/rowgroup/rowgroup-tests.cpp @@ -91,15 +91,9 @@ class RowDecimalTest : public ::testing::Test { int128_t nullValue = 0; int128_t bigValue = 0; uint64_t* uint128_pod = reinterpret_cast(&nullValue); - uint128_pod[0] = joblist::BINARYNULL; - uint128_pod[1] = joblist::BINARYEMPTYROW; + uint128_pod[0] = joblist::UBIGINTNULL; + uint128_pod[1] = joblist::UBIGINTEMPTYROW; bigValue = -static_cast(0xFFFFFFFF)*0xFFFFFFFFFFFFFFFF; - //char buf[utils::precisionByWidth(16)+3]; - //memset(&buf[0], 0, sizeof(buf)); - //int scale1 = 3; - //dataconvert::DataConvert::decimalToString(&bigValue, scale1, buf, - // utils::precisionByWidth(sizeof(bigValue))+3,types[0]); - //std::cout << buf << std::endl; sValueVector.push_back(nullValue); sValueVector.push_back(-42); sValueVector.push_back(bigValue); @@ -136,8 +130,6 @@ class RowDecimalTest : public ::testing::Test { s64ValueVector.push_back(0x81); s64ValueVector.push_back(joblist::BIGINTNULL-1); - //r.initToNull(); - //r.nextRow(rowSize); for(size_t i = 0; i < sValueVector.size(); i++) { r.setBinaryField_offset(&sValueVector[i], sizeof(sValueVector[0]), offsets[0]); diff --git a/utils/rowgroup/rowgroup.cpp b/utils/rowgroup/rowgroup.cpp index 448c8ad5c..3fe84f92f 100644 --- a/utils/rowgroup/rowgroup.cpp +++ b/utils/rowgroup/rowgroup.cpp @@ -44,6 +44,7 @@ using namespace execplan; #include "rowgroup.h" #include "dataconvert.h" #include "columnwidth.h" +#include "widedecimalutils.h" #include "collation.h" @@ -850,9 +851,7 @@ void Row::initToNull() case 16 : { - uint64_t *dec = reinterpret_cast(&data[offsets[i]]); - dec[0] = joblist::BINARYNULL; - dec[1] = joblist::BINARYEMPTYROW; + utils::setWideDecimalNullValue(reinterpret_cast(data[offsets[i]])); break; } default: @@ -881,9 +880,7 @@ void Row::initToNull() break; case CalpontSystemCatalog::BINARY: { - uint64_t *dec = reinterpret_cast(&data[offsets[i]]); - dec[0] = joblist::BINARYNULL; - dec[1] = joblist::BINARYEMPTYROW; + utils::setWideDecimalNullValue(reinterpret_cast(data[offsets[i]])); } break; @@ -915,11 +912,11 @@ inline bool Row::isNullValue_offset( uint32_t offset) const { - const int64_t *intPtr = reinterpret_cast(&data[offset]); - return ((intPtr[0] == static_cast(joblist::BINARYNULL)) && - (intPtr[1] == static_cast(joblist::BINARYEMPTYROW)) && - (intPtr[2] == static_cast(joblist::BINARYEMPTYROW)) && - (intPtr[3] == static_cast(joblist::BINARYEMPTYROW))); + const uint64_t *intPtr = reinterpret_cast(&data[offset]); + return ((intPtr[0] == static_cast(utils::BINARYNULLVALUELOW)) && + (intPtr[1] == static_cast(utils::BINARYNULLVALUELOW)) && + (intPtr[2] == static_cast(utils::BINARYNULLVALUELOW)) && + (intPtr[3] == static_cast(utils::BINARYEMPTYVALUEHIGH))); } template<> @@ -927,9 +924,8 @@ inline bool Row::isNullValue_offset( uint32_t offset) const { - const int64_t *intPtr = reinterpret_cast(&data[offset]); - return ((intPtr[0] == static_cast(joblist::BINARYNULL)) - && (intPtr[1] == static_cast(joblist::BINARYEMPTYROW))); + const int128_t *intPtr = reinterpret_cast(&data[offset]); + return utils::isWideDecimalNullValue (*intPtr); } template<> @@ -937,9 +933,8 @@ inline bool Row::isNullValue_offset( uint32_t offset) const { - const int64_t *intPtr = reinterpret_cast(&data[offset]); - return ((intPtr[0] == static_cast(joblist::BINARYNULL)) - && (intPtr[1] == static_cast(joblist::BINARYEMPTYROW))); + const int128_t *intPtr = reinterpret_cast(&data[offset]); + return utils::isWideDecimalNullValue (*intPtr); } template<> @@ -1059,8 +1054,7 @@ bool Row::isNullValue(uint32_t colIndex) const case CalpontSystemCatalog::UDECIMAL: { // WIP MCOL-641 Allmighty hack. - int32_t width = getColumnWidth(colIndex); - switch (width) + switch (getColumnWidth(colIndex)) { // MCOL-641 case 16: diff --git a/utils/rowgroup/rowgroup.h b/utils/rowgroup/rowgroup.h index 831fa6d0b..9fa0b98fc 100644 --- a/utils/rowgroup/rowgroup.h +++ b/utils/rowgroup/rowgroup.h @@ -814,22 +814,27 @@ inline uint32_t Row::getStringLength(uint32_t colIndex) const memcpy(&data[offset], strdata, length); }*/ -// WIP MCOL-641. This method can be applied to uint8_t* buffers. +// MCOL-641. This method can be applied to uint8_t* buffers. template inline void Row::setBinaryField(T* value, uint32_t width, uint32_t colIndex) { memcpy(&data[offsets[colIndex]], value, width); } -// WIP MCOL-641. This method !cannot! be applied to uint8_t* buffers. +// MCOL-641. This method !cannot! be applied to uint8_t* buffers. template inline void Row::setBinaryField_offset(T* value, uint32_t width, uint32_t offset) { - // WIP Compare performance. - //memcpy(&data[offset], value, width); + // WIP Compare performance. *reinterpret_cast(&data[offset]) = *value; } +template<> +inline void Row::setBinaryField_offset(uint8_t* value, uint32_t width, uint32_t offset) +{ + memcpy(&data[offset], value, width); +} + inline void Row::setStringField(const uint8_t* strdata, uint32_t length, uint32_t colIndex) { uint64_t offset; diff --git a/writeengine/server/we_dmlcommandproc.cpp b/writeengine/server/we_dmlcommandproc.cpp index 2eaa1895d..83e75588d 100644 --- a/writeengine/server/we_dmlcommandproc.cpp +++ b/writeengine/server/we_dmlcommandproc.cpp @@ -51,8 +51,8 @@ using namespace BRM; #include "cacheutils.h" #include "IDBDataFile.h" #include "IDBPolicy.h" - #include "checks.h" +#include "columnwidth.h" namespace WriteEngine { @@ -3000,21 +3000,16 @@ uint8_t WE_DMLCommandProc::processUpdate(messageqcpp::ByteStream& bs, case CalpontSystemCatalog::UDECIMAL: { // WIP MCOL-641 - // decimal width > 8 cannot be stored in an integer - if (fetchColColwidths[fetchColPos] > 8) + if (fetchColColwidths[fetchColPos] == 16) { int128_t* dec; - char buf[41]; + char buf[utils::MAXLENGTH16BYTES]; dec = row.getBinaryField(fetchColPos); - dataconvert::DataConvert::decimalToString(dec, + dataconvert::DataConvert::decimalToString(dec, (unsigned)fetchColScales[fetchColPos], buf, sizeof(buf), fetchColTypes[fetchColPos]); - value = buf; - - //value = row.getStringField(fetchColPos); - //unsigned i = strlen(value.c_str()); - //value = value.substr(0, i); + value.assign(buf); break; } @@ -3368,22 +3363,17 @@ uint8_t WE_DMLCommandProc::processUpdate(messageqcpp::ByteStream& bs, case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { - // WIP MCOL-641 - // decimal width > 8 cannot be stored in an integer - if (fetchColColwidths[fetchColPos] > 8) + if (fetchColColwidths[fetchColPos] == 16) { + // WIP MCOL-641 int128_t* dec; - char buf[41]; + char buf[utils::MAXLENGTH16BYTES]; dec = row.getBinaryField(fetchColPos); - dataconvert::DataConvert::decimalToString(dec, + dataconvert::DataConvert::decimalToString(dec, (unsigned)fetchColScales[fetchColPos], buf, sizeof(buf), fetchColTypes[fetchColPos]); value = buf; - - //value = row.getStringField(fetchColPos); - //unsigned i = strlen(value.c_str()); - //value = value.substr(0, i); break; } diff --git a/writeengine/wrapper/writeengine.cpp b/writeengine/wrapper/writeengine.cpp index f08943a51..7ce12b5a3 100644 --- a/writeengine/wrapper/writeengine.cpp +++ b/writeengine/wrapper/writeengine.cpp @@ -58,6 +58,7 @@ using namespace execplan; #include "MonitorProcMem.h" using namespace idbdatafile; #include "dataconvert.h" +#include "widedecimalutils.h" #ifdef _MSC_VER #define isnan _isnan @@ -3973,11 +3974,16 @@ void WriteEngineWrapper::printInputValue(const ColStructList& colStructList, curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(long long)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); + else if (curTuple.data.type() == typeid(int128_t)) + { + // WIP replace with a single call + char buf[utils::MAXLENGTH16BYTES]; + int128_t val = boost::any_cast(curTuple.data); + dataconvert::DataConvert::toString(&val, 0, buf, utils::MAXLENGTH16BYTES); + curStr.assign(buf); + } else if (curTuple.data.type() == typeid(double)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); -// else -// if (curTuple.data.type() == typeid(bool)) -// curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(short)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(char))