#pragma once #include #include #include #include #include #include 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 { public: template bool operator() (const T & l, const U & r) const { if constexpr (std::is_same_v || std::is_same_v) { if constexpr (std::is_same_v && std::is_same_v) return l == r; return false; } else if constexpr (std::is_same_v) { return operator()(UInt8(l), r); } else if constexpr (std::is_same_v) { return operator()(l, UInt8(r)); } else { if constexpr (std::is_same_v) return l == r; if constexpr (std::is_arithmetic_v && std::is_arithmetic_v) return accurate::equalsOp(l, r); /// TODO This is wrong (does not respect scale). if constexpr (is_decimal_field && is_decimal_field) return l == r; if constexpr (is_decimal_field && std::is_arithmetic_v) return l == DecimalField(Decimal256(r), 0); if constexpr (std::is_arithmetic_v && is_decimal_field) return DecimalField(Decimal256(l), 0) == r; if constexpr (std::is_same_v && std::is_arithmetic_v) { ReadBufferFromString in(l); U parsed; readText(parsed, in); return operator()(parsed, r); } if constexpr (std::is_same_v && std::is_arithmetic_v) { ReadBufferFromString in(r); T parsed; readText(parsed, in); return operator()(l, parsed); } } throw Exception("Cannot compare " + demangle(typeid(T).name()) + " with " + demangle(typeid(U).name()), ErrorCodes::BAD_TYPE_OF_FIELD); } }; class FieldVisitorAccurateLess : public StaticVisitor { public: template bool operator() (const T & l, const U & r) const { if constexpr (std::is_same_v && std::is_same_v) { return l.isNegativeInfinity() && r.isPositiveInfinity(); } else if constexpr (std::is_same_v) { return l.isNegativeInfinity(); } else if constexpr (std::is_same_v) { return r.isPositiveInfinity(); } else if constexpr (std::is_same_v) { return operator()(UInt8(l), r); } else if constexpr (std::is_same_v) { return operator()(l, UInt8(r)); } else { if constexpr (std::is_same_v) return l < r; if constexpr (std::is_arithmetic_v && std::is_arithmetic_v) return accurate::lessOp(l, r); /// TODO This is wrong (does not respect scale). if constexpr (is_decimal_field && is_decimal_field) return l < r; if constexpr (is_decimal_field && std::is_arithmetic_v) return l < DecimalField(Decimal256(r), 0); if constexpr (std::is_arithmetic_v && is_decimal_field) return DecimalField(Decimal256(l), 0) < r; if constexpr (std::is_same_v && std::is_arithmetic_v) { ReadBufferFromString in(l); U parsed; readText(parsed, in); return operator()(parsed, r); } if constexpr (std::is_same_v && std::is_arithmetic_v) { ReadBufferFromString in(r); T parsed; readText(parsed, in); return operator()(l, parsed); } } throw Exception("Cannot compare " + demangle(typeid(T).name()) + " with " + demangle(typeid(U).name()), ErrorCodes::BAD_TYPE_OF_FIELD); } }; class FieldVisitorAccurateLessOrEqual : public StaticVisitor { public: template bool operator()(const T & l, const U & r) const { auto less_cmp = FieldVisitorAccurateLess(); return !less_cmp(r, l); } }; }