| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "dbcommon/function/decimal-function.h" |
| |
| #include <algorithm> |
| #include <functional> |
| #include <limits> |
| #include <memory> |
| #include <string> |
| #include <type_traits> |
| |
| #include "boost/multiprecision/cpp_dec_float.hpp" |
| #include "boost/multiprecision/cpp_int.hpp" |
| |
| #include "dbcommon/common/vector.h" |
| #include "dbcommon/common/vector/fixed-length-vector.h" |
| #include "dbcommon/common/vector/variable-length-vector.h" |
| #include "dbcommon/function/arithmetic-function.h" |
| #include "dbcommon/function/invoker.h" |
| #include "dbcommon/function/mathematical-function.h" |
| #include "dbcommon/type/type-util.h" |
| #include "dbcommon/utils/macro.h" |
| |
| namespace dbcommon { |
| |
| typedef bool (*cmpWithZero)(Int128 x); |
| static inline bool LTZero(Int128 x) { return x < 0; } |
| static inline bool LEZero(Int128 x) { return x <= 0; } |
| static inline bool EQZero(Int128 x) { return x == 0; } |
| static inline bool NEZero(Int128 x) { return x != 0; } |
| static inline bool GEZero(Int128 x) { return x >= 0; } |
| static inline bool GTZero(Int128 x) { return x > 0; } |
| |
| template <cmpWithZero cmpCondition> |
| static inline force_inline bool decimalCmp(Int128 val1, int64_t scale1, |
| Int128 val2, int64_t scale2) { |
| if (scale1 < scale2) { |
| val1 = |
| scaleUpInt128ByPowerOfTen(val1, static_cast<int32_t>(scale2 - scale1)); |
| } |
| if (scale1 > scale2) { |
| val2 = |
| scaleUpInt128ByPowerOfTen(val2, static_cast<int32_t>(scale1 - scale2)); |
| } |
| val1 -= val2; |
| return cmpCondition(val1); |
| } |
| |
| template <cmpWithZero cmpCondition> |
| Datum DECIMAL_VAL_VAL_CMP(Datum *params, uint64_t size) { |
| assert(size == 3 && "invalid input"); |
| Scalar *ret = DatumGetValue<Scalar *>(params[0]); |
| Scalar *left = DatumGetValue<Scalar *>(params[1]); |
| Scalar *right = DatumGetValue<Scalar *>(params[2]); |
| DecimalVar *value1 = DatumGetValue<DecimalVar *>(left->value); |
| DecimalVar *value2 = DatumGetValue<DecimalVar *>(right->value); |
| |
| Int128 ival1 = Int128(value1->highbits, value1->lowbits); |
| Int128 ival2 = Int128(value2->highbits, value2->lowbits); |
| |
| int r = decimalCmp<cmpCondition>(ival1, value1->scale, ival2, value2->scale); |
| ret->value = CreateDatum(static_cast<bool>(r)); |
| return CreateDatum(ret); |
| } |
| |
| template <cmpWithZero cmpCondition> |
| Datum DECIMAL_VAL_VEC_CMP(Datum *params, uint64_t size) { |
| assert(size == 3 && "invalid input"); |
| SelectList *selected = DatumGetValue<SelectList *>(params[0]); |
| Scalar *para = DatumGetValue<Scalar *>(params[1]); |
| DecimalVar *val = DatumGetValue<DecimalVar *>(para->value); |
| Int128 srcVal = Int128(val->highbits, val->lowbits); |
| int64_t scale1 = val->scale; |
| DecimalVector *vec = DatumGetValue<DecimalVector *>(params[2]); |
| |
| const int64_t *highbitVal = (const int64_t *)(vec->getAuxiliaryValue()); |
| const uint64_t *lowbitVal = (const uint64_t *)(vec->getValue()); |
| const int64_t *scaleVal = (const int64_t *)(vec->getScaleValue()); |
| bool hasNull = vec->hasNullValue(); |
| SelectList *sel = vec->getSelected(); |
| uint64_t sz = vec->getNumOfRows(); |
| |
| uint64_t counter = 0; |
| selected->setNulls(vec->getNumOfRowsPlain(), sel, selected->getNulls(), |
| vec->getNulls()); |
| SelectList::value_type *__restrict__ res = selected->begin(); |
| if (sel) { |
| if (hasNull) { |
| const bool *nulls = vec->getNullBuffer()->getBools(); |
| for (uint64_t i = 0; i < sz; ++i) { |
| uint64_t index = (*sel)[i]; |
| if (!nulls[index]) { |
| Int128 vecVal = Int128(highbitVal[index], lowbitVal[index]); |
| if (decimalCmp<cmpCondition>(srcVal, scale1, vecVal, |
| scaleVal[index])) { |
| res[counter++] = index; |
| } |
| } |
| } |
| } else { |
| for (uint64_t i = 0; i < sz; ++i) { |
| uint64_t index = (*sel)[i]; |
| Int128 vecVal = Int128(highbitVal[index], lowbitVal[index]); |
| if (decimalCmp<cmpCondition>(srcVal, scale1, vecVal, scaleVal[index])) { |
| res[counter++] = index; |
| } |
| } |
| } |
| } else { |
| if (hasNull) { |
| const bool *nulls = vec->getNullBuffer()->getBools(); |
| for (uint64_t i = 0; i < sz; ++i) { |
| if (!nulls[i]) { |
| Int128 vecVal = Int128(highbitVal[i], lowbitVal[i]); |
| if (decimalCmp<cmpCondition>(srcVal, scale1, vecVal, scaleVal[i])) { |
| res[counter++] = i; |
| } |
| } |
| } |
| } else { |
| for (uint64_t i = 0; i < sz; ++i) { |
| Int128 vecVal = Int128(highbitVal[i], lowbitVal[i]); |
| if (decimalCmp<cmpCondition>(srcVal, scale1, vecVal, scaleVal[i])) { |
| res[counter++] = i; |
| } |
| } |
| } |
| } |
| selected->resize(counter); |
| return CreateDatum(selected); |
| } |
| |
| template <cmpWithZero cmpCondition> |
| Datum DECIMAL_VEC_VAL_CMP(Datum *params, uint64_t size) { |
| assert(size == 3 && "invalid input"); |
| SelectList *selected = DatumGetValue<SelectList *>(params[0]); |
| Scalar *para = DatumGetValue<Scalar *>(params[2]); |
| DecimalVar *val = DatumGetValue<DecimalVar *>(para->value); |
| int64_t scale2 = val->scale; |
| Int128 srcVal = Int128(val->highbits, val->lowbits); |
| DecimalVector *vec = DatumGetValue<DecimalVector *>(params[1]); |
| |
| const int64_t *highbitVal = (const int64_t *)(vec->getAuxiliaryValue()); |
| const uint64_t *lowbitVal = (const uint64_t *)(vec->getValue()); |
| const int64_t *scaleVal = (const int64_t *)(vec->getScaleValue()); |
| bool hasNull = vec->hasNullValue(); |
| SelectList *sel = vec->getSelected(); |
| uint64_t sz = vec->getNumOfRows(); |
| |
| uint64_t counter = 0; |
| selected->setNulls(vec->getNumOfRowsPlain(), sel, selected->getNulls(), |
| vec->getNulls()); |
| SelectList::value_type *__restrict__ res = selected->begin(); |
| if (sel) { |
| if (hasNull) { |
| const bool *nulls = vec->getNullBuffer()->getBools(); |
| for (uint64_t i = 0; i < sz; ++i) { |
| uint64_t index = (*sel)[i]; |
| if (!nulls[index]) { |
| Int128 vecVal = Int128(highbitVal[index], lowbitVal[index]); |
| if (decimalCmp<cmpCondition>(vecVal, scaleVal[index], srcVal, |
| scale2)) { |
| res[counter++] = index; |
| } |
| } |
| } |
| } else { |
| for (uint64_t i = 0; i < sz; ++i) { |
| uint64_t index = (*sel)[i]; |
| Int128 vecVal = Int128(highbitVal[index], lowbitVal[index]); |
| if (decimalCmp<cmpCondition>(vecVal, scaleVal[index], srcVal, scale2)) { |
| res[counter++] = index; |
| } |
| } |
| } |
| } else { |
| if (hasNull) { |
| const bool *nulls = vec->getNullBuffer()->getBools(); |
| for (uint64_t i = 0; i < sz; ++i) { |
| if (!nulls[i]) { |
| Int128 vecVal = Int128(highbitVal[i], lowbitVal[i]); |
| if (decimalCmp<cmpCondition>(vecVal, scaleVal[i], srcVal, scale2)) { |
| res[counter++] = i; |
| } |
| } |
| } |
| } else { |
| for (uint64_t i = 0; i < sz; ++i) { |
| Int128 vecVal = Int128(highbitVal[i], lowbitVal[i]); |
| if (decimalCmp<cmpCondition>(vecVal, scaleVal[i], srcVal, scale2)) { |
| res[counter++] = i; |
| } |
| } |
| } |
| } |
| selected->resize(counter); |
| return CreateDatum(selected); |
| } |
| |
| template <cmpWithZero cmpCondition> |
| Datum DECIMAL_VEC_VEC_CMP(Datum *params, uint64_t size) { |
| assert(size == 3 && "invalid input"); |
| SelectList *selected = DatumGetValue<SelectList *>(params[0]); |
| |
| DecimalVector *vec1 = DatumGetValue<DecimalVector *>(params[1]); |
| const int64_t *highbitVal1 = (const int64_t *)(vec1->getAuxiliaryValue()); |
| const uint64_t *lowbitVal1 = (const uint64_t *)(vec1->getValue()); |
| const int64_t *scaleVal1 = (const int64_t *)(vec1->getScaleValue()); |
| bool hasNull1 = vec1->hasNullValue(); |
| SelectList *sel1 = vec1->getSelected(); |
| |
| DecimalVector *vec2 = DatumGetValue<DecimalVector *>(params[2]); |
| const int64_t *highbitVal2 = (const int64_t *)(vec2->getAuxiliaryValue()); |
| const uint64_t *lowbitVal2 = (const uint64_t *)(vec2->getValue()); |
| const int64_t *scaleVal2 = (const int64_t *)(vec2->getScaleValue()); |
| bool hasNull2 = vec2->hasNullValue(); |
| SelectList *sel2 = vec2->getSelected(); |
| |
| assert(vec1->getNumOfRows() == vec2->getNumOfRows() && "invalid parameter"); |
| uint64_t sz = vec1->getNumOfRows(); |
| uint64_t counter = 0; |
| selected->setNulls(vec1->getNumOfRowsPlain(), sel1, selected->getNulls(), |
| vec1->getNulls(), vec2->getNulls()); |
| SelectList::value_type *__restrict__ res = selected->begin(); |
| if (sel1) { |
| assert(*sel1 == *sel2); |
| if (!hasNull1 && !hasNull2) { |
| for (uint64_t i = 0; i < sz; ++i) { |
| uint64_t index = (*sel1)[i]; |
| Int128 vecVal1 = Int128(highbitVal1[index], lowbitVal1[index]); |
| Int128 vecVal2 = Int128(highbitVal2[index], lowbitVal2[index]); |
| if (decimalCmp<cmpCondition>(vecVal1, scaleVal1[index], vecVal2, |
| scaleVal2[index])) { |
| res[counter++] = index; |
| } |
| } |
| } else { |
| for (uint64_t i = 0; i < sz; ++i) { |
| uint64_t index = (*sel1)[i]; |
| Int128 vecVal1 = Int128(highbitVal1[index], lowbitVal1[index]); |
| Int128 vecVal2 = Int128(highbitVal2[index], lowbitVal2[index]); |
| if (!vec1->isNullPlain(index) && !vec2->isNullPlain(index) && |
| decimalCmp<cmpCondition>(vecVal1, scaleVal1[index], vecVal2, |
| scaleVal2[index])) { |
| res[counter++] = index; |
| } |
| } |
| } |
| } else { |
| if (!hasNull1 && !hasNull2) { |
| for (uint64_t i = 0; i < sz; ++i) { |
| Int128 vecVal1 = Int128(highbitVal1[i], lowbitVal1[i]); |
| Int128 vecVal2 = Int128(highbitVal2[i], lowbitVal2[i]); |
| if (decimalCmp<cmpCondition>(vecVal1, scaleVal1[i], vecVal2, |
| scaleVal2[i])) { |
| res[counter++] = i; |
| } |
| } |
| } else { |
| for (uint64_t i = 0; i < sz; ++i) { |
| Int128 vecVal1 = Int128(highbitVal1[i], lowbitVal1[i]); |
| Int128 vecVal2 = Int128(highbitVal2[i], lowbitVal2[i]); |
| if (!vec1->isNullPlain(i) && !vec2->isNullPlain(i) && |
| decimalCmp<cmpCondition>(vecVal1, scaleVal1[i], vecVal2, |
| scaleVal2[i])) { |
| res[counter++] = i; |
| } |
| } |
| } |
| } |
| |
| selected->resize(counter); |
| return CreateDatum(selected); |
| } |
| |
| Datum decimal_val_less_than_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VAL_CMP<LTZero>(params, size); |
| } |
| Datum decimal_val_less_than_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VEC_CMP<LTZero>(params, size); |
| } |
| Datum decimal_vec_less_than_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VAL_CMP<LTZero>(params, size); |
| } |
| Datum decimal_vec_less_than_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VEC_CMP<LTZero>(params, size); |
| } |
| |
| Datum decimal_val_less_eq_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VAL_CMP<LEZero>(params, size); |
| } |
| Datum decimal_val_less_eq_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VEC_CMP<LEZero>(params, size); |
| } |
| Datum decimal_vec_less_eq_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VAL_CMP<LEZero>(params, size); |
| } |
| Datum decimal_vec_less_eq_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VEC_CMP<LEZero>(params, size); |
| } |
| |
| Datum decimal_val_equal_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VAL_CMP<EQZero>(params, size); |
| } |
| Datum decimal_val_equal_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VEC_CMP<EQZero>(params, size); |
| } |
| Datum decimal_vec_equal_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VAL_CMP<EQZero>(params, size); |
| } |
| Datum decimal_vec_equal_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VEC_CMP<EQZero>(params, size); |
| } |
| |
| Datum decimal_val_not_equal_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VAL_CMP<NEZero>(params, size); |
| } |
| Datum decimal_val_not_equal_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VEC_CMP<NEZero>(params, size); |
| } |
| Datum decimal_vec_not_equal_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VAL_CMP<NEZero>(params, size); |
| } |
| Datum decimal_vec_not_equal_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VEC_CMP<NEZero>(params, size); |
| } |
| |
| Datum decimal_val_greater_than_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VAL_CMP<GTZero>(params, size); |
| } |
| |
| Datum decimal_val_greater_than_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VEC_CMP<GTZero>(params, size); |
| } |
| |
| Datum decimal_vec_greater_than_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VAL_CMP<GTZero>(params, size); |
| } |
| |
| Datum decimal_vec_greater_than_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VEC_CMP<GTZero>(params, size); |
| } |
| |
| Datum decimal_val_greater_eq_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VAL_CMP<GEZero>(params, size); |
| } |
| |
| Datum decimal_val_greater_eq_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VAL_VEC_CMP<GEZero>(params, size); |
| } |
| Datum decimal_vec_greater_eq_decimal_val(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VAL_CMP<GEZero>(params, size); |
| } |
| |
| Datum decimal_vec_greater_eq_decimal_vec(Datum *params, uint64_t size) { |
| return DECIMAL_VEC_VEC_CMP<GEZero>(params, size); |
| } |
| |
| std::string decimal_round_internal(std::string srcStr, const int64_t rscale) { |
| bool positive = true; |
| if (srcStr.length() > 0 && srcStr[0] == '-') { |
| positive = false; |
| srcStr = srcStr.substr(1); |
| } |
| |
| std::string rstr = srcStr, intDigits, decDigits; |
| uint64_t cscale = 0; |
| size_t pointIdx = srcStr.find("."); |
| if (pointIdx == std::string::npos) { |
| intDigits = srcStr; |
| cscale = 0; |
| } else { |
| cscale = srcStr.length() - pointIdx - 1; |
| intDigits = srcStr.substr(0, pointIdx); |
| decDigits = srcStr.substr(pointIdx + 1); |
| } |
| |
| if (rscale == 0) { |
| boost::multiprecision::cpp_int intNum(intDigits); |
| if (cscale > 0) { |
| intNum = (decDigits[rscale] >= '5' ? intNum + 1 : intNum); |
| } |
| rstr = intNum.str(); |
| } else if (rscale < 0) { |
| int carrierIndex = intDigits.length() + rscale; |
| if (carrierIndex < 0) { |
| rstr = "0"; |
| } else { |
| char cdigit = intDigits[carrierIndex]; |
| Int128 intNum = Int128(intDigits); |
| Int128 divisor = Int128(POWERS_OF_TEN[-rscale]); |
| Int128 remainder; |
| intNum.divide(divisor, remainder); |
| intNum -= remainder; |
| intNum = cdigit >= '5' ? intNum += divisor : intNum; |
| rstr = intNum.toString(); |
| } |
| } else { |
| if (cscale > rscale) { |
| char cdigit = decDigits[rscale]; |
| decDigits = decDigits.substr(0, rscale); |
| if (cdigit >= '5') { |
| int nzero = 0; |
| while (decDigits[nzero] == '0') nzero++; |
| std::string newDecDigits = decDigits.substr(nzero); |
| boost::multiprecision::cpp_int decNum(newDecDigits); |
| decNum += 1; |
| newDecDigits = decNum.str(); |
| nzero = decDigits.length() - newDecDigits.length(); |
| std::string zeroStr(std::max(nzero, 0), '0'); |
| decDigits = zeroStr + newDecDigits; |
| if (decDigits.length() > rscale) { |
| boost::multiprecision::cpp_int intNum(intDigits); |
| intNum += 1; |
| intDigits = intNum.str(); |
| decDigits = decDigits.substr(1, rscale); |
| } |
| } |
| } else { |
| int zeros2add = rscale - cscale; |
| while (zeros2add-- > 0) decDigits += "0"; |
| } |
| rstr = intDigits + "." + decDigits; |
| } |
| |
| if (!positive && !decimal_equals_zero(rstr)) rstr = "-" + rstr; |
| return rstr; |
| } |
| |
| Int128 get_decimal_sign(Int128 val) { |
| Int128 result; |
| if (val > 0) { |
| result = 1; |
| } else if (val < 0) { |
| result = -1; |
| } else { |
| result = 0; |
| } |
| return result; |
| } |
| |
| bool decimal_equals_zero(std::string str) { |
| assert(str.length() != 0); |
| for (char c : str) { |
| if (c != '-' && c != '.' && c != '0') return false; |
| } |
| return true; |
| } |
| |
| bool decimal_is_nan(std::string str) { |
| std::string cp(str); |
| std::transform(cp.begin(), cp.end(), cp.begin(), tolower); |
| if (str == "nan") return true; |
| return false; |
| } |
| |
| template <typename Operator, bool isDivide = false> |
| Datum decimal_val_op_decimal_val(Datum *params, uint64_t size) { |
| Scalar *retScalar = params[0]; |
| Scalar *lhsScalar = params[1]; |
| Scalar *rhsScalar = params[2]; |
| |
| if (lhsScalar->isnull || rhsScalar->isnull) { |
| retScalar->isnull = true; |
| } else { |
| retScalar->isnull = false; |
| |
| DecimalVar *retVal = retScalar->allocateValue<DecimalVar>(); |
| |
| DecimalVar *lhsVal = DatumGetValue<DecimalVar *>(lhsScalar->value); |
| DecimalVar *rhsVal = DatumGetValue<DecimalVar *>(rhsScalar->value); |
| if (isDivide && Int128(rhsVal->highbits, rhsVal->lowbits) == Int128(0, 0)) |
| LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| *retVal = Operator()(*lhsVal, *rhsVal); |
| } |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, bool isDivides = false> |
| Datum decimal_val_op_decimal_vec(Datum *params, uint64_t size) { |
| // Retrieve Scalar and Vector from params |
| DecimalVector *retVector = params[0]; |
| Scalar *lhsScalar = params[1]; |
| DecimalVector *rhsVector = params[2]; |
| |
| DecimalVar lhsVal = *static_cast<DecimalVar *>(lhsScalar->value); |
| |
| if (isDivides && rhsVector->checkZeroValue()) |
| LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| // Setup return Vector |
| DecimalVectorRawData rhs(rhsVector); |
| retVector->resize(rhs.plainSize, rhs.sel, rhs.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| auto operation = [&](int plainIdx) { |
| DecimalVar rhsVal(rhs.hightbits[plainIdx], rhs.lowbits[plainIdx], |
| rhs.scales[plainIdx]); |
| DecimalVar retVal = Operator()(lhsVal, rhsVal); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(retVal.highbits, retVal.lowbits, retVal.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, operation); |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, bool isDivides = false> |
| Datum decimal_vec_op_decimal_val(Datum *params, uint64_t size) { |
| // Retrieve Scalar and Vector from params |
| DecimalVector *retVector = params[0]; |
| DecimalVector *lhsVector = params[1]; |
| Scalar *rhsScalar = params[2]; |
| |
| DecimalVar rhsVal = *static_cast<DecimalVar *>(rhsScalar->value); |
| |
| if (isDivides && Int128(rhsVal.highbits, rhsVal.lowbits) == Int128(0, 0)) |
| LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| // Setup return Vector |
| DecimalVectorRawData lhs(lhsVector); |
| retVector->resize(lhs.plainSize, lhs.sel, lhs.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| auto operation = [&](int plainIdx) { |
| DecimalVar lhsVal(lhs.hightbits[plainIdx], lhs.lowbits[plainIdx], |
| lhs.scales[plainIdx]); |
| DecimalVar retVal = Operator()(lhsVal, rhsVal); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(retVal.highbits, retVal.lowbits, retVal.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, operation); |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, bool isDivides = false> |
| Datum decimal_vec_op_decimal_vec(Datum *params, uint64_t size) { |
| // Retrieve Vector from params |
| DecimalVector *retVector = params[0]; |
| DecimalVector *lhsVector = params[1]; |
| DecimalVector *rhsVector = params[2]; |
| |
| if (isDivides && rhsVector->checkZeroValue()) |
| LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| // Setup return Vector |
| DecimalVectorRawData lhs(lhsVector), rhs(rhsVector); |
| retVector->resize(lhs.plainSize, lhs.sel, lhs.nulls, rhs.nulls); |
| DecimalVectorRawData ret(retVector); |
| assert(lhs.sel == rhs.sel && lhs.plainSize == rhs.plainSize); |
| |
| auto operation = [&](int plainIdx) { |
| DecimalVar lhsVal(lhs.hightbits[plainIdx], lhs.lowbits[plainIdx], |
| lhs.scales[plainIdx]); |
| DecimalVar rhsVal(rhs.hightbits[plainIdx], rhs.lowbits[plainIdx], |
| rhs.scales[plainIdx]); |
| DecimalVar retVal = Operator()(lhsVal, rhsVal); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(retVal.highbits, retVal.lowbits, retVal.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, operation); |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, bool isDivide = false> |
| Datum decimal_op_decimal(Datum *params, uint64_t size) { |
| return type1_op_type2_bind<decimal_vec_op_decimal_vec<Operator, isDivide>, |
| decimal_vec_op_decimal_val<Operator, isDivide>, |
| decimal_val_op_decimal_vec<Operator, isDivide>, |
| decimal_val_op_decimal_val<Operator, isDivide>>( |
| params, size); |
| } |
| |
| Datum decimal_add_decimal(Datum *params, uint64_t size) { |
| return decimal_op_decimal<std::plus<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_sub_decimal(Datum *params, uint64_t size) { |
| return decimal_op_decimal<std::minus<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_mul_decimal(Datum *params, uint64_t size) { |
| return decimal_op_decimal<std::multiplies<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_div_decimal(Datum *params, uint64_t size) { |
| return decimal_op_decimal<std::divides<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_to_decimal(Datum *params, uint64_t size) { |
| assert(size == 3 && "invalid input"); |
| assert(dynamic_cast<Scalar *>(DatumGetValue<Object *>(params[2]))); |
| |
| Object *para = DatumGetValue<Object *>(params[1]); |
| int64_t typeMod = DatumGetValue<Scalar *>(params[2])->value; |
| int64_t scale = TypeModifierUtil::getScale(typeMod); |
| |
| if (dynamic_cast<Vector *>(para)) { // Vector input |
| assert(dynamic_cast<DecimalVector *>(DatumGetValue<Object *>(params[0]))); |
| DecimalVector *retVector = params[0]; |
| DecimalVector *srcVector = params[1]; |
| |
| DecimalVectorRawData src(srcVector); |
| retVector->resize(src.plainSize, src.sel, src.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| auto cast = [&](size_t plainIdx) { |
| DecimalVar val(src.hightbits[plainIdx], src.lowbits[plainIdx], |
| src.scales[plainIdx]); |
| val = val.cast(scale); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(val.highbits, val.lowbits, val.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, cast); |
| |
| } else { // Scalar input |
| Scalar *retScalar = params[0]; |
| Scalar *srcScalar = params[1]; |
| if (srcScalar->isnull) { |
| retScalar->isnull = true; |
| } else { |
| retScalar->isnull = false; |
| DecimalVar *retVal = retScalar->allocateValue<DecimalVar>(); |
| *retVal = DatumGetValue<DecimalVar *>(srcScalar->value)->cast(scale); |
| } |
| } |
| return params[0]; |
| } |
| |
| template <typename Integer> |
| Datum integer_to_decimal(Datum *params, uint64_t size) { |
| assert(size == 2 && "invalid input"); |
| |
| Object *para = DatumGetValue<Object *>(params[1]); |
| |
| if (dynamic_cast<Vector *>(para)) { // Case1. Vector input |
| assert(dynamic_cast<DecimalVector *>(DatumGetValue<Object *>(params[0]))); |
| DecimalVector *retVector = params[0]; |
| DecimalVector *srcVector = params[1]; |
| |
| FixedSizeTypeVectorRawData<Integer> src(srcVector); |
| retVector->resize(src.plainSize, src.sel, src.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| // fill high bits |
| auto fillHighbit = [&](size_t plainIdx) { |
| ret.hightbits[plainIdx] = (src.values[plainIdx] >= 0) ? 0 : uint64_t(-1); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, fillHighbit); |
| |
| // fill low bits |
| auto fillLowbit = [&](size_t plainIdx) { |
| ret.lowbits[plainIdx] = static_cast<int64_t>(src.values[plainIdx]); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, fillLowbit); |
| |
| // fill scale |
| memset(ret.scales, 0, ret.plainSize * sizeof(ret.scales[0])); |
| |
| } else { // Case2. Scalar input |
| Scalar *retScalar = params[0]; |
| Scalar *srcScalar = params[1]; |
| if (srcScalar->isnull) { |
| retScalar->isnull = true; |
| } else { |
| retScalar->isnull = false; |
| DecimalVar *retVal = retScalar->allocateValue<DecimalVar>(); |
| *retVal = DecimalVar( |
| static_cast<int64_t>(DatumGetValue<Integer>(srcScalar->value))); |
| } |
| } |
| return params[0]; |
| } |
| |
| Datum int8_to_decimal(Datum *params, uint64_t size) { |
| return integer_to_decimal<int8_t>(params, size); |
| } |
| Datum int16_to_decimal(Datum *params, uint64_t size) { |
| return integer_to_decimal<int16_t>(params, size); |
| } |
| Datum int32_to_decimal(Datum *params, uint64_t size) { |
| return integer_to_decimal<int32_t>(params, size); |
| } |
| Datum int64_to_decimal(Datum *params, uint64_t size) { |
| return integer_to_decimal<int64_t>(params, size); |
| } |
| |
| template <typename Integer> |
| Datum decimal_to_integer(Datum *params, uint64_t size) { |
| assert(size == 2 && "invalid input"); |
| |
| uint64_t upperBound = static_cast<uint64_t>( |
| static_cast<typename std::make_unsigned<Integer>::type>( |
| std::numeric_limits<Integer>::max())); |
| uint64_t lowerBound = static_cast<uint64_t>( |
| static_cast<int64_t>(std::numeric_limits<Integer>::min())); |
| |
| Object *para = DatumGetValue<Object *>(params[1]); |
| |
| if (dynamic_cast<Vector *>(para)) { // Case1. Vector input |
| Vector *retVector = params[0]; |
| DecimalVector *srcVector = params[1]; |
| |
| DecimalVectorRawData src(srcVector); |
| retVector->resize(src.plainSize, src.sel, src.nulls); |
| FixedSizeTypeVectorRawData<Integer> ret(retVector); |
| |
| // cast to int128 |
| std::unique_ptr<Int128[]> scaleDownInt128s(new Int128[src.plainSize]); |
| auto castToInt128 = [&](size_t plainIdx) { |
| scaleDownInt128s[plainIdx] = scaleDownInt128ByPowerOfTen( |
| Int128(src.hightbits[plainIdx], src.lowbits[plainIdx]), |
| src.scales[plainIdx]); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, castToInt128); |
| |
| // check overflow |
| bool castOk = true; |
| auto checkIntegerOverflow = [&](size_t plainIdx) { |
| uint64_t highbits = scaleDownInt128s[plainIdx].getHighBits(); |
| uint64_t lowbits = scaleDownInt128s[plainIdx].getLowBits(); |
| castOk &= ((highbits == -1) & (lowbits >= lowerBound)) | |
| ((highbits == 0) & (lowbits <= upperBound)); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, checkIntegerOverflow); |
| if (!castOk) |
| LOG_ERROR(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, "%s out of range", |
| TypeUtil::instance() |
| ->getTypeEntryById(retVector->getTypeKind()) |
| ->name.c_str()); |
| |
| // cast to Integer |
| auto castToInteger = [&](size_t plainIdx) { |
| ret.values[plainIdx] = static_cast<Integer>( |
| static_cast<int64_t>(scaleDownInt128s[plainIdx].getLowBits())); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, castToInteger); |
| |
| } else { // Case2. Scalar input |
| Scalar *retScalar = params[0]; |
| Scalar *srcScalar = params[1]; |
| if (srcScalar->isnull) { |
| retScalar->isnull = true; |
| } else { |
| retScalar->isnull = false; |
| DecimalVar x = *DatumGetValue<DecimalVar *>(srcScalar->value); |
| Int128 scaleDownInt128 = |
| scaleDownInt128ByPowerOfTen(Int128(x.highbits, x.lowbits), x.scale); |
| |
| uint64_t highbits = scaleDownInt128.getHighBits(); |
| uint64_t lowbits = scaleDownInt128.getLowBits(); |
| if ((highbits == -1 && lowbits >= lowerBound) || |
| (highbits == 0 && lowbits <= upperBound)) { |
| retScalar->value = CreateDatum(static_cast<Integer>(lowbits)); |
| } else { |
| LOG_ERROR(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, "%s out of range", |
| TypeUtil::instance() |
| ->getTypeEntryById(TypeMapping<Integer>::type) |
| ->name.c_str()); |
| } |
| } |
| } |
| return params[0]; |
| } |
| |
| Datum decimal_to_int8(Datum *params, uint64_t size) { |
| return decimal_to_integer<int8_t>(params, size); |
| } |
| Datum decimal_to_int16(Datum *params, uint64_t size) { |
| return decimal_to_integer<int16_t>(params, size); |
| } |
| Datum decimal_to_int32(Datum *params, uint64_t size) { |
| return decimal_to_integer<int32_t>(params, size); |
| } |
| Datum decimal_to_int64(Datum *params, uint64_t size) { |
| return decimal_to_integer<int64_t>(params, size); |
| } |
| |
| template <typename Operator, typename rhsType> |
| Datum decimal_val_op_integer_val(Datum *params, uint64_t size) { |
| Scalar *retScalar = params[0]; |
| Scalar *lhsScalar = params[1]; |
| Scalar *rhsScalar = params[2]; |
| |
| if (lhsScalar->isnull || rhsScalar->isnull) { |
| retScalar->isnull = true; |
| } else { |
| retScalar->isnull = false; |
| DecimalVar *retVal = retScalar->allocateValue<DecimalVar>(); |
| |
| DecimalVar *lhsVal = DatumGetValue<DecimalVar *>(lhsScalar->value); |
| rhsType rhsVal = DatumGetValue<rhsType>(rhsScalar->value); |
| |
| *retVal = Operator()(*lhsVal, rhsVal); |
| } |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, typename rhsType, bool isDivides = false> |
| Datum decimal_val_op_integer_vec(Datum *params, uint64_t size) { |
| DecimalVector *retVector = params[0]; |
| Scalar *lhsScalar = params[1]; |
| Vector *rhsVector = params[2]; |
| |
| DecimalVar lhsVal = *static_cast<DecimalVar *>(lhsScalar->value); |
| |
| if (isDivides) LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| FixedSizeTypeVectorRawData<rhsType> rhs(rhsVector); |
| retVector->resize(rhs.plainSize, rhs.sel, rhs.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| auto operation = [&](int plainIdx) { |
| rhsType rhsVal = rhs.values[plainIdx]; |
| DecimalVar retVal = Operator()(lhsVal, rhsVal); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(retVal.highbits, retVal.lowbits, retVal.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, operation); |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, typename rhsType, bool isDivides = false> |
| Datum decimal_vec_op_integer_val(Datum *params, uint64_t size) { |
| DecimalVector *retVector = params[0]; |
| DecimalVector *lhsVector = params[1]; |
| Scalar *rhsScalar = params[2]; |
| |
| rhsType rhsVal = DatumGetValue<rhsType>(rhsScalar->value); |
| |
| if (isDivides) LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| DecimalVectorRawData lhs(lhsVector); |
| retVector->resize(lhs.plainSize, lhs.sel, lhs.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| auto operation = [&](int plainIdx) { |
| DecimalVar lhsVal(lhs.hightbits[plainIdx], lhs.lowbits[plainIdx], |
| lhs.scales[plainIdx]); |
| DecimalVar retVal = Operator()(lhsVal, rhsVal); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(retVal.highbits, retVal.lowbits, retVal.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, operation); |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, typename rhsType, bool isDivides = false> |
| Datum decimal_vec_op_integer_vec(Datum *params, uint64_t size) { |
| DecimalVector *retVector = params[0]; |
| DecimalVector *lhsVector = params[1]; |
| Vector *rhsVector = params[2]; |
| |
| if (isDivides) LOG_ERROR(ERRCODE_DIVISION_BY_ZERO, "division by zero"); |
| |
| DecimalVectorRawData lhs(lhsVector); |
| FixedSizeTypeVectorRawData<rhsType> rhs(rhsVector); |
| retVector->resize(lhs.plainSize, lhs.sel, lhs.nulls, rhs.nulls); |
| DecimalVectorRawData ret(retVector); |
| |
| assert(lhs.sel == rhs.sel && lhs.plainSize == rhs.plainSize); |
| |
| auto operation = [&](int plainIdx) { |
| DecimalVar lhsVal(lhs.hightbits[plainIdx], lhs.lowbits[plainIdx], |
| lhs.scales[plainIdx]); |
| rhsType rhsVal = rhs.values[plainIdx]; |
| DecimalVar retVal = Operator()(lhsVal, rhsVal); |
| std::tie(ret.hightbits[plainIdx], ret.lowbits[plainIdx], |
| ret.scales[plainIdx]) = |
| std::make_tuple(retVal.highbits, retVal.lowbits, retVal.scale); |
| }; |
| transformVector(ret.plainSize, ret.sel, ret.nulls, operation); |
| |
| return params[0]; |
| } |
| |
| template <typename Operator, typename rhsType> |
| Datum decimal_op_integer(Datum *params, uint64_t size) { |
| return type1_op_type2_bind<decimal_vec_op_integer_vec<Operator, rhsType>, |
| decimal_vec_op_integer_val<Operator, rhsType>, |
| decimal_val_op_integer_vec<Operator, rhsType>, |
| decimal_val_op_integer_val<Operator, rhsType>>( |
| params, size); |
| } |
| |
| Datum decimal_abs(Datum *params, uint64_t size) { |
| return op_decimal<abs<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_sign(Datum *params, uint64_t size) { |
| return op_decimal<sign<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_ceil(Datum *params, uint64_t size) { |
| return op_decimal<ceil<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_floor(Datum *params, uint64_t size) { |
| return op_decimal<floor<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_round(Datum *params, uint64_t size) { |
| return decimal_op_integer<round<DecimalVar>, int32_t>(params, size); |
| } |
| |
| Datum decimal_round_without_scale(Datum *params, uint64_t size) { |
| return op_decimal<round<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_trunc(Datum *params, uint64_t size) { |
| return decimal_op_integer<trunc<DecimalVar>, int32_t>(params, size); |
| } |
| |
| Datum decimal_trunc_without_scale(Datum *params, uint64_t size) { |
| return op_decimal<trunc<DecimalVar>>(params, size); |
| } |
| |
| Datum decimal_mod(Datum *params, uint64_t size) { |
| return decimal_op_decimal<mod<DecimalVar, DecimalVar, DecimalVar>, true>( |
| params, size); |
| } |
| } // namespace dbcommon |