decimal field extraction (from column or type)

This commit is contained in:
chertus 2018-08-10 17:57:55 +03:00
parent 479166283e
commit 01c8b1d7bb
8 changed files with 129 additions and 18 deletions

View File

@ -8,6 +8,12 @@
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
/** Stuff for comparing numbers.
* Integer values are compared as usual.
* Floating-point numbers are compared this way that NaNs always end up at the end
@ -117,6 +123,54 @@ template <> inline UInt64 unionCastToUInt64(Float32 x)
}
/// PaddedPODArray extended by Decimal scale
template <typename T, size_t INITIAL_SIZE = 4096>
class DecPaddedPODArray : public PODArray<T, INITIAL_SIZE, Allocator<false>, sizeof(T)-1>
{
public:
using Base = PODArray<T, INITIAL_SIZE, Allocator<false>, sizeof(T)-1>;
using Base::operator[];
DecPaddedPODArray()
{}
DecPaddedPODArray(size_t n)
: Base(n)
{}
DecPaddedPODArray(size_t n, const T & x)
: Base(n, x)
{}
DecPaddedPODArray(typename Base::const_iterator from_begin, typename Base::const_iterator from_end)
: Base(from_begin, from_end)
{}
DecPaddedPODArray(std::initializer_list<T> il)
: DecPaddedPODArray(std::begin(il), std::end(il))
{}
DecPaddedPODArray(DecPaddedPODArray && other)
{
this->swap(other);
std::swap(scale, other.scale);
}
DecPaddedPODArray & operator= (DecPaddedPODArray && other)
{
this->swap(other);
std::swap(scale, other.scale);
return *this;
}
void setScale(UInt32 s) { scale = s; }
UInt32 getScale() const { return scale; }
private:
UInt32 scale = std::numeric_limits<UInt32>::max();
};
/** A template for columns that use a simple array to store.
*/
template <typename T>
@ -131,7 +185,7 @@ private:
public:
using value_type = T;
using Container = PaddedPODArray<value_type>;
using Container = std::conditional_t<decTrait<T>(), DecPaddedPODArray<value_type>, PaddedPODArray<value_type>>;
private:
ColumnVector() {}
@ -215,12 +269,20 @@ public:
Field operator[](size_t n) const override
{
return typename NearestFieldType<T>::Type(data[n]);
if constexpr (decTrait<T>())
{
UInt32 scale = data.getScale();
if (scale == std::numeric_limits<UInt32>::max())
throw Exception("Extracting Decimal field with unknown scale. Scale is lost.", ErrorCodes::LOGICAL_ERROR);
return DecField(data[n], scale);
}
else
return typename NearestFieldType<T>::Type(data[n]);
}
void get(size_t n, Field & res) const override
{
res = typename NearestFieldType<T>::Type(data[n]);
res = (*this)[n];
}
UInt64 get64(size_t n) const override;

View File

@ -41,6 +41,7 @@ public:
operator Dec32() const { return dec; }
operator Dec64() const { return dec; }
operator Dec128() const { return dec; }
UInt32 getScale() const { return scale; }
bool operator < (const DecField & r) const;
@ -51,8 +52,6 @@ public:
bool operator >= (const DecField & r) const { return r <= * this; }
bool operator != (const DecField & r) const { return !(*this == r); }
bool hasScale() const { return scale != wrongScale(); }
private:
Int128 dec;
UInt32 scale;

View File

@ -148,7 +148,9 @@ Field DataTypeDecimal<T>::getDefault() const
template <typename T>
MutableColumnPtr DataTypeDecimal<T>::createColumn() const
{
return ColumnType::create();
auto column = ColumnType::create();
column->getData().setScale(scale);
return column;
}

View File

@ -15,6 +15,18 @@ namespace common
return __builtin_add_overflow(x, y, &res);
}
template <>
inline bool addOverflow(Int32 x, Int32 y, Int32 & res)
{
return __builtin_sadd_overflow(x, y, &res);
}
template <>
inline bool addOverflow(Int64 x, Int64 y, Int64 & res)
{
return __builtin_saddl_overflow(x, y, &res);
}
template <>
inline bool addOverflow(__int128 x, __int128 y, __int128 & res)
{
@ -28,6 +40,18 @@ namespace common
return __builtin_sub_overflow(x, y, &res);
}
template <>
inline bool subOverflow(Int32 x, Int32 y, Int32 & res)
{
return __builtin_ssub_overflow(x, y, &res);
}
template <>
inline bool subOverflow(Int64 x, Int64 y, Int64 & res)
{
return __builtin_ssubl_overflow(x, y, &res);
}
template <>
inline bool subOverflow(__int128 x, __int128 y, __int128 & res)
{
@ -41,6 +65,18 @@ namespace common
return __builtin_mul_overflow(x, y, &res);
}
template <>
inline bool mulOverflow(Int32 x, Int32 y, Int32 & res)
{
return __builtin_smul_overflow(x, y, &res);
}
template <>
inline bool mulOverflow(Int64 x, Int64 y, Int64 & res)
{
return __builtin_smull_overflow(x, y, &res);
}
template <>
inline bool mulOverflow(__int128 x, __int128 y, __int128 & res)
{

View File

@ -90,8 +90,10 @@ template <typename A, typename Op>
struct UnaryOperationImpl
{
using ResultType = typename Op::ResultType;
using ArrayA = typename ColumnVector<A>::Container;
using ArrayC = typename ColumnVector<ResultType>::Container;
static void NO_INLINE vector(const PaddedPODArray<A> & a, PaddedPODArray<ResultType> & c)
static void NO_INLINE vector(const ArrayA & a, ArrayC & c)
{
size_t size = a.size();
for (size_t i = 0; i < size; ++i)
@ -729,6 +731,9 @@ struct DecimalBinaryOperation
using ResultType = ResultType_;
using NativeResultType = typename NativeType<ResultType>::Type;
using Op = Operation<NativeResultType, NativeResultType>;
using ArrayA = typename ColumnVector<A>::Container;
using ArrayB = typename ColumnVector<B>::Container;
using ArrayC = typename ColumnVector<ResultType>::Container;
static constexpr bool is_plus_minus = std::is_same_v<Operation<Int32, Int32>, PlusImpl<Int32, Int32>> ||
std::is_same_v<Operation<Int32, Int32>, MinusImpl<Int32, Int32>>;
@ -739,7 +744,7 @@ struct DecimalBinaryOperation
static constexpr bool is_plus_minus_compare = is_plus_minus || is_compare;
static constexpr bool can_overflow = is_plus_minus || is_multiply;
static void NO_INLINE vector_vector(const PaddedPODArray<A> & a, const PaddedPODArray<B> & b, PaddedPODArray<ResultType> & c,
static void NO_INLINE vector_vector(const ArrayA & a, const ArrayB & b, ArrayC & c,
ResultType scale_a [[maybe_unused]], ResultType scale_b [[maybe_unused]])
{
size_t size = a.size();
@ -770,7 +775,7 @@ struct DecimalBinaryOperation
c[i] = apply(a[i], b[i]);
}
static void NO_INLINE vector_constant(const PaddedPODArray<A> & a, B b, PaddedPODArray<ResultType> & c,
static void NO_INLINE vector_constant(const ArrayA & a, B b, ArrayC & c,
ResultType scale_a [[maybe_unused]], ResultType scale_b [[maybe_unused]])
{
size_t size = a.size();
@ -801,7 +806,7 @@ struct DecimalBinaryOperation
c[i] = apply(a[i], b);
}
static void NO_INLINE constant_vector(A a, const PaddedPODArray<B> & b, PaddedPODArray<ResultType> & c,
static void NO_INLINE constant_vector(A a, const ArrayB & b, ArrayC & c,
ResultType scale_a [[maybe_unused]], ResultType scale_b [[maybe_unused]])
{
size_t size = b.size();
@ -1221,6 +1226,8 @@ public:
if constexpr (result_is_decimal)
{
ResultDataType type = decimalResultType(left, right, is_multiply, is_division);
vec_res.setScale(type.getScale());
typename ResultDataType::FieldType scale_a = type.scaleFactorFor(left, is_multiply);
typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division);
if constexpr (IsDecimal<RightDataType> && is_division)
@ -1238,6 +1245,8 @@ public:
if constexpr (result_is_decimal)
{
ResultDataType type = decimalResultType(left, right, is_multiply, is_division);
vec_res.setScale(type.getScale());
typename ResultDataType::FieldType scale_a = type.scaleFactorFor(left, is_multiply);
typename ResultDataType::FieldType scale_b = type.scaleFactorFor(right, is_multiply || is_division);
if constexpr (IsDecimal<RightDataType> && is_division)

View File

@ -225,6 +225,10 @@ class DecimalComparison
public:
using CompareInt = typename DecCompareInt<A, B>::Type;
using Op = Operation<CompareInt, CompareInt>;
using ColVecA = ColumnVector<A>;
using ColVecB = ColumnVector<B>;
using ArrayA = typename ColVecA::Container;
using ArrayB = typename ColVecB::Container;
DecimalComparison(Block & block, size_t result, const ColumnWithTypeAndName & col_left, const ColumnWithTypeAndName & col_right)
{
@ -332,9 +336,6 @@ private:
template <bool scale_left, bool scale_right>
static ColumnPtr apply(const ColumnPtr & c0, const ColumnPtr & c1, CompareInt scale)
{
using ColVecA = ColumnVector<A>;
using ColVecB = ColumnVector<B>;
auto c_res = ColumnUInt8::create();
if constexpr (_actual)
@ -424,7 +425,7 @@ private:
}
template <bool scale_left, bool scale_right>
static void NO_INLINE vector_vector(const PaddedPODArray<A> & a, const PaddedPODArray<B> & b, PaddedPODArray<UInt8> & c,
static void NO_INLINE vector_vector(const ArrayA & a, const ArrayB & b, PaddedPODArray<UInt8> & c,
CompareInt scale)
{
size_t size = a.size();
@ -443,7 +444,7 @@ private:
}
template <bool scale_left, bool scale_right>
static void NO_INLINE vector_constant(const PaddedPODArray<A> & a, B b, PaddedPODArray<UInt8> & c, CompareInt scale)
static void NO_INLINE vector_constant(const ArrayA & a, B b, PaddedPODArray<UInt8> & c, CompareInt scale)
{
size_t size = a.size();
const A * a_pos = &a[0];
@ -459,7 +460,7 @@ private:
}
template <bool scale_left, bool scale_right>
static void NO_INLINE constant_vector(A a, const PaddedPODArray<B> & b, PaddedPODArray<UInt8> & c, CompareInt scale)
static void NO_INLINE constant_vector(A a, const ArrayB & b, PaddedPODArray<UInt8> & c, CompareInt scale)
{
size_t size = b.size();
const B * b_pos = &b[0];

View File

@ -33,3 +33,5 @@
0 1
0 1
0 1
-42 -42 -42 -0.420000000 -0.420000000000000000 -0.42000000000000000000000000000000000000 -42.42000 -42.420000000 -42.420000000000000000 -42.42
42 42 42 0.420000000 0.420000000000000000 0.42000000000000000000000000000000000000 42.42000 42.420000000 42.420000000000000000 42.42

View File

@ -62,7 +62,7 @@ SELECT h = 10000000000 FROM test.decimal WHERE a = 42; -- { serverError 405 }
SELECT i = 10000000000, (i - g + 10000000000) = 10000000000 FROM test.decimal WHERE a = 42;
SELECT 10000000000 = i, 10000000000 = (i - g + 10000000000) FROM test.decimal WHERE a = 42;
--SELECT min(a), min(b), min(c), min(d), min(e), min(f), min(g), min(h), min(i), min(j) FROM test.decimal;
--SELECT max(a), max(b), max(c), max(d), max(e), max(f), max(g), max(h), max(i), max(j) FROM test.decimal;
SELECT min(a), min(b), min(c), min(d), min(e), min(f), min(g), min(h), min(i), min(j) FROM test.decimal;
SELECT max(a), max(b), max(c), max(d), max(e), max(f), max(g), max(h), max(i), max(j) FROM test.decimal;
DROP TABLE IF EXISTS test.decimal;