diff --git a/datatypes/mcs_decimal.h b/datatypes/mcs_decimal.h index 54071c03b..cf70a357d 100644 --- a/datatypes/mcs_decimal.h +++ b/datatypes/mcs_decimal.h @@ -19,6 +19,7 @@ #define H_DECIMALDATATYPE #include +#include #include "calpontsystemcatalog.h" @@ -240,6 +241,102 @@ class Decimal ct.scale = 0; } } + + /** + @brief The method converts a __float128 value to an int64_t. + */ + static inline int64_t getInt64FromFloat128(const __float128& value) + { + if (value > static_cast<__float128>(INT64_MAX)) + return INT64_MAX; + else if (value < static_cast<__float128>(INT64_MIN)) + return INT64_MIN; + + return static_cast(value); + } + + /** + @brief The method converts a __float128 value to an uint64_t. + */ + static inline uint64_t getUInt64FromFloat128(const __float128& value) + { + if (value > static_cast<__float128>(UINT64_MAX)) + return UINT64_MAX; + else if (value < 0) + return 0; + + return static_cast(value); + } + + /** + @brief The method converts a __float128 value to a double. + */ + static inline double getDoubleFromFloat128(const __float128& value) + { + if (value > static_cast<__float128>(DBL_MAX)) + return DBL_MAX; + else if (value < -static_cast<__float128>(DBL_MAX)) + return -DBL_MAX; + + return static_cast(value); + } + + /** + @brief The method converts a wide decimal value to a double. + */ + static inline double getDoubleFromWideDecimal(const int128_t& value, int8_t scale) + { + int128_t scaleDivisor; + + getScaleDivisor(scaleDivisor, scale); + + __float128 tmpval = (__float128) value / scaleDivisor; + + return getDoubleFromFloat128(tmpval); + } + + /** + @brief The method converts a wide decimal value to a double. + */ + static inline double getDoubleFromWideDecimal(const int128_t& value) + { + return getDoubleFromFloat128(static_cast<__float128>(value)); + } + + /** + @brief The method converts a __float128 value to a long double. + */ + static inline long double getLongDoubleFromFloat128(const __float128& value) + { + if (value > static_cast<__float128>(LDBL_MAX)) + return LDBL_MAX; + else if (value < -static_cast<__float128>(LDBL_MAX)) + return -LDBL_MAX; + + return static_cast(value); + } + + /** + @brief The method converts a wide decimal value to a long double. + */ + static inline long double getLongDoubleFromWideDecimal(const int128_t& value) + { + return getLongDoubleFromFloat128(static_cast<__float128>(value)); + } + + /** + @brief The method converts a wide decimal value to an int64_t, + saturating the value if necessary. + */ + static inline int64_t getInt64FromWideDecimal(const int128_t& value) + { + if (value > static_cast(INT64_MAX)) + return INT64_MAX; + else if (value < static_cast(INT64_MIN)) + return INT64_MIN; + + return static_cast(value); + } }; /** diff --git a/dbcon/execplan/functioncolumn.h b/dbcon/execplan/functioncolumn.h index 9952910ad..4d398d9a8 100644 --- a/dbcon/execplan/functioncolumn.h +++ b/dbcon/execplan/functioncolumn.h @@ -256,14 +256,24 @@ public: (datatypes::Decimal::isWideDecimalType(decimal.precision)) ? decimal.s128Value : decimal.value; - int128_t scaleMultiplier, result; + int128_t scaleMultiplier; int32_t scaleDiff = fResultType.scale - decimal.scale; datatypes::getScaleDivisor(scaleMultiplier, abs(scaleDiff)); - // WIP MCOL-641 Unconditionall overflow check - datatypes::MultiplicationOverflowCheck mul; - decimal.s128Value = (scaleDiff > 0 - && mul(decimal.s128Value, scaleMultiplier, result)) - ? result : decimal.s128Value / scaleMultiplier; + if (scaleMultiplier > 1) + { + if (scaleDiff > 0) + { + // WIP MCOL-641 Unconditionall overflow check + datatypes::MultiplicationNoOverflowCheck mul; + mul(decimal.s128Value, scaleMultiplier, decimal.s128Value); + } + else + { + decimal.s128Value = (int128_t)(decimal.s128Value > 0 ? + (__float128)decimal.s128Value / scaleMultiplier + 0.5 : + (__float128)decimal.s128Value / scaleMultiplier - 0.5); + } + } } else if (fResultType.colWidth == utils::MAXLEGACYWIDTH) { diff --git a/dbcon/execplan/treenode.h b/dbcon/execplan/treenode.h index be105cf92..56f21ccdd 100644 --- a/dbcon/execplan/treenode.h +++ b/dbcon/execplan/treenode.h @@ -63,17 +63,16 @@ typedef execplan::CalpontSystemCatalog::ColType Type; */ struct IDB_Decimal { - IDB_Decimal(): value(0), scale(0), precision(0) + IDB_Decimal(): s128Value(0), value(0), scale(0), precision(0) { - s128Value = 0; } - IDB_Decimal(int64_t val, int8_t s, uint8_t p) : - value (val), + IDB_Decimal(int64_t val, int8_t s, uint8_t p, int128_t val128 = 0) : + s128Value(val128), + value(val), scale(s), precision(p) { - s128Value = 0; } int decimalComp(const IDB_Decimal& d) const @@ -117,13 +116,32 @@ struct IDB_Decimal bool operator==(const IDB_Decimal& rhs) const { - if (utils::widthByPrecision(precision) == 16) + if (precision > datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) { if (scale == rhs.scale) return s128Value == rhs.s128Value; else return (datatypes::Decimal::compare(*this, rhs) == 0); } + else if (precision > datatypes::INT64MAXPRECISION && + rhs.precision <= datatypes::INT64MAXPRECISION) + { + const_cast(rhs).s128Value = rhs.value; + + if (scale == rhs.scale) + return s128Value == rhs.s128Value; + else + return (datatypes::Decimal::compare(*this, rhs) == 0); + } + else if (precision <= datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) + { + if (scale == rhs.scale) + return (int128_t) value == rhs.s128Value; + else + return (datatypes::Decimal::compare(IDB_Decimal(0, scale, precision, (int128_t) value), rhs) == 0); + } else { if (scale == rhs.scale) @@ -135,13 +153,32 @@ struct IDB_Decimal bool operator>(const IDB_Decimal& rhs) const { - if (utils::widthByPrecision(precision) == 16) + if (precision > datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) { if (scale == rhs.scale) return s128Value > rhs.s128Value; else return (datatypes::Decimal::compare(*this, rhs) > 0); } + else if (precision > datatypes::INT64MAXPRECISION && + rhs.precision <= datatypes::INT64MAXPRECISION) + { + IDB_Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value); + + if (scale == rhstmp.scale) + return s128Value > rhstmp.s128Value; + else + return (datatypes::Decimal::compare(*this, rhstmp) > 0); + } + else if (precision <= datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) + { + if (scale == rhs.scale) + return (int128_t) value > rhs.s128Value; + else + return (datatypes::Decimal::compare(IDB_Decimal(0, scale, precision, (int128_t) value), rhs) > 0); + } else { if (scale == rhs.scale) @@ -153,13 +190,32 @@ struct IDB_Decimal bool operator<(const IDB_Decimal& rhs) const { - if (utils::widthByPrecision(precision) == 16) + if (precision > datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) { if (scale == rhs.scale) return s128Value < rhs.s128Value; else return (datatypes::Decimal::compare(*this, rhs) < 0); } + else if (precision > datatypes::INT64MAXPRECISION && + rhs.precision <= datatypes::INT64MAXPRECISION) + { + IDB_Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value); + + if (scale == rhstmp.scale) + return s128Value < rhstmp.s128Value; + else + return (datatypes::Decimal::compare(*this, rhstmp) < 0); + } + else if (precision <= datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) + { + if (scale == rhs.scale) + return (int128_t) value < rhs.s128Value; + else + return (datatypes::Decimal::compare(IDB_Decimal(0, scale, precision, (int128_t) value), rhs) < 0); + } else { if (scale == rhs.scale) @@ -171,13 +227,32 @@ struct IDB_Decimal bool operator>=(const IDB_Decimal& rhs) const { - if (utils::widthByPrecision(precision) == 16) + if (precision > datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) { if (scale == rhs.scale) return s128Value >= rhs.s128Value; else return (datatypes::Decimal::compare(*this, rhs) >= 0); } + else if (precision > datatypes::INT64MAXPRECISION && + rhs.precision <= datatypes::INT64MAXPRECISION) + { + IDB_Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value); + + if (scale == rhstmp.scale) + return s128Value >= rhstmp.s128Value; + else + return (datatypes::Decimal::compare(*this, rhstmp) >= 0); + } + else if (precision <= datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) + { + if (scale == rhs.scale) + return (int128_t) value >= rhs.s128Value; + else + return (datatypes::Decimal::compare(IDB_Decimal(0, scale, precision, (int128_t) value), rhs) >= 0); + } else { if (scale == rhs.scale) @@ -189,13 +264,32 @@ struct IDB_Decimal bool operator<=(const IDB_Decimal& rhs) const { - if (utils::widthByPrecision(precision) == 16) + if (precision > datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) { if (scale == rhs.scale) return s128Value <= rhs.s128Value; else return (datatypes::Decimal::compare(*this, rhs) <= 0); } + else if (precision > datatypes::INT64MAXPRECISION && + rhs.precision <= datatypes::INT64MAXPRECISION) + { + IDB_Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value); + + if (scale == rhstmp.scale) + return s128Value <= rhstmp.s128Value; + else + return (datatypes::Decimal::compare(*this, rhstmp) <= 0); + } + else if (precision <= datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) + { + if (scale == rhs.scale) + return (int128_t) value <= rhs.s128Value; + else + return (datatypes::Decimal::compare(IDB_Decimal(0, scale, precision, (int128_t) value), rhs) <= 0); + } else { if (scale == rhs.scale) @@ -207,13 +301,32 @@ struct IDB_Decimal bool operator!=(const IDB_Decimal& rhs) const { - if (utils::widthByPrecision(precision) == 16) + if (precision > datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) { if (scale == rhs.scale) return s128Value != rhs.s128Value; else return (datatypes::Decimal::compare(*this, rhs) != 0); } + else if (precision > datatypes::INT64MAXPRECISION && + rhs.precision <= datatypes::INT64MAXPRECISION) + { + IDB_Decimal rhstmp(0, rhs.scale, rhs.precision, (int128_t) rhs.value); + + if (scale == rhstmp.scale) + return s128Value != rhstmp.s128Value; + else + return (datatypes::Decimal::compare(*this, rhstmp) != 0); + } + else if (precision <= datatypes::INT64MAXPRECISION && + rhs.precision > datatypes::INT64MAXPRECISION) + { + if (scale == rhs.scale) + return (int128_t) value != rhs.s128Value; + else + return (datatypes::Decimal::compare(IDB_Decimal(0, scale, precision, (int128_t) value), rhs) != 0); + } else { if (scale == rhs.scale) @@ -308,7 +421,7 @@ struct Result { Result(): intVal(0), uintVal(0), origIntVal(0), dummy(0), doubleVal(0), longDoubleVal(0), floatVal(0), boolVal(false), - strVal(""), decimalVal(IDB_Decimal(0, 0, 0)), + strVal(""), decimalVal(IDB_Decimal()), valueConverted(false) {} int64_t intVal; uint64_t uintVal; @@ -783,7 +896,10 @@ inline const std::string& TreeNode::getStrVal(const std::string& timeZone) case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { - dataconvert::DataConvert::decimalToString(fResult.decimalVal.value, fResult.decimalVal.scale, tmp, 22, fResultType.colDataType); + if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) + dataconvert::DataConvert::decimalToString(&fResult.decimalVal.s128Value, fResult.decimalVal.scale, tmp, utils::MAXLENGTH16BYTES, fResultType.colDataType); + else + dataconvert::DataConvert::decimalToString(fResult.decimalVal.value, fResult.decimalVal.scale, tmp, 22, fResultType.colDataType); fResult.strVal = std::string(tmp); break; } @@ -880,7 +996,20 @@ inline int64_t TreeNode::getIntVal() case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { - return (int64_t)(fResult.decimalVal.value / pow((double)10, fResult.decimalVal.scale)); + if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor; + + datatypes::getScaleDivisor(scaleDivisor, fResult.decimalVal.scale); + + int128_t tmpval = fResult.decimalVal.s128Value / scaleDivisor; + + return datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + return (int64_t)(fResult.decimalVal.value / pow((double)10, fResult.decimalVal.scale)); + } } case CalpontSystemCatalog::DATE: @@ -1062,8 +1191,15 @@ inline double TreeNode::getDoubleVal() case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { - // this may not be accurate. if this is problematic, change to pre-calculated power array. - return (double)(fResult.decimalVal.value / pow((double)10, fResult.decimalVal.scale)); + if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) + { + return datatypes::Decimal::getDoubleFromWideDecimal(fResult.decimalVal.s128Value, fResult.decimalVal.scale); + } + else + { + // this may not be accurate. if this is problematic, change to pre-calculated power array. + return (double)(fResult.decimalVal.value / pow((double)10, fResult.decimalVal.scale)); + } } case CalpontSystemCatalog::DATE: diff --git a/dbcon/joblist/tupleconstantstep.cpp b/dbcon/joblist/tupleconstantstep.cpp index 5b8f53810..2a6a2ee7f 100644 --- a/dbcon/joblist/tupleconstantstep.cpp +++ b/dbcon/joblist/tupleconstantstep.cpp @@ -529,7 +529,9 @@ void TupleConstantStep::fillInConstants(const rowgroup::Row& rowIn, rowgroup::Ro //fRowConst.copyField(rowOut.getData()+2, 0); // hardcoded 2 for rid length for (uint32_t i = 1; i < rowOut.getColumnCount(); i++) // WIP MCOL-641 implement copyBinaryField inside copyField - if (UNLIKELY(utils::isWide(rowIn.getColumnWidth(i - 1)))) + if (UNLIKELY(utils::isWide(rowIn.getColumnWidth(i - 1)) && + (rowIn.getColType(i - 1) == CalpontSystemCatalog::DECIMAL || + rowIn.getColType(i - 1) == CalpontSystemCatalog::UDECIMAL))) rowIn.copyBinaryField(rowOut, i, i - 1); else rowIn.copyField(rowOut, i, i - 1); diff --git a/dbcon/mysql/ha_mcs_execplan.cpp b/dbcon/mysql/ha_mcs_execplan.cpp index 20a2158bc..a3a72428f 100755 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -4095,6 +4095,20 @@ ReturnedColumn* buildFunctionColumn( fc->functionParms(funcParms); fc->resultType(colType_MysqlToIDB(ifp)); + // if the result type is DECIMAL and any function parameter is a wide decimal + // column, set the result colwidth to wide + if (fc->resultType().colDataType == CalpontSystemCatalog::DECIMAL) + { + for (size_t i = 0; i < funcParms.size(); i++) + { + if (datatypes::Decimal::isWideDecimalType(funcParms[i]->data()->resultType())) + { + fc->resultType().colWidth = datatypes::MAXDECIMALWIDTH; + break; + } + } + } + // MySQL give string result type for date function, but has the flag set. // we should set the result type to be datetime for comparision. if (ifp->field_type() == MYSQL_TYPE_DATETIME || @@ -4410,6 +4424,14 @@ ConstantColumn* buildDecimalColumn(Item* item, gp_walk_info& gwi) i = 1; } + bool specialPrecision = false; + + // handle the case when the constant value is 0.12345678901234567890123456789012345678 + // In this case idp->decimal_precision() = 39, but we can + if (((i + 1) < str->length()) && + str->ptr()[i] == '0' && str->ptr()[i + 1] == '.') + specialPrecision = true; + for (; i < str->length(); i++) { if (str->ptr()[i] == '.') @@ -4420,7 +4442,9 @@ ConstantColumn* buildDecimalColumn(Item* item, gp_walk_info& gwi) if (idp->decimal_precision() <= datatypes::INT64MAXPRECISION) columnstore_decimal.value = strtoll(columnstore_decimal_val.str().c_str(), 0, 10); - else if (idp->decimal_precision() <= datatypes::INT128MAXPRECISION) + else if (idp->decimal_precision() <= datatypes::INT128MAXPRECISION || + (idp->decimal_precision() <= datatypes::INT128MAXPRECISION + 1 && + specialPrecision)) { bool dummy = false; columnstore_decimal.s128Value = @@ -4435,9 +4459,10 @@ ConstantColumn* buildDecimalColumn(Item* item, gp_walk_info& gwi) columnstore_decimal.value = (int64_t)(val > 0 ? val + 0.5 : val - 0.5); } else - columnstore_decimal.scale = idp->decimals; + columnstore_decimal.scale = idp->decimal_scale(); - columnstore_decimal.precision = idp->max_length - idp->decimals; + columnstore_decimal.precision = (idp->decimal_precision() > datatypes::INT128MAXPRECISION) ? + datatypes::INT128MAXPRECISION : idp->decimal_precision(); ConstantColumn* cc = new ConstantColumn(valStr, columnstore_decimal); cc->timeZone(gwi.thd->variables.time_zone->get_name()->ptr()); cc->charsetNumber(idp->collation.collation->number); diff --git a/utils/dataconvert/dataconvert.cpp b/utils/dataconvert/dataconvert.cpp index 546c24057..b7a0f9985 100644 --- a/utils/dataconvert/dataconvert.cpp +++ b/utils/dataconvert/dataconvert.cpp @@ -78,30 +78,6 @@ const int64_t columnstore_precision[19] = 999999999999999999LL }; -const string columnstore_big_precision[20] = -{ - "9999999999999999999", - "99999999999999999999", - "999999999999999999999", - "9999999999999999999999", - "99999999999999999999999", - "999999999999999999999999", - "9999999999999999999999999", - "99999999999999999999999999", - "999999999999999999999999999", - "9999999999999999999999999999", - "99999999999999999999999999999", - "999999999999999999999999999999", - "9999999999999999999999999999999", - "99999999999999999999999999999999", - "999999999999999999999999999999999", - "9999999999999999999999999999999999", - "99999999999999999999999999999999999", - "999999999999999999999999999999999999", - "9999999999999999999999999999999999999", - "99999999999999999999999999999999999999" -}; - template bool from_string(T& t, const std::string& s, std::ios_base & (*f)(std::ios_base&)) { diff --git a/utils/dataconvert/dataconvert.h b/utils/dataconvert/dataconvert.h index f70ec7f87..7c9f69278 100644 --- a/utils/dataconvert/dataconvert.h +++ b/utils/dataconvert/dataconvert.h @@ -118,6 +118,30 @@ const int64_t IDB_pow[19] = 1000000000000000000LL }; +const std::string columnstore_big_precision[20] = +{ + "9999999999999999999", + "99999999999999999999", + "999999999999999999999", + "9999999999999999999999", + "99999999999999999999999", + "999999999999999999999999", + "9999999999999999999999999", + "99999999999999999999999999", + "999999999999999999999999999", + "9999999999999999999999999999", + "99999999999999999999999999999", + "999999999999999999999999999999", + "9999999999999999999999999999999", + "99999999999999999999999999999999", + "999999999999999999999999999999999", + "9999999999999999999999999999999999", + "99999999999999999999999999999999999", + "999999999999999999999999999999999999", + "9999999999999999999999999999999999999", + "99999999999999999999999999999999999999" +}; + const int32_t SECS_PER_MIN = 60; const int32_t MINS_PER_HOUR = 60; const int32_t HOURS_PER_DAY = 24; diff --git a/utils/funcexp/CMakeLists.txt b/utils/funcexp/CMakeLists.txt index 889b44d64..8d194f105 100644 --- a/utils/funcexp/CMakeLists.txt +++ b/utils/funcexp/CMakeLists.txt @@ -112,7 +112,7 @@ add_library(funcexp SHARED ${funcexp_LIB_SRCS}) add_dependencies(funcexp loggingcpp) -target_link_libraries(funcexp ${NETSNMP_LIBRARIES}) +target_link_libraries(funcexp ${NETSNMP_LIBRARIES} quadmath) install(TARGETS funcexp DESTINATION ${ENGINE_LIBDIR} COMPONENT columnstore-engine) diff --git a/utils/funcexp/func_abs.cpp b/utils/funcexp/func_abs.cpp index 7b04408ba..830a48a6d 100644 --- a/utils/funcexp/func_abs.cpp +++ b/utils/funcexp/func_abs.cpp @@ -66,7 +66,11 @@ IDB_Decimal Func_abs::getDecimalVal(Row& row, CalpontSystemCatalog::ColType&) { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - d.value = llabs(d.value); + + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + d.s128Value = (d.s128Value < 0) ? -d.s128Value : d.s128Value; + else + d.value = llabs(d.value); return d; } diff --git a/utils/funcexp/func_bitwise.cpp b/utils/funcexp/func_bitwise.cpp index 2154f125b..beef7d290 100644 --- a/utils/funcexp/func_bitwise.cpp +++ b/utils/funcexp/func_bitwise.cpp @@ -102,22 +102,56 @@ bool getUIntValFromParm( { IDB_Decimal d = parm->data()->getDecimalVal(row, isNull); - if (parm->data()->resultType().colDataType == execplan::CalpontSystemCatalog::UDECIMAL && - d.value < 0) + if (parm->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) { - d.value = 0; + if (parm->data()->resultType().colDataType == execplan::CalpontSystemCatalog::UDECIMAL && + d.value < 0) + { + value = 0; + break; + } + + int128_t scaleDivisor, scaleDivisor2; + + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + if (tmpval > static_cast(INT64_MAX)) + tmpval = INT64_MAX; + else if (tmpval < static_cast(INT64_MIN)) + tmpval = INT64_MIN; + + value = tmpval; } - double dscale = d.scale; - int64_t tmpval = d.value / pow(10.0, dscale); - int lefto = (d.value - tmpval * pow(10.0, dscale)) / pow(10.0, dscale - 1); + else + { + if (parm->data()->resultType().colDataType == execplan::CalpontSystemCatalog::UDECIMAL && + d.value < 0) + { + d.value = 0; + } + double dscale = d.scale; + int64_t tmpval = d.value / pow(10.0, dscale); + int lefto = (d.value - tmpval * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( tmpval >= 0 && lefto > 4 ) - tmpval++; + if (tmpval >= 0 && lefto > 4) + tmpval++; - if ( tmpval < 0 && lefto < -4 ) - tmpval--; + if (tmpval < 0 && lefto < -4) + tmpval--; - value = tmpval; + value = tmpval; + } } break; diff --git a/utils/funcexp/func_cast.cpp b/utils/funcexp/func_cast.cpp index 3584b7102..a4c9fbe49 100644 --- a/utils/funcexp/func_cast.cpp +++ b/utils/funcexp/func_cast.cpp @@ -22,6 +22,8 @@ #include using namespace std; +#include + #include "functor_dtm.h" #include "functor_int.h" #include "functor_real.h" @@ -183,17 +185,40 @@ int64_t Func_cast_signed::getIntVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - int64_t value = d.value / pow(10.0, dscale); - int lefto = (d.value - value * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( value >= 0 && lefto > 4 ) - value++; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor, scaleDivisor2; - if ( value < 0 && lefto < -4 ) - value--; + datatypes::getScaleDivisor(scaleDivisor, d.scale); - return value; + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + return datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + double dscale = d.scale; + int64_t value = d.value / pow(10.0, dscale); + int lefto = (d.value - value * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( value >= 0 && lefto > 4 ) + value++; + + if ( value < 0 && lefto < -4 ) + value--; + + return value; + } } break; @@ -341,20 +366,48 @@ uint64_t Func_cast_unsigned::getUintVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - if (d.value < 0) + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) { - return 0; - } + if (d.s128Value < 0) + { + return 0; + } - uint64_t value = d.value / pow(10.0, dscale); - int lefto = (d.value - value * pow(10.0, dscale)) / pow(10.0, dscale - 1); + int128_t scaleDivisor, scaleDivisor2; + + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + uint128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval > static_cast(UINT64_MAX)) + tmpval = UINT64_MAX; + + return static_cast(tmpval); + } + else + { + if (d.value < 0) + { + return 0; + } + + double dscale = d.scale; + + uint64_t value = d.value / pow(10.0, dscale); + int lefto = (d.value - value * pow(10.0, dscale)) / pow(10.0, dscale - 1); if ( utils::is_nonnegative(value) && lefto > 4 ) value++; - return value; + return value; + } } break; @@ -491,7 +544,10 @@ string Func_cast_char::getStrVal(Row& row, char buf[80]; - dataconvert::DataConvert::decimalToString( d.value, d.scale, buf, 80, parm[0]->data()->resultType().colDataType); + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + dataconvert::DataConvert::decimalToString( &d.s128Value, d.scale, buf, 80, parm[0]->data()->resultType().colDataType); + else + dataconvert::DataConvert::decimalToString( d.value, d.scale, buf, 80, parm[0]->data()->resultType().colDataType); string sbuf = buf; return sbuf.substr(0, length); @@ -583,10 +639,16 @@ IDB_Decimal Func_cast_date::getDecimalVal(Row& row, { IDB_Decimal decimal; - decimal.value = Func_cast_date::getDatetimeIntVal(row, - parm, - isNull, - operationColType); + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + decimal.s128Value = Func_cast_date::getDatetimeIntVal(row, + parm, + isNull, + operationColType); + else + decimal.value = Func_cast_date::getDatetimeIntVal(row, + parm, + isNull, + operationColType); return decimal; } @@ -886,10 +948,16 @@ IDB_Decimal Func_cast_datetime::getDecimalVal(Row& row, { IDB_Decimal decimal; - decimal.value = Func_cast_datetime::getDatetimeIntVal(row, - parm, - isNull, - operationColType); + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + decimal.s128Value = Func_cast_datetime::getDatetimeIntVal(row, + parm, + isNull, + operationColType); + else + decimal.value = Func_cast_datetime::getDatetimeIntVal(row, + parm, + isNull, + operationColType); return decimal; } @@ -1139,6 +1207,17 @@ int64_t Func_cast_decimal::getIntVal(Row& row, isNull, operationColType); + if (decimal.precision > datatypes::INT64MAXPRECISION) + { + int128_t scaleDivisor; + + datatypes::getScaleDivisor(scaleDivisor, decimal.scale); + + int128_t tmpval = decimal.s128Value / scaleDivisor; + + return datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + return (int64_t) decimal.value / helpers::powerOf10_c[decimal.scale]; } @@ -1155,7 +1234,10 @@ string Func_cast_decimal::getStrVal(Row& row, char buf[80]; - dataconvert::DataConvert::decimalToString( decimal.value, decimal.scale, buf, 80, operationColType.colDataType); + if (decimal.precision > datatypes::INT64MAXPRECISION) + dataconvert::DataConvert::decimalToString( &decimal.s128Value, decimal.scale, buf, 80, operationColType.colDataType); + else + dataconvert::DataConvert::decimalToString( decimal.value, decimal.scale, buf, 80, operationColType.colDataType); string value = buf; return value; @@ -1173,12 +1255,10 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, int32_t decimals = parm[1]->data()->getIntVal(row, isNull); int64_t max_length = parm[2]->data()->getIntVal(row, isNull); - // As of 2.0, max length columnStore can support is 18 - // decimal(0,0) is valid, and no limit on integer number - if (max_length > 18 || max_length <= 0) - max_length = 18; + if (max_length > datatypes::INT128MAXPRECISION || max_length <= 0) + max_length = datatypes::INT128MAXPRECISION; - int64_t max_number_decimal = helpers::maxNumber_c[max_length]; + decimal.precision = max_length; switch (parm[0]->data()->resultType().colDataType) { @@ -1188,19 +1268,45 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::SMALLINT: { - decimal.value = parm[0]->data()->getIntVal(row, isNull); - decimal.scale = 0; - int64_t value = decimal.value * helpers::powerOf10_c[decimals]; + if (max_length > datatypes::INT64MAXPRECISION) + { + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); + decimal.s128Value = parm[0]->data()->getIntVal(row, isNull); + decimal.scale = 0; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, decimals); + int128_t value = decimal.s128Value * scaleDivisor; - if ( value > max_number_decimal ) - { - decimal.value = max_number_decimal; - decimal.scale = decimals; + if ( value > max_number_decimal ) + { + decimal.s128Value = max_number_decimal; + decimal.scale = decimals; + } + else if ( value < -max_number_decimal ) + { + decimal.s128Value = -max_number_decimal; + decimal.scale = decimals; + } } - else if ( value < -max_number_decimal ) + else { - decimal.value = -max_number_decimal; - decimal.scale = decimals; + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; + decimal.value = parm[0]->data()->getIntVal(row, isNull); + decimal.scale = 0; + int64_t value = decimal.value * helpers::powerOf10_c[decimals]; + + if ( value > max_number_decimal ) + { + decimal.value = max_number_decimal; + decimal.scale = decimals; + } + else if ( value < -max_number_decimal ) + { + decimal.value = -max_number_decimal; + decimal.scale = decimals; + } } } break; @@ -1211,21 +1317,51 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, case execplan::CalpontSystemCatalog::UTINYINT: case execplan::CalpontSystemCatalog::USMALLINT: { - uint64_t uval = parm[0]->data()->getUintVal(row, isNull); - - if (uval > (uint64_t)numeric_limits::max()) + if (max_length > datatypes::INT64MAXPRECISION) { - uval = numeric_limits::max(); + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); + + uint128_t uval = parm[0]->data()->getUintVal(row, isNull); + + if (uval > (uint128_t)datatypes::Decimal::maxInt128) + { + uval = datatypes::Decimal::maxInt128; + } + + decimal.s128Value = uval; + decimal.scale = 0; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, decimals); + int128_t value = decimal.s128Value * scaleDivisor; + + if ( value > max_number_decimal ) + { + decimal.s128Value = max_number_decimal; + decimal.scale = decimals; + } } - - decimal.value = uval; - decimal.scale = 0; - int64_t value = decimal.value * helpers::powerOf10_c[decimals]; - - if ( value > max_number_decimal ) + else { - decimal.value = max_number_decimal; - decimal.scale = decimals; + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; + + uint64_t uval = parm[0]->data()->getUintVal(row, isNull); + + if (uval > (uint64_t)numeric_limits::max()) + { + uval = numeric_limits::max(); + } + + decimal.value = uval; + decimal.scale = 0; + int64_t value = decimal.value * helpers::powerOf10_c[decimals]; + + if ( value > max_number_decimal ) + { + decimal.value = max_number_decimal; + decimal.scale = decimals; + } } } break; @@ -1235,67 +1371,172 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, case execplan::CalpontSystemCatalog::FLOAT: case execplan::CalpontSystemCatalog::UFLOAT: { - double value = parm[0]->data()->getDoubleVal(row, isNull); + if (max_length > datatypes::INT64MAXPRECISION) + { + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); - if (value > 0) - decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] + 0.5); - else if (value < 0) - decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] - 0.5); + __float128 value = parm[0]->data()->getDoubleVal(row, isNull); + + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, decimals); + + if (value > 0) + decimal.s128Value = (int128_t) (value * scaleDivisor + 0.5); + else if (value < 0) + decimal.s128Value = (int128_t) (value * scaleDivisor - 0.5); + else + decimal.s128Value = 0; + + decimal.scale = decimals; + + if ( value > max_number_decimal ) + decimal.s128Value = max_number_decimal; + else if ( value < -max_number_decimal ) + decimal.s128Value = -max_number_decimal; + } else - decimal.value = 0; + { + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; - decimal.scale = decimals; + double value = parm[0]->data()->getDoubleVal(row, isNull); - if ( value > max_number_decimal ) - decimal.value = max_number_decimal; - else if ( value < -max_number_decimal ) - decimal.value = -max_number_decimal; + if (value > 0) + decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] + 0.5); + else if (value < 0) + decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] - 0.5); + else + decimal.value = 0; + + decimal.scale = decimals; + + if ( value > max_number_decimal ) + decimal.value = max_number_decimal; + else if ( value < -max_number_decimal ) + decimal.value = -max_number_decimal; + } } break; case execplan::CalpontSystemCatalog::LONGDOUBLE: { - long double value = parm[0]->data()->getLongDoubleVal(row, isNull); + if (max_length > datatypes::INT64MAXPRECISION) + { + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); - if (value > 0) - decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] + 0.5); - else if (value < 0) - decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] - 0.5); + __float128 value = parm[0]->data()->getLongDoubleVal(row, isNull); + + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, decimals); + + if (value > 0) + decimal.s128Value = (int128_t) (value * scaleDivisor + 0.5); + else if (value < 0) + decimal.s128Value = (int128_t) (value * scaleDivisor - 0.5); + else + decimal.s128Value = 0; + + decimal.scale = decimals; + + if ( value > max_number_decimal ) + decimal.s128Value = max_number_decimal; + else if ( value < -max_number_decimal ) + decimal.s128Value = -max_number_decimal; + } else - decimal.value = 0; + { + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; - decimal.scale = decimals; + long double value = parm[0]->data()->getLongDoubleVal(row, isNull); - if ( value > max_number_decimal ) - decimal.value = max_number_decimal; - else if ( value < -max_number_decimal ) - decimal.value = -max_number_decimal; + if (value > 0) + decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] + 0.5); + else if (value < 0) + decimal.value = (int64_t) (value * helpers::powerOf10_c[decimals] - 0.5); + else + decimal.value = 0; + + decimal.scale = decimals; + + if ( value > max_number_decimal ) + decimal.value = max_number_decimal; + else if ( value < -max_number_decimal ) + decimal.value = -max_number_decimal; + } } break; case execplan::CalpontSystemCatalog::DECIMAL: case execplan::CalpontSystemCatalog::UDECIMAL: { - decimal = parm[0]->data()->getDecimalVal(row, isNull); + if (max_length > datatypes::INT64MAXPRECISION) + { + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); + decimal = parm[0]->data()->getDecimalVal(row, isNull); - if (decimals > decimal.scale) - decimal.value *= helpers::powerOf10_c[decimals - decimal.scale]; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, abs(decimals - decimal.scale)); + + if (decimal.precision <= datatypes::INT64MAXPRECISION) + decimal.s128Value = decimal.value; + + decimal.precision = max_length; + + if (scaleDivisor > 1) + { + if (decimals > decimal.scale) + decimal.s128Value *= scaleDivisor; + else + decimal.s128Value = (int128_t)(decimal.s128Value > 0 ? + (__float128)decimal.s128Value / scaleDivisor + 0.5 : + (__float128)decimal.s128Value / scaleDivisor - 0.5); + } + + decimal.scale = decimals; + + if ( decimal.s128Value > max_number_decimal ) + decimal.s128Value = max_number_decimal; + else if ( decimal.s128Value < -max_number_decimal ) + decimal.s128Value = -max_number_decimal; + } else - decimal.value = (int64_t)(decimal.value > 0 ? - (double)decimal.value / helpers::powerOf10_c[decimal.scale - decimals] + 0.5 : - (double)decimal.value / helpers::powerOf10_c[decimal.scale - decimals] - 0.5); + { + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; - decimal.scale = decimals; + decimal = parm[0]->data()->getDecimalVal(row, isNull); + if (decimal.precision > datatypes::INT64MAXPRECISION) + { + if ( decimal.s128Value > (int128_t) max_number_decimal ) + decimal.value = max_number_decimal; + else if ( decimal.s128Value < (int128_t) -max_number_decimal ) + decimal.value = -max_number_decimal; + else + decimal.value = decimal.s128Value; + } + decimal.precision = max_length; - //int64_t value = decimal.value; + if (decimals > decimal.scale) + decimal.value *= helpers::powerOf10_c[decimals - decimal.scale]; + else + decimal.value = (int64_t)(decimal.value > 0 ? + (double)decimal.value / helpers::powerOf10_c[decimal.scale - decimals] + 0.5 : + (double)decimal.value / helpers::powerOf10_c[decimal.scale - decimals] - 0.5); - if ( decimal.value > max_number_decimal ) - decimal.value = max_number_decimal; - else if ( decimal.value < -max_number_decimal ) - decimal.value = -max_number_decimal; + decimal.scale = decimals; + + if ( decimal.value > max_number_decimal ) + decimal.value = max_number_decimal; + else if ( decimal.value < -max_number_decimal ) + decimal.value = -max_number_decimal; + } } break; @@ -1313,9 +1554,6 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, int negate = 1; bool bFoundSign = false; bool bRound = false; - double floatValue; - int64_t value = 0; - int64_t frac = 0; if (strValue.empty()) { @@ -1331,27 +1569,63 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, { if (*s == 'e' || *s == 'E') { - floatValue = strtod(str, 0); + if (max_length > datatypes::INT64MAXPRECISION) + { + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); - // If the float value is too large, the saturated result may end up with - // the wrong sign, so we just check first. - if ((int64_t)floatValue > max_number_decimal) - decimal.value = max_number_decimal; - else if ((int64_t)floatValue < -max_number_decimal) - decimal.value = -max_number_decimal; - else if (floatValue > 0) - decimal.value = (int64_t) (floatValue * helpers::powerOf10_c[decimals] + 0.5); - else if (floatValue < 0) - decimal.value = (int64_t) (floatValue * helpers::powerOf10_c[decimals] - 0.5); + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, decimals); + + __float128 floatValue = strtoflt128 (str, 0); + + // If the float value is too large, the saturated result may end up with + // the wrong sign, so we just check first. + if ((int128_t)floatValue > max_number_decimal) + decimal.s128Value = max_number_decimal; + else if ((int128_t)floatValue < -max_number_decimal) + decimal.s128Value = -max_number_decimal; + else if (floatValue > 0) + decimal.s128Value = (int128_t) (floatValue * scaleDivisor + 0.5); + else if (floatValue < 0) + decimal.s128Value = (int128_t) (floatValue * scaleDivisor - 0.5); + else + decimal.s128Value = 0; + + if (decimal.s128Value > max_number_decimal) + decimal.s128Value = max_number_decimal; + else if (decimal.s128Value < -max_number_decimal) + decimal.s128Value = -max_number_decimal; + + return decimal; + } else - decimal.value = 0; + { + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; - if (decimal.value > max_number_decimal) - decimal.value = max_number_decimal; - else if (decimal.value < -max_number_decimal) - decimal.value = -max_number_decimal; + double floatValue = strtod(str, 0); - return decimal; + // If the float value is too large, the saturated result may end up with + // the wrong sign, so we just check first. + if ((int64_t)floatValue > max_number_decimal) + decimal.value = max_number_decimal; + else if ((int64_t)floatValue < -max_number_decimal) + decimal.value = -max_number_decimal; + else if (floatValue > 0) + decimal.value = (int64_t) (floatValue * helpers::powerOf10_c[decimals] + 0.5); + else if (floatValue < 0) + decimal.value = (int64_t) (floatValue * helpers::powerOf10_c[decimals] - 0.5); + else + decimal.value = 0; + + if (decimal.value > max_number_decimal) + decimal.value = max_number_decimal; + else if (decimal.value < -max_number_decimal) + decimal.value = -max_number_decimal; + + return decimal; + } } } @@ -1392,54 +1666,119 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, } } - errno = 0; - - if (firstInt) // Checking to see if we have a decimal point, but no previous digits. + if (max_length > datatypes::INT64MAXPRECISION) { - value = strtoll(firstInt, &endptr, 10); - } + bool dummy = false; + char *ep = NULL; + int128_t max_number_decimal = dataconvert::strtoll128(columnstore_big_precision[max_length - 19].c_str(), dummy, &ep); - if (!errno && endptr) - { - // Scale the integer portion according to the DECIMAL description - value *= helpers::powerOf10_c[decimals]; + int128_t value = 0, frac = 0; - // Get the fractional part. - if (endptr && (*endptr == *convData->decimal_point || *endptr == '.')) + if (firstInt) // Checking to see if we have a decimal point, but no previous digits. { - s = endptr + 1; - - // Get the digits to the right of the decimal - // Only retrieve those that matter based on scale. - for (fracChars = 0; - *s && isdigit(*s) && fracChars < decimals; - ++fracChars, ++s) - { - // Save the frac characters to a side buffer. This way we can limit - // ourselves to the scale without modifying the original string. - fracBuf[fracChars] = *s; - } - - fracBuf[fracChars] = 0; - - // Check to see if we need to round - if (isdigit(*s) && *s > '4') - { - bRound = true; - } + value = dataconvert::strtoll128(firstInt, dummy, &endptr); } - frac = strtoll(fracBuf, &endptr, 10); - value += frac + (bRound ? 1 : 0); - value *= negate; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, decimals); + + if (!dummy && endptr) + { + // Scale the integer portion according to the DECIMAL description + value *= scaleDivisor; + + // Get the fractional part. + if (endptr && (*endptr == *convData->decimal_point || *endptr == '.')) + { + s = endptr + 1; + + // Get the digits to the right of the decimal + // Only retrieve those that matter based on scale. + for (fracChars = 0; + *s && isdigit(*s) && fracChars < decimals; + ++fracChars, ++s) + { + // Save the frac characters to a side buffer. This way we can limit + // ourselves to the scale without modifying the original string. + fracBuf[fracChars] = *s; + } + + fracBuf[fracChars] = 0; + + // Check to see if we need to round + if (isdigit(*s) && *s > '4') + { + bRound = true; + } + } + + frac = dataconvert::strtoll128(fracBuf, dummy, &ep); + value += frac + (bRound ? 1 : 0); + value *= negate; + } + + decimal.s128Value = value; + + if (decimal.s128Value > max_number_decimal) + decimal.s128Value = max_number_decimal; + else if (decimal.s128Value < -max_number_decimal) + decimal.s128Value = -max_number_decimal; } + else + { + int64_t max_number_decimal = helpers::maxNumber_c[max_length]; - decimal.value = value; + int64_t value = 0, frac = 0; - if (decimal.value > max_number_decimal) - decimal.value = max_number_decimal; - else if (decimal.value < -max_number_decimal) - decimal.value = -max_number_decimal; + errno = 0; + + if (firstInt) // Checking to see if we have a decimal point, but no previous digits. + { + value = strtoll(firstInt, &endptr, 10); + } + + if (!errno && endptr) + { + // Scale the integer portion according to the DECIMAL description + value *= helpers::powerOf10_c[decimals]; + + // Get the fractional part. + if (endptr && (*endptr == *convData->decimal_point || *endptr == '.')) + { + s = endptr + 1; + + // Get the digits to the right of the decimal + // Only retrieve those that matter based on scale. + for (fracChars = 0; + *s && isdigit(*s) && fracChars < decimals; + ++fracChars, ++s) + { + // Save the frac characters to a side buffer. This way we can limit + // ourselves to the scale without modifying the original string. + fracBuf[fracChars] = *s; + } + + fracBuf[fracChars] = 0; + + // Check to see if we need to round + if (isdigit(*s) && *s > '4') + { + bRound = true; + } + } + + frac = strtoll(fracBuf, &endptr, 10); + value += frac + (bRound ? 1 : 0); + value *= negate; + } + + decimal.value = value; + + if (decimal.value > max_number_decimal) + decimal.value = max_number_decimal; + else if (decimal.value < -max_number_decimal) + decimal.value = -max_number_decimal; + } } break; @@ -1452,7 +1791,11 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, if (!isNull) { - decimal.value = x; + if (max_length > datatypes::INT64MAXPRECISION) + decimal.s128Value = x; + else + decimal.value = x; + decimal.scale = s; } } @@ -1471,7 +1814,11 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, if (!isNull) { - decimal.value = x; + if (max_length > datatypes::INT64MAXPRECISION) + decimal.s128Value = x; + else + decimal.value = x; + decimal.scale = s; } } @@ -1490,7 +1837,11 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, if (!isNull) { - decimal.value = x; + if (max_length > datatypes::INT64MAXPRECISION) + decimal.s128Value = x; + else + decimal.value = x; + decimal.scale = s; } } @@ -1509,7 +1860,11 @@ IDB_Decimal Func_cast_decimal::getDecimalVal(Row& row, if (!isNull) { - decimal.value = x; + if (max_length > datatypes::INT64MAXPRECISION) + decimal.s128Value = x; + else + decimal.value = x; + decimal.scale = s; } } @@ -1536,6 +1891,11 @@ double Func_cast_decimal::getDoubleVal(Row& row, isNull, operationColType); + if (decimal.precision > datatypes::INT64MAXPRECISION) + { + return datatypes::Decimal::getDoubleFromWideDecimal(decimal.s128Value, decimal.scale); + } + return (double) decimal.value / helpers::powerOf10_c[decimal.scale]; } @@ -1642,7 +2002,14 @@ double Func_cast_double::getDoubleVal(Row& row, { IDB_Decimal decimal = parm[0]->data()->getDecimalVal(row, isNull); - dblval = (double)(decimal.value / pow((double)10, decimal.scale)); + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + dblval = datatypes::Decimal::getDoubleFromWideDecimal(decimal.s128Value, decimal.scale); + } + else + { + dblval = (double)(decimal.value / pow((double)10, decimal.scale)); + } } break; diff --git a/utils/funcexp/func_ceil.cpp b/utils/funcexp/func_ceil.cpp index 967989c74..26200a94f 100644 --- a/utils/funcexp/func_ceil.cpp +++ b/utils/funcexp/func_ceil.cpp @@ -65,42 +65,58 @@ int64_t Func_ceil::getIntVal(Row& row, case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: - case CalpontSystemCatalog::DECIMAL: - case CalpontSystemCatalog::UDECIMAL: { - if (op_ct.scale == 0) - { - ret = parm[0]->data()->getIntVal(row, isNull); - break; - } + ret = parm[0]->data()->getIntVal(row, isNull); + } + break; - IDB_Decimal decimal = parm[0]->data()->getDecimalVal(row, isNull); + // ceil(decimal(38,38)) leads to this path + // otherwise Func_ceil::getDecimalVal() is called + case execplan::CalpontSystemCatalog::DECIMAL: + case execplan::CalpontSystemCatalog::UDECIMAL: + { + IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); if (isNull) break; - ret = decimal.value; - // negative scale is not supported by CNX yet - if (decimal.scale > 0) + if (d.scale > 0) { - - if (decimal.scale >= 19) + if (d.scale > datatypes::INT128MAXPRECISION) { std::ostringstream oss; - oss << "ceil: datatype of " << colDataTypeToString(op_ct.colDataType) - << " with scale " << (int) decimal.scale << " is beyond supported scale"; + oss << "ceil: datatype of " << execplan::colDataTypeToString(op_ct.colDataType) + << " with scale " << (int) d.scale << " is beyond supported scale"; throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT); } - // Adjust to an int based on the scale. - int64_t tmp = ret; - ret /= helpers::powerOf10_c[decimal.scale]; + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t tmp = d.s128Value; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + d.s128Value /= scaleDivisor; - // Add 1 if this is a positive number and there were values to the right of the - // decimal point so that we return the largest integer value not less than X. - if ((tmp - (ret * helpers::powerOf10_c[decimal.scale]) > 0)) - ret += 1; + // Add 1 if this is a positive number and there were values to the right of the + // decimal point so that we return the largest integer value not less than X. + if ((tmp - (d.s128Value * scaleDivisor)) > 0) + d.s128Value += 1; + + ret = datatypes::Decimal::getInt64FromWideDecimal(d.s128Value); + } + else + { + int64_t tmp = d.value; + d.value /= helpers::powerOf10_c[d.scale]; + + // Add 1 if this is a positive number and there were values to the right of the + // decimal point so that we return the largest integer value not less than X. + if ((tmp - (d.value * helpers::powerOf10_c[d.scale])) > 0) + d.value += 1; + + ret = d.value; + } } } break; @@ -308,6 +324,20 @@ double Func_ceil::getDoubleVal(Row& row, { ret = (double)ceill(parm[0]->data()->getLongDoubleVal(row, isNull)); } + else if (op_ct.colDataType == CalpontSystemCatalog::DECIMAL || + op_ct.colDataType == CalpontSystemCatalog::UDECIMAL) + { + IDB_Decimal tmp = getDecimalVal(row, parm, isNull, op_ct); + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + ret = datatypes::Decimal::getDoubleFromWideDecimal(tmp.s128Value); + } + else + { + ret = (double) tmp.value; + } + } else { if (isUnsigned(op_ct.colDataType)) @@ -350,6 +380,20 @@ long double Func_ceil::getLongDoubleVal(Row& row, if (!isNull) ret = ceil(strtod(str.c_str(), 0)); } + else if (op_ct.colDataType == CalpontSystemCatalog::DECIMAL || + op_ct.colDataType == CalpontSystemCatalog::UDECIMAL) + { + IDB_Decimal tmp = getDecimalVal(row, parm, isNull, op_ct); + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + ret = datatypes::Decimal::getLongDoubleFromWideDecimal(tmp.s128Value); + } + else + { + ret = (long double) tmp.value; + } + } else { if (isUnsigned(op_ct.colDataType)) @@ -403,6 +447,20 @@ string Func_ceil::getStrVal(Row& row, *d = '\0'; } + else if (op_ct.colDataType == CalpontSystemCatalog::DECIMAL || + op_ct.colDataType == CalpontSystemCatalog::UDECIMAL) + { + IDB_Decimal d = getDecimalVal(row, parm, isNull, op_ct); + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + dataconvert::DataConvert::decimalToString(&d.s128Value, d.scale, tmp, 511, op_ct.colDataType); + } + else + { + dataconvert::DataConvert::decimalToString(d.value, d.scale, tmp, 511, op_ct.colDataType); + } + } else if (isUnsigned(op_ct.colDataType)) { #ifndef __LP64__ @@ -424,5 +482,156 @@ string Func_ceil::getStrVal(Row& row, } +IDB_Decimal Func_ceil::getDecimalVal(Row& row, + FunctionParm& parm, + bool& isNull, + CalpontSystemCatalog::ColType& op_ct) +{ + IDB_Decimal ret; + + switch (op_ct.colDataType) + { + case execplan::CalpontSystemCatalog::BIGINT: + case execplan::CalpontSystemCatalog::INT: + case execplan::CalpontSystemCatalog::MEDINT: + case execplan::CalpontSystemCatalog::TINYINT: + case execplan::CalpontSystemCatalog::SMALLINT: + { + ret.value = parm[0]->data()->getIntVal(row, isNull); + } + break; + + case execplan::CalpontSystemCatalog::DECIMAL: + case execplan::CalpontSystemCatalog::UDECIMAL: + { + ret = parm[0]->data()->getDecimalVal(row, isNull); + + if (isNull) + break; + + // negative scale is not supported by CNX yet + if (ret.scale > 0) + { + if (ret.scale > datatypes::INT128MAXPRECISION) + { + std::ostringstream oss; + oss << "ceil: datatype of " << execplan::colDataTypeToString(op_ct.colDataType) + << " with scale " << (int) ret.scale << " is beyond supported scale"; + throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT); + } + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t tmp = ret.s128Value; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, ret.scale); + ret.s128Value /= scaleDivisor; + + // Add 1 if this is a positive number and there were values to the right of the + // decimal point so that we return the largest integer value not less than X. + if ((tmp - (ret.s128Value * scaleDivisor)) > 0) + ret.s128Value += 1; + } + else + { + int64_t tmp = ret.value; + ret.value /= helpers::powerOf10_c[ret.scale]; + + // Add 1 if this is a positive number and there were values to the right of the + // decimal point so that we return the largest integer value not less than X. + if ((tmp - (ret.value * helpers::powerOf10_c[ret.scale])) > 0) + ret.value += 1; + } + } + } + break; + + case execplan::CalpontSystemCatalog::UBIGINT: + case execplan::CalpontSystemCatalog::UINT: + case execplan::CalpontSystemCatalog::UMEDINT: + case execplan::CalpontSystemCatalog::UTINYINT: + case execplan::CalpontSystemCatalog::USMALLINT: + { + ret.value = (int64_t)parm[0]->data()->getUintVal(row, isNull); + } + break; + + case execplan::CalpontSystemCatalog::DOUBLE: + case execplan::CalpontSystemCatalog::UDOUBLE: + case execplan::CalpontSystemCatalog::FLOAT: + case execplan::CalpontSystemCatalog::UFLOAT: + { + ret.value = (int64_t) ceil(parm[0]->data()->getDoubleVal(row, isNull)); + } + break; + + case execplan::CalpontSystemCatalog::LONGDOUBLE: + { + ret.value = (int64_t) ceill(parm[0]->data()->getLongDoubleVal(row, isNull)); + } + break; + + case execplan::CalpontSystemCatalog::VARCHAR: + case execplan::CalpontSystemCatalog::CHAR: + case execplan::CalpontSystemCatalog::TEXT: + { + const string& str = parm[0]->data()->getStrVal(row, isNull); + + if (!isNull) + ret.value = (int64_t) ceil(strtod(str.c_str(), 0)); + } + break; + + case CalpontSystemCatalog::DATE: + { + Date d (parm[0]->data()->getDateIntVal(row, isNull)); + + if (!isNull) + ret.value = d.convertToMySQLint(); + } + break; + + case CalpontSystemCatalog::DATETIME: + { + DateTime dt(parm[0]->data()->getDatetimeIntVal(row, isNull)); + + if (!isNull) + ret.value = dt.convertToMySQLint(); + } + break; + + case CalpontSystemCatalog::TIMESTAMP: + { + TimeStamp dt(parm[0]->data()->getTimestampIntVal(row, isNull)); + + if (!isNull) + ret.value = dt.convertToMySQLint(timeZone()); + } + break; + + case CalpontSystemCatalog::TIME: + { + Time dt(parm[0]->data()->getTimeIntVal(row, isNull)); + + if (!isNull) + ret.value = dt.convertToMySQLint(); + } + break; + + default: + { + std::ostringstream oss; + oss << "ceil: datatype of " << colDataTypeToString(op_ct.colDataType) + << " is not supported"; + throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT); + } + } + + ret.scale = 0; + + return ret; +} + + } // namespace funcexp // vim:ts=4 sw=4: diff --git a/utils/funcexp/func_char.cpp b/utils/funcexp/func_char.cpp index c4a27730e..d9904ba63 100644 --- a/utils/funcexp/func_char.cpp +++ b/utils/funcexp/func_char.cpp @@ -134,15 +134,50 @@ string Func_char::getStrVal(Row& row, case execplan::CalpontSystemCatalog::DECIMAL: case execplan::CalpontSystemCatalog::UDECIMAL: { - IDB_Decimal d = rc->getDecimalVal(row, isNull); - double dscale = d.scale; - // get decimal and round up - value = d.value / pow(10.0, dscale); - int lefto = (d.value - value * pow(10.0, dscale)) / pow(10.0, dscale - 1); + IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - if ( lefto > 4 ) - value++; - + if (ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + if (d.s128Value < 0) + return ""; + + int128_t scaleDivisor, scaleDivisor2; + + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (lefto > 4) + tmpval++; + + if (tmpval > static_cast(INT64_MAX)) + tmpval = INT64_MAX; + + if ( !getChar((int64_t)tmpval, buf) ) + { + isNull = true; + return ""; + } + } + else + { + double dscale = d.scale; + // get decimal and round up + int value = d.value / pow(10.0, dscale); + int lefto = (d.value - value * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( lefto > 4 ) + value++; + + if ( !getChar((int64_t)value, buf) ) + { + isNull = true; + return ""; + } + } } break; diff --git a/utils/funcexp/func_elt.cpp b/utils/funcexp/func_elt.cpp index ccdca2cae..2fd377dd4 100644 --- a/utils/funcexp/func_elt.cpp +++ b/utils/funcexp/func_elt.cpp @@ -73,15 +73,38 @@ string Func_elt::getStrVal(rowgroup::Row& row, case CalpontSystemCatalog::DECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - number = d.value / pow(10.0, dscale); - int lefto = (d.value - number * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( utils::is_nonnegative(number) && lefto > 4 ) - number++; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor, scaleDivisor2; - if ( utils::is_negative(number) && lefto < -4 ) - number--; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (utils::is_nonnegative(tmpval) >= 0 && lefto > 4) + tmpval++; + + if (utils::is_negative(tmpval) < 0 && lefto < -4) + tmpval--; + + number = datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + double dscale = d.scale; + number = d.value / pow(10.0, dscale); + int lefto = (d.value - number * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( utils::is_nonnegative(number) && lefto > 4 ) + number++; + + if ( utils::is_negative(number) && lefto < -4 ) + number--; + } break; } diff --git a/utils/funcexp/func_floor.cpp b/utils/funcexp/func_floor.cpp index 1e0ee7f09..5116a9a54 100644 --- a/utils/funcexp/func_floor.cpp +++ b/utils/funcexp/func_floor.cpp @@ -62,41 +62,8 @@ int64_t Func_floor::getIntVal(Row& row, case execplan::CalpontSystemCatalog::MEDINT: case execplan::CalpontSystemCatalog::TINYINT: case execplan::CalpontSystemCatalog::SMALLINT: - case execplan::CalpontSystemCatalog::DECIMAL: - case execplan::CalpontSystemCatalog::UDECIMAL: { - if (op_ct.scale == 0) - { - ret = parm[0]->data()->getIntVal(row, isNull); - break; - } - - IDB_Decimal decimal = parm[0]->data()->getDecimalVal(row, isNull); - - if (isNull) - break; - - ret = decimal.value; - - // negative scale is not supported by CNX yet - if (decimal.scale > 0) - { - - if (decimal.scale >= 19) - { - std::ostringstream oss; - oss << "floor: datatype of " << execplan::colDataTypeToString(op_ct.colDataType) - << " with scale " << (int) decimal.scale << " is beyond supported scale"; - throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT); - } - - int64_t tmp = ret; - ret /= helpers::powerOf10_c[decimal.scale]; - - // Largest integer value not greater than X. - if (tmp < 0 && tmp < ret) - ret -= 1; - } + ret = parm[0]->data()->getIntVal(row, isNull); } break; @@ -338,6 +305,20 @@ double Func_floor::getDoubleVal(Row& row, if (!isNull) ret = floor(strtod(str.c_str(), 0)); } + else if (op_ct.colDataType == CalpontSystemCatalog::DECIMAL || + op_ct.colDataType == CalpontSystemCatalog::UDECIMAL) + { + IDB_Decimal tmp = getDecimalVal(row, parm, isNull, op_ct); + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + ret = datatypes::Decimal::getDoubleFromWideDecimal(tmp.s128Value); + } + else + { + ret = (double) tmp.value; + } + } else { ret = (double) getIntVal(row, parm, isNull, op_ct); @@ -371,6 +352,20 @@ long double Func_floor::getLongDoubleVal(Row& row, if (!isNull) ret = floor(strtod(str.c_str(), 0)); } + else if (op_ct.colDataType == CalpontSystemCatalog::DECIMAL || + op_ct.colDataType == CalpontSystemCatalog::UDECIMAL) + { + IDB_Decimal tmp = getDecimalVal(row, parm, isNull, op_ct); + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + ret = datatypes::Decimal::getLongDoubleFromWideDecimal(tmp.s128Value); + } + else + { + ret = (long double) tmp.value; + } + } else { ret = (long double) getIntVal(row, parm, isNull, op_ct); @@ -416,6 +411,20 @@ string Func_floor::getStrVal(Row& row, *d = '\0'; } + else if (op_ct.colDataType == CalpontSystemCatalog::DECIMAL || + op_ct.colDataType == CalpontSystemCatalog::UDECIMAL) + { + IDB_Decimal d = getDecimalVal(row, parm, isNull, op_ct); + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + dataconvert::DataConvert::decimalToString(&d.s128Value, d.scale, tmp, 511, op_ct.colDataType); + } + else + { + dataconvert::DataConvert::decimalToString(d.value, d.scale, tmp, 511, op_ct.colDataType); + } + } else if (isUnsigned(op_ct.colDataType)) { #ifndef __LP64__ @@ -436,6 +445,165 @@ string Func_floor::getStrVal(Row& row, return string(tmp); } +IDB_Decimal Func_floor::getDecimalVal(Row& row, + FunctionParm& parm, + bool& isNull, + CalpontSystemCatalog::ColType& op_ct) +{ + IDB_Decimal ret; + + switch (op_ct.colDataType) + { + case execplan::CalpontSystemCatalog::BIGINT: + case execplan::CalpontSystemCatalog::INT: + case execplan::CalpontSystemCatalog::MEDINT: + case execplan::CalpontSystemCatalog::TINYINT: + case execplan::CalpontSystemCatalog::SMALLINT: + { + ret.value = parm[0]->data()->getIntVal(row, isNull); + } + break; + + case execplan::CalpontSystemCatalog::DECIMAL: + case execplan::CalpontSystemCatalog::UDECIMAL: + { + ret = parm[0]->data()->getDecimalVal(row, isNull); + + if (isNull) + break; + + // negative scale is not supported by CNX yet + if (ret.scale > 0) + { + if (ret.scale > datatypes::INT128MAXPRECISION) + { + std::ostringstream oss; + oss << "floor: datatype of " << execplan::colDataTypeToString(op_ct.colDataType) + << " with scale " << (int) ret.scale << " is beyond supported scale"; + throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT); + } + + if (op_ct.colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t tmp = ret.s128Value; + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, ret.scale); + ret.s128Value /= scaleDivisor; + + // Largest integer value not greater than X. + if (tmp < 0 && tmp < ret.s128Value) + ret.s128Value -= 1; + } + else + { + int64_t tmp = ret.value; + ret.value /= helpers::powerOf10_c[ret.scale]; + + // Largest integer value not greater than X. + if (tmp < 0 && tmp < ret.value) + ret.value -= 1; + } + } + } + break; + + case execplan::CalpontSystemCatalog::UBIGINT: + case execplan::CalpontSystemCatalog::UINT: + case execplan::CalpontSystemCatalog::UMEDINT: + case execplan::CalpontSystemCatalog::UTINYINT: + case execplan::CalpontSystemCatalog::USMALLINT: + { + ret.value = (int64_t)parm[0]->data()->getUintVal(row, isNull); + } + break; + + case execplan::CalpontSystemCatalog::DOUBLE: + case execplan::CalpontSystemCatalog::UDOUBLE: + case execplan::CalpontSystemCatalog::FLOAT: + case execplan::CalpontSystemCatalog::UFLOAT: + { + ret.value = (int64_t) floor(parm[0]->data()->getDoubleVal(row, isNull)); + } + break; + + case execplan::CalpontSystemCatalog::LONGDOUBLE: + { + ret.value = (int64_t) floorl(parm[0]->data()->getLongDoubleVal(row, isNull)); + } + break; + + case execplan::CalpontSystemCatalog::VARCHAR: + case execplan::CalpontSystemCatalog::CHAR: + case execplan::CalpontSystemCatalog::TEXT: + { + const string& str = parm[0]->data()->getStrVal(row, isNull); + + if (!isNull) + ret.value = (int64_t) floor(strtod(str.c_str(), 0)); + } + break; + + case execplan::CalpontSystemCatalog::DATE: + { + string str = DataConvert::dateToString1(parm[0]->data()->getDateIntVal(row, isNull)); + + if (!isNull) + ret.value = atoll(str.c_str()); + } + break; + + case execplan::CalpontSystemCatalog::DATETIME: + { + string str = + DataConvert::datetimeToString1(parm[0]->data()->getDatetimeIntVal(row, isNull)); + + // strip off micro seconds + str = str.substr(0, 14); + + if (!isNull) + ret.value = atoll(str.c_str()); + } + break; + + case execplan::CalpontSystemCatalog::TIMESTAMP: + { + string str = + DataConvert::timestampToString1(parm[0]->data()->getTimestampIntVal(row, isNull), timeZone()); + + // strip off micro seconds + str = str.substr(0, 14); + + if (!isNull) + ret.value = atoll(str.c_str()); + } + break; + + case execplan::CalpontSystemCatalog::TIME: + { + string str = + DataConvert::timeToString1(parm[0]->data()->getTimeIntVal(row, isNull)); + + // strip off micro seconds + str = str.substr(0, 14); + + if (!isNull) + ret.value = atoll(str.c_str()); + } + break; + + default: + { + std::ostringstream oss; + oss << "floor: datatype of " << execplan::colDataTypeToString(op_ct.colDataType); + throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT); + } + } + + ret.scale = 0; + + return ret; +} + } // namespace funcexp // vim:ts=4 sw=4: diff --git a/utils/funcexp/func_inet_aton.cpp b/utils/funcexp/func_inet_aton.cpp index 4bcdc3115..2f0e5295e 100644 --- a/utils/funcexp/func_inet_aton.cpp +++ b/utils/funcexp/func_inet_aton.cpp @@ -154,21 +154,34 @@ execplan::IDB_Decimal Func_inet_aton::getDecimalVal(rowgroup::Row& row, bool& isNull, execplan::CalpontSystemCatalog::ColType& op_ct) { -// std::cout << "In Func_inet_aton::getDecimalVal" << std::endl; - - execplan::IDB_Decimal dValue ( joblist::NULL_INT64, 0, 0 ); + execplan::CalpontSystemCatalog::ColType colType = fp[0]->data()->resultType(); const std::string& sValue = fp[0]->data()->getStrVal(row, isNull); - if (!isNull) + if (colType.precision <= datatypes::INT64MAXPRECISION) { - int64_t iValue = convertAton( sValue, isNull ); - if (!isNull) - return execplan::IDB_Decimal( iValue, 0, 0 ); - } + { + int64_t iValue = convertAton( sValue, isNull ); - return dValue; + if (!isNull) + return execplan::IDB_Decimal( iValue, colType.scale, colType.precision ); + } + + return execplan::IDB_Decimal( joblist::NULL_INT64, colType.scale, colType.precision ); + } + else + { + if (!isNull) + { + int64_t iValue = convertAton( sValue, isNull ); + + if (!isNull) + return execplan::IDB_Decimal( 0, colType.scale, colType.precision, (int128_t) iValue ); + } + + return execplan::IDB_Decimal( 0, colType.scale, colType.precision, datatypes::Decimal128Null ); + } } //------------------------------------------------------------------------------ diff --git a/utils/funcexp/func_inet_ntoa.cpp b/utils/funcexp/func_inet_ntoa.cpp index b9a31b08e..0d33d5ec1 100644 --- a/utils/funcexp/func_inet_ntoa.cpp +++ b/utils/funcexp/func_inet_ntoa.cpp @@ -211,8 +211,6 @@ execplan::IDB_Decimal Func_inet_ntoa::getDecimalVal(rowgroup::Row& row, bool& isNull, execplan::CalpontSystemCatalog::ColType& op_ct) { -// std::cout << "In Func_inet_ntoa::getDecimalVal" << std::endl; - // IDB_Decimal dValue = fp[0]->data()->getDecimalVal(row, isNull); execplan::IDB_Decimal dValue ( joblist::NULL_INT64, 0, 0 ); isNull = true; diff --git a/utils/funcexp/func_makedate.cpp b/utils/funcexp/func_makedate.cpp index 8c8c50abf..8efc3f171 100644 --- a/utils/funcexp/func_makedate.cpp +++ b/utils/funcexp/func_makedate.cpp @@ -68,15 +68,38 @@ uint64_t makedate(rowgroup::Row& row, case CalpontSystemCatalog::DECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - year = d.value / pow(10.0, dscale); - int lefto = (d.value - year * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( year >= 0 && lefto > 4 ) - year++; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor, scaleDivisor2; - if ( year < 0 && lefto < -4 ) - year--; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + year = datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + double dscale = d.scale; + year = d.value / pow(10.0, dscale); + int lefto = (d.value - year * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( year >= 0 && lefto > 4 ) + year++; + + if ( year < 0 && lefto < -4 ) + year--; + } break; } @@ -128,23 +151,53 @@ uint64_t makedate(rowgroup::Row& row, case CalpontSystemCatalog::DECIMAL: { IDB_Decimal d = parm[1]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - int64_t tmp = d.value / pow(10.0, dscale); - int lefto = (d.value - tmp * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( tmp >= 0 && lefto > 4 ) - tmp++; - - if ( tmp < 0 && lefto < -4 ) - tmp--; - - if (tmp < 1) + if (parm[1]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) { - isNull = true; - return 0; - } + int128_t scaleDivisor, scaleDivisor2; - dayofyear = helpers::intToString(tmp); + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + if (tmpval < 1) + { + isNull = true; + return 0; + } + + int64_t tmpval64 = datatypes::Decimal::getInt64FromWideDecimal(tmpval); + dayofyear = helpers::intToString(tmpval64); + } + else + { + double dscale = d.scale; + int64_t tmp = d.value / pow(10.0, dscale); + int lefto = (d.value - tmp * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if (tmp >= 0 && lefto > 4) + tmp++; + + if (tmp < 0 && lefto < -4) + tmp--; + + if (tmp < 1) + { + isNull = true; + return 0; + } + + dayofyear = helpers::intToString(tmp); + } break; } diff --git a/utils/funcexp/func_maketime.cpp b/utils/funcexp/func_maketime.cpp index b43fed4ab..3bc7b8c27 100644 --- a/utils/funcexp/func_maketime.cpp +++ b/utils/funcexp/func_maketime.cpp @@ -74,15 +74,38 @@ string Func_maketime::getStrVal(rowgroup::Row& row, case CalpontSystemCatalog::DECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - hour = d.value / pow(10.0, dscale); - int lefto = (d.value - hour * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( hour >= 0 && lefto > 4 ) - hour++; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor, scaleDivisor2; - if ( hour < 0 && lefto < -4 ) - hour--; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + hour = datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + double dscale = d.scale; + hour = d.value / pow(10.0, dscale); + int lefto = (d.value - hour * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( hour >= 0 && lefto > 4 ) + hour++; + + if ( hour < 0 && lefto < -4 ) + hour--; + } break; } @@ -114,15 +137,38 @@ string Func_maketime::getStrVal(rowgroup::Row& row, case CalpontSystemCatalog::DECIMAL: { IDB_Decimal d = parm[1]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - min = d.value / pow(10.0, dscale); - int lefto = (d.value - min * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( min >= 0 && lefto > 4 ) - min++; + if (parm[1]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor, scaleDivisor2; - if ( min < 0 && lefto < -4 ) - min--; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + min = datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + double dscale = d.scale; + min = d.value / pow(10.0, dscale); + int lefto = (d.value - min * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( min >= 0 && lefto > 4 ) + min++; + + if ( min < 0 && lefto < -4 ) + min--; + } break; } @@ -160,15 +206,38 @@ string Func_maketime::getStrVal(rowgroup::Row& row, case CalpontSystemCatalog::DECIMAL: { IDB_Decimal d = parm[2]->data()->getDecimalVal(row, isNull); - double dscale = d.scale; - sec = d.value / pow(10.0, dscale); - int lefto = (d.value - sec * pow(10.0, dscale)) / pow(10.0, dscale - 1); - if ( sec >= 0 && lefto > 4 ) - sec++; + if (parm[2]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + int128_t scaleDivisor, scaleDivisor2; - if ( sec < 0 && lefto < -4 ) - sec--; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + + scaleDivisor2 = (scaleDivisor <= 10) ? 1 : (scaleDivisor / 10); + + int128_t tmpval = d.s128Value / scaleDivisor; + int128_t lefto = (d.s128Value - tmpval * scaleDivisor) / scaleDivisor2; + + if (tmpval >= 0 && lefto > 4) + tmpval++; + + if (tmpval < 0 && lefto < -4) + tmpval--; + + sec = datatypes::Decimal::getInt64FromWideDecimal(tmpval); + } + else + { + double dscale = d.scale; + sec = d.value / pow(10.0, dscale); + int lefto = (d.value - sec * pow(10.0, dscale)) / pow(10.0, dscale - 1); + + if ( sec >= 0 && lefto > 4 ) + sec++; + + if ( sec < 0 && lefto < -4 ) + sec--; + } break; } diff --git a/utils/funcexp/func_mod.cpp b/utils/funcexp/func_mod.cpp index 214fd2b6c..1afc308f5 100644 --- a/utils/funcexp/func_mod.cpp +++ b/utils/funcexp/func_mod.cpp @@ -25,6 +25,8 @@ #include using namespace std; +#include + #include "functor_real.h" #include "funchelpers.h" #include "functioncolumn.h" @@ -54,7 +56,6 @@ IDB_Decimal Func_mod::getDecimalVal(Row& row, bool& isNull, CalpontSystemCatalog::ColType& operationColType) { - IDB_Decimal retValue; retValue.value = 0; retValue.scale = 0; @@ -65,22 +66,85 @@ IDB_Decimal Func_mod::getDecimalVal(Row& row, return retValue; } - int64_t div = parm[1]->data()->getIntVal(row, isNull); - - if ( div == 0 ) + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH || + parm[1]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) { - isNull = true; - return retValue; + IDB_Decimal div = parm[1]->data()->getDecimalVal(row, isNull); + + int128_t divInt, dividendInt; + + if (parm[1]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + divInt = div.s128Value; + else + divInt = div.value; + + if (divInt == 0) + { + isNull = true; + return retValue; + } + + IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); + + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + dividendInt = d.s128Value; + else + dividendInt = d.value; + + // integer division + if (d.scale == 0 && div.scale == 0) + { + retValue.s128Value = dividendInt % divInt; + } + // special case integer division + else if (div.scale == 0) + { + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + int128_t value = dividendInt / scaleDivisor; + int128_t lefto = dividendInt % scaleDivisor; + int128_t mod = (value % divInt) * scaleDivisor + lefto; + retValue.s128Value = mod; + } + // float division + else + { + __float128 divF, dividendF; + + int128_t scaleDivisor; + + datatypes::getScaleDivisor(scaleDivisor, div.scale); + divF = (__float128) divInt / scaleDivisor; + + datatypes::getScaleDivisor(scaleDivisor, d.scale); + dividendF = (__float128) dividendInt / scaleDivisor; + + __float128 mod = fmodq(dividendF, divF) * scaleDivisor; + + retValue.s128Value = (int128_t) mod; + } + retValue.scale = d.scale; + retValue.precision = datatypes::INT128MAXPRECISION; } + else + { + int64_t div = parm[1]->data()->getIntVal(row, isNull); - IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - int64_t value = d.value / pow(10.0, d.scale); - int lefto = d.value % (int)pow(10.0, d.scale); + if ( div == 0 ) + { + isNull = true; + return retValue; + } - int64_t mod = (value % div) * pow(10.0, d.scale) + lefto; + IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); + int64_t value = d.value / pow(10.0, d.scale); + int lefto = d.value % (int)pow(10.0, d.scale); - retValue.value = mod; - retValue.scale = d.scale; + int64_t mod = (value % div) * pow(10.0, d.scale) + lefto; + + retValue.value = mod; + retValue.scale = d.scale; + } return retValue; } @@ -164,9 +228,28 @@ double Func_mod::getDoubleVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - int64_t value = d.value / pow(10.0, d.scale); - mod = value % div; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + if (d.scale == 0) + { + mod = d.s128Value % div; + } + else + { + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + int128_t value = d.s128Value / scaleDivisor; + int128_t lefto = d.s128Value % scaleDivisor; + __float128 tmp = (__float128) (value % div) + (__float128) lefto / scaleDivisor; + mod = datatypes::Decimal::getDoubleFromFloat128(tmp); + } + } + else + { + int64_t value = d.value / pow(10.0, d.scale); + mod = value % div; + } } break; @@ -268,9 +351,28 @@ long double Func_mod::getLongDoubleVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - int64_t value = d.value / pow(10.0, d.scale); - mod = value % div; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + if (d.scale == 0) + { + mod = d.s128Value % div; + } + else + { + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + int128_t value = d.s128Value / scaleDivisor; + int128_t lefto = d.s128Value % scaleDivisor; + __float128 tmp = (__float128) (value % div) + (__float128) lefto / scaleDivisor; + mod = datatypes::Decimal::getLongDoubleFromFloat128(tmp); + } + } + else + { + int64_t value = d.value / pow(10.0, d.scale); + mod = value % div; + } } break; @@ -375,9 +477,28 @@ int64_t Func_mod::getIntVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - int64_t value = d.value / pow(10.0, d.scale); - mod = value % div; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + if (d.scale == 0) + { + mod = d.s128Value % div; + } + else + { + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + int128_t value = d.s128Value / scaleDivisor; + int128_t lefto = d.s128Value % scaleDivisor; + __float128 tmp = (__float128) (value % div) + (__float128) lefto / scaleDivisor; + mod = datatypes::Decimal::getInt64FromFloat128(tmp); + } + } + else + { + int64_t value = d.value / pow(10.0, d.scale); + mod = value % div; + } } break; @@ -473,9 +594,28 @@ uint64_t Func_mod::getUIntVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - int64_t value = d.value / pow(10.0, d.scale); - mod = value % div; + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + { + if (d.scale == 0) + { + mod = d.s128Value % div; + } + else + { + int128_t scaleDivisor; + datatypes::getScaleDivisor(scaleDivisor, d.scale); + int128_t value = d.s128Value / scaleDivisor; + int128_t lefto = d.s128Value % scaleDivisor; + __float128 tmp = (__float128) (value % div) + (__float128) lefto / scaleDivisor; + mod = datatypes::Decimal::getUInt64FromFloat128(tmp); + } + } + else + { + int64_t value = d.value / pow(10.0, d.scale); + mod = value % div; + } } break; diff --git a/utils/funcexp/func_monthname.cpp b/utils/funcexp/func_monthname.cpp index 7c27c9581..f04c37158 100644 --- a/utils/funcexp/func_monthname.cpp +++ b/utils/funcexp/func_monthname.cpp @@ -197,7 +197,11 @@ execplan::IDB_Decimal Func_monthname::getDecimalVal(rowgroup::Row& row, execplan::CalpontSystemCatalog::ColType& op_ct) { IDB_Decimal d; - d.value = getIntVal(row, fp, isNull, op_ct); + + if (fp[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + d.s128Value = getIntVal(row, fp, isNull, op_ct); + else + d.value = getIntVal(row, fp, isNull, op_ct); d.scale = 0; return d; } diff --git a/utils/funcexp/func_period_diff.cpp b/utils/funcexp/func_period_diff.cpp index 0f1b923c9..3f344fd8f 100644 --- a/utils/funcexp/func_period_diff.cpp +++ b/utils/funcexp/func_period_diff.cpp @@ -86,7 +86,24 @@ int64_t Func_period_diff::getIntVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[0]->data()->getDecimalVal(row, isNull); - period1 = d.value / pow(10.0, d.scale); + + 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; } @@ -135,7 +152,24 @@ int64_t Func_period_diff::getIntVal(rowgroup::Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { IDB_Decimal d = parm[1]->data()->getDecimalVal(row, isNull); - period2 = d.value / pow(10.0, d.scale); + + 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; } diff --git a/utils/funcexp/func_round.cpp b/utils/funcexp/func_round.cpp index 0064ae8df..780b499b0 100644 --- a/utils/funcexp/func_round.cpp +++ b/utils/funcexp/func_round.cpp @@ -116,18 +116,36 @@ int64_t Func_round::getIntVal(Row& row, { IDB_Decimal x = getDecimalVal(row, parm, isNull, op_ct); - if (x.scale > 0) + if (!datatypes::Decimal::isWideDecimalType(op_ct)) { - while (x.scale-- > 0) - x.value /= 10; + if (x.scale > 0) + { + while (x.scale-- > 0) + x.value /= 10; + } + else + { + while (x.scale++ < 0) + x.value *= 10; + } + + return x.value; } else { - while (x.scale++ < 0) - x.value *= 10; - } + if (x.scale > 0) + { + while (x.scale-- > 0) + x.s128Value /= 10; + } + else + { + while (x.scale++ < 0) + x.s128Value *= 10; + } - return x.value; + return datatypes::Decimal::getInt64FromWideDecimal(x.s128Value); + } } @@ -187,7 +205,12 @@ double Func_round::getDoubleVal(Row& row, if (isNull) return 0.0; - double d = x.value; + double d; + + if (!datatypes::Decimal::isWideDecimalType(op_ct)) + d = x.value; + else + d = datatypes::Decimal::getDoubleFromWideDecimal(x.s128Value); if (x.scale > 0) { @@ -249,7 +272,12 @@ long double Func_round::getLongDoubleVal(Row& row, if (isNull) return 0.0; - double d = x.value; + double d; + + if (!datatypes::Decimal::isWideDecimalType(op_ct)) + d = x.value; + else + d = datatypes::Decimal::getDoubleFromWideDecimal(x.s128Value); if (x.scale > 0) { @@ -283,62 +311,130 @@ IDB_Decimal Func_round::getDecimalVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { int64_t d = 0; - //@Bug 3101 - GCC 4.5.1 optimizes too aggressively here. Mark as volatile. - volatile int64_t p = 1; decimal = parm[0]->data()->getDecimalVal(row, isNull); - if (!isNull && parm.size() > 1) // round(X, D) + if (!datatypes::Decimal::isWideDecimalType(op_ct)) { - int64_t nvp = p; - d = parm[1]->data()->getIntVal(row, isNull); + //@Bug 3101 - GCC 4.5.1 optimizes too aggressively here. Mark as volatile. + volatile int64_t p = 1; - if (!isNull) - helpers::decimalPlaceDec(d, nvp, decimal.scale); - - p = nvp; - } - - if (isNull) - break; - - int64_t x = decimal.value; - - if (d > 0) - { - x = x * p; - } - else if (d < 0) - { - int64_t h = p / 2; // 0.5 - - if ((x >= h) || (x <= -h)) + if (!isNull && parm.size() > 1) // round(X, D) { - if (x >= 0) - x += h; - else - x -= h; + int64_t nvp = p; + d = parm[1]->data()->getIntVal(row, isNull); - if (p != 0) - x = x / p; + if (!isNull) + helpers::decimalPlaceDec(d, nvp, decimal.scale); + + p = nvp; + } + + if (isNull) + break; + + int64_t x = decimal.value; + + if (d > 0) + { + x = x * p; + } + else if (d < 0) + { + int64_t h = p / 2; // 0.5 + + if ((x >= h) || (x <= -h)) + { + if (x >= 0) + x += h; + else + x -= h; + + if (p != 0) + x = x / p; + else + x = 0; + } else + { x = 0; + } } - else + + // negative scale is not supported by CNX yet, set d to 0. + if (decimal.scale < 0) { - x = 0; + do + x *= 10; + + while (++decimal.scale < 0); } - } - // negative scale is not supported by CNX yet, set d to 0. - if (decimal.scale < 0) + decimal.value = x; + } + else { - do - x *= 10; + //@Bug 3101 - GCC 4.5.1 optimizes too aggressively here. Mark as volatile. + volatile int128_t p = 1; - while (++decimal.scale < 0); + if (!isNull && parm.size() > 1) // round(X, D) + { + int128_t nvp = p; + d = parm[1]->data()->getIntVal(row, isNull); + + if (!isNull) + helpers::decimalPlaceDec(d, nvp, decimal.scale); + + p = nvp; + } + + if (isNull) + break; + + if (d < -datatypes::INT128MAXPRECISION) + { + decimal.s128Value = 0; + break; + } + + int128_t x = decimal.s128Value; + + if (d > 0) + { + x = x * p; + } + else if (d < 0) + { + int128_t h = p / 2; // 0.5 + + if ((x >= h) || (x <= -h)) + { + if (x >= 0) + x += h; + else + x -= h; + + if (p != 0) + x = x / p; + else + x = 0; + } + else + { + x = 0; + } + } + + // negative scale is not supported by CNX yet, set d to 0. + if (decimal.scale < 0) + { + do + x *= 10; + + while (++decimal.scale < 0); + } + + decimal.s128Value = x; } - - decimal.value = x; } break; @@ -624,7 +720,14 @@ string Func_round::getStrVal(Row& row, break; } - return dataconvert::DataConvert::decimalToString(x.value, x.scale, op_ct.colDataType); + if (!datatypes::Decimal::isWideDecimalType(op_ct)) + return dataconvert::DataConvert::decimalToString(x.value, x.scale, op_ct.colDataType); + else + { + char buf[utils::MAXLENGTH16BYTES]; + dataconvert::DataConvert::decimalToString( &x.s128Value, x.scale, buf, utils::MAXLENGTH16BYTES, op_ct.colDataType); + return string(buf); + } } diff --git a/utils/funcexp/func_sec_to_time.cpp b/utils/funcexp/func_sec_to_time.cpp index 3fc94b5ef..afb532ec1 100644 --- a/utils/funcexp/func_sec_to_time.cpp +++ b/utils/funcexp/func_sec_to_time.cpp @@ -257,12 +257,15 @@ execplan::IDB_Decimal Func_sec_to_time::getDecimalVal(rowgroup::Row& row, execplan::CalpontSystemCatalog::ColType& op_ct) { IDB_Decimal d; + int64_t val = parm[0]->data()->getIntVal(row, isNull); + int64_t tmpVal; + if (val > 3020399) - d.value = 8385959; + tmpVal = 8385959; else if (val < -3020399) - d.value = 4286581337LL; + tmpVal = 4286581337LL; else { string time = getStrVal(row, parm, isNull, op_ct); @@ -277,15 +280,17 @@ execplan::IDB_Decimal Func_sec_to_time::getDecimalVal(rowgroup::Row& row, char* ep = NULL; const char* str = time.c_str(); errno = 0; - d.value = strtoll(str, &ep, 10); + tmpVal = strtoll(str, &ep, 10); } + if (parm[0]->data()->resultType().colWidth == datatypes::MAXDECIMALWIDTH) + d.s128Value = tmpVal; + else + d.value = tmpVal; + d.scale = 0; return d; } - - - } // namespace funcexp // vim:ts=4 sw=4: diff --git a/utils/funcexp/func_truncate.cpp b/utils/funcexp/func_truncate.cpp index 057a1c299..d60fa6e70 100644 --- a/utils/funcexp/func_truncate.cpp +++ b/utils/funcexp/func_truncate.cpp @@ -119,18 +119,36 @@ int64_t Func_truncate::getIntVal(Row& row, { IDB_Decimal x = getDecimalVal(row, parm, isNull, op_ct); - if (x.scale > 0) + if (!datatypes::Decimal::isWideDecimalType(op_ct)) { - while (x.scale-- > 0) - x.value /= 10; + if (x.scale > 0) + { + while (x.scale-- > 0) + x.value /= 10; + } + else + { + while (x.scale++ < 0) + x.value *= 10; + } + + return x.value; } else { - while (x.scale++ < 0) - x.value *= 10; - } + if (x.scale > 0) + { + while (x.scale-- > 0) + x.s128Value /= 10; + } + else + { + while (x.scale++ < 0) + x.s128Value *= 10; + } - return x.value; + return datatypes::Decimal::getInt64FromWideDecimal(x.s128Value); + } } @@ -210,7 +228,12 @@ double Func_truncate::getDoubleVal(Row& row, if (isNull) return 0.0; - double d = x.value; + double d; + + if (!datatypes::Decimal::isWideDecimalType(op_ct)) + d = x.value; + else + d = datatypes::Decimal::getDoubleFromWideDecimal(x.s128Value); if (x.scale > 0) { @@ -265,7 +288,12 @@ long double Func_truncate::getLongDoubleVal(Row& row, if (isNull) return 0.0; - double d = x.value; + double d; + + if (!datatypes::Decimal::isWideDecimalType(op_ct)) + d = x.value; + else + d = datatypes::Decimal::getDoubleFromWideDecimal(x.s128Value); if (x.scale > 0) { @@ -304,55 +332,116 @@ IDB_Decimal Func_truncate::getDecimalVal(Row& row, case execplan::CalpontSystemCatalog::UDECIMAL: { int64_t d = 0; - //@Bug 3101 - GCC 4.5.1 optimizes too aggressively here. Mark as volatile. - volatile int64_t p = 1; decimal = parm[0]->data()->getDecimalVal(row, isNull); - if (!isNull) + if (!datatypes::Decimal::isWideDecimalType(op_ct)) { - int64_t nvp = p; - d = parm[1]->data()->getIntVal(row, isNull); + //@Bug 3101 - GCC 4.5.1 optimizes too aggressively here. Mark as volatile. + volatile int64_t p = 1; if (!isNull) - helpers::decimalPlaceDec(d, nvp, decimal.scale); - - p = nvp; - } - - if (isNull) - break; - - int64_t x = decimal.value; - - if (d > 0) - { - x = x * p; - } - else if (d < 0) - { - if ((x >= p) || (x <= -p)) { - if (p != 0) - x = x / p; + int64_t nvp = p; + d = parm[1]->data()->getIntVal(row, isNull); + + if (!isNull) + helpers::decimalPlaceDec(d, nvp, decimal.scale); + + p = nvp; + } + + if (isNull) + break; + + int64_t x = decimal.value; + + if (d > 0) + { + x = x * p; + } + else if (d < 0) + { + if ((x >= p) || (x <= -p)) + { + if (p != 0) + x = x / p; + else + x = 0; + } else + { x = 0; + } } - else + + // negative scale is not supported by CNX yet, set d to 0. + if (decimal.scale < 0) { - x = 0; + do + x *= 10; + + while (++decimal.scale < 0); } - } - // negative scale is not supported by CNX yet, set d to 0. - if (decimal.scale < 0) + decimal.value = x; + } + else { - do - x *= 10; + //@Bug 3101 - GCC 4.5.1 optimizes too aggressively here. Mark as volatile. + volatile int128_t p = 1; - while (++decimal.scale < 0); + if (!isNull) + { + int128_t nvp = p; + d = parm[1]->data()->getIntVal(row, isNull); + + if (!isNull) + helpers::decimalPlaceDec(d, nvp, decimal.scale); + + p = nvp; + } + + if (isNull) + break; + + if (d < -datatypes::INT128MAXPRECISION) + { + decimal.s128Value = 0; + break; + } + + int128_t x = decimal.s128Value; + + if (d > 0) + { + x = x * p; + } + else if (d < 0) + { + if ((x >= p) || (x <= -p)) + { + if (p != 0) + x = x / p; + else + x = 0; + } + else + { + x = 0; + } + } + + // negative scale is not supported by CNX yet, set d to 0. + if (decimal.scale < 0) + { + do + x *= 10; + + while (++decimal.scale < 0); + } + + decimal.s128Value = x; } - - decimal.value = x; } break; @@ -650,7 +739,14 @@ string Func_truncate::getStrVal(Row& row, break; } - return dataconvert::DataConvert::decimalToString(x.value, x.scale, op_ct.colDataType); + if (!datatypes::Decimal::isWideDecimalType(op_ct)) + return dataconvert::DataConvert::decimalToString(x.value, x.scale, op_ct.colDataType); + else + { + char buf[utils::MAXLENGTH16BYTES]; + dataconvert::DataConvert::decimalToString( &x.s128Value, x.scale, buf, utils::MAXLENGTH16BYTES, op_ct.colDataType); + return string(buf); + } } diff --git a/utils/funcexp/funchelpers.h b/utils/funcexp/funchelpers.h index 8f017d544..709d441bc 100644 --- a/utils/funcexp/funchelpers.h +++ b/utils/funcexp/funchelpers.h @@ -470,7 +470,8 @@ inline int power ( int16_t a ) return b; } -inline void decimalPlaceDec(int64_t& d, int64_t& p, int8_t& s) +template +inline void decimalPlaceDec(int64_t& d, T& p, int8_t& s) { // find new scale if D < s if (d < s) diff --git a/utils/funcexp/functor_real.h b/utils/funcexp/functor_real.h index 0f5137891..d31a55686 100644 --- a/utils/funcexp/functor_real.h +++ b/utils/funcexp/functor_real.h @@ -281,6 +281,11 @@ public: FunctionParm& fp, bool& isNull, execplan::CalpontSystemCatalog::ColType& op_ct); + + execplan::IDB_Decimal getDecimalVal(rowgroup::Row& row, + FunctionParm& fp, + bool& isNull, + execplan::CalpontSystemCatalog::ColType& op_ct); }; @@ -318,6 +323,11 @@ public: FunctionParm& fp, bool& isNull, execplan::CalpontSystemCatalog::ColType& op_ct); + + execplan::IDB_Decimal getDecimalVal(rowgroup::Row& row, + FunctionParm& fp, + bool& isNull, + execplan::CalpontSystemCatalog::ColType& op_ct); }; diff --git a/utils/rowgroup/rowgroup.h b/utils/rowgroup/rowgroup.h index edd552c93..17d955a1f 100644 --- a/utils/rowgroup/rowgroup.h +++ b/utils/rowgroup/rowgroup.h @@ -1947,6 +1947,10 @@ inline void copyRow(const Row& in, Row* out, uint32_t colCount) out->setUintField(in.getUintField(i), i); else if (UNLIKELY(in.getColTypes()[i] == execplan::CalpontSystemCatalog::LONGDOUBLE)) out->setLongDoubleField(in.getLongDoubleField(i), i); + else if (UNLIKELY((in.getColType(i) == execplan::CalpontSystemCatalog::DECIMAL || + in.getColType(i) == execplan::CalpontSystemCatalog::UDECIMAL) && + in.getColumnWidth(i) == datatypes::MAXDECIMALWIDTH)) + in.copyBinaryField(*out, i, i); else out->setIntField(in.getIntField(i), i); }