diff --git a/datatypes/mcs_decimal.h b/datatypes/mcs_decimal.h index 1fac9485e..11d463f95 100644 --- a/datatypes/mcs_decimal.h +++ b/datatypes/mcs_decimal.h @@ -24,6 +24,7 @@ #include "calpontsystemcatalog.h" using int128_t = __int128; +using uint128_t = unsigned __int128; using ColTypeAlias = execplan::CalpontSystemCatalog::ColType; using ColDataTypeAlias = execplan::CalpontSystemCatalog::ColDataType; @@ -32,6 +33,45 @@ namespace execplan struct IDB_Decimal; } +// A class by Fabio Fernandes pulled off of stackoverflow +// Creates a type _xxl that can be used to create 128bit constant values +// Ex: int128_t i128 = 12345678901234567890123456789_xxl +namespace detail_xxl +{ + constexpr uint8_t hexval(char c) + { return c>='a' ? (10+c-'a') : c>='A' ? (10+c-'A') : c-'0'; } + + template + constexpr uint128_t lit_eval() { return V; } + + template + constexpr uint128_t lit_eval() { + static_assert( BASE!=16 || sizeof...(Cs) <= 32-1, "Literal too large for BASE=16"); + static_assert( BASE!=10 || sizeof...(Cs) <= 39-1, "Literal too large for BASE=10"); + static_assert( BASE!=8 || sizeof...(Cs) <= 44-1, "Literal too large for BASE=8"); + static_assert( BASE!=2 || sizeof...(Cs) <= 128-1, "Literal too large for BASE=2"); + return lit_eval(); + } + + template struct LitEval + {static constexpr uint128_t eval() {return lit_eval<10,0,Cs...>();} }; + + template struct LitEval<'0','x',Cs...> + {static constexpr uint128_t eval() {return lit_eval<16,0,Cs...>();} }; + + template struct LitEval<'0','b',Cs...> + {static constexpr uint128_t eval() {return lit_eval<2,0,Cs...>();} }; + + template struct LitEval<'0',Cs...> + {static constexpr uint128_t eval() {return lit_eval<8,0,Cs...>();} }; + + template + constexpr uint128_t operator "" _xxl() {return LitEval::eval();} +} + +template +constexpr uint128_t operator "" _xxl() {return ::detail_xxl::operator "" _xxl();} + namespace datatypes { @@ -65,6 +105,29 @@ const uint64_t mcs_pow_10[20] = 1000000000000000000ULL, 10000000000000000000ULL }; +const uint128_t mcs_pow_10_128[20] = +{ + 10000000000000000000_xxl, + 100000000000000000000_xxl, + 1000000000000000000000_xxl, + 10000000000000000000000_xxl, + 100000000000000000000000_xxl, + 1000000000000000000000000_xxl, + 10000000000000000000000000_xxl, + 100000000000000000000000000_xxl, + 1000000000000000000000000000_xxl, + 10000000000000000000000000000_xxl, + 100000000000000000000000000000_xxl, + 1000000000000000000000000000000_xxl, + 10000000000000000000000000000000_xxl, + 100000000000000000000000000000000_xxl, + 1000000000000000000000000000000000_xxl, + 10000000000000000000000000000000000_xxl, + 100000000000000000000000000000000000_xxl, + 1000000000000000000000000000000000000_xxl, + 10000000000000000000000000000000000000_xxl, + 100000000000000000000000000000000000000_xxl +}; constexpr uint32_t maxPowOf10 = sizeof(mcs_pow_10)/sizeof(mcs_pow_10[0])-1; constexpr int128_t Decimal128Null = int128_t(0x8000000000000000LL) << 64; @@ -75,21 +138,21 @@ constexpr int128_t Decimal128Empty = (int128_t(0x8000000000000000LL) << 64) + 1; @brief The function to produce scale multiplier/divisor for wide decimals. */ -inline void getScaleDivisor(int128_t& divisor, const int8_t scale) +template +inline void getScaleDivisor(T& divisor, const int8_t scale) { - divisor = 1; - switch (scale/maxPowOf10) + if (scale < 0) { - case 2: - divisor *= mcs_pow_10[maxPowOf10]; - divisor *= mcs_pow_10[maxPowOf10]; - break; - case 1: - divisor *= mcs_pow_10[maxPowOf10]; - case 0: - divisor *= mcs_pow_10[scale%maxPowOf10]; - default: - break; + std::string msg = "getScaleDivisor called with negative scale: " + std::to_string(scale); + throw std::invalid_argument(msg); + } + if (scale < 19) + { + divisor = mcs_pow_10[scale]; + } + else + { + divisor = mcs_pow_10_128[scale-18]; } } diff --git a/dbcon/execplan/windowfunctioncolumn.cpp b/dbcon/execplan/windowfunctioncolumn.cpp index d32e41651..21f09aa06 100644 --- a/dbcon/execplan/windowfunctioncolumn.cpp +++ b/dbcon/execplan/windowfunctioncolumn.cpp @@ -361,7 +361,9 @@ bool WindowFunctionColumn::hasWindowFunc() void WindowFunctionColumn::adjustResultType() { - if (fResultType.colDataType == CalpontSystemCatalog::DECIMAL && + if ((fResultType.colDataType == CalpontSystemCatalog::DECIMAL || + fResultType.colDataType == CalpontSystemCatalog::UDECIMAL) + && !boost::iequals(fFunctionName, "COUNT") && !boost::iequals(fFunctionName, "COUNT(*)") && !boost::iequals(fFunctionName, "ROW_NUMBER") && @@ -389,7 +391,8 @@ void WindowFunctionColumn::adjustResultType() boost::iequals(fFunctionName, "AVG") || boost::iequals(fFunctionName, "AVG_DISTINCT")) { - if (fFunctionParms[0]->resultType().colDataType == CalpontSystemCatalog::DECIMAL) + if (fFunctionParms[0]->resultType().colDataType == CalpontSystemCatalog::DECIMAL || + fFunctionParms[0]->resultType().colDataType == CalpontSystemCatalog::UDECIMAL) { fResultType.colWidth = sizeof(int128_t); } diff --git a/utils/rowgroup/rowgroup.h b/utils/rowgroup/rowgroup.h index 31712c2ad..049520b95 100644 --- a/utils/rowgroup/rowgroup.h +++ b/utils/rowgroup/rowgroup.h @@ -380,7 +380,7 @@ public: template inline bool equals(uint64_t val, uint32_t colIndex) const; inline bool equals(long double val, uint32_t colIndex) const; bool equals(const std::string& val, uint32_t colIndex) const; - inline bool equals(int128_t val, uint32_t colIndex) const; + inline bool equals(const int128_t& val, uint32_t colIndex) const; inline double getDoubleField(uint32_t colIndex) const; inline float getFloatField(uint32_t colIndex) const; @@ -709,7 +709,7 @@ inline bool Row::equals(long double val, uint32_t colIndex) const return *((long double*) &data[offsets[colIndex]]) == val; } -inline bool Row::equals(int128_t val, uint32_t colIndex) const +inline bool Row::equals(const int128_t& val, uint32_t colIndex) const { return *((int128_t*) &data[offsets[colIndex]]) == val; } diff --git a/utils/windowfunction/windowfunctiontype.cpp b/utils/windowfunction/windowfunctiontype.cpp index 6356a04bb..7d7329e48 100644 --- a/utils/windowfunction/windowfunctiontype.cpp +++ b/utils/windowfunction/windowfunctiontype.cpp @@ -40,7 +40,6 @@ using namespace logging; using namespace ordering; #include "calpontsystemcatalog.h" -#include "dataconvert.h" // int64_t IDB_pow[19] using namespace execplan; #include "windowfunctionstep.h" @@ -59,6 +58,7 @@ using namespace joblist; #include "wf_stats.h" #include "wf_sum_avg.h" #include "wf_udaf.h" +#include "mcs_decimal.h" namespace windowfunction { @@ -480,7 +480,7 @@ template void WindowFunctionType::implicit2T(uint64_t i, T& t, int s) { int ct = fRow.getColType(i); - int pw = 0; + int64_t divisor = 1; switch (ct) { @@ -491,13 +491,6 @@ void WindowFunctionType::implicit2T(uint64_t i, T& t, int s) case CalpontSystemCatalog::BIGINT: { t = (T) fRow.getIntField(i); - pw = s - fRow.getScale(i); // pw is difference of scales, will be in [-18, 18] - - if (pw > 0) - t *= IDB_pow[pw]; - else if (pw < 0) - t /= IDB_pow[-pw]; - break; } @@ -508,13 +501,6 @@ void WindowFunctionType::implicit2T(uint64_t i, T& t, int s) case CalpontSystemCatalog::UBIGINT: { t = (T) fRow.getUintField(i); - pw = s - fRow.getScale(i); // pw is difference of scales, will be in [-18, 18] - - if (pw > 0) - t *= IDB_pow[pw]; - else if (pw < 0) - t /= IDB_pow[-pw]; - break; } @@ -525,13 +511,6 @@ void WindowFunctionType::implicit2T(uint64_t i, T& t, int s) t = (T) fRow.getIntField(i); else t = (T) fRow.getInt128Field(i); - pw = s - fRow.getScale(i); // pw is difference of scales, will be in [-18, 18] - - if (pw > 0) - t *= IDB_pow[pw]; - else if (pw < 0) - t /= IDB_pow[-pw]; - break; } @@ -542,45 +521,26 @@ void WindowFunctionType::implicit2T(uint64_t i, T& t, int s) t = (T) fRow.getUintField(i); else t = (T) fRow.getUint128Field(i); - pw = s - fRow.getScale(i); // pw is difference of scales, will be in [-18, 18] - - if (pw > 0) - t *= IDB_pow[pw]; - else if (pw < 0) - t /= IDB_pow[-pw]; - break; } case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: { - if (s == 0) - t = (T) fRow.getDoubleField(i); - else - t = (T) (fRow.getDoubleField(i) * IDB_pow[s]); // s is scale, [0, 18] - + t = (T) fRow.getDoubleField(i); break; } case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: { - if (s == 0) - t = (T) fRow.getFloatField(i); - else - t = (T) (fRow.getFloatField(i) * IDB_pow[s]); // s is scale, [0, 18] - + t = (T) fRow.getFloatField(i); break; } case CalpontSystemCatalog::LONGDOUBLE: { - if (s == 0) - t = (T) fRow.getLongDoubleField(i); - else - t = (T) (fRow.getLongDoubleField(i) * IDB_pow[s]); // s is scale, [0, 18] - + t = (T) fRow.getLongDoubleField(i); break; } @@ -596,6 +556,15 @@ void WindowFunctionType::implicit2T(uint64_t i, T& t, int s) break; } } + + s -= fRow.getScale(i); // we scale only the difference of scales + datatypes::getScaleDivisor(divisor, abs(s)); + if (s > 0) + t *= divisor; + else if (s < 0) + t /= divisor; + + } template<>