mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
Correct index comparisons in case constants cannot be precisely casted [#CLICKHOUSE-3002]
This commit is contained in:
parent
a77369d082
commit
e9f8f99e06
@ -196,39 +196,4 @@ void FieldVisitorHash::operator() (const Array & x) const
|
||||
applyVisitor(*this, elem);
|
||||
}
|
||||
|
||||
|
||||
UInt64 stringToDateOrDateTime(const String & s)
|
||||
{
|
||||
if (s.size() == strlen("YYYY-MM-DD"))
|
||||
return stringToDate(s);
|
||||
else
|
||||
return stringToDateTime(s);
|
||||
}
|
||||
|
||||
|
||||
DayNum_t stringToDate(const String & s)
|
||||
{
|
||||
ReadBufferFromString in(s);
|
||||
DayNum_t date{};
|
||||
|
||||
readDateText(date, in);
|
||||
if (!in.eof())
|
||||
throw Exception("String is too long for Date: " + s);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
UInt64 stringToDateTime(const String & s)
|
||||
{
|
||||
ReadBufferFromString in(s);
|
||||
time_t date_time{};
|
||||
|
||||
readDateTimeText(date_time, in);
|
||||
if (!in.eof())
|
||||
throw Exception("String is too long for DateTime: " + s);
|
||||
|
||||
return UInt64(date_time);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Field.h>
|
||||
#include <Functions/AccurateComparison.h>
|
||||
#include <common/DateLUT.h>
|
||||
|
||||
|
||||
@ -174,26 +175,12 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/// Converts string with date or datetime (in format 'YYYY-MM-DD hh:mm:ss') to UInt64 containing numeric value of date (or datetime)
|
||||
UInt64 stringToDateOrDateTime(const String & s);
|
||||
|
||||
/// Converts string with date to UInt16 (which is alias of DayNum_t) containing numeric value of date
|
||||
DayNum_t stringToDate(const String & s);
|
||||
|
||||
/// Converts string with date to UInt64 containing numeric value of datetime
|
||||
UInt64 stringToDateTime(const String & s);
|
||||
|
||||
|
||||
/** 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).
|
||||
* Except in cases when comparing signed and unsigned integers, which is unspecified behavior in FunctionsComparison,
|
||||
* and when comparing integers and floats. Comparison is accurate here.
|
||||
*/
|
||||
class FieldVisitorAccurateEquals : public StaticVisitor<bool>
|
||||
{
|
||||
using Double128 = long double; /// Non portable. Must have 64 bit mantissa to provide accurate comparisons.
|
||||
|
||||
public:
|
||||
bool operator() (const Null & l, const Null & r) const { return true; }
|
||||
bool operator() (const Null & l, const UInt64 & r) const { return false; }
|
||||
@ -205,30 +192,30 @@ public:
|
||||
|
||||
bool operator() (const UInt64 & l, const Null & r) const { return false; }
|
||||
bool operator() (const UInt64 & l, const UInt64 & r) const { return l == r; }
|
||||
bool operator() (const UInt64 & l, const Int64 & r) const { return r >= 0 && l == UInt64(r); }
|
||||
bool operator() (const UInt64 & l, const Float64 & r) const { return Double128(l) == Double128(r); }
|
||||
bool operator() (const UInt64 & l, const String & r) const { return l == stringToDateOrDateTime(r); }
|
||||
bool operator() (const UInt64 & l, const Int64 & r) const { return accurate::equalsOp(l, r); }
|
||||
bool operator() (const UInt64 & l, const Float64 & r) const { return accurate::equalsOp(l, r); }
|
||||
bool operator() (const UInt64 & l, const String & r) const { return false; }
|
||||
bool operator() (const UInt64 & l, const Array & r) const { return false; }
|
||||
bool operator() (const UInt64 & l, const Tuple & r) const { return false; }
|
||||
|
||||
bool operator() (const Int64 & l, const Null & r) const { return false; }
|
||||
bool operator() (const Int64 & l, const UInt64 & r) const { return l >= 0 && UInt64(l) == r; }
|
||||
bool operator() (const Int64 & l, const UInt64 & r) const { return accurate::equalsOp(l, r); }
|
||||
bool operator() (const Int64 & l, const Int64 & r) const { return l == r; }
|
||||
bool operator() (const Int64 & l, const Float64 & r) const { return Double128(l) == Double128(r); }
|
||||
bool operator() (const Int64 & l, const Float64 & r) const { return accurate::equalsOp(l, r); }
|
||||
bool operator() (const Int64 & l, const String & r) const { return false; }
|
||||
bool operator() (const Int64 & l, const Array & r) const { return false; }
|
||||
bool operator() (const Int64 & l, const Tuple & r) const { return false; }
|
||||
|
||||
bool operator() (const Float64 & l, const Null & r) const { return false; }
|
||||
bool operator() (const Float64 & l, const UInt64 & r) const { return Double128(l) == Double128(r); }
|
||||
bool operator() (const Float64 & l, const Int64 & r) const { return Double128(l) == Double128(r); }
|
||||
bool operator() (const Float64 & l, const UInt64 & r) const { return accurate::equalsOp(l, r); }
|
||||
bool operator() (const Float64 & l, const Int64 & r) const { return accurate::equalsOp(l, r); }
|
||||
bool operator() (const Float64 & l, const Float64 & r) const { return l == r; }
|
||||
bool operator() (const Float64 & l, const String & r) const { return false; }
|
||||
bool operator() (const Float64 & l, const Array & r) const { return false; }
|
||||
bool operator() (const Float64 & l, const Tuple & r) const { return false; }
|
||||
|
||||
bool operator() (const String & l, const Null & r) const { return false; }
|
||||
bool operator() (const String & l, const UInt64 & r) const { return stringToDateOrDateTime(l) == r; }
|
||||
bool operator() (const String & l, const UInt64 & r) const { return false; }
|
||||
bool operator() (const String & l, const Int64 & r) const { return false; }
|
||||
bool operator() (const String & l, const Float64 & r) const { return false; }
|
||||
bool operator() (const String & l, const String & r) const { return l == r; }
|
||||
@ -254,8 +241,6 @@ public:
|
||||
|
||||
class FieldVisitorAccurateLess : public StaticVisitor<bool>
|
||||
{
|
||||
using Double128 = long double; /// Non portable. Must have 64 bit mantissa to provide accurate comparisons.
|
||||
|
||||
public:
|
||||
bool operator() (const Null & l, const Null & r) const { return false; }
|
||||
bool operator() (const Null & l, const UInt64 & r) const { return true; }
|
||||
@ -267,30 +252,30 @@ public:
|
||||
|
||||
bool operator() (const UInt64 & l, const Null & r) const { return false; }
|
||||
bool operator() (const UInt64 & l, const UInt64 & r) const { return l < r; }
|
||||
bool operator() (const UInt64 & l, const Int64 & r) const { return r >= 0 && l < UInt64(r); }
|
||||
bool operator() (const UInt64 & l, const Float64 & r) const { return Double128(l) < Double128(r); }
|
||||
bool operator() (const UInt64 & l, const String & r) const { return l < stringToDateOrDateTime(r); }
|
||||
bool operator() (const UInt64 & l, const Int64 & r) const { return accurate::lessOp(l, r); }
|
||||
bool operator() (const UInt64 & l, const Float64 & r) const { return accurate::lessOp(l, r); }
|
||||
bool operator() (const UInt64 & l, const String & r) const { return true; }
|
||||
bool operator() (const UInt64 & l, const Array & r) const { return true; }
|
||||
bool operator() (const UInt64 & l, const Tuple & r) const { return true; }
|
||||
|
||||
bool operator() (const Int64 & l, const Null & r) const { return false; }
|
||||
bool operator() (const Int64 & l, const UInt64 & r) const { return l < 0 || UInt64(l) < r; }
|
||||
bool operator() (const Int64 & l, const UInt64 & r) const { return accurate::lessOp(l, r); }
|
||||
bool operator() (const Int64 & l, const Int64 & r) const { return l < r; }
|
||||
bool operator() (const Int64 & l, const Float64 & r) const { return Double128(l) < Double128(r); }
|
||||
bool operator() (const Int64 & l, const Float64 & r) const { return accurate::lessOp(l, r); }
|
||||
bool operator() (const Int64 & l, const String & r) const { return true; }
|
||||
bool operator() (const Int64 & l, const Array & r) const { return true; }
|
||||
bool operator() (const Int64 & l, const Tuple & r) const { return true; }
|
||||
|
||||
bool operator() (const Float64 & l, const Null & r) const { return false; }
|
||||
bool operator() (const Float64 & l, const UInt64 & r) const { return Double128(l) < Double128(r); }
|
||||
bool operator() (const Float64 & l, const Int64 & r) const { return Double128(l) < Double128(r); }
|
||||
bool operator() (const Float64 & l, const UInt64 & r) const { return accurate::lessOp(l, r); }
|
||||
bool operator() (const Float64 & l, const Int64 & r) const { return accurate::lessOp(l, r); }
|
||||
bool operator() (const Float64 & l, const Float64 & r) const { return l < r; }
|
||||
bool operator() (const Float64 & l, const String & r) const { return true; }
|
||||
bool operator() (const Float64 & l, const Array & r) const { return true; }
|
||||
bool operator() (const Float64 & l, const Tuple & r) const { return true; }
|
||||
|
||||
bool operator() (const String & l, const Null & r) const { return false; }
|
||||
bool operator() (const String & l, const UInt64 & r) const { return stringToDateOrDateTime(l) < r; }
|
||||
bool operator() (const String & l, const UInt64 & r) const { return false; }
|
||||
bool operator() (const String & l, const Int64 & r) const { return false; }
|
||||
bool operator() (const String & l, const Float64 & r) const { return false; }
|
||||
bool operator() (const String & l, const String & r) const { return l < r; }
|
||||
|
@ -30,12 +30,12 @@ using DB::UInt64;
|
||||
|
||||
// Case 1. Is pair of floats or pair of ints or pair of uints
|
||||
template <typename A, typename B>
|
||||
using is_safe_convervsion = std::integral_constant<bool, (std::is_floating_point<A>::value && std::is_floating_point<B>::value)
|
||||
using is_safe_conversion = std::integral_constant<bool, (std::is_floating_point<A>::value && std::is_floating_point<B>::value)
|
||||
|| (std::is_integral<A>::value && std::is_integral<B>::value && !(std::is_signed<A>::value ^ std::is_signed<B>::value))>;
|
||||
template <typename A, typename B>
|
||||
using bool_if_safe_convervsion = std::enable_if_t<is_safe_convervsion<A, B>::value, bool>;
|
||||
using bool_if_safe_conversion = std::enable_if_t<is_safe_conversion<A, B>::value, bool>;
|
||||
template <typename A, typename B>
|
||||
using bool_if_not_safe_convervsion = std::enable_if_t<!is_safe_convervsion<A, B>::value, bool>;
|
||||
using bool_if_not_safe_conversion = std::enable_if_t<!is_safe_conversion<A, B>::value, bool>;
|
||||
|
||||
|
||||
/// Case 2. Are params IntXX and UIntYY ?
|
||||
@ -144,13 +144,13 @@ inline bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAFloat a, TAInt
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_convervsion<A, B> greaterOp(A a, B b)
|
||||
inline bool_if_not_safe_conversion<A, B> greaterOp(A a, B b)
|
||||
{
|
||||
return greaterOpTmpl(a, b);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_convervsion<A, B> greaterOp(A a, B b)
|
||||
inline bool_if_safe_conversion<A, B> greaterOp(A a, B b)
|
||||
{
|
||||
return a > b;
|
||||
}
|
||||
@ -227,13 +227,13 @@ inline bool greaterOp<DB::UInt64, DB::Float32>(DB::UInt64 u, DB::Float32 f)
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_convervsion<A, B> equalsOp(A a, B b)
|
||||
inline bool_if_not_safe_conversion<A, B> equalsOp(A a, B b)
|
||||
{
|
||||
return equalsOpTmpl(a, b);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_convervsion<A, B> equalsOp(A a, B b)
|
||||
inline bool_if_safe_conversion<A, B> equalsOp(A a, B b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
@ -288,52 +288,52 @@ inline bool equalsOp<DB::Int64, DB::Float32>(DB::Int64 u, DB::Float32 f)
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_convervsion<A, B> notEqualsOp(A a, B b)
|
||||
inline bool_if_not_safe_conversion<A, B> notEqualsOp(A a, B b)
|
||||
{
|
||||
return !equalsOp(a, b);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_convervsion<A, B> notEqualsOp(A a, B b)
|
||||
inline bool_if_safe_conversion<A, B> notEqualsOp(A a, B b)
|
||||
{
|
||||
return a != b;
|
||||
}
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_convervsion<A, B> lessOp(A a, B b)
|
||||
inline bool_if_not_safe_conversion<A, B> lessOp(A a, B b)
|
||||
{
|
||||
return greaterOp(b, a);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_convervsion<A, B> lessOp(A a, B b)
|
||||
inline bool_if_safe_conversion<A, B> lessOp(A a, B b)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_convervsion<A, B> lessOrEqualsOp(A a, B b)
|
||||
inline bool_if_not_safe_conversion<A, B> lessOrEqualsOp(A a, B b)
|
||||
{
|
||||
return !greaterOp(a, b);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_convervsion<A, B> lessOrEqualsOp(A a, B b)
|
||||
inline bool_if_safe_conversion<A, B> lessOrEqualsOp(A a, B b)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_convervsion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
inline bool_if_not_safe_conversion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
{
|
||||
return !greaterOp(b, a);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_convervsion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
inline bool_if_safe_conversion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
{
|
||||
return a >= b;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <Interpreters/convertFieldToType.h>
|
||||
|
||||
#include <IO/ReadBufferFromString.h>
|
||||
#include <IO/ReadHelpers.h>
|
||||
|
||||
@ -12,9 +14,7 @@
|
||||
#include <Functions/DataTypeTraits.h>
|
||||
|
||||
#include <Core/FieldVisitors.h>
|
||||
|
||||
#include <Interpreters/convertFieldToType.h>
|
||||
|
||||
#include <Functions/AccurateComparison.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -43,7 +43,7 @@ static Field convertNumericTypeImpl(const Field & from)
|
||||
{
|
||||
From value = from.get<From>();
|
||||
|
||||
if (static_cast<long double>(value) != static_cast<long double>(To(value)))
|
||||
if (!accurate::equalsOp(value, To(value)))
|
||||
return {};
|
||||
|
||||
return Field(typename NearestFieldType<To>::Type(value));
|
||||
@ -64,6 +64,31 @@ static Field convertNumericType(const Field & from, const IDataType & type)
|
||||
}
|
||||
|
||||
|
||||
DayNum_t stringToDate(const String & s)
|
||||
{
|
||||
ReadBufferFromString in(s);
|
||||
DayNum_t date{};
|
||||
|
||||
readDateText(date, in);
|
||||
if (!in.eof())
|
||||
throw Exception("String is too long for Date: " + s);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
UInt64 stringToDateTime(const String & s)
|
||||
{
|
||||
ReadBufferFromString in(s);
|
||||
time_t date_time{};
|
||||
|
||||
readDateTimeText(date_time, in);
|
||||
if (!in.eof())
|
||||
throw Exception("String is too long for DateTime: " + s);
|
||||
|
||||
return UInt64(date_time);
|
||||
}
|
||||
|
||||
|
||||
Field convertFieldToTypeImpl(const Field & src, const IDataType & type)
|
||||
{
|
||||
if (type.isNumeric())
|
||||
|
@ -484,7 +484,11 @@ bool PKCondition::atomFromAST(const ASTPtr & node, const Context & context, Bloc
|
||||
if (atom_it == std::end(atom_map))
|
||||
return false;
|
||||
|
||||
if (!is_set_const) /// Set args are already casted inside Set::createFromAST
|
||||
bool cast_not_needed =
|
||||
is_set_const /// Set args are already casted inside Set::createFromAST
|
||||
|| (key_expr_type->behavesAsNumber() && const_type->behavesAsNumber()); /// Numbers are accurately compared without cast.
|
||||
|
||||
if (!cast_not_needed)
|
||||
castValueToType(key_expr_type, const_value, const_type, node);
|
||||
|
||||
return atom_it->second(out, const_value, node);
|
||||
|
Loading…
Reference in New Issue
Block a user