From 01c8b1d7bb063270c734873ff3fdde13a8a0f3cd Mon Sep 17 00:00:00 2001 From: chertus Date: Fri, 10 Aug 2018 17:57:55 +0300 Subject: [PATCH] decimal field extraction (from column or type) --- dbms/src/Columns/ColumnVector.h | 68 ++++++++++++++++++- dbms/src/Core/Field.h | 3 +- dbms/src/DataTypes/DataTypesDecimal.cpp | 4 +- dbms/src/Functions/FunctionHelpers.h | 36 ++++++++++ dbms/src/Functions/FunctionsArithmetic.h | 17 +++-- dbms/src/Functions/FunctionsComparison.h | 13 ++-- .../00700_decimal_compare.reference | 2 + .../0_stateless/00700_decimal_compare.sql | 4 +- 8 files changed, 129 insertions(+), 18 deletions(-) diff --git a/dbms/src/Columns/ColumnVector.h b/dbms/src/Columns/ColumnVector.h index 8c57d4188ab..01b8d5a6638 100644 --- a/dbms/src/Columns/ColumnVector.h +++ b/dbms/src/Columns/ColumnVector.h @@ -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 +class DecPaddedPODArray : public PODArray, sizeof(T)-1> +{ +public: + using Base = PODArray, 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 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::max(); +}; + + /** A template for columns that use a simple array to store. */ template @@ -131,7 +185,7 @@ private: public: using value_type = T; - using Container = PaddedPODArray; + using Container = std::conditional_t(), DecPaddedPODArray, PaddedPODArray>; private: ColumnVector() {} @@ -215,12 +269,20 @@ public: Field operator[](size_t n) const override { - return typename NearestFieldType::Type(data[n]); + if constexpr (decTrait()) + { + UInt32 scale = data.getScale(); + if (scale == std::numeric_limits::max()) + throw Exception("Extracting Decimal field with unknown scale. Scale is lost.", ErrorCodes::LOGICAL_ERROR); + return DecField(data[n], scale); + } + else + return typename NearestFieldType::Type(data[n]); } void get(size_t n, Field & res) const override { - res = typename NearestFieldType::Type(data[n]); + res = (*this)[n]; } UInt64 get64(size_t n) const override; diff --git a/dbms/src/Core/Field.h b/dbms/src/Core/Field.h index f07b96cc237..7c63b3a9be7 100644 --- a/dbms/src/Core/Field.h +++ b/dbms/src/Core/Field.h @@ -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; diff --git a/dbms/src/DataTypes/DataTypesDecimal.cpp b/dbms/src/DataTypes/DataTypesDecimal.cpp index 166fd3e3319..f0e2c58490d 100644 --- a/dbms/src/DataTypes/DataTypesDecimal.cpp +++ b/dbms/src/DataTypes/DataTypesDecimal.cpp @@ -148,7 +148,9 @@ Field DataTypeDecimal::getDefault() const template MutableColumnPtr DataTypeDecimal::createColumn() const { - return ColumnType::create(); + auto column = ColumnType::create(); + column->getData().setScale(scale); + return column; } diff --git a/dbms/src/Functions/FunctionHelpers.h b/dbms/src/Functions/FunctionHelpers.h index ed980afef06..5dbfd6a5054 100644 --- a/dbms/src/Functions/FunctionHelpers.h +++ b/dbms/src/Functions/FunctionHelpers.h @@ -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) { diff --git a/dbms/src/Functions/FunctionsArithmetic.h b/dbms/src/Functions/FunctionsArithmetic.h index 68aab495278..cbcbc28d00e 100644 --- a/dbms/src/Functions/FunctionsArithmetic.h +++ b/dbms/src/Functions/FunctionsArithmetic.h @@ -90,8 +90,10 @@ template struct UnaryOperationImpl { using ResultType = typename Op::ResultType; + using ArrayA = typename ColumnVector::Container; + using ArrayC = typename ColumnVector::Container; - static void NO_INLINE vector(const PaddedPODArray & a, PaddedPODArray & 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::Type; using Op = Operation; + using ArrayA = typename ColumnVector::Container; + using ArrayB = typename ColumnVector::Container; + using ArrayC = typename ColumnVector::Container; static constexpr bool is_plus_minus = std::is_same_v, PlusImpl> || std::is_same_v, MinusImpl>; @@ -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, const PaddedPODArray & b, PaddedPODArray & 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, B b, PaddedPODArray & 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, PaddedPODArray & 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 && 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 && is_division) diff --git a/dbms/src/Functions/FunctionsComparison.h b/dbms/src/Functions/FunctionsComparison.h index 60b10af9512..8d58564fdf8 100644 --- a/dbms/src/Functions/FunctionsComparison.h +++ b/dbms/src/Functions/FunctionsComparison.h @@ -225,6 +225,10 @@ class DecimalComparison public: using CompareInt = typename DecCompareInt::Type; using Op = Operation; + using ColVecA = ColumnVector; + using ColVecB = ColumnVector; + 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 static ColumnPtr apply(const ColumnPtr & c0, const ColumnPtr & c1, CompareInt scale) { - using ColVecA = ColumnVector; - using ColVecB = ColumnVector; - auto c_res = ColumnUInt8::create(); if constexpr (_actual) @@ -424,7 +425,7 @@ private: } template - static void NO_INLINE vector_vector(const PaddedPODArray & a, const PaddedPODArray & b, PaddedPODArray & c, + static void NO_INLINE vector_vector(const ArrayA & a, const ArrayB & b, PaddedPODArray & c, CompareInt scale) { size_t size = a.size(); @@ -443,7 +444,7 @@ private: } template - static void NO_INLINE vector_constant(const PaddedPODArray & a, B b, PaddedPODArray & c, CompareInt scale) + static void NO_INLINE vector_constant(const ArrayA & a, B b, PaddedPODArray & c, CompareInt scale) { size_t size = a.size(); const A * a_pos = &a[0]; @@ -459,7 +460,7 @@ private: } template - static void NO_INLINE constant_vector(A a, const PaddedPODArray & b, PaddedPODArray & c, CompareInt scale) + static void NO_INLINE constant_vector(A a, const ArrayB & b, PaddedPODArray & c, CompareInt scale) { size_t size = b.size(); const B * b_pos = &b[0]; diff --git a/dbms/tests/queries/0_stateless/00700_decimal_compare.reference b/dbms/tests/queries/0_stateless/00700_decimal_compare.reference index 2616a0afa92..32f0b0a6dea 100644 --- a/dbms/tests/queries/0_stateless/00700_decimal_compare.reference +++ b/dbms/tests/queries/0_stateless/00700_decimal_compare.reference @@ -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 diff --git a/dbms/tests/queries/0_stateless/00700_decimal_compare.sql b/dbms/tests/queries/0_stateless/00700_decimal_compare.sql index 450a06428c8..9bc743ec622 100644 --- a/dbms/tests/queries/0_stateless/00700_decimal_compare.sql +++ b/dbms/tests/queries/0_stateless/00700_decimal_compare.sql @@ -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;