diff --git a/datatypes/mcs_datatype.h b/datatypes/mcs_datatype.h index 01361c657..1d25400ef 100644 --- a/datatypes/mcs_datatype.h +++ b/datatypes/mcs_datatype.h @@ -230,6 +230,16 @@ public: } } + /** + @brief The method returns true if the column precision + belongs to a wide decimal range. + */ + inline bool isWideDecimalPrecision() const + { + return ((precision > INT64MAXPRECISION) && + (precision <= INT128MAXPRECISION)); + } + }; class TypeHolderStd: public TypeAttributesStd diff --git a/datatypes/mcs_decimal.h b/datatypes/mcs_decimal.h index 56050388d..1229a8632 100644 --- a/datatypes/mcs_decimal.h +++ b/datatypes/mcs_decimal.h @@ -172,6 +172,8 @@ class Decimal: public TSInt128 public: static constexpr uint8_t MAXLENGTH16BYTES = TSInt128::maxLength(); static constexpr uint8_t MAXLENGTH8BYTES = 23; + static constexpr int128_t minInt128 = TFloat128::minInt128; + static constexpr int128_t maxInt128 = TFloat128::maxInt128; static inline bool isWideDecimalNullValue(const int128_t& val) { @@ -193,9 +195,6 @@ class Decimal: public TSInt128 val = TSInt128::EmptyValue; } - static constexpr int128_t minInt128 = int128_t(0x8000000000000000LL) << 64; - static constexpr int128_t maxInt128 = (int128_t(0x7FFFFFFFFFFFFFFFLL) << 64) + 0xFFFFFFFFFFFFFFFFLL; - /** @brief Compares two Decimal taking scale into account. */ diff --git a/datatypes/mcs_float128.h b/datatypes/mcs_float128.h index 52c12c150..9af7e8556 100644 --- a/datatypes/mcs_float128.h +++ b/datatypes/mcs_float128.h @@ -50,6 +50,9 @@ struct get_integral_type{ class TFloat128 { public: + static constexpr int128_t minInt128 = int128_t(0x8000000000000000LL) << 64; + static constexpr int128_t maxInt128 = (int128_t(0x7FFFFFFFFFFFFFFFLL) << 64) + 0xFFFFFFFFFFFFFFFFLL; + static constexpr uint16_t MAXLENGTH16BYTES = 42; // A variety of ctors for aligned and unaligned arguments TFloat128(): value(0) { } @@ -64,7 +67,21 @@ class TFloat128 return TFloat128::MAXLENGTH16BYTES; } - // The method converts a TFloat128 to integral types + inline int128_t toTSInt128() const + { + if (value > static_cast<__float128>(maxInt128)) + return maxInt128; + else if (value < static_cast<__float128>(minInt128)) + return minInt128; + + return static_cast(value); + } + + inline operator int128_t() const + { + return toTSInt128(); + } + inline operator double() const { return toDouble(); @@ -100,7 +117,7 @@ class TFloat128 return toTSInt64(); } - inline int64_t toTUInt64() const + inline uint64_t toTUInt64() const { if (value > static_cast<__float128>(UINT64_MAX)) return UINT64_MAX; diff --git a/datatypes/mcs_int128.h b/datatypes/mcs_int128.h index 291114e4d..154342952 100644 --- a/datatypes/mcs_int128.h +++ b/datatypes/mcs_int128.h @@ -119,10 +119,12 @@ class TSInt128 static constexpr int128_t NullValue = int128_t(0x8000000000000000LL) << 64; static constexpr int128_t EmptyValue = (int128_t(0x8000000000000000LL) << 64) + 1; - // A variety of ctors for aligned and unaligned arguments TSInt128(): s128Value(0) { } + // Copy ctor + TSInt128(const TSInt128& other): s128Value(other.s128Value) { } + // aligned argument TSInt128(const int128_t& x) { s128Value = x; } diff --git a/dbcon/execplan/aggregatecolumn.cpp b/dbcon/execplan/aggregatecolumn.cpp index 0141ed832..675f6cefb 100644 --- a/dbcon/execplan/aggregatecolumn.cpp +++ b/dbcon/execplan/aggregatecolumn.cpp @@ -525,14 +525,26 @@ void AggregateColumn::evaluate(Row& row, bool& isNull) case CalpontSystemCatalog::UDECIMAL: switch (fResultType.colWidth) { + case 16: + { + datatypes::TSInt128 val = row.getTSInt128Field(fInputIndex); + + if (val.isNull()) + isNull = true; + else + fResult.decimalVal = IDB_Decimal(val, fResultType.scale, fResultType.precision); + + break; + } + case 1: if (row.equals<1>(TINYINTNULL, fInputIndex)) isNull = true; else - { - fResult.decimalVal.value = row.getIntField<1>(fInputIndex); - fResult.decimalVal.scale = (unsigned)fResultType.scale; - } + fResult.decimalVal = IDB_Decimal( + row.getIntField<1>(fInputIndex), + fResultType.scale, + fResultType.precision); break; @@ -540,10 +552,10 @@ void AggregateColumn::evaluate(Row& row, bool& isNull) if (row.equals<2>(SMALLINTNULL, fInputIndex)) isNull = true; else - { - fResult.decimalVal.value = row.getIntField<2>(fInputIndex); - fResult.decimalVal.scale = (unsigned)fResultType.scale; - } + fResult.decimalVal = IDB_Decimal( + row.getIntField<2>(fInputIndex), + fResultType.scale, + fResultType.precision); break; @@ -551,10 +563,10 @@ void AggregateColumn::evaluate(Row& row, bool& isNull) if (row.equals<4>(INTNULL, fInputIndex)) isNull = true; else - { - fResult.decimalVal.value = row.getIntField<4>(fInputIndex); - fResult.decimalVal.scale = (unsigned)fResultType.scale; - } + fResult.decimalVal = IDB_Decimal( + row.getIntField<4>(fInputIndex), + fResultType.scale, + fResultType.precision); break; @@ -562,10 +574,10 @@ void AggregateColumn::evaluate(Row& row, bool& isNull) if (row.equals<8>(BIGINTNULL, fInputIndex)) isNull = true; else - { - fResult.decimalVal.value = (int64_t)row.getUintField<8>(fInputIndex); - fResult.decimalVal.scale = (unsigned)fResultType.scale; - } + fResult.decimalVal = IDB_Decimal( + (int64_t) row.getUintField<8>(fInputIndex), + fResultType.scale, + fResultType.precision); break; } diff --git a/dbcon/execplan/treenode.h b/dbcon/execplan/treenode.h index 9017f562b..f3f067681 100644 --- a/dbcon/execplan/treenode.h +++ b/dbcon/execplan/treenode.h @@ -1003,41 +1003,82 @@ inline IDB_Decimal TreeNode::getDecimalVal() throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: non-support conversion from binary string"); case CalpontSystemCatalog::BIGINT: + { + idbassert(fResultType.scale == 0); + + if (fResultType.isWideDecimalPrecision()) + fResult.decimalVal = IDB_Decimal(0, 0, fResultType.precision, + (int128_t)fResult.intVal); + else + fResult.decimalVal = IDB_Decimal(fResult.intVal, 0, + fResultType.precision); + + break; + } + case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::TINYINT: - fResult.decimalVal.value = (int64_t)(fResult.intVal * pow((double)10.0, fResultType.scale)); - fResult.decimalVal.scale = fResultType.scale; - fResult.decimalVal.precision = fResultType.precision; + { + idbassert(fResultType.scale == 0); + + fResult.decimalVal = IDB_Decimal(fResult.intVal, 0, + fResultType.precision); + break; + } case CalpontSystemCatalog::UBIGINT: + { + idbassert(fResultType.scale == 0); + + if (fResultType.isWideDecimalPrecision()) + fResult.decimalVal = IDB_Decimal(0, 0, fResultType.precision, + (int128_t)fResult.uintVal); + else + fResult.decimalVal = IDB_Decimal((int64_t)fResult.uintVal, 0, + fResultType.precision); + + break; + } + case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UTINYINT: - fResult.decimalVal.value = (int64_t)(fResult.uintVal * pow((double)10.0, fResultType.scale)); - fResult.decimalVal.scale = fResultType.scale; - fResult.decimalVal.precision = fResultType.precision; + { + idbassert(fResultType.scale == 0); + + fResult.decimalVal = IDB_Decimal((int64_t)fResult.uintVal, 0, + fResultType.precision); + break; + } case CalpontSystemCatalog::LONGDOUBLE: + { + long double dlScaled = fResult.longDoubleVal; + + if (fResultType.scale > 0) { - long double dlScaled = fResult.longDoubleVal; - if (fResultType.scale > 0) - { - dlScaled= fResult.longDoubleVal * pow((double)10.0, fResultType.scale); - } - if (dlScaled > (double)MAX_BIGINT) - { - throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: decimal overflow."); - } - fResult.decimalVal.value = (int64_t)roundl((fResult.longDoubleVal * pow((double)10.0, fResultType.scale))); - fResult.decimalVal.scale = fResultType.scale; - fResult.decimalVal.precision = fResultType.precision; + dlScaled = fResult.longDoubleVal * pow((double)10.0, fResultType.scale); } + + if ((dlScaled > (long double)INT64_MAX) || (dlScaled < (long double)(INT64_MIN))) + { + datatypes::TFloat128 temp((__float128)dlScaled); + fResult.decimalVal = IDB_Decimal(0, fResultType.scale, + fResultType.precision, static_cast(temp)); + } + else + { + fResult.decimalVal = IDB_Decimal((int64_t)lroundl(dlScaled), + fResultType.scale, fResultType.precision); + } + break; + } case CalpontSystemCatalog::DATE: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: Invalid conversion from date."); diff --git a/dbcon/joblist/tupleaggregatestep.cpp b/dbcon/joblist/tupleaggregatestep.cpp index db0fc6c8a..8891c82d8 100644 --- a/dbcon/joblist/tupleaggregatestep.cpp +++ b/dbcon/joblist/tupleaggregatestep.cpp @@ -3475,11 +3475,11 @@ void TupleAggregateStep::prep2PhasesAggregate( if (aggOp == ROWAGG_SUM) { - wideDecimalOrLongDouble(colPm, typeProj[colPm], - precisionProj, scaleProj, widthAggPm, + wideDecimalOrLongDouble(colPm, typeAggPm[colPm], + precisionAggPm, scaleAggPm, widthAggPm, typeAggUm, scaleAggUm, precisionAggUm, widthAggUm); - oidsAggUm.push_back(oidsProj[colPm]); + oidsAggUm.push_back(oidsAggPm[colPm]); keysAggUm.push_back(retKey); csNumAggUm.push_back(8); } diff --git a/dbcon/mysql/ha_mcs_execplan.cpp b/dbcon/mysql/ha_mcs_execplan.cpp index a5daf7048..0e52ebb65 100755 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -4949,7 +4949,7 @@ ReturnedColumn* buildAggregateColumn(Item* item, gp_walk_info& gwi) CalpontSystemCatalog::ColType ct; ct.colDataType = CalpontSystemCatalog::BIGINT; ct.colWidth = 8; - ct.scale = parm->resultType().scale; + ct.scale = 0; ac->resultType(ct); } else if (isp->sum_func() == Item_sum::STD_FUNC ||