ClickHouse/src/Common/FieldVisitorsAccurateComparison.h

141 lines
4.5 KiB
C++
Raw Normal View History

2020-06-14 18:42:10 +00:00
#pragma once
#include <Core/Field.h>
#include <Core/AccurateComparison.h>
#include <common/demangle.h>
#include <Common/FieldVisitors.h>
#include <IO/ReadBufferFromString.h>
#include <IO/ReadHelpers.h>
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_TYPE_OF_FIELD;
}
/** More precise comparison, used for index.
* Differs from Field::operator< and Field::operator== in that it also compares values of different types.
* Comparison rules are same as in FunctionsComparison (to be consistent with expression evaluation in query).
*/
class FieldVisitorAccurateEquals : public StaticVisitor<bool>
{
public:
template <typename T, typename U>
bool operator() (const T & l, const U & r) const
{
if constexpr (std::is_same_v<T, Null> || std::is_same_v<U, Null>
|| std::is_same_v<T, NegativeInfinity> || std::is_same_v<T, PositiveInfinity>
|| std::is_same_v<U, NegativeInfinity> || std::is_same_v<U, PositiveInfinity>)
{
2020-06-14 18:42:10 +00:00
return std::is_same_v<T, U>;
}
2020-06-14 18:42:10 +00:00
else
{
if constexpr (std::is_same_v<T, U>)
return l == r;
if constexpr (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
return accurate::equalsOp(l, r);
2021-05-09 15:05:20 +00:00
/// TODO This is wrong (does not respect scale).
2021-06-14 03:05:27 +00:00
if constexpr (is_decimal_field<T> && is_decimal_field<U>)
2020-06-14 18:42:10 +00:00
return l == r;
2021-06-14 03:05:27 +00:00
if constexpr (is_decimal_field<T> && std::is_arithmetic_v<U>)
2021-04-25 09:30:43 +00:00
return l == DecimalField<Decimal256>(Decimal256(r), 0);
2020-06-14 18:42:10 +00:00
2021-06-14 03:05:27 +00:00
if constexpr (std::is_arithmetic_v<T> && is_decimal_field<U>)
2021-04-25 09:30:43 +00:00
return DecimalField<Decimal256>(Decimal256(l), 0) == r;
2020-06-14 18:42:10 +00:00
2021-01-27 00:54:57 +00:00
if constexpr (std::is_same_v<T, String> && std::is_arithmetic_v<U>)
2020-06-14 18:42:10 +00:00
{
2021-05-03 22:46:51 +00:00
ReadBufferFromString in(l);
U parsed;
readText(parsed, in);
return operator()(parsed, r);
2020-06-14 18:42:10 +00:00
}
2021-01-27 00:54:57 +00:00
if constexpr (std::is_same_v<U, String> && std::is_arithmetic_v<T>)
2020-06-14 18:42:10 +00:00
{
2021-01-27 00:54:57 +00:00
ReadBufferFromString in(r);
T parsed;
readText(parsed, in);
return operator()(l, parsed);
2020-06-14 18:42:10 +00:00
}
}
throw Exception("Cannot compare " + demangle(typeid(T).name()) + " with " + demangle(typeid(U).name()),
ErrorCodes::BAD_TYPE_OF_FIELD);
}
};
class FieldVisitorAccurateLess : public StaticVisitor<bool>
{
public:
template <typename T, typename U>
bool operator() (const T & l, const U & r) const
{
if constexpr (std::is_same_v<T, Null> || std::is_same_v<U, Null>)
return false;
else if constexpr (std::is_same_v<T, NegativeInfinity> || std::is_same_v<U, PositiveInfinity>)
return !std::is_same_v<T, U>;
else if constexpr (std::is_same_v<U, NegativeInfinity> || std::is_same_v<T, PositiveInfinity>)
return false;
2020-06-14 18:42:10 +00:00
else
{
if constexpr (std::is_same_v<T, U>)
return l < r;
if constexpr (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>)
return accurate::lessOp(l, r);
2021-05-09 15:05:20 +00:00
/// TODO This is wrong (does not respect scale).
2021-06-14 03:05:27 +00:00
if constexpr (is_decimal_field<T> && is_decimal_field<U>)
2020-06-14 18:42:10 +00:00
return l < r;
2021-06-14 03:05:27 +00:00
if constexpr (is_decimal_field<T> && std::is_arithmetic_v<U>)
2021-04-25 09:30:43 +00:00
return l < DecimalField<Decimal256>(Decimal256(r), 0);
2020-06-14 18:42:10 +00:00
2021-06-14 03:05:27 +00:00
if constexpr (std::is_arithmetic_v<T> && is_decimal_field<U>)
2021-04-25 09:30:43 +00:00
return DecimalField<Decimal256>(Decimal256(l), 0) < r;
2020-06-14 18:42:10 +00:00
2021-01-27 00:54:57 +00:00
if constexpr (std::is_same_v<T, String> && std::is_arithmetic_v<U>)
2020-06-14 18:42:10 +00:00
{
2021-05-03 22:46:51 +00:00
ReadBufferFromString in(l);
U parsed;
readText(parsed, in);
return operator()(parsed, r);
2020-06-14 18:42:10 +00:00
}
2021-01-27 00:54:57 +00:00
if constexpr (std::is_same_v<U, String> && std::is_arithmetic_v<T>)
2020-06-14 18:42:10 +00:00
{
2021-01-27 00:54:57 +00:00
ReadBufferFromString in(r);
T parsed;
readText(parsed, in);
return operator()(l, parsed);
2020-06-14 18:42:10 +00:00
}
}
throw Exception("Cannot compare " + demangle(typeid(T).name()) + " with " + demangle(typeid(U).name()),
ErrorCodes::BAD_TYPE_OF_FIELD);
}
};
class FieldVisitorAccurateLessOrEqual : public StaticVisitor<bool>
{
public:
template <typename T, typename U>
bool operator()(const T & l, const U & r) const
{
auto less_cmp = FieldVisitorAccurateLess();
return !less_cmp(r, l);
}
};
2020-06-14 18:42:10 +00:00
}