DecField (in progress)

This commit is contained in:
chertus 2018-08-09 19:32:01 +03:00
parent 2b4171af1f
commit 479166283e
9 changed files with 151 additions and 85 deletions

View File

@ -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>>

View File

@ -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);
}
}

View File

@ -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; };

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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
{

View File

@ -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
{

View File

@ -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);

View File

@ -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;