From 813742e5d736f1bdc04586524451b0c5660a244e Mon Sep 17 00:00:00 2001 From: Andrey Mironov Date: Fri, 21 Nov 2014 17:28:39 +0300 Subject: [PATCH] dbms: add intDivOrZero function. [#METR-13159] --- .../DB/Functions/FunctionsArithmetic.h | 30 +++++++++++++++++++ dbms/src/Functions/FunctionsArithmetic.cpp | 1 + .../00081_int_div_or_zero.reference | 5 ++++ .../0_stateless/00081_int_div_or_zero.sql | 5 ++++ 4 files changed, 41 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00081_int_div_or_zero.reference create mode 100644 dbms/tests/queries/0_stateless/00081_int_div_or_zero.sql diff --git a/dbms/include/DB/Functions/FunctionsArithmetic.h b/dbms/include/DB/Functions/FunctionsArithmetic.h index 72dcf215602..9fd2d7856dc 100644 --- a/dbms/include/DB/Functions/FunctionsArithmetic.h +++ b/dbms/include/DB/Functions/FunctionsArithmetic.h @@ -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 +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::value && std::is_signed::value && a == std::numeric_limits::min() && b == -1)) + return true; + + return false; +} + + #pragma GCC diagnostic pop @@ -155,6 +171,18 @@ struct DivideIntegralImpl } }; +template +struct DivideIntegralOrZeroImpl +{ + typedef typename NumberTraits::ResultOfIntegerDivision::Type ResultType; + + template + static inline Result apply(A a, B b) + { + return unlikely(divisionLeadsToFPE(a, b)) ? 0 : static_cast(a) / b; + } +}; + template 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 FunctionMinus; typedef FunctionBinaryArithmetic FunctionMultiply; typedef FunctionBinaryArithmetic FunctionDivideFloating; typedef FunctionBinaryArithmetic FunctionDivideIntegral; +typedef FunctionBinaryArithmetic FunctionDivideIntegralOrZero; typedef FunctionBinaryArithmetic FunctionModulo; typedef FunctionUnaryArithmetic FunctionNegate; typedef FunctionBinaryArithmetic FunctionBitAnd; diff --git a/dbms/src/Functions/FunctionsArithmetic.cpp b/dbms/src/Functions/FunctionsArithmetic.cpp index b515273a197..dab8dc242eb 100644 --- a/dbms/src/Functions/FunctionsArithmetic.cpp +++ b/dbms/src/Functions/FunctionsArithmetic.cpp @@ -11,6 +11,7 @@ void registerFunctionsArithmetic(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); diff --git a/dbms/tests/queries/0_stateless/00081_int_div_or_zero.reference b/dbms/tests/queries/0_stateless/00081_int_div_or_zero.reference new file mode 100644 index 00000000000..627e1097cda --- /dev/null +++ b/dbms/tests/queries/0_stateless/00081_int_div_or_zero.reference @@ -0,0 +1,5 @@ +1 +1 +1 +1 +1 diff --git a/dbms/tests/queries/0_stateless/00081_int_div_or_zero.sql b/dbms/tests/queries/0_stateless/00081_int_div_or_zero.sql new file mode 100644 index 00000000000..204cac83ba4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00081_int_div_or_zero.sql @@ -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;