Merge pull request #335 from ludv1x/CLICKHOUSE-29

Add support of (Int64, UInt64) arguments for least() and greatest() functions .
This commit is contained in:
alexey-milovidov 2017-01-14 01:35:18 +04:00 committed by GitHub
commit f7402a524e
6 changed files with 95 additions and 26 deletions

View File

@ -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);
}

View File

@ -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
{

View File

@ -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.

View File

@ -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"

View File

@ -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

View File

@ -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);