mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-23 02:00:49 +00:00
own DecimalField for Decimal32/64/128, better field comparison CLICKHOUSE-3765
This commit is contained in:
parent
c61ccc4dfe
commit
cbb80f52c2
@ -153,7 +153,7 @@ public:
|
||||
UInt32 getScale() const { return scale; }
|
||||
|
||||
private:
|
||||
UInt32 scale = DecimalField::wrongScale();
|
||||
UInt32 scale = DecimalField<Decimal32>::wrongScale();
|
||||
};
|
||||
|
||||
|
||||
@ -258,7 +258,7 @@ public:
|
||||
if constexpr (IsDecimalNumber<T>)
|
||||
{
|
||||
UInt32 scale = data.getScale();
|
||||
if (scale == DecimalField::wrongScale())
|
||||
if (scale == DecimalField<Decimal32>::wrongScale())
|
||||
throw Exception("Extracting Decimal field with unknown scale. Scale is lost.", ErrorCodes::LOGICAL_ERROR);
|
||||
return DecimalField(data[n], scale);
|
||||
}
|
||||
|
@ -273,21 +273,36 @@ namespace DB
|
||||
}
|
||||
|
||||
|
||||
bool DecimalField::operator < (const DecimalField & r) const
|
||||
template <typename T>
|
||||
static bool decEqual(T x, T y, UInt32 x_scale, UInt32 y_scale)
|
||||
{
|
||||
using Comparator = DecimalComparison<Decimal128, Decimal128, LessOp>;
|
||||
return Comparator::compare(Decimal128(dec), Decimal128(r.dec), scale, r.scale);
|
||||
using Comparator = DecimalComparison<T, T, EqualsOp>;
|
||||
return Comparator::compare(x, y, x_scale, y_scale);
|
||||
}
|
||||
|
||||
bool DecimalField::operator <= (const DecimalField & r) const
|
||||
template <typename T>
|
||||
static bool decLess(T x, T y, UInt32 x_scale, UInt32 y_scale)
|
||||
{
|
||||
using Comparator = DecimalComparison<Decimal128, Decimal128, LessOrEqualsOp>;
|
||||
return Comparator::compare(Decimal128(dec), Decimal128(r.dec), scale, r.scale);
|
||||
using Comparator = DecimalComparison<T, T, LessOp>;
|
||||
return Comparator::compare(x, y, x_scale, y_scale);
|
||||
}
|
||||
|
||||
bool DecimalField::operator == (const DecimalField & r) const
|
||||
template <typename T>
|
||||
static bool decLessOrEqual(T x, T y, UInt32 x_scale, UInt32 y_scale)
|
||||
{
|
||||
using Comparator = DecimalComparison<Decimal128, Decimal128, EqualsOp>;
|
||||
return Comparator::compare(Decimal128(dec), Decimal128(r.dec), scale, r.scale);
|
||||
using Comparator = DecimalComparison<T, T, LessOrEqualsOp>;
|
||||
return Comparator::compare(x, y, x_scale, y_scale);
|
||||
}
|
||||
|
||||
template <> bool decimalEqual(Decimal32 x, Decimal32 y, UInt32 xs, UInt32 ys) { return decEqual(x, y, xs, ys); }
|
||||
template <> bool decimalLess(Decimal32 x, Decimal32 y, UInt32 xs, UInt32 ys) { return decLess(x, y, xs, ys); }
|
||||
template <> bool decimalLessOrEqual(Decimal32 x, Decimal32 y, UInt32 xs, UInt32 ys) { return decLessOrEqual(x, y, xs, ys); }
|
||||
|
||||
template <> bool decimalEqual(Decimal64 x, Decimal64 y, UInt32 xs, UInt32 ys) { return decEqual(x, y, xs, ys); }
|
||||
template <> bool decimalLess(Decimal64 x, Decimal64 y, UInt32 xs, UInt32 ys) { return decLess(x, y, xs, ys); }
|
||||
template <> bool decimalLessOrEqual(Decimal64 x, Decimal64 y, UInt32 xs, UInt32 ys) { return decLessOrEqual(x, y, xs, ys); }
|
||||
|
||||
template <> bool decimalEqual(Decimal128 x, Decimal128 y, UInt32 xs, UInt32 ys) { return decEqual(x, y, xs, ys); }
|
||||
template <> bool decimalLess(Decimal128 x, Decimal128 y, UInt32 xs, UInt32 ys) { return decLess(x, y, xs, ys); }
|
||||
template <> bool decimalLessOrEqual(Decimal128 x, Decimal128 y, UInt32 xs, UInt32 ys) { return decLessOrEqual(x, y, xs, ys); }
|
||||
}
|
||||
|
@ -27,33 +27,52 @@ using Array = std::vector<Field>;
|
||||
using TupleBackend = std::vector<Field>;
|
||||
STRONG_TYPEDEF(TupleBackend, Tuple) /// Array and Tuple are different types with equal representation inside Field.
|
||||
|
||||
template <typename T> bool decimalEqual(T x, T y, UInt32 x_scale, UInt32 y_scale);
|
||||
template <typename T> bool decimalLess(T x, T y, UInt32 x_scale, UInt32 y_scale);
|
||||
template <typename T> bool decimalLessOrEqual(T x, T y, UInt32 x_scale, UInt32 y_scale);
|
||||
|
||||
template <typename T>
|
||||
class DecimalField
|
||||
{
|
||||
public:
|
||||
static constexpr UInt32 wrongScale() { return std::numeric_limits<UInt32>::max(); }
|
||||
|
||||
DecimalField(Int128 value, UInt32 scale_ = wrongScale())
|
||||
DecimalField(T value, UInt32 scale_ = wrongScale())
|
||||
: dec(value),
|
||||
scale(scale_)
|
||||
{}
|
||||
|
||||
operator Decimal32() const { return dec; }
|
||||
operator Decimal64() const { return dec; }
|
||||
operator Decimal128() const { return dec; }
|
||||
operator T() const { return dec; }
|
||||
|
||||
UInt32 getScale() const { return scale; }
|
||||
|
||||
bool operator < (const DecimalField & r) const;
|
||||
bool operator <= (const DecimalField & r) const;
|
||||
bool operator == (const DecimalField & r) const;
|
||||
template <typename U>
|
||||
bool operator < (const DecimalField<U> & r) const
|
||||
{
|
||||
using MaxType = std::conditional_t<(sizeof(T) > sizeof(U)), T, U>;
|
||||
return decimalLess<MaxType>(dec, r, scale, r.getScale());
|
||||
}
|
||||
|
||||
bool operator > (const DecimalField & r) const { return r < *this; }
|
||||
bool operator >= (const DecimalField & r) const { return r <= * this; }
|
||||
bool operator != (const DecimalField & r) const { return !(*this == r); }
|
||||
template <typename U>
|
||||
bool operator <= (const DecimalField<U> & r) const
|
||||
{
|
||||
using MaxType = std::conditional_t<(sizeof(T) > sizeof(U)), T, U>;
|
||||
return decimalLessOrEqual<MaxType>(dec, r, scale, r.getScale());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
bool operator == (const DecimalField<U> & r) const
|
||||
{
|
||||
using MaxType = std::conditional_t<(sizeof(T) > sizeof(U)), T, U>;
|
||||
return decimalEqual<MaxType>(dec, r, scale, r.getScale());
|
||||
}
|
||||
|
||||
template <typename U> bool operator > (const DecimalField<U> & r) const { return r < *this; }
|
||||
template <typename U> bool operator >= (const DecimalField<U> & r) const { return r <= * this; }
|
||||
template <typename U> bool operator != (const DecimalField<U> & r) const { return !(*this == r); }
|
||||
|
||||
private:
|
||||
Int128 dec;
|
||||
T dec;
|
||||
UInt32 scale;
|
||||
};
|
||||
|
||||
@ -91,7 +110,9 @@ public:
|
||||
String = 16,
|
||||
Array = 17,
|
||||
Tuple = 18,
|
||||
Decimal = 19,
|
||||
Decimal32 = 19,
|
||||
Decimal64 = 20,
|
||||
Decimal128 = 21,
|
||||
};
|
||||
|
||||
static const int MIN_NON_POD = 16;
|
||||
@ -109,7 +130,9 @@ public:
|
||||
case String: return "String";
|
||||
case Array: return "Array";
|
||||
case Tuple: return "Tuple";
|
||||
case Decimal: return "Decimal";
|
||||
case Decimal32: return "Decimal32";
|
||||
case Decimal64: return "Decimal64";
|
||||
case Decimal128: return "Decimal128";
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
@ -121,6 +144,7 @@ public:
|
||||
template <typename T> struct TypeToEnum;
|
||||
template <Types::Which which> struct EnumToType;
|
||||
|
||||
static bool IsDecimal(Types::Which which) { return which >= Types::Decimal32 && which <= Types::Decimal128; }
|
||||
|
||||
Field()
|
||||
: which(Types::Null)
|
||||
@ -294,7 +318,9 @@ 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>();
|
||||
case Types::Decimal: return get<DecimalField>() < rhs.get<DecimalField>();
|
||||
case Types::Decimal32: return get<DecimalField<Decimal32>>() < rhs.get<DecimalField<Decimal32>>();
|
||||
case Types::Decimal64: return get<DecimalField<Decimal64>>() < rhs.get<DecimalField<Decimal64>>();
|
||||
case Types::Decimal128: return get<DecimalField<Decimal128>>() < rhs.get<DecimalField<Decimal128>>();
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
@ -323,7 +349,9 @@ 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>();
|
||||
case Types::Decimal: return get<DecimalField>() <= rhs.get<DecimalField>();
|
||||
case Types::Decimal32: return get<DecimalField<Decimal32>>() <= rhs.get<DecimalField<Decimal32>>();
|
||||
case Types::Decimal64: return get<DecimalField<Decimal64>>() <= rhs.get<DecimalField<Decimal64>>();
|
||||
case Types::Decimal128: return get<DecimalField<Decimal128>>() <= rhs.get<DecimalField<Decimal128>>();
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
@ -350,7 +378,9 @@ 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>();
|
||||
case Types::Decimal: return get<DecimalField>() == rhs.get<DecimalField>();
|
||||
case Types::Decimal32: return get<DecimalField<Decimal32>>() == rhs.get<DecimalField<Decimal32>>();
|
||||
case Types::Decimal64: return get<DecimalField<Decimal64>>() == rhs.get<DecimalField<Decimal64>>();
|
||||
case Types::Decimal128: return get<DecimalField<Decimal128>>() == rhs.get<DecimalField<Decimal128>>();
|
||||
}
|
||||
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
@ -363,7 +393,8 @@ public:
|
||||
|
||||
private:
|
||||
std::aligned_union_t<DBMS_MIN_FIELD_SIZE - sizeof(Types::Which),
|
||||
Null, UInt64, UInt128, Int64, Int128, Float64, String, Array, Tuple, DecimalField
|
||||
Null, UInt64, UInt128, Int64, Int128, Float64, String, Array, Tuple,
|
||||
DecimalField<Decimal32>, DecimalField<Decimal64>, DecimalField<Decimal128>
|
||||
> storage;
|
||||
|
||||
Types::Which which;
|
||||
@ -412,7 +443,9 @@ 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<DecimalField>()); return;
|
||||
case Types::Decimal32: f(field.template get<DecimalField<Decimal32>>()); return;
|
||||
case Types::Decimal64: f(field.template get<DecimalField<Decimal64>>()); return;
|
||||
case Types::Decimal128: f(field.template get<DecimalField<Decimal128>>()); return;
|
||||
|
||||
default:
|
||||
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
|
||||
@ -496,7 +529,9 @@ template <> struct Field::TypeToEnum<Float64> { static const Types::Which value
|
||||
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<DecimalField>{ static const Types::Which value = Types::Decimal; };
|
||||
template <> struct Field::TypeToEnum<DecimalField<Decimal32>>{ static const Types::Which value = Types::Decimal32; };
|
||||
template <> struct Field::TypeToEnum<DecimalField<Decimal64>>{ static const Types::Which value = Types::Decimal64; };
|
||||
template <> struct Field::TypeToEnum<DecimalField<Decimal128>>{ static const Types::Which value = Types::Decimal128; };
|
||||
|
||||
template <> struct Field::EnumToType<Field::Types::Null> { using Type = Null; };
|
||||
template <> struct Field::EnumToType<Field::Types::UInt64> { using Type = UInt64; };
|
||||
@ -507,7 +542,9 @@ template <> struct Field::EnumToType<Field::Types::Float64> { using Type = Float
|
||||
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 = DecimalField; };
|
||||
template <> struct Field::EnumToType<Field::Types::Decimal32> { using Type = DecimalField<Decimal32>; };
|
||||
template <> struct Field::EnumToType<Field::Types::Decimal64> { using Type = DecimalField<Decimal64>; };
|
||||
template <> struct Field::EnumToType<Field::Types::Decimal128> { using Type = DecimalField<Decimal128>; };
|
||||
|
||||
|
||||
template <typename T>
|
||||
@ -551,9 +588,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<Decimal32> { using Type = DecimalField; };
|
||||
template <> struct NearestFieldType<Decimal64> { using Type = DecimalField; };
|
||||
template <> struct NearestFieldType<Decimal128> { using Type = DecimalField; };
|
||||
template <> struct NearestFieldType<Decimal32> { using Type = DecimalField<Decimal32>; };
|
||||
template <> struct NearestFieldType<Decimal64> { using Type = DecimalField<Decimal64>; };
|
||||
template <> struct NearestFieldType<Decimal128> { using Type = DecimalField<Decimal128>; };
|
||||
template <> struct NearestFieldType<Float32> { using Type = Float64; };
|
||||
template <> struct NearestFieldType<Float64> { using Type = Float64; };
|
||||
template <> struct NearestFieldType<String> { using Type = String; };
|
||||
|
@ -102,7 +102,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<DecimalField>(field);
|
||||
FieldType x = get<DecimalField<T>>(field);
|
||||
writeBinary(x, ostr);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user