refactor code2

This commit is contained in:
zhanglistar 2024-10-10 16:10:14 +08:00
parent 4a1535cc37
commit 2cf83d2cee
32 changed files with 260 additions and 195 deletions

View File

@ -27,8 +27,11 @@ inline void throwIfDivisionLeadsToFPE(A a, B b)
throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Division by zero");
/// http://avva.livejournal.com/2548306.html
if (unlikely(is_signed_v<A> && is_signed_v<B> && a == std::numeric_limits<A>::min() && b == -1))
throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Division of minimal signed number by minus one");
if constexpr (is_signed_v<A> && is_signed_v<B>)
{
if (unlikely(a == std::numeric_limits<A>::min() && b == -1))
throw Exception(ErrorCodes::ILLEGAL_DIVISION, "Division of minimal signed number by minus one");
}
}
template <typename A, typename B>
@ -37,8 +40,11 @@ inline bool divisionLeadsToFPE(A a, B b)
if (unlikely(b == 0))
return true;
if (unlikely(is_signed_v<A> && is_signed_v<B> && a == std::numeric_limits<A>::min() && b == -1))
return true;
if constexpr (is_signed_v<A> && is_signed_v<B>)
{
if (unlikely(a == std::numeric_limits<A>::min() && b == -1))
return true;
}
return false;
}

View File

@ -284,7 +284,7 @@ struct BinaryOperation
static ResultType process(A a, B b) { return Op::template apply<ResultType>(a, b); }
static ResultType process(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr) { return Op::template apply<ResultType>(a, b, m); }
static ResultType process(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr) { return Op::template apply<ResultType>(a, b); }
private:
template <OpCase op_case>
@ -553,7 +553,7 @@ private:
public:
template <OpCase op_case, bool is_decimal_a, bool is_decimal_b>
static void NO_INLINE process(const auto & a, const auto & b, ResultContainerType & c,
NativeResultType scale_a, NativeResultType scale_b, const NullMap * right_nullmap = nullptr)
NativeResultType scale_a, NativeResultType scale_b, const NullMap * right_nullmap = nullptr, NullMap * res_nullmap = nullptr)
{
if constexpr (op_case == OpCase::LeftConstant) static_assert(!is_decimal<decltype(a)>);
if constexpr (op_case == OpCase::RightConstant) static_assert(!is_decimal<decltype(b)>);
@ -609,7 +609,7 @@ public:
}
else if constexpr (is_division && is_decimal_b)
{
processWithRightNullmapImpl<op_case>(a, b, c, size, right_nullmap, [&scale_a](const auto & left, const auto & right)
processWithRightNullmapImpl<op_case>(a, b, c, size, right_nullmap, res_nullmap, [&scale_a](const auto & left, const auto & right)
{
return applyScaledDiv<is_decimal_a>(
static_cast<NativeResultType>(left), right, scale_a);
@ -618,7 +618,7 @@ public:
}
processWithRightNullmapImpl<op_case>(
a, b, c, size, right_nullmap,
a, b, c, size, right_nullmap, res_nullmap,
[](const auto & left, const auto & right)
{
return apply(
@ -628,25 +628,42 @@ public:
}
template <bool is_decimal_a, bool is_decimal_b, class A, class B>
static ResultType process(A a, B b, NativeResultType scale_a, NativeResultType scale_b)
static ResultType process(A a, B b, NativeResultType scale_a, NativeResultType scale_b, NullMap * res_nullmap)
requires(!is_decimal<A> && !is_decimal<B>)
{
if constexpr (is_division && is_decimal_b)
return applyScaledDiv<is_decimal_a>(a, b, scale_a);
else if constexpr (is_plus_minus_compare)
try
{
if (scale_a != 1)
return applyScaled<true>(a, b, scale_a);
if (scale_b != 1)
return applyScaled<false>(a, b, scale_b);
}
if constexpr (is_division && is_decimal_b)
return applyScaledDiv<is_decimal_a>(a, b, scale_a);
else if constexpr (is_plus_minus_compare)
{
if (scale_a != 1)
return applyScaled<true>(a, b, scale_a);
if (scale_b != 1)
return applyScaled<false>(a, b, scale_b);
}
return apply(a, b);
ResultType res = apply(a, b);
if constexpr (std::is_floating_point_v<ResultType>)
{
if (!std::isfinite(res) && res_nullmap)
(*res_nullmap)[0] = 1;
}
return res;
}
catch (const std::exception&)
{
if (res_nullmap)
(*res_nullmap)[0] = 1;
else
throw;
return ResultType();
}
}
private:
template <OpCase op_case, typename ApplyFunc>
static void processWithRightNullmapImpl(const auto & a, const auto & b, ResultContainerType & c, size_t size, const NullMap * right_nullmap, ApplyFunc apply_func)
static void processWithRightNullmapImpl(const auto & a, const auto & b, ResultContainerType & c, size_t size, const NullMap * right_nullmap, NullMap * res_nullmap, ApplyFunc apply_func)
{
if (right_nullmap)
{
@ -660,7 +677,24 @@ private:
}
for (size_t i = 0; i < size; ++i)
c[i] = apply_func(undec(a[i]), undec(b));
{
try
{
c[i] = apply_func(undec(a[i]), undec(b));
if constexpr (std::is_floating_point_v<ResultContainerType>)
{
if (!std::isfinite(c[i]) && res_nullmap)
(*res_nullmap)[i] = 1;
}
}
catch (const std::exception&)
{
if (res_nullmap)
(*res_nullmap)[i] = 1;
else
throw;
}
}
}
else
{
@ -669,19 +703,55 @@ private:
if ((*right_nullmap)[i])
c[i] = ResultType();
else
c[i] = apply_func(unwrap<op_case, OpCase::LeftConstant>(a, i), undec(b[i]));
{
try
{
c[i] = apply_func(unwrap<op_case, OpCase::LeftConstant>(a, i), undec(b[i]));
if constexpr (std::is_floating_point_v<ResultContainerType>)
{
if (!std::isfinite(c[i]) && res_nullmap)
(*res_nullmap)[i] = 1;
}
}
catch (const std::exception&)
{
if (res_nullmap)
(*res_nullmap)[i] = 1;
else
throw;
}
}
}
}
}
else
{
for (size_t i = 0; i < size; ++i)
c[i] = apply_func(unwrap<op_case, OpCase::LeftConstant>(a, i), unwrap<op_case, OpCase::RightConstant>(b, i));
{
try
{
c[i] = apply_func(unwrap<op_case, OpCase::LeftConstant>(a, i), unwrap<op_case, OpCase::RightConstant>(b, i));
if constexpr (std::is_floating_point_v<ResultContainerType>)
{
if (!std::isfinite(c[i]) && res_nullmap)
(*res_nullmap)[i] = 1;
}
}
catch (const std::exception&)
{
if (res_nullmap)
(*res_nullmap)[i] = 1;
else
throw;
}
}
}
}
static constexpr bool is_plus_minus = IsOperation<Operation>::plus ||
IsOperation<Operation>::minus;
static constexpr bool is_multiply = IsOperation<Operation>::multiply;
static constexpr bool is_float_division = IsOperation<Operation>::div_floating;
static constexpr bool is_float_division = IsOperation<Operation>::div_floating || IsOperation<Operation>::divide_or_null;
static constexpr bool is_int_division = IsOperation<Operation>::int_div ||
IsOperation<Operation>::int_div_or_zero;
static constexpr bool is_division = is_float_division || is_int_division;
@ -1346,12 +1416,12 @@ class FunctionBinaryArithmetic : public IFunction
}
template <OpCase op_case, bool left_decimal, bool right_decimal, typename OpImpl, typename OpImplCheck>
void helperInvokeEither(const auto& left, const auto& right, auto& vec_res, auto scale_a, auto scale_b, const NullMap * right_nullmap) const
void helperInvokeEither(const auto& left, const auto& right, auto& vec_res, auto scale_a, auto scale_b, const NullMap * right_nullmap, NullMap * res_nullmap) const
{
if (check_decimal_overflow)
OpImplCheck::template process<op_case, left_decimal, right_decimal>(left, right, vec_res, scale_a, scale_b, right_nullmap);
OpImplCheck::template process<op_case, left_decimal, right_decimal>(left, right, vec_res, scale_a, scale_b, right_nullmap, res_nullmap);
else
OpImpl::template process<op_case, left_decimal, right_decimal>(left, right, vec_res, scale_a, scale_b, right_nullmap);
OpImpl::template process<op_case, left_decimal, right_decimal>(left, right, vec_res, scale_a, scale_b, right_nullmap, res_nullmap);
}
template <class LeftDataType, class RightDataType, class ResultDataType>
@ -1359,7 +1429,7 @@ class FunctionBinaryArithmetic : public IFunction
const auto & left, const auto & right,
const ColumnConst * const col_left_const, const ColumnConst * const col_right_const,
const auto * const col_left, const auto * const col_right,
size_t col_left_size, const NullMap * right_nullmap) const
size_t col_left_size, const NullMap * right_nullmap, NullMap * res_nullmap) const
{
using T0 = typename LeftDataType::FieldType;
using T1 = typename RightDataType::FieldType;
@ -1414,8 +1484,8 @@ class FunctionBinaryArithmetic : public IFunction
ResultType res = {};
if (!right_nullmap || !(*right_nullmap)[0])
res = check_decimal_overflow
? OpImplCheck::template process<left_is_decimal, right_is_decimal>(const_a, const_b, scale_a, scale_b)
: OpImpl::template process<left_is_decimal, right_is_decimal>(const_a, const_b, scale_a, scale_b);
? OpImplCheck::template process<left_is_decimal, right_is_decimal>(const_a, const_b, scale_a, scale_b, res_nullmap)
: OpImpl::template process<left_is_decimal, right_is_decimal>(const_a, const_b, scale_a, scale_b, res_nullmap);
return ResultDataType(type.getPrecision(), type.getScale())
.createColumnConst(col_left_const->size(), toField(res, type.getScale()));
@ -1429,7 +1499,7 @@ class FunctionBinaryArithmetic : public IFunction
if (col_left && col_right)
{
helperInvokeEither<OpCase::Vector, left_is_decimal, right_is_decimal, OpImpl, OpImplCheck>(
col_left->getData(), col_right->getData(), vec_res, scale_a, scale_b, right_nullmap);
col_left->getData(), col_right->getData(), vec_res, scale_a, scale_b, right_nullmap, res_nullmap);
}
else if (col_left_const && col_right)
{
@ -1437,7 +1507,7 @@ class FunctionBinaryArithmetic : public IFunction
helperGetOrConvert<T0, ResultDataType>(col_left_const, left));
helperInvokeEither<OpCase::LeftConstant, left_is_decimal, right_is_decimal, OpImpl, OpImplCheck>(
const_a, col_right->getData(), vec_res, scale_a, scale_b, right_nullmap);
const_a, col_right->getData(), vec_res, scale_a, scale_b, right_nullmap, res_nullmap);
}
else if (col_left && col_right_const)
{
@ -1445,7 +1515,7 @@ class FunctionBinaryArithmetic : public IFunction
helperGetOrConvert<T1, ResultDataType>(col_right_const, right));
helperInvokeEither<OpCase::RightConstant, left_is_decimal, right_is_decimal, OpImpl, OpImplCheck>(
col_left->getData(), const_b, vec_res, scale_a, scale_b, right_nullmap);
col_left->getData(), const_b, vec_res, scale_a, scale_b, right_nullmap, res_nullmap);
}
else
return nullptr;
@ -2098,7 +2168,8 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
col_left_const, col_right_const,
col_left, col_right,
col_left_size,
right_nullmap);
right_nullmap,
res_nullmap);
}
/// Here we check if we have `intDiv` or `intDivOrZero` and at least one of the arguments is decimal, because in this case originally we had result as decimal, so we need to convert result into integer after calculations
else if constexpr (!decimal_with_float && (is_int_div || is_int_div_or_zero) && (IsDataTypeDecimal<LeftDataType> || IsDataTypeDecimal<RightDataType>))
@ -2122,7 +2193,8 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
col_left_const, col_right_const,
col_left, col_right,
col_left_size,
right_nullmap);
right_nullmap,
res_nullmap);
auto col = ColumnWithTypeAndName(res, type_res, name);
return castColumn(col, std::make_shared<ResultDataType>());
@ -2253,10 +2325,9 @@ ColumnPtr executeStringInteger(const ColumnsWithTypeAndName & arguments, const A
auto res = executeImpl2(createBlockWithNestedColumns(arguments), removeNullable(result_type), input_rows_count, &right_null_map, &res_null_map);
return wrapInNullable(res, arguments, result_type, input_rows_count, &res_null_map);
}
/// Process special case when operation is divideOrNull and moduloOrNull
/// Process special case when operation is divideOrNull and moduloOrNull which will return NULL divided zero.
else if ((is_divide_or_null || is_modulo_or_null) && !res_nullmap)
{
std::cerr << "gethere divornull or modornull and resnull map is null" << std::endl;
NullMap res_null_map(input_rows_count, 0);
auto res = executeImpl2(arguments, result_type, input_rows_count, nullptr, &res_null_map);
return wrapInNullable(res, arguments, result_type, input_rows_count, &res_null_map);

View File

@ -5,7 +5,6 @@
#include <base/extended_types.h>
#include <limits>
#include <type_traits>
#include <Columns/ColumnNullable.h>
#include "config.h"
@ -50,20 +49,6 @@ struct GCDLCMImpl
return Impl::applyImpl(a, b);
}
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type *m)
{
try
{
return apply(a, b);
}
catch (const std::exception&)
{
*m = 1;
return Result();
}
}
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = false; /// exceptions (and a non-trivial algorithm)
#endif

View File

@ -64,7 +64,7 @@ struct IsOperation
static constexpr bool bit_hamming_distance = IsSameOperation<Op, BitHammingDistanceImpl>::value;
static constexpr bool division = div_floating || int_div || int_div_or_zero || modulo || modulo_or_null;
static constexpr bool division = div_floating || int_div || int_div_or_zero || modulo || modulo_or_null || divide_or_null;
// NOTE: allow_decimal should not fully contain `division` because of divInt
static constexpr bool allow_decimal = plus || minus || multiply || division || least || greatest;
};

View File

@ -20,7 +20,7 @@ struct BitAndImpl
static constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
return static_cast<Result>(a) & static_cast<Result>(b);
}

View File

@ -25,20 +25,12 @@ struct BitBoolMaskAndImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply([[maybe_unused]] A left, [[maybe_unused]] B right, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply([[maybe_unused]] A left, [[maybe_unused]] B right)
{
// Should be a logical error, but this function is callable from SQL.
// Need to investigate this.
if constexpr (!std::is_same_v<A, ResultType> || !std::is_same_v<B, ResultType>)
{
if (!m)
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "It's a bug! Only UInt8 type is supported by __bitBoolMaskAnd.");
else
{
*m = 1;
return Result();
}
}
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "It's a bug! Only UInt8 type is supported by __bitBoolMaskAnd.");
auto left_bits = littleBits<A>(left);
auto right_bits = littleBits<B>(right);

View File

@ -25,20 +25,12 @@ struct BitBoolMaskOrImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply([[maybe_unused]] A left, [[maybe_unused]] B right, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply([[maybe_unused]] A left, [[maybe_unused]] B right)
{
if constexpr (!std::is_same_v<A, ResultType> || !std::is_same_v<B, ResultType>)
{
if (!m)
// Should be a logical error, but this function is callable from SQL.
// Need to investigate this.
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "It's a bug! Only UInt8 type is supported by __bitBoolMaskOr.");
else
{
*m = 1;
return Result();
}
}
throw DB::Exception(ErrorCodes::BAD_ARGUMENTS, "It's a bug! Only UInt8 type is supported by __bitBoolMaskOr.");
auto left_bits = littleBits<A>(left);
auto right_bits = littleBits<B>(right);

View File

@ -1,6 +1,5 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include <Functions/FunctionFactory.h>
#include "Columns/ColumnNullable.h"
#include <bit>
@ -20,7 +19,7 @@ struct BitHammingDistanceImpl
static constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a, B b)
{
/// Note: it's unspecified if signed integers should be promoted with sign-extension or with zero-fill.
/// This behavior can change in the future.
@ -40,15 +39,7 @@ struct BitHammingDistanceImpl
return res;
}
else
{
if (!m)
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Unsupported data type combination in function 'bitHammingDistance'");
else
{
*m = 1;
return Result();
}
}
throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Unsupported data type combination in function 'bitHammingDistance'");
}
#if USE_EMBEDDED_COMPILER

View File

@ -19,7 +19,7 @@ struct BitOrImpl
static constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
return static_cast<Result>(a) | static_cast<Result>(b);
}

View File

@ -1,6 +1,5 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include "Columns/ColumnNullable.h"
#include "Core/Types.h"
namespace DB
@ -22,7 +21,7 @@ struct BitRotateLeftImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]], NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]])
{
if constexpr (is_big_int_v<A> || is_big_int_v<B>)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Bit rotate is not implemented for big integers");

View File

@ -1,6 +1,5 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -21,7 +20,7 @@ struct BitRotateRightImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]], NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]])
{
if constexpr (is_big_int_v<A> || is_big_int_v<B>)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Bit rotate is not implemented for big integers");

View File

@ -21,20 +21,12 @@ struct BitShiftLeftImpl
static const constexpr bool allow_string_integer = true;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]], NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]])
{
if constexpr (is_big_int_v<B>)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "BitShiftLeft is not implemented for big integers as second argument");
else if (b < 0 || static_cast<UInt256>(b) > 8 * sizeof(A))
{
if (!m)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "The number of shift positions needs to be a non-negative value and less or equal to the bit width of the value to shift");
else
{
*m = 1;
return Result();
}
}
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "The number of shift positions needs to be a non-negative value and less or equal to the bit width of the value to shift");
else if constexpr (is_big_int_v<A>)
return static_cast<Result>(a) << static_cast<UInt32>(b);
else

View File

@ -1,7 +1,6 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <base/hex.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -23,20 +22,12 @@ struct BitShiftRightImpl
static const constexpr bool allow_string_integer = true;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]], NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a [[maybe_unused]], B b [[maybe_unused]])
{
if constexpr (is_big_int_v<B>)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "BitShiftRight is not implemented for big integers as second argument");
else if (b < 0 || static_cast<UInt256>(b) > 8 * sizeof(A))
{
if (!m)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "The number of shift positions needs to be a non-negative value and less or equal to the bit width of the value to shift");
else
{
*m = 1;
return Result();
}
}
else if constexpr (is_big_int_v<A>)
return static_cast<Result>(a) >> static_cast<UInt32>(b);
else

View File

@ -1,7 +1,6 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <Core/Defines.h>
#include "Columns/ColumnNullable.h"
namespace DB
@ -23,7 +22,7 @@ struct BitTestImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a [[maybe_unused]], B b [[maybe_unused]], NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a [[maybe_unused]], B b [[maybe_unused]])
{
if constexpr (is_big_int_v<A> || is_big_int_v<B>)
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "bitTest is not implemented for big integers as second argument");
@ -33,17 +32,9 @@ struct BitTestImpl
typename NumberTraits::ToInteger<B>::Type b_int = b;
const auto max_position = static_cast<decltype(b)>((8 * sizeof(a)) - 1);
if (b_int > max_position || b_int < 0)
{
if (!m)
throw Exception(ErrorCodes::PARAMETER_OUT_OF_BOUND,
throw Exception(ErrorCodes::PARAMETER_OUT_OF_BOUND,
"The bit position argument needs to a positive value and less or equal to {} for integer {}",
std::to_string(max_position), std::to_string(a_int));
else
{
*m = 1;
return Result();
}
}
return (a_int >> b_int) & 1;
}
}

View File

@ -1,6 +1,5 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -20,7 +19,7 @@ struct BitXorImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
return static_cast<Result>(a) ^ static_cast<Result>(b);
}

View File

@ -3,7 +3,6 @@
#include <Functions/GCDLCMImpl.h>
#include <boost/integer/common_factor.hpp>
#include "Columns/ColumnNullable.h"
namespace DB
@ -19,7 +18,7 @@ struct GCDImpl : public GCDLCMImpl<A, B, GCDImpl<A, B>, NameGCD>
{
using ResultType = typename GCDLCMImpl<A, B, GCDImpl, NameGCD>::ResultType;
static ResultType applyImpl(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static ResultType applyImpl(A a, B b)
{
using Int = typename NumberTraits::ToInteger<ResultType>::Type;
return boost::integer::gcd(Int(a), Int(b)); // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)

View File

@ -2,7 +2,6 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include <Core/AccurateComparison.h>
#include <Functions/LeastGreatestGeneric.h>
#include "Columns/ColumnNullable.h"
namespace DB
@ -16,7 +15,7 @@ struct GreatestBaseImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
return static_cast<Result>(a) > static_cast<Result>(b) ?
static_cast<Result>(a) : static_cast<Result>(b);
@ -47,7 +46,7 @@ struct GreatestSpecialImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
static_assert(std::is_same_v<Result, ResultType>, "ResultType != Result");
return accurate::greaterOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);

View File

@ -1,7 +1,6 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include "Columns/ColumnNullable.h"
#include "divide/divide.h"
@ -27,7 +26,7 @@ struct DivideIntegralByConstantImpl
static const constexpr bool allow_string_integer = false;
template <OpCase op_case>
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap, NullMap * res_nullmap)
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap, NullMap * res_nullmap[[maybe_unused]])
{
if constexpr (op_case == OpCase::RightConstant)
{
@ -40,20 +39,19 @@ struct DivideIntegralByConstantImpl
{
if (right_nullmap)
{
assert(res_nullmap);
for (size_t i = 0; i < size; ++i)
if ((*right_nullmap)[i])
c[i] = ResultType();
else
apply<op_case, true>(a, b, c, i, &((*res_nullmap)[i]));
apply<op_case>(a, b, c, i);
}
else
for (size_t i = 0; i < size; ++i)
apply<op_case, false>(a, b, c, i);
apply<op_case>(a, b, c, i);
}
}
static ResultType process(A a, B b, NullMap::value_type * m = nullptr) { return Op::template apply<ResultType>(a, b, m); }
static ResultType process(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr) { return Op::template apply<ResultType>(a, b); }
static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict a_pos, B b, ResultType * __restrict c_pos, size_t size)
{
@ -81,23 +79,13 @@ struct DivideIntegralByConstantImpl
}
private:
template <OpCase op_case, bool nullable>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i, NullMap::value_type * m = nullptr)
template <OpCase op_case>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i)
{
if constexpr (nullable)
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i], m);
else
c[i] = Op::template apply<ResultType>(*a, b[i], m);
}
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
};

View File

@ -13,7 +13,7 @@ struct DivideIntegralOrZeroImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
if (unlikely(divisionLeadsToFPE(a, b)))
return 0;

View File

@ -3,7 +3,6 @@
#include <Functions/GCDLCMImpl.h>
#include <boost/integer/common_factor.hpp>
#include "Columns/ColumnNullable.h"
namespace
@ -38,7 +37,7 @@ struct LCMImpl : public GCDLCMImpl<A, B, LCMImpl<A, B>, NameLCM>
{
using ResultType = typename GCDLCMImpl<A, B, LCMImpl<A, B>, NameLCM>::ResultType;
static ResultType applyImpl(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static ResultType applyImpl(A a, B b)
{
using Int = typename NumberTraits::ToInteger<ResultType>::Type;
using Unsigned = make_unsigned_t<Int>;

View File

@ -2,7 +2,6 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include <Core/AccurateComparison.h>
#include <Functions/LeastGreatestGeneric.h>
#include "Columns/ColumnNullable.h"
namespace DB
@ -22,13 +21,6 @@ struct LeastBaseImpl
return static_cast<Result>(a) < static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
}
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type *)
{
/** gcc 4.9.2 successfully vectorizes a loop from this function. */
return static_cast<Result>(a) < static_cast<Result>(b) ? static_cast<Result>(a) : static_cast<Result>(b);
}
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = true;
@ -54,7 +46,7 @@ struct LeastSpecialImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
static_assert(std::is_same_v<Result, ResultType>, "ResultType != Result");
return accurate::lessOp(a, b) ? static_cast<Result>(a) : static_cast<Result>(b);

View File

@ -1,7 +1,6 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <base/arithmeticOverflow.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -14,7 +13,7 @@ struct MinusImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a, B b)
{
if constexpr (is_big_int_v<A> || is_big_int_v<B>)
{

View File

@ -2,7 +2,6 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include <libdivide-config.h>
#include "Columns/ColumnNullable.h"
#include <libdivide.h>
@ -28,7 +27,7 @@ struct ModuloByConstantImpl
static const constexpr bool allow_string_integer = false;
template <OpCase op_case>
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap, NullMap * res_nullmap)
static void NO_INLINE process(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t size, const NullMap * right_nullmap, NullMap * res_nullmap [[maybe_unused]] = nullptr)
{
if constexpr (op_case == OpCase::RightConstant)
{
@ -44,20 +43,29 @@ struct ModuloByConstantImpl
if ((*right_nullmap)[i])
c[i] = ResultType();
else
apply<op_case, true>(a, b, c, i, &((*res_nullmap)[i]));
apply<op_case>(a, b, c, i);
}
else
for (size_t i = 0; i < size; ++i)
apply<op_case, false>(a, b, c, i);
apply<op_case>(a, b, c, i);
}
}
static ResultType process(A a, B b, NullMap::value_type * m = nullptr) { return Op::template apply<ResultType>(a, b, m); }
static ResultType process(A a, B b, NullMap::value_type * res_nullmap [[maybe_unused]] = nullptr) { return Op::template apply<ResultType>(a, b); }
static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict src, B b, ResultType * __restrict dst, size_t size)
{
/// Modulo with too small divisor.
if (unlikely((std::is_signed_v<B> && b == -1) || b == 1))
if constexpr (std::is_signed_v<B>)
{
if (unlikely((b == -1)))
{
for (size_t i = 0; i < size; ++i)
dst[i] = 0;
return;
}
}
if (b == 1)
{
for (size_t i = 0; i < size; ++i)
dst[i] = 0;
@ -105,24 +113,13 @@ struct ModuloByConstantImpl
}
private:
template <OpCase op_case, bool nullable>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i, NullMap::value_type * m = nullptr)
template <OpCase op_case>
static void apply(const A * __restrict a, const B * __restrict b, ResultType * __restrict c, size_t i)
{
if constexpr (nullable)
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i], m);
else
c[i] = Op::template apply<ResultType>(*a, b[i], m);
}
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
{
if constexpr (op_case == OpCase::Vector)
c[i] = Op::template apply<ResultType>(a[i], b[i]);
else
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
c[i] = Op::template apply<ResultType>(*a, b[i]);
}
};

View File

@ -4,6 +4,7 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include "Common/StackTrace.h"
#include <Common/Exception.h>
#include "Functions/StringHelpers.h"
#include "base/extended_types.h"
#include <libdivide.h>
@ -46,11 +47,21 @@ struct ModuloOrNullImpl
try
{
res = Op::template apply<ResultType>(a, b);
if constexpr (std::is_floating_point_v<ResultType>)
{
if (!std::isfinite(res) && m)
*m = 1;
}
}
catch (const std::exception&)
{
if (m)
*m = 1;
else
{
std::cerr << "gethere 1" << std::endl;
throw;
}
}
return res;
}
@ -58,7 +69,16 @@ struct ModuloOrNullImpl
static void NO_INLINE NO_SANITIZE_UNDEFINED vectorConstant(const A * __restrict src, B b, ResultType * __restrict dst, size_t size, NullMap * res_nullmap)
{
/// Modulo with too small divisor.
if (unlikely((std::is_signed_v<B> && b == -1) || b == 1))
if constexpr (std::is_signed_v<B>)
{
if (unlikely((b == -1)))
{
for (size_t i = 0; i < size; ++i)
dst[i] = 0;
return;
}
}
if (b == 1)
{
for (size_t i = 0; i < size; ++i)
dst[i] = 0;
@ -120,7 +140,7 @@ struct ModuloOrNullImpl
if constexpr (std::is_floating_point_v<Result>)
{
if (!std::isfinite(res) && m)
* m = 1;
*m = 1;
}
}
catch (const std::exception&)
@ -128,6 +148,11 @@ struct ModuloOrNullImpl
std::cerr <<"gethere 6 exception, m vallue:" << !!m << std::endl;
std::cerr << StackTrace().toString() << std::endl;
if (m) *m = 1;
else
{
std::cerr << "gethere 7" << std::endl;
throw;
}
}
return res;
}

View File

@ -1,6 +1,5 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -15,7 +14,7 @@ struct ModuloOrZeroImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static Result apply(A a, B b)
{
if constexpr (std::is_floating_point_v<ResultType>)
{

View File

@ -2,7 +2,6 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <base/arithmeticOverflow.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -15,7 +14,7 @@ struct MultiplyImpl
static const constexpr bool allow_string_integer = false;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a, B b)
{
if constexpr (is_big_int_v<A> || is_big_int_v<B>)
{

View File

@ -1,7 +1,6 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionBinaryArithmetic.h>
#include <base/arithmeticOverflow.h>
#include "Columns/ColumnNullable.h"
namespace DB
{
@ -15,7 +14,7 @@ struct PlusImpl
static const constexpr bool is_commutative = true;
template <typename Result = ResultType>
static NO_SANITIZE_UNDEFINED Result apply(A a, B b, NullMap::value_type * m [[maybe_unused]] = nullptr)
static NO_SANITIZE_UNDEFINED Result apply(A a, B b)
{
/// Next everywhere, static_cast - so that there is no wrong result in expressions of the form Int64 c = UInt32(a) * Int32(-1).
if constexpr (is_big_int_v<A> || is_big_int_v<B>)

View File

@ -54,7 +54,9 @@ struct PlusName { static constexpr auto name = "plus"; };
struct MinusName { static constexpr auto name = "minus"; };
struct MultiplyName { static constexpr auto name = "multiply"; };
struct DivideName { static constexpr auto name = "divide"; };
struct DivideOrNullName { static constexpr auto name = "divideOrNull"; };
struct ModuloName { static constexpr auto name = "modulo"; };
struct ModuloOrNullName { static constexpr auto name = "moduloOrNull"; };
struct IntDivName { static constexpr auto name = "intDiv"; };
struct IntDivOrZeroName { static constexpr auto name = "intDivOrZero"; };
@ -152,8 +154,12 @@ using FunctionTupleMultiply = FunctionTupleOperator<MultiplyName>;
using FunctionTupleDivide = FunctionTupleOperator<DivideName>;
using FunctionTupleDivideOrNull = FunctionTupleOperator<DivideOrNullName>;
using FunctionTupleModulo = FunctionTupleOperator<ModuloName>;
using FunctionTupleModuloOrNull = FunctionTupleOperator<ModuloOrNullName>;
using FunctionTupleIntDiv = FunctionTupleOperator<IntDivName>;
using FunctionTupleIntDivOrZero = FunctionTupleOperator<IntDivOrZeroName>;
@ -307,12 +313,16 @@ using FunctionTupleMultiplyByNumber = FunctionTupleOperatorByNumber<MultiplyName
using FunctionTupleDivideByNumber = FunctionTupleOperatorByNumber<DivideName>;
using FunctionTupleDivideOrNullByNumber = FunctionTupleOperatorByNumber<DivideOrNullName>;
using FunctionTupleModuloByNumber = FunctionTupleOperatorByNumber<ModuloName>;
using FunctionTupleIntDivByNumber = FunctionTupleOperatorByNumber<IntDivName>;
using FunctionTupleIntDivOrZeroByNumber = FunctionTupleOperatorByNumber<IntDivOrZeroName>;
using FunctionTupleModuloOrNullByNumber = FunctionTupleOperatorByNumber<ModuloOrNullName>;
class FunctionDotProduct : public ITupleFunction
{
public:
@ -1581,7 +1591,9 @@ REGISTER_FUNCTION(VectorFunctions)
factory.registerAlias("vectorDifference", FunctionTupleMinus::name, FunctionFactory::Case::Insensitive);
factory.registerFunction<FunctionTupleMultiply>();
factory.registerFunction<FunctionTupleDivide>();
factory.registerFunction<FunctionTupleDivideOrNull>();
factory.registerFunction<FunctionTupleModulo>();
factory.registerFunction<FunctionTupleModuloOrNull>();
factory.registerFunction<FunctionTupleIntDiv>();
factory.registerFunction<FunctionTupleIntDivOrZero>();
factory.registerFunction<FunctionTupleNegate>();
@ -1647,7 +1659,9 @@ If the types of the first interval (or the interval in the tuple) and the second
factory.registerFunction<FunctionTupleMultiplyByNumber>();
factory.registerFunction<FunctionTupleDivideByNumber>();
factory.registerFunction<FunctionTupleDivideOrNullByNumber>();
factory.registerFunction<FunctionTupleModuloByNumber>();
factory.registerFunction<FunctionTupleModuloOrNullByNumber>();
factory.registerFunction<FunctionTupleIntDivByNumber>();
factory.registerFunction<FunctionTupleIntDivOrZeroByNumber>();

View File

@ -20,3 +20,13 @@ Nullable(UInt8)
\N
\N
\N
\N
\N
\N
\N
\N
\N
(NULL,1,1)
(0,1,1)
(NULL,NULL,NULL)
(1,0,1)

View File

@ -9,14 +9,14 @@ select moduloOrNull(1, materialize(0));
select moduloOrNull(materialize(1), 0);
select moduloOrNull(materialize(1), materialize(0));
select moduloOrNull(1, toNullable(materialize(toUInt64(0))));
select moduloOrNull(1.1, toNullable(materialize(toUInt64(0))));
select moduloOrNull(materialize(1), toNullable(materialize(toUInt64(0))));
select moduloOrNull(toNullable(materialize(1)), toNullable(materialize(toUInt64(0))));
select moduloOrNull(toNullable(materialize(toFloat32(1))), toNullable(materialize(toInt64(0))));
select moduloOrNull(1, toNullable(materialize(toInt128(0))));
select moduloOrNull(1.1, toNullable(materialize(toInt128(0))));
select moduloOrNull(toNullable(materialize(toFloat64(1))), toNullable(materialize(toInt128(0))));
select moduloOrNull(toNullable(materialize(toFloat64(1))), toNullable(materialize(toInt256(0))));
select moduloOrNull(1, toNullable(materialize(toInt256(0))));
select moduloOrNull(1.0, toNullable(materialize(toInt256(0))));
SELECT moduloOrNull(toNullable(materialize(1)), toNullable(materialize(0)));
SELECT moduloOrNull(toNullable(materialize(toFloat32(1))), toNullable(materialize(0)));
@ -24,3 +24,16 @@ SELECT moduloOrNull(toNullable(materialize(toFloat32(1))), materialize(0));
SELECT moduloOrNull(toNullable(materialize(toFloat32(1))), toNullable(0));
SELECT moduloOrNull(materialize(1), CAST(materialize(NULL), 'Nullable(Float32)'));
SELECT moduloOrNull(toDecimal32(16.2, 2), 0.0);
SELECT moduloOrNull(toDecimal32(16.2, 2), toDecimal32(0.0, 2));
SELECT moduloOrNull((16.2), 0.0);
SELECT moduloOrNull(materialize(16.2), 0.0);
SELECT moduloOrNull(16.2, materialize(0.0));
SELECT moduloOrNull(materialize(16.2), materialize(0.0));
SELECT tupleModuloOrNull((15, 10, 5), (0, 3, 2));
SELECT tupleModuloOrNull((15, 10, 5), (5, 3, 2));
SELECT tupleModuloOrNullByNumber((15, 10, 5), 0);
SELECT tupleModuloOrNullByNumber((15, 10, 5), 2);

View File

@ -17,3 +17,14 @@
1.7777777777777777
1.7777777777777777
1.7777777777777777
\N
\N
\N
\N
\N
\N
\N
(NULL,NULL,NULL)
(3,NULL,NULL)
(3,2,1)
(NULL,NULL,NULL)

View File

@ -22,3 +22,17 @@ SELECT divideOrNull(CAST(16, 'Int8'), CAST(materialize(9), 'Nullable(Int128)'));
SELECT divideOrNull(CAST(16, 'Int128'), CAST(materialize(9), 'Nullable(Int128)'));
SELECT divideOrNull(CAST(16, 'UInt256'), CAST(materialize(9), 'Nullable(UInt128)'));
SELECT divideOrNull(CAST(16, 'UInt256'), CAST(materialize(9), 'Nullable(UInt128)'));
SELECT divideOrNull(toDecimal32(16.2, 2), toDecimal32(0.0, 1));
SELECT divideOrNull(toDecimal32(16.2, 2), materialize(toDecimal32(0.0, 1)));
SELECT divideOrNull(materialize(toDecimal32(16.2, 2)), toDecimal32(0.0, 1));
SELECT divideOrNull(materialize(toDecimal32(16.2, 2)), materialize(toDecimal32(0.0, 1)));
SELECT divideOrNull(toDecimal32(16.2, 2), 0.0);
SELECT divideOrNull(toDecimal32(16.2, 2), materialize(0.0));
SELECT divideOrNull(materialize(toDecimal32(16.2, 2)), materialize(0.0));
SELECT tupleDivideOrNull((15, 10, 5), (0, 0, 0));
SELECT tupleDivideOrNull((15, 10, 5), (5, 0, 0));
SELECT tupleDivideOrNullByNumber((15, 10, 5), 5);
SELECT tupleDivideOrNullByNumber((15, 10, 5), 0);