#include #include #include "divide/divide.h" namespace DB { namespace ErrorCodes { extern const int ILLEGAL_DIVISION; } namespace { /// Optimizations for integer division by a constant. template struct DivideIntegralByConstantImpl : BinaryOperation> { using Op = DivideIntegralImpl; using ResultType = typename Op::ResultType; static const constexpr bool allow_fixed_string = false; static const constexpr bool allow_string_integer = false; template static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap) { if constexpr (op_case == OpCase::RightConstant) { if (right_nullmap && (*right_nullmap)[0]) return; vectorConstant(a, *b, c, size); } else { if (right_nullmap) { for (size_t i = 0; i < size; ++i) if ((*right_nullmap)[i]) c[i] = ResultType(); else apply(a, b, c, i); } else for (size_t i = 0; i < size; ++i) apply(a, b, c, i); } } static ResultType process(A a, B b) { return Op::template apply(a, b); } static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict a_pos, B b, ResultType * __restrict c_pos, size_t size) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" /// Division by -1. By the way, we avoid FPE by division of the largest negative number by -1. if (unlikely(is_signed_v && b == -1)) { for (size_t i = 0; i < size; ++i) c_pos[i] = -make_unsigned_t(a_pos[i]); /// Avoid UBSan report in signed integer overflow. return; } /// Division with too large divisor. if (unlikely(b > std::numeric_limits::max() || (std::is_signed_v && std::is_signed_v && b < std::numeric_limits::lowest()))) { for (size_t i = 0; i < size; ++i) c_pos[i] = 0; return; } #pragma GCC diagnostic pop if (unlikely(static_cast(b) == 0)) throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION); divideImpl(a_pos, b, c_pos, size); } private: template static inline void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i) { if constexpr (op_case == OpCase::Vector) c[i] = Op::template apply(a[i], b[i]); else c[i] = Op::template apply(*a, b[i]); } }; /** Specializations are specified for dividing numbers of the type UInt64, UInt32, Int64, Int32 by the numbers of the same sign. * Can be expanded to all possible combinations, but more code is needed. */ } namespace impl_ { template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; template <> struct BinaryOperationImpl> : DivideIntegralByConstantImpl {}; } struct NameIntDiv { static constexpr auto name = "intDiv"; }; using FunctionIntDiv = BinaryArithmeticOverloadResolver; void registerFunctionIntDiv(FunctionFactory & factory) { factory.registerFunction(); } }