dbms: add intDivOrZero function. [#METR-13159]

This commit is contained in:
Andrey Mironov 2014-11-21 17:28:39 +03:00
parent eaa8a75a63
commit 813742e5d7
4 changed files with 41 additions and 0 deletions

View File

@ -139,6 +139,22 @@ inline void throwIfDivisionLeadsToFPE(A a, B b)
throw Exception("Division of minimal signed number by minus one", ErrorCodes::ILLEGAL_DIVISION);
}
template <typename A, typename B>
inline bool divisionLeadsToFPE(A a, B b)
{
/// Возможно, лучше вместо проверок использовать siglongjmp?
if (unlikely(b == 0))
return true;
/// http://avva.livejournal.com/2548306.html
if (unlikely(std::is_signed<A>::value && std::is_signed<B>::value && a == std::numeric_limits<A>::min() && b == -1))
return true;
return false;
}
#pragma GCC diagnostic pop
@ -155,6 +171,18 @@ struct DivideIntegralImpl
}
};
template<typename A, typename B>
struct DivideIntegralOrZeroImpl
{
typedef typename NumberTraits::ResultOfIntegerDivision<A, B>::Type ResultType;
template <typename Result = ResultType>
static inline Result apply(A a, B b)
{
return unlikely(divisionLeadsToFPE(a, b)) ? 0 : static_cast<Result>(a) / b;
}
};
template<typename A, typename B>
struct ModuloImpl
{
@ -752,6 +780,7 @@ struct NameMinus { static constexpr auto name = "minus"; };
struct NameMultiply { static constexpr auto name = "multiply"; };
struct NameDivideFloating { static constexpr auto name = "divide"; };
struct NameDivideIntegral { static constexpr auto name = "intDiv"; };
struct NameDivideIntegralOrZero { static constexpr auto name = "intDivOrZero"; };
struct NameModulo { static constexpr auto name = "modulo"; };
struct NameNegate { static constexpr auto name = "negate"; };
struct NameBitAnd { static constexpr auto name = "bitAnd"; };
@ -766,6 +795,7 @@ typedef FunctionBinaryArithmetic<MinusImpl, NameMinus> FunctionMinus;
typedef FunctionBinaryArithmetic<MultiplyImpl, NameMultiply> FunctionMultiply;
typedef FunctionBinaryArithmetic<DivideFloatingImpl, NameDivideFloating> FunctionDivideFloating;
typedef FunctionBinaryArithmetic<DivideIntegralImpl, NameDivideIntegral> FunctionDivideIntegral;
typedef FunctionBinaryArithmetic<DivideIntegralOrZeroImpl, NameDivideIntegralOrZero> FunctionDivideIntegralOrZero;
typedef FunctionBinaryArithmetic<ModuloImpl, NameModulo> FunctionModulo;
typedef FunctionUnaryArithmetic<NegateImpl, NameNegate> FunctionNegate;
typedef FunctionBinaryArithmetic<BitAndImpl, NameBitAnd> FunctionBitAnd;

View File

@ -11,6 +11,7 @@ void registerFunctionsArithmetic(FunctionFactory & factory)
factory.registerFunction<FunctionMultiply>();
factory.registerFunction<FunctionDivideFloating>();
factory.registerFunction<FunctionDivideIntegral>();
factory.registerFunction<FunctionDivideIntegralOrZero>();
factory.registerFunction<FunctionModulo>();
factory.registerFunction<FunctionNegate>();
factory.registerFunction<FunctionBitAnd>();

View File

@ -0,0 +1,5 @@
1
1
1
1
1

View File

@ -0,0 +1,5 @@
select intDivOrZero(0, 0) = 0;
select intDivOrZero(-128, -1) = 0;
select intDivOrZero(-127, -1) = 127;
select intDivOrZero(1, 1) = 1;
select intDivOrZero(4, 2) = 2;