New behavior for least() and greatest() function with (Int64, UInt64) arguments. [#CLICKHOUSE-29]

This commit is contained in:
Vitaliy Lyudvichenko 2017-01-13 21:15:12 +03:00
parent 56743008dd
commit a1dcd24a76
4 changed files with 85 additions and 7 deletions

View File

@ -271,9 +271,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)
@ -283,10 +283,37 @@ struct LeastImpl
}
};
template<typename A, typename B>
struct GreatestImpl
template<typename A>
struct LeastSpecialImpl
{
using ResultType = typename NumberTraits::ResultOfIf<A, B>::Type;
using ResultType = std::make_signed_t<A>;
using SecondType = std::make_unsigned_t<A>;
template <typename Result = ResultType>
static inline Result apply(ResultType a, SecondType b)
{
static_assert(std::is_same<Result, ResultType>::value, "typeof(a) != Result");
return (a < static_cast<Result>(b) || a < 0 || b > static_cast<SecondType>(std::numeric_limits<ResultType>::max()))
? a : static_cast<Result>(b);
}
template <typename Result = ResultType>
static inline Result apply(SecondType a, ResultType b)
{
static_assert(std::is_same<Result, ResultType>::value, "typeof(b) != Result");
return (b < static_cast<Result>(a) || b < 0 || a > static_cast<SecondType>(std::numeric_limits<ResultType>::max()))
? b : static_cast<Result>(a);
}
};
template<typename A, typename B>
using LeastImpl = std::conditional_t<!NumberTraits::GreatestAndLeastSpecialCase<A, B>::value, LeastBaseImpl<A, B>, LeastSpecialImpl<A>>;
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 +322,33 @@ struct GreatestImpl
}
};
template<typename A>
struct GreatestSpecialImpl
{
using ResultType = std::make_unsigned_t<A>;
using SecondType = std::make_signed_t<A>;
template <typename Result = ResultType>
static inline Result apply(ResultType a, SecondType b)
{
static_assert(std::is_same<Result, ResultType>::value, "typeof(a) != Result");
return (a > static_cast<Result>(b) || b < 0 || a > static_cast<Result>((std::numeric_limits<SecondType>::max())))
? a : static_cast<Result>(b);
}
template <typename Result = ResultType>
static inline Result apply(SecondType a, ResultType b)
{
static_assert(std::is_same<Result, ResultType>::value, "typeof(b) != Result");
return (b > static_cast<Result>(a) || a < 0 || b > static_cast<Result>((std::numeric_limits<SecondType>::max())))
? b : static_cast<Result>(a);
}
};
template<typename A, typename B>
using GreatestImpl = std::conditional_t<!NumberTraits::GreatestAndLeastSpecialCase<A, B>::value, GreatestBaseImpl<A, B>, GreatestSpecialImpl<A>>;
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,26 @@ 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
template <typename A, typename B>
using GreatestAndLeastSpecialCase = std::integral_constant<bool, std::is_integral<A>::value && std::is_integral<B>::value
&& (sizeof(A) == sizeof(B)) && (std::is_signed<A>::value ^ std::is_signed<B>::value)>;
template <typename A, typename B>
using ResultOfLeast = std::conditional_t<GreatestAndLeastSpecialCase<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<GreatestAndLeastSpecialCase<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

@ -0,0 +1,3 @@
Int8 UInt8 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(-1, 1)), toTypeName(greatest(-1, 1)), 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);