Skip to content

Commit

Permalink
Optimize overflow check when cast to decimal (#3912)
Browse files Browse the repository at this point in the history
close #3721
  • Loading branch information
guo-shaoge authored Mar 11, 2022
1 parent 5f912af commit 360d2bd
Show file tree
Hide file tree
Showing 6 changed files with 877 additions and 141 deletions.
2 changes: 2 additions & 0 deletions dbms/src/Columns/ColumnDecimal.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ class ColumnDecimal final : public COWPtrHelper<ColumnVectorHelper, ColumnDecima
const T & getElement(size_t n) const { return data[n]; }
T & getElement(size_t n) { return data[n]; }

UInt32 getScale() const { return scale; }

protected:
Container data;
UInt32 scale;
Expand Down
36 changes: 31 additions & 5 deletions dbms/src/Common/Decimal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ using ScaleType = UInt32;
constexpr PrecType decimal_max_prec = 65;
constexpr ScaleType decimal_max_scale = 30;

// IntPrec indicates the max precision of different integer types.
// For now, the binary arithmetic functions use it to calculate result precision.
// And cast function use it to do some optimizations, such as skipping overflow check.
// But in TiDB the signed types will plus 1, for example IntPrec<int8_t>::prec is 4.
// This is a little confusing because we will add 1 when return result to client.
// Here we make sure TiFlash code is clean and will fix TiDB later.
template <typename T>
struct IntPrec
{
};
template <>
struct IntPrec<int8_t>
{
static constexpr PrecType prec = 4;
static constexpr PrecType prec = 3;
};
template <>
struct IntPrec<uint8_t>
Expand All @@ -37,7 +43,7 @@ struct IntPrec<uint8_t>
template <>
struct IntPrec<int16_t>
{
static constexpr PrecType prec = 6;
static constexpr PrecType prec = 5;
};
template <>
struct IntPrec<uint16_t>
Expand All @@ -47,7 +53,7 @@ struct IntPrec<uint16_t>
template <>
struct IntPrec<int32_t>
{
static constexpr PrecType prec = 11;
static constexpr PrecType prec = 10;
};
template <>
struct IntPrec<uint32_t>
Expand All @@ -57,14 +63,26 @@ struct IntPrec<uint32_t>
template <>
struct IntPrec<int64_t>
{
static constexpr PrecType prec = 20;
static constexpr PrecType prec = 19;
};
template <>
struct IntPrec<uint64_t>
{
static constexpr PrecType prec = 20;
};

template <>
struct IntPrec<Int128>
{
static constexpr PrecType prec = 39;
};

template <>
struct IntPrec<Int256>
{
static constexpr PrecType prec = 78;
};

// 1) If the declared type of both operands of a dyadic arithmetic operator is exact numeric, then the declared
// type of the result is an implementation-defined exact numeric type, with precision and scale determined as
// follows:
Expand Down Expand Up @@ -359,6 +377,8 @@ class DecimalMaxValue final : public ext::Singleton<DecimalMaxValue>
public:
static Int256 get(PrecType idx)
{
// In case DecimalMaxValue::get(IntPrec<Int256>::prec), where IntPrec<Int256>::prec > 65.
assert(idx <= decimal_max_prec);
return instance().getInternal(idx);
}

Expand All @@ -384,12 +404,18 @@ class DecimalMaxValue final : public ext::Singleton<DecimalMaxValue>

// In some case, getScaleMultiplier and its callee may not be auto inline by the compiler.
// This may hurt performance. __attribute__((flatten)) tells compliler to inline the callee of this function.
template <typename T>
template <typename T, std::enable_if_t<IsDecimal<T>> * = nullptr>
__attribute__((flatten)) inline typename T::NativeType getScaleMultiplier(ScaleType scale)
{
return static_cast<typename T::NativeType>(DecimalMaxValue::get(scale) + 1);
}

template <typename T, std::enable_if_t<is_integer_v<T>> * = nullptr>
__attribute__((flatten)) inline T getScaleMultiplier(ScaleType scale)
{
return static_cast<T>(DecimalMaxValue::get(scale) + 1);
}

template <typename T>
inline void checkDecimalOverflow(Decimal<T> v, PrecType prec)
{
Expand Down
Loading

0 comments on commit 360d2bd

Please sign in to comment.