fix bug in cast decimalint to int
This commit is contained in:
@ -162,41 +162,62 @@ public:
|
||||
/// 3. that is, when dividing, scale_factor should be uint64_t.
|
||||
///@param [in] scale >= 0, negative scale for decimalint is illegal
|
||||
template<typename T, typename scale_type, class = typename std::enable_if<sizeof(T) < sizeof(int128_t)>::type>
|
||||
static inline int64_t scale_to_integer(T &lhs,
|
||||
static inline int64_t scale_to_integer(const T &lhs,
|
||||
scale_type &scale_factor,
|
||||
int16_t scale,
|
||||
int &err,
|
||||
bool round_up = true) {
|
||||
uint64_t sf = static_cast<int64_t>(scale_factor);
|
||||
int64_t q = lhs;
|
||||
T q = lhs;
|
||||
int64_t sf = static_cast<int64_t>(scale_factor);
|
||||
err = 0;
|
||||
if (OB_LIKELY(sf > 1)) {
|
||||
bool is_neg = lhs < 0;
|
||||
if (is_neg) { q = -lhs; }
|
||||
int64_t r = q % sf;
|
||||
T r = q % sf;
|
||||
q = q / sf;
|
||||
round_up &= (r >= (sf>>1));
|
||||
if (round_up) { q = q + 1; }
|
||||
if (is_neg) { q = -q; }
|
||||
}
|
||||
return q;
|
||||
int64_t out_val = 0;
|
||||
if (OB_UNLIKELY(q > INT64_MAX)) {
|
||||
out_val = INT64_MAX;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else if (OB_UNLIKELY(q < INT64_MIN)) {
|
||||
out_val = INT64_MIN;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else {
|
||||
out_val = q;
|
||||
}
|
||||
return out_val;
|
||||
}
|
||||
template<unsigned Bits, typename scale_type>
|
||||
static inline int64_t scale_to_integer(const wide::ObWideInteger<Bits> &lhs,
|
||||
const scale_type &scale_factor,
|
||||
int16_t scale,
|
||||
int &err,
|
||||
bool round_up = true) {
|
||||
int64_t q = 0;
|
||||
int64_t decint = static_cast<int64_t>(lhs);
|
||||
if (OB_UNLIKELY(scale == 0)) {
|
||||
q = (lhs < INT64_MIN) ? INT64_MIN : (lhs > INT64_MAX ? INT64_MAX : decint);
|
||||
if (OB_UNLIKELY(lhs > INT64_MAX)) {
|
||||
q = INT64_MAX;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else if (OB_UNLIKELY(lhs < INT64_MIN)) {
|
||||
q = INT64_MIN;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else {
|
||||
q = decint;
|
||||
}
|
||||
} else if (OB_LIKELY(INT64_MIN <= lhs && lhs <= INT64_MAX)) {
|
||||
uint64_t sf = pow10(scale);
|
||||
q = scale_to_integer(decint, sf, scale, round_up);
|
||||
q = scale_to_integer(decint, sf, scale, err, round_up);
|
||||
} else {
|
||||
static const uint64_t constexpr DIGITS10_BASE = 10000000000000000000ULL; // 10^19
|
||||
if (scale > 19) {
|
||||
wide::ObWideInteger<Bits> num = lhs / DIGITS10_BASE;
|
||||
scale_type sf = get_scale_factor<scale_type>(scale - 19);
|
||||
q = scale_to_integer(num, sf, scale - 19, round_up);
|
||||
q = scale_to_integer(num, sf, scale - 19, err, round_up);
|
||||
} else {
|
||||
bool is_neg = (lhs < 0);
|
||||
wide::ObWideInteger<Bits> num = (is_neg ? -lhs : lhs);
|
||||
@ -208,7 +229,15 @@ public:
|
||||
if (round_up) { num = num + 1; }
|
||||
if (is_neg) { num = -num; }
|
||||
q = static_cast<int64_t>(num);
|
||||
q = (num < INT64_MIN) ? INT64_MIN : (num > INT64_MAX ? INT64_MAX : q);
|
||||
if (OB_UNLIKELY(num > INT64_MAX)) {
|
||||
q = INT64_MAX;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else if (OB_UNLIKELY(num < INT64_MIN)) {
|
||||
q = INT64_MIN;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else {
|
||||
q = static_cast<int64_t>(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
return q;
|
||||
@ -218,36 +247,51 @@ public:
|
||||
static inline uint64_t scale_to_unsigned_integer(T &lhs,
|
||||
scale_type &scale_factor,
|
||||
int16_t scale,
|
||||
int &err,
|
||||
bool round_up = true) {
|
||||
uint64_t sf = static_cast<int64_t>(scale_factor);
|
||||
uint64_t q = lhs;
|
||||
T q = lhs;
|
||||
uint64_t sf = static_cast<uint64_t>(scale_factor);
|
||||
err = 0;
|
||||
if (OB_LIKELY(sf > 1)) {
|
||||
int64_t r = q % sf;
|
||||
q = q / sf;
|
||||
round_up &= (r >= (sf>>1));
|
||||
if (round_up) { q = q + 1; }
|
||||
}
|
||||
return q;
|
||||
uint64_t out_val = 0;
|
||||
if (OB_UNLIKELY(q > UINT64_MAX)) {
|
||||
out_val = INT64_MAX;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else {
|
||||
out_val = q;
|
||||
}
|
||||
return out_val;
|
||||
}
|
||||
template<unsigned Bits, typename scale_type>
|
||||
static inline uint64_t scale_to_unsigned_integer(const wide::ObWideInteger<Bits> &lhs,
|
||||
const scale_type &scale_factor,
|
||||
int16_t scale,
|
||||
int &err,
|
||||
bool round_up = true) {
|
||||
uint64_t q = 0;
|
||||
uint64_t decint = static_cast<int64_t>(lhs);
|
||||
if (OB_UNLIKELY(scale == 0)) {
|
||||
q = (lhs > UINT64_MAX ? UINT64_MAX : decint);
|
||||
if (OB_UNLIKELY(lhs > UINT64_MAX)) {
|
||||
q = UINT64_MAX;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else {
|
||||
q = decint;
|
||||
}
|
||||
} else if (OB_LIKELY(lhs <= UINT64_MAX)) {
|
||||
uint64_t sf = pow10(scale);
|
||||
q = scale_to_unsigned_integer(decint, sf, scale, round_up);
|
||||
q = scale_to_unsigned_integer(decint, sf, scale, err, round_up);
|
||||
} else {
|
||||
static const uint64_t constexpr DIGITS10_BASE = 10000000000000000000ULL; // 10^19
|
||||
wide::ObWideInteger<Bits> num;
|
||||
if (scale > 19) {
|
||||
num = lhs / DIGITS10_BASE;
|
||||
scale_type sf = get_scale_factor<scale_type>(scale - 19);
|
||||
q = scale_to_unsigned_integer(num, sf, scale - 19, round_up);
|
||||
q = scale_to_unsigned_integer(num, sf, scale - 19, err, round_up);
|
||||
} else {
|
||||
wide::ObWideInteger<Bits> remain;
|
||||
uint64_t sf = pow10(scale);
|
||||
@ -255,7 +299,12 @@ public:
|
||||
divide<wide::IgnoreOverFlow>(lhs, sf, num, remain);
|
||||
round_up &= (remain >= (sf >> 1));
|
||||
if (round_up) { num = num + 1; }
|
||||
q = (num > UINT64_MAX ? UINT64_MAX : static_cast<int64_t>(num));
|
||||
if (OB_UNLIKELY(num > UINT64_MAX)) {
|
||||
q = UINT64_MAX;
|
||||
err = OB_ERRNO_ERANGE;
|
||||
} else {
|
||||
q = static_cast<uint64_t>(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
return q;
|
||||
@ -303,6 +352,7 @@ public:
|
||||
int64_t &int_part, int64_t &dec_part)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int err = 0;
|
||||
if (scale < 6) { // 20010528.1430 -> 20010528, 143000 000
|
||||
if (OB_UNLIKELY(decint > INT64_MAX)) {
|
||||
ret = OB_INVALID_DATE_VALUE;
|
||||
@ -315,14 +365,14 @@ public:
|
||||
}
|
||||
} else { // 20010528.1430307654321 -> 20010528, 143031 000
|
||||
calc_type sf = get_scale_factor<calc_type>(scale);
|
||||
int_part = CastHelperImpl::scale_to_integer(decint, sf, scale, false);
|
||||
int_part = CastHelperImpl::scale_to_integer(decint, sf, scale, err, false);
|
||||
calc_type sf_minus6 = get_scale_factor<calc_type>(scale - 6);
|
||||
if (scale < 19) {
|
||||
int64_t remain = decint - sf * int_part;
|
||||
dec_part = CastHelperImpl::scale_to_integer(remain, sf_minus6, scale - 6);
|
||||
dec_part = CastHelperImpl::scale_to_integer(remain, sf_minus6, scale - 6, err);
|
||||
} else {
|
||||
calc_type remain = decint - sf * int_part;
|
||||
dec_part = CastHelperImpl::scale_to_integer(remain, sf_minus6, scale - 6);
|
||||
dec_part = CastHelperImpl::scale_to_integer(remain, sf_minus6, scale - 6, err);
|
||||
}
|
||||
dec_part *= 1000;
|
||||
}
|
||||
|
||||
@ -192,7 +192,8 @@ struct ToDateCastImpl
|
||||
ret = OB_INVALID_DATE_VALUE;
|
||||
SQL_LOG(WARN, "invalid date value", K(ret), K(lhs));
|
||||
} else {
|
||||
uint64_t uint64 = CastHelperImpl::scale_to_unsigned_integer(lhs, sf_, in_scale_, false);
|
||||
int err = 0;
|
||||
uint64_t uint64 = CastHelperImpl::scale_to_unsigned_integer(lhs, sf_, in_scale_, err, false);
|
||||
int64_t int64 = uint64;
|
||||
if (OB_UNLIKELY(uint64 > INT64_MAX)) {
|
||||
int64 = INT64_MAX;
|
||||
|
||||
@ -486,7 +486,7 @@ struct ToIntegerCastImpl
|
||||
} else {
|
||||
OUT_TYPE out_val = int_val;
|
||||
bool need_range_check = std::is_same<OUT_TYPE, int64_t>::value
|
||||
? out_type_ < ObInt32Type : out_type_ < ObUInt32Type;
|
||||
? out_type_ < ObIntType : out_type_ < ObUInt64Type;
|
||||
if (need_range_check && CAST_FAIL(numeric_range_check(out_val, type_min_val_,
|
||||
type_max_val_, out_val))) {
|
||||
SQL_LOG(WARN, "int_range_check failed", K(ret));
|
||||
@ -534,9 +534,15 @@ struct ToIntegerCastImpl
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
IN_TYPE lhs = *reinterpret_cast<const IN_TYPE *>(arg_vec_->get_payload(idx));
|
||||
int64_t out_val = CastHelperImpl::scale_to_integer(lhs, sf_, in_scale_);
|
||||
int warning = OB_SUCCESS;
|
||||
if (out_type_ < ObIntType && CAST_FAIL(int_range_check(out_type_, out_val, out_val))) {
|
||||
int err = 0;
|
||||
int64_t out_val = CastHelperImpl::scale_to_integer(lhs, sf_, in_scale_, err);
|
||||
if (OB_ERRNO_ERANGE == err && (INT64_MIN == out_val || INT64_MAX == out_val)) {
|
||||
ret = OB_DATA_OUT_OF_RANGE;
|
||||
}
|
||||
if (CAST_FAIL(ret)) {
|
||||
SQL_LOG(WARN, "decimalint int failed", K(ret));
|
||||
} else if (out_type_ < ObIntType && CAST_FAIL(int_range_check(out_type_, out_val, out_val))) {
|
||||
SQL_LOG(WARN, "int_range_check failed", K(ret), K(expr.extra_));
|
||||
} else {
|
||||
res_vec_->set_int(idx, out_val);
|
||||
@ -577,11 +583,22 @@ struct ToIntegerCastImpl
|
||||
OB_INLINE int operator() (const ObExpr &expr, int idx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
IN_TYPE lhs = *reinterpret_cast<const IN_TYPE *>(arg_vec_->get_payload(idx));
|
||||
uint64_t out_val = (lhs < 0) ? 0 :
|
||||
CastHelperImpl::scale_to_unsigned_integer(lhs, sf_, in_scale_);
|
||||
int warning = OB_SUCCESS;
|
||||
if ((out_type_ < ObUInt64Type && CM_NEED_RANGE_CHECK(expr.extra_))
|
||||
int err = 0;
|
||||
IN_TYPE lhs = *reinterpret_cast<const IN_TYPE *>(arg_vec_->get_payload(idx));
|
||||
uint64_t out_val = 0;
|
||||
if (OB_UNLIKELY(lhs < 0)) {
|
||||
out_val = 0;
|
||||
ret = OB_DATA_OUT_OF_RANGE;
|
||||
} else {
|
||||
out_val = CastHelperImpl::scale_to_unsigned_integer(lhs, sf_, in_scale_, err);
|
||||
}
|
||||
if (OB_ERRNO_ERANGE == err && (0 == out_val || UINT64_MAX == out_val)) {
|
||||
ret = OB_DATA_OUT_OF_RANGE;
|
||||
}
|
||||
if (CAST_FAIL(ret)) {
|
||||
SQL_LOG(WARN, "decimalint uint failed", K(ret));
|
||||
} else if ((out_type_ < ObUInt64Type && CM_NEED_RANGE_CHECK(expr.extra_))
|
||||
&& CAST_FAIL(uint_upper_check(out_type_, out_val))) {
|
||||
SQL_LOG(WARN, "int_range_check failed", K(ret), K(expr.extra_));
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user