mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
DecField (in progress)
This commit is contained in:
parent
2b4171af1f
commit
479166283e
@ -118,7 +118,6 @@ template <> inline UInt64 unionCastToUInt64(Float32 x)
|
||||
|
||||
|
||||
/** A template for columns that use a simple array to store.
|
||||
* If _simpleType then T and columnType are the same.
|
||||
*/
|
||||
template <typename T>
|
||||
class ColumnVector final : public COWPtrHelper<IColumn, ColumnVector<T>>
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <Core/Field.h>
|
||||
#include <Common/FieldVisitors.h>
|
||||
#include <Functions/FunctionsComparison.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -270,4 +271,23 @@ namespace DB
|
||||
DB::String res = applyVisitor(DB::FieldVisitorToString(), DB::Field(x));
|
||||
buf.write(res.data(), res.size());
|
||||
}
|
||||
|
||||
|
||||
bool DecField::operator < (const DecField & r) const
|
||||
{
|
||||
using Comparator = DecimalComparison<Dec128, Dec128, LessOp>;
|
||||
return Comparator::compare(Dec128(dec), Dec128(r.dec), scale, r.scale);
|
||||
}
|
||||
|
||||
bool DecField::operator <= (const DecField & r) const
|
||||
{
|
||||
using Comparator = DecimalComparison<Dec128, Dec128, LessOrEqualsOp>;
|
||||
return Comparator::compare(Dec128(dec), Dec128(r.dec), scale, r.scale);
|
||||
}
|
||||
|
||||
bool DecField::operator == (const DecField & r) const
|
||||
{
|
||||
using Comparator = DecimalComparison<Dec128, Dec128, EqualsOp>;
|
||||
return Comparator::compare(Dec128(dec), Dec128(r.dec), scale, r.scale);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,36 @@ using TupleBackend = std::vector<Field>;
|
||||
STRONG_TYPEDEF(TupleBackend, Tuple); /// Array and Tuple are different types with equal representation inside Field.
|
||||
|
||||
|
||||
class DecField
|
||||
{
|
||||
public:
|
||||
static constexpr UInt32 wrongScale() { return std::numeric_limits<UInt32>::max(); }
|
||||
|
||||
DecField(Int128 value, UInt32 scale_ = wrongScale())
|
||||
: dec(value),
|
||||
scale(scale_)
|
||||
{}
|
||||
|
||||
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;
|
||||
bool operator <= (const DecField & r) const;
|
||||
bool operator == (const DecField & r) const;
|
||||
|
||||
bool operator > (const DecField & r) const { return r < *this; }
|
||||
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;
|
||||
};
|
||||
|
||||
/** 32 is enough. Round number is used for alignment and for better arithmetic inside std::vector.
|
||||
* NOTE: Actually, sizeof(std::string) is 32 when using libc++, so Field is 40 bytes.
|
||||
*/
|
||||
@ -56,14 +86,13 @@ public:
|
||||
Float64 = 3,
|
||||
UInt128 = 4,
|
||||
Int128 = 5,
|
||||
Dec64 = 6,
|
||||
Dec128 = 7,
|
||||
|
||||
/// Non-POD types.
|
||||
|
||||
String = 16,
|
||||
Array = 17,
|
||||
Tuple = 18,
|
||||
Decimal = 19,
|
||||
};
|
||||
|
||||
static const int MIN_NON_POD = 16;
|
||||
@ -78,15 +107,13 @@ public:
|
||||
case Int64: return "Int64";
|
||||
case Int128: return "Int128";
|
||||
case Float64: return "Float64";
|
||||
case Dec64: return "Dec64";
|
||||
case Dec128: return "Dec128";
|
||||
case String: return "String";
|
||||
case Array: return "Array";
|
||||
case Tuple: return "Tuple";
|
||||
|
||||
default:
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
case Decimal: return "Decimal";
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
}
|
||||
};
|
||||
|
||||
@ -268,10 +295,10 @@ public:
|
||||
case Types::String: return get<String>() < rhs.get<String>();
|
||||
case Types::Array: return get<Array>() < rhs.get<Array>();
|
||||
case Types::Tuple: return get<Tuple>() < rhs.get<Tuple>();
|
||||
|
||||
default:
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
case Types::Decimal: return get<DecField>() < rhs.get<DecField>();
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
}
|
||||
|
||||
bool operator> (const Field & rhs) const
|
||||
@ -297,11 +324,10 @@ public:
|
||||
case Types::String: return get<String>() <= rhs.get<String>();
|
||||
case Types::Array: return get<Array>() <= rhs.get<Array>();
|
||||
case Types::Tuple: return get<Tuple>() <= rhs.get<Tuple>();
|
||||
|
||||
|
||||
default:
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
case Types::Decimal: return get<DecField>() <= rhs.get<DecField>();
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
}
|
||||
|
||||
bool operator>= (const Field & rhs) const
|
||||
@ -325,10 +351,10 @@ public:
|
||||
case Types::Tuple: return get<Tuple>() == rhs.get<Tuple>();
|
||||
case Types::UInt128: return get<UInt128>() == rhs.get<UInt128>();
|
||||
case Types::Int128: return get<Int128>() == rhs.get<Int128>();
|
||||
|
||||
default:
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
case Types::Decimal: return get<DecField>() == rhs.get<DecField>();
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
}
|
||||
|
||||
bool operator!= (const Field & rhs) const
|
||||
@ -338,7 +364,7 @@ public:
|
||||
|
||||
private:
|
||||
std::aligned_union_t<DBMS_MIN_FIELD_SIZE - sizeof(Types::Which),
|
||||
Null, UInt64, UInt128, Int64, Int128, Dec64, Dec128, Float64, String, Array, Tuple
|
||||
Null, UInt64, UInt128, Int64, Int128, Float64, String, Array, Tuple, DecField
|
||||
> storage;
|
||||
|
||||
Types::Which which;
|
||||
@ -380,8 +406,6 @@ private:
|
||||
case Types::UInt128: f(field.template get<UInt128>()); return;
|
||||
case Types::Int64: f(field.template get<Int64>()); return;
|
||||
case Types::Int128: f(field.template get<Int128>()); return;
|
||||
case Types::Dec64: f(field.template get<Dec64>()); return;
|
||||
case Types::Dec128: f(field.template get<Dec128>()); return;
|
||||
case Types::Float64: f(field.template get<Float64>()); return;
|
||||
#if !__clang__
|
||||
#pragma GCC diagnostic pop
|
||||
@ -389,6 +413,7 @@ private:
|
||||
case Types::String: f(field.template get<String>()); return;
|
||||
case Types::Array: f(field.template get<Array>()); return;
|
||||
case Types::Tuple: f(field.template get<Tuple>()); return;
|
||||
case Types::Decimal: f(field.template get<DecField>()); return;
|
||||
|
||||
default:
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
@ -468,24 +493,22 @@ template <> struct Field::TypeToEnum<UInt64> { static const Types::Which value
|
||||
template <> struct Field::TypeToEnum<UInt128> { static const Types::Which value = Types::UInt128; };
|
||||
template <> struct Field::TypeToEnum<Int64> { static const Types::Which value = Types::Int64; };
|
||||
template <> struct Field::TypeToEnum<Int128> { static const Types::Which value = Types::Int128; };
|
||||
template <> struct Field::TypeToEnum<Dec64> { static const Types::Which value = Types::Dec64; };
|
||||
template <> struct Field::TypeToEnum<Dec128> { static const Types::Which value = Types::Dec128; };
|
||||
template <> struct Field::TypeToEnum<Float64> { static const Types::Which value = Types::Float64; };
|
||||
template <> struct Field::TypeToEnum<String> { static const Types::Which value = Types::String; };
|
||||
template <> struct Field::TypeToEnum<Array> { static const Types::Which value = Types::Array; };
|
||||
template <> struct Field::TypeToEnum<Tuple> { static const Types::Which value = Types::Tuple; };
|
||||
template <> struct Field::TypeToEnum<DecField>{ static const Types::Which value = Types::Decimal; };
|
||||
|
||||
template <> struct Field::EnumToType<Field::Types::Null> { using Type = Null; };
|
||||
template <> struct Field::EnumToType<Field::Types::UInt64> { using Type = UInt64; };
|
||||
template <> struct Field::EnumToType<Field::Types::UInt128> { using Type = UInt128; };
|
||||
template <> struct Field::EnumToType<Field::Types::Int64> { using Type = Int64; };
|
||||
template <> struct Field::EnumToType<Field::Types::Int128> { using Type = Int128; };
|
||||
template <> struct Field::EnumToType<Field::Types::Dec64> { using Type = Dec64; };
|
||||
template <> struct Field::EnumToType<Field::Types::Dec128> { using Type = Dec128; };
|
||||
template <> struct Field::EnumToType<Field::Types::Float64> { using Type = Float64; };
|
||||
template <> struct Field::EnumToType<Field::Types::String> { using Type = String; };
|
||||
template <> struct Field::EnumToType<Field::Types::Array> { using Type = Array; };
|
||||
template <> struct Field::EnumToType<Field::Types::Tuple> { using Type = Tuple; };
|
||||
template <> struct Field::EnumToType<Field::Types::Decimal> { using Type = DecField; };
|
||||
|
||||
|
||||
template <typename T>
|
||||
@ -529,9 +552,9 @@ template <> struct NearestFieldType<Int16> { using Type = Int64; };
|
||||
template <> struct NearestFieldType<Int32> { using Type = Int64; };
|
||||
template <> struct NearestFieldType<Int64> { using Type = Int64; };
|
||||
template <> struct NearestFieldType<Int128> { using Type = Int128; };
|
||||
template <> struct NearestFieldType<Dec32> { using Type = Dec64; };
|
||||
template <> struct NearestFieldType<Dec64> { using Type = Dec64; };
|
||||
template <> struct NearestFieldType<Dec128> { using Type = Dec128; };
|
||||
template <> struct NearestFieldType<Dec32> { using Type = DecField; };
|
||||
template <> struct NearestFieldType<Dec64> { using Type = DecField; };
|
||||
template <> struct NearestFieldType<Dec128> { using Type = DecField; };
|
||||
template <> struct NearestFieldType<Float32> { using Type = Float64; };
|
||||
template <> struct NearestFieldType<Float64> { using Type = Float64; };
|
||||
template <> struct NearestFieldType<String> { using Type = String; };
|
||||
|
@ -86,7 +86,7 @@ T DataTypeDecimal<T>::parseFromString(const String & str) const
|
||||
template <typename T>
|
||||
void DataTypeDecimal<T>::serializeBinary(const Field & field, WriteBuffer & ostr) const
|
||||
{
|
||||
FieldType x = get<typename NearestFieldType<FieldType>::Type>(field);
|
||||
FieldType x = get<DecField>(field);
|
||||
writeBinary(x, ostr);
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ void DataTypeDecimal<T>::deserializeBinary(Field & field, ReadBuffer & istr) con
|
||||
{
|
||||
typename FieldType::NativeType x;
|
||||
readBinary(x, istr);
|
||||
field = typename NearestFieldType<FieldType>::Type(x);
|
||||
field = DecField(T(x), scale);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -141,7 +141,7 @@ void DataTypeDecimal<T>::deserializeBinaryBulk(IColumn & column, ReadBuffer & is
|
||||
template <typename T>
|
||||
Field DataTypeDecimal<T>::getDefault() const
|
||||
{
|
||||
return typename NearestFieldType<FieldType>::Type();
|
||||
return DecField(T(0), scale);
|
||||
}
|
||||
|
||||
|
||||
|
@ -190,11 +190,11 @@ public:
|
||||
|
||||
T parseFromString(const String & str) const;
|
||||
|
||||
static T getScaleMultiplier(UInt32 scale);
|
||||
|
||||
private:
|
||||
const UInt32 precision;
|
||||
const UInt32 scale; /// TODO: should we support scales out of [0, precision]?
|
||||
|
||||
static T getScaleMultiplier(UInt32 scale);
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,6 +7,47 @@
|
||||
#include <Core/Block.h>
|
||||
#include <Core/ColumnNumbers.h>
|
||||
|
||||
namespace common
|
||||
{
|
||||
template <typename T>
|
||||
inline bool addOverflow(T x, T y, T & res)
|
||||
{
|
||||
return __builtin_add_overflow(x, y, &res);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool addOverflow(__int128 x, __int128 y, __int128 & res)
|
||||
{
|
||||
res = x + y;
|
||||
return (res - y) != x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool subOverflow(T x, T y, T & res)
|
||||
{
|
||||
return __builtin_sub_overflow(x, y, &res);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool subOverflow(__int128 x, __int128 y, __int128 & res)
|
||||
{
|
||||
res = x - y;
|
||||
return (res + y) != x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool mulOverflow(T x, T y, T & res)
|
||||
{
|
||||
return __builtin_mul_overflow(x, y, &res);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool mulOverflow(__int128 x, __int128 y, __int128 & res)
|
||||
{
|
||||
res = x * y;
|
||||
return (res / y) != x;
|
||||
}
|
||||
}
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
@ -29,49 +29,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
namespace common
|
||||
{
|
||||
template <typename T>
|
||||
inline bool addOverflow(T x, T y, T & res)
|
||||
{
|
||||
return __builtin_add_overflow(x, y, &res);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool addOverflow(__int128 x, __int128 y, __int128 & res)
|
||||
{
|
||||
res = x + y;
|
||||
return (res - y) != x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool subOverflow(T x, T y, T & res)
|
||||
{
|
||||
return __builtin_sub_overflow(x, y, &res);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool subOverflow(__int128 x, __int128 y, __int128 & res)
|
||||
{
|
||||
res = x - y;
|
||||
return (res + y) != x;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool mulOverflow(T x, T y, T & res)
|
||||
{
|
||||
return __builtin_mul_overflow(x, y, &res);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool mulOverflow(__int128 x, __int128 y, __int128 & res)
|
||||
{
|
||||
res = x * y;
|
||||
return (res / y) != x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
@ -241,13 +241,7 @@ public:
|
||||
ColumnPtr c_res;
|
||||
Shift shift = getScales<A, B>(col_left.type, col_right.type);
|
||||
|
||||
if (shift.a == 1 && shift.b == 1)
|
||||
c_res = apply<false, false>(col_left.column, col_right.column, 1);
|
||||
else if (shift.a == 1)
|
||||
c_res = apply<false, true>(col_left.column, col_right.column, shift.b);
|
||||
else
|
||||
c_res = apply<true, false>(col_left.column, col_right.column, shift.a);
|
||||
|
||||
c_res = applyWithScale(col_left.column, col_right.column, shift);
|
||||
if (c_res)
|
||||
block.getByPosition(result).column = std::move(c_res);
|
||||
return true;
|
||||
@ -255,13 +249,42 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool compare(A a, B b, UInt32 scale_a, UInt32 scale_b)
|
||||
{
|
||||
static const UInt32 max_scale = maxDecimalPrecision<Dec128>();
|
||||
if (scale_a > max_scale || scale_b > max_scale)
|
||||
throw Exception("Bad scale of decimal field", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
|
||||
Shift shift;
|
||||
if (scale_a < scale_b)
|
||||
shift.a = DataTypeDecimal<B>(maxDecimalPrecision<B>(), scale_b).getScaleMultiplier(scale_b - scale_a);
|
||||
if (scale_a > scale_b)
|
||||
shift.b = DataTypeDecimal<A>(maxDecimalPrecision<A>(), scale_a).getScaleMultiplier(scale_a - scale_b);
|
||||
|
||||
return applyWithScale(a, b, shift);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Shift
|
||||
{
|
||||
CompareInt a = 1;
|
||||
CompareInt b = 1;
|
||||
|
||||
bool none() const { return a == 1 && b == 1; }
|
||||
bool left() const { return a != 1; }
|
||||
bool right() const { return b != 1; }
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
static auto applyWithScale(T a, U b, const Shift & shift)
|
||||
{
|
||||
if (shift.left())
|
||||
return apply<true, false>(a, b, shift.a);
|
||||
else if (shift.right())
|
||||
return apply<false, true>(a, b, shift.b);
|
||||
return apply<false, false>(a, b, 1);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static std::enable_if_t<decTrait<T>() && decTrait<U>(), Shift>
|
||||
getScales(const DataTypePtr & left_type, const DataTypePtr & right_type)
|
||||
@ -390,9 +413,9 @@ private:
|
||||
overflow |= (y < 0);
|
||||
|
||||
if constexpr (scale_left)
|
||||
overflow |= __builtin_mul_overflow(x, scale, &x);
|
||||
overflow |= common::mulOverflow(x, scale, x);
|
||||
if constexpr (scale_right)
|
||||
overflow |= __builtin_mul_overflow(y, scale, &y);
|
||||
overflow |= common::mulOverflow(y, scale, y);
|
||||
|
||||
if (overflow)
|
||||
throw Exception("Can't compare", ErrorCodes::DECIMAL_OVERFLOW);
|
||||
|
@ -62,4 +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;
|
||||
|
||||
DROP TABLE IF EXISTS test.decimal;
|
||||
|
Loading…
Reference in New Issue
Block a user