mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-30 05:30:51 +00:00
Merge pull request #335 from ludv1x/CLICKHOUSE-29
Add support of (Int64, UInt64) arguments for least() and greatest() functions .
This commit is contained in:
commit
f7402a524e
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#include <DB/Core/Types.h>
|
||||
|
||||
/** Preceptually-correct number comparisons.
|
||||
@ -48,27 +49,27 @@ template <typename TInt, typename TUInt>
|
||||
using bool_if_le_int_vs_uint_t = std::enable_if_t<is_le_int_vs_uint_t<TInt, TUInt>::value, bool>;
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
bool_if_le_int_vs_uint_t<TInt, TUInt> greaterOpTmpl(TInt a, TUInt b)
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> greaterOpTmpl(TInt a, TUInt b)
|
||||
{
|
||||
return (b > static_cast<TUInt>(std::numeric_limits<TInt>::max()) || a < 0) ? false : static_cast<TUInt>(a) > b;
|
||||
return static_cast<TUInt>(a) > b && a >= 0 && b <= static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
}
|
||||
|
||||
template <typename TUInt, typename TInt>
|
||||
bool_if_le_int_vs_uint_t<TInt, TUInt> greaterOpTmpl(TUInt a, TInt b)
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> greaterOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return (a > static_cast<TUInt>(std::numeric_limits<TInt>::max()) || b < 0) ? true : a > static_cast<TUInt>(b);
|
||||
return a > static_cast<TUInt>(b) || b < 0 || a > static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
bool_if_le_int_vs_uint_t<TInt, TUInt> equalsOpTmpl(TInt a, TUInt b)
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> equalsOpTmpl(TInt a, TUInt b)
|
||||
{
|
||||
return (a < 0 || b > static_cast<TUInt>(std::numeric_limits<TInt>::max())) ? false : static_cast<TUInt>(a) == b;
|
||||
return static_cast<TUInt>(a) == b && a >= 0 && b <= static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
}
|
||||
|
||||
template <typename TUInt, typename TInt>
|
||||
bool_if_le_int_vs_uint_t<TInt, TUInt> equalsOpTmpl(TUInt a, TInt b)
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> equalsOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return (b < 0 || a > static_cast<TUInt>(std::numeric_limits<TInt>::max())) ? false : a == static_cast<TUInt>(b);
|
||||
return a == static_cast<TUInt>(b) && b >= 0 && a <= static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
}
|
||||
|
||||
|
||||
@ -80,25 +81,25 @@ template <typename TInt, typename TUInt>
|
||||
using bool_if_gt_int_vs_uint = std::enable_if_t<is_gt_int_vs_uint<TInt, TUInt>::value, bool>;
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
bool_if_gt_int_vs_uint<TInt, TUInt> greaterOpTmpl(TInt a, TUInt b)
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> greaterOpTmpl(TInt a, TUInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) > static_cast<TInt>(b);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
bool_if_gt_int_vs_uint<TInt, TUInt> greaterOpTmpl(TUInt a, TInt b)
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> greaterOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) > static_cast<TInt>(b);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
bool_if_gt_int_vs_uint<TInt, TUInt> equalsOpTmpl(TInt a, TUInt b)
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> equalsOpTmpl(TInt a, TUInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) == static_cast<TInt>(b);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
bool_if_gt_int_vs_uint<TInt, TUInt> equalsOpTmpl(TUInt a, TInt b)
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> equalsOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) == static_cast<TInt>(b);
|
||||
}
|
||||
@ -111,25 +112,25 @@ using bool_if_double_can_be_used = std::enable_if_t<
|
||||
bool>;
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
bool_if_double_can_be_used<TAInt, TAFloat> greaterOpTmpl(TAInt a, TAFloat b)
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> greaterOpTmpl(TAInt a, TAFloat b)
|
||||
{
|
||||
return static_cast<double>(a) > static_cast<double>(b);
|
||||
}
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
bool_if_double_can_be_used<TAInt, TAFloat> greaterOpTmpl(TAFloat a, TAInt b)
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> greaterOpTmpl(TAFloat a, TAInt b)
|
||||
{
|
||||
return static_cast<double>(a) > static_cast<double>(b);
|
||||
}
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAInt a, TAFloat b)
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAInt a, TAFloat b)
|
||||
{
|
||||
return static_cast<double>(a) == static_cast<double>(b);
|
||||
}
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAFloat a, TAInt b)
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAFloat a, TAInt b)
|
||||
{
|
||||
return static_cast<double>(a) == static_cast<double>(b);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <DB/DataTypes/DataTypeDateTime.h>
|
||||
#include <DB/Functions/IFunction.h>
|
||||
#include <DB/Functions/NumberTraits.h>
|
||||
#include <DB/Functions/AccurateComparison.h>
|
||||
#include <DB/Core/FieldVisitors.h>
|
||||
|
||||
|
||||
@ -271,9 +272,9 @@ struct BitShiftRightImpl
|
||||
|
||||
|
||||
template<typename A, typename B>
|
||||
struct LeastImpl
|
||||
struct LeastBaseImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfIf<A, B>::Type;
|
||||
using ResultType = NumberTraits::ResultOfLeast<A, B>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
@ -284,9 +285,26 @@ struct LeastImpl
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct GreatestImpl
|
||||
struct LeastSpecialImpl
|
||||
{
|
||||
using ResultType = typename NumberTraits::ResultOfIf<A, B>::Type;
|
||||
using ResultType = std::make_signed_t<A>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
static_assert(std::is_same<Result, ResultType>::value, "ResultType != Result");
|
||||
return accurate::lessOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
using LeastImpl = std::conditional_t<!NumberTraits::LeastGreatestSpecialCase<A, B>::value, LeastBaseImpl<A, B>, LeastSpecialImpl<A, B>>;
|
||||
|
||||
|
||||
template<typename A, typename B>
|
||||
struct GreatestBaseImpl
|
||||
{
|
||||
using ResultType = NumberTraits::ResultOfGreatest<A, B>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
@ -295,6 +313,23 @@ struct GreatestImpl
|
||||
}
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct GreatestSpecialImpl
|
||||
{
|
||||
using ResultType = std::make_unsigned_t<A>;
|
||||
|
||||
template <typename Result = ResultType>
|
||||
static inline Result apply(A a, B b)
|
||||
{
|
||||
static_assert(std::is_same<Result, ResultType>::value, "ResultType != Result");
|
||||
return accurate::greaterOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
using GreatestImpl = std::conditional_t<!NumberTraits::LeastGreatestSpecialCase<A, B>::value, GreatestBaseImpl<A, B>, GreatestSpecialImpl<A, B>>;
|
||||
|
||||
|
||||
template<typename A>
|
||||
struct NegateImpl
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <DB/Core/Types.h>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -263,6 +264,7 @@ template <typename A> struct ResultOfBitNot
|
||||
typename Traits<A>::Nullity>::Type Type;
|
||||
};
|
||||
|
||||
|
||||
/** Приведение типов для функции if:
|
||||
* 1) void, Type -> Type
|
||||
* 2) UInt<x>, UInt<y> -> UInt<max(x,y)>
|
||||
@ -302,7 +304,7 @@ struct ResultOfIf
|
||||
typename Traits<B>::Floatness,
|
||||
typename Traits<B>::Bits,
|
||||
typename ExactNext<typename Traits<B>::Bits>::Type>::type>::type,
|
||||
Bits32>::type,
|
||||
Bits32>::type,
|
||||
typename boost::mpl::or_<typename Traits<A>::Nullity, typename Traits<B>::Nullity>::type>::Type,
|
||||
/// 2) and 3)
|
||||
typename boost::mpl::if_<
|
||||
@ -342,10 +344,28 @@ template <typename A> struct ToInteger
|
||||
typename Traits<A>::Floatness,
|
||||
Bits64,
|
||||
typename Traits<A>::Bits>::type,
|
||||
typename Traits<A>::Nullity
|
||||
typename Traits<A>::Nullity
|
||||
>::Type Type;
|
||||
};
|
||||
|
||||
|
||||
// CLICKHOUSE-29. The same depth, different signs
|
||||
// NOTE: This case is applied for 64-bit integers only (for backward compability), but colud be used for any-bit integers
|
||||
template <typename A, typename B>
|
||||
using LeastGreatestSpecialCase = std::integral_constant<bool, std::is_integral<A>::value && std::is_integral<B>::value
|
||||
&& (8 == sizeof(A) && sizeof(A) == sizeof(B))
|
||||
&& (std::is_signed<A>::value ^ std::is_signed<B>::value)>;
|
||||
|
||||
template <typename A, typename B>
|
||||
using ResultOfLeast = std::conditional_t<LeastGreatestSpecialCase<A, B>::value,
|
||||
typename Construct<Signed, Integer, typename Traits<A>::Bits, HasNoNull>::Type,
|
||||
typename ResultOfIf<A, B>::Type>;
|
||||
|
||||
template <typename A, typename B>
|
||||
using ResultOfGreatest = std::conditional_t<LeastGreatestSpecialCase<A, B>::value,
|
||||
typename Construct<Unsigned, Integer, typename Traits<A>::Bits, HasNoNull>::Type,
|
||||
typename ResultOfIf<A, B>::Type>;
|
||||
|
||||
/// Notes on type composition.
|
||||
///
|
||||
/// I. Problem statement.
|
||||
|
@ -8,20 +8,27 @@ clickhouse-client -q "INSERT INTO test.comparisons SELECT toInt64(rand64()) + nu
|
||||
function test_cmp {
|
||||
echo -n "$1 : "
|
||||
echo "SELECT count() FROM test.comparisons WHERE ($1)" | clickhouse-benchmark --max_threads=1 -i 20 -d 0 --json test.json 1>&2 2>/dev/null
|
||||
python2 -c "import json; print json.load(open('test.json'))['query_time_percentiles']['0']"
|
||||
python2 -c "import json; print '%.3f' % float(json.load(open('test.json'))['query_time_percentiles']['0'])"
|
||||
rm test.json
|
||||
}
|
||||
|
||||
test_cmp "u64 = i64"
|
||||
test_cmp "u64 >= i64"
|
||||
test_cmp "u64 > i64 "
|
||||
test_cmp "u64 > toInt64(1) "
|
||||
test_cmp "i64 > u64 "
|
||||
test_cmp "i64 > toUInt64(1) "
|
||||
|
||||
test_cmp "u64 = i64 "
|
||||
test_cmp "u64 = toInt64(1) "
|
||||
test_cmp "i64 = u64 "
|
||||
test_cmp "i64 = toUInt64(1) "
|
||||
|
||||
test_cmp "u64 >= i64"
|
||||
test_cmp "i64 > -1 "
|
||||
test_cmp "i64 = 0 "
|
||||
test_cmp "u64 != 0 "
|
||||
|
||||
test_cmp "i64 = f64"
|
||||
test_cmp "i64 < f64"
|
||||
|
||||
test_cmp "f64 >= 0 "
|
||||
|
||||
clickhouse-client -q "DROP TABLE IF EXISTS test.comparisons"
|
||||
|
@ -0,0 +1,3 @@
|
||||
Int64 UInt64
|
||||
0 -400 127 -1 -1 -128 -128 -9223372036854775808 -9223372036854775807 9223372036854775807
|
||||
1 -200 255 1 1 254 255 18446744073709551615 18446744073709551615 9223372036854775808
|
@ -0,0 +1,3 @@
|
||||
SELECT toTypeName(least(-9223372036854775808, 18446744073709551615)), toTypeName(greatest(-9223372036854775808, 18446744073709551615));
|
||||
SELECT least(0, 1), least(-400, -200), least(toInt8(127), 255), least(-1, 1), least(toUInt64(1), toInt64(-1)), least(-128, 254), least(-128, 255), least(-9223372036854775808, 18446744073709551615), least(-9223372036854775807, 18446744073709551615), least(toInt64(9223372036854775807), 9223372036854775808);
|
||||
SELECT greatest(0, 1), greatest(-400, -200), greatest(toInt8(127), 255), greatest(-1, 1), greatest(toUInt64(1), toInt64(-1)), greatest(-128, 254), greatest(-128, 255), greatest(-9223372036854775808, 18446744073709551615), greatest(-9223372036854775807, 18446744073709551615), greatest(toInt64(9223372036854775807), 9223372036854775808);
|
Loading…
Reference in New Issue
Block a user