// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // This file is copied from // https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/divide.cpp // and modified by Doris #include #include "core/column/column_vector.h" #include "core/data_type/data_type_decimal.h" #include "core/data_type/number_traits.h" #include "core/types.h" #include "core/value/decimalv2_value.h" #include "exprs/function/cast_type_to_either.h" #include "exprs/function/function_helpers.h" #include "exprs/function/simple_function_factory.h" namespace doris { struct DivideFloatingImpl; template class FunctionDiv : public IFunction { static constexpr bool result_is_decimal = !std::is_same_v; public: static constexpr auto name = "divide"; static FunctionPtr create() { return std::make_shared(); } FunctionDiv() = default; String get_name() const override { return name; } bool need_replace_null_data_to_default() const override { return Impl::need_replace_null_data_to_default; } size_t get_number_of_arguments() const override { return 2; } bool use_default_implementation_for_constants() const final { return false; } DataTypes get_variadic_argument_types_impl() const override { return Impl::get_variadic_argument_types(); } DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { return make_nullable(arguments[0]); } Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, uint32_t result, size_t input_rows_count) const override { auto& column_left = block.get_by_position(arguments[0]).column; auto& column_right = block.get_by_position(arguments[1]).column; const auto* type_left = assert_cast( block.get_by_position(arguments[0]).type.get()); const auto* type_right = assert_cast( block.get_by_position(arguments[1]).type.get()); const auto& res_data_type = remove_nullable(block.get_by_position(result).type); bool is_const_left = is_column_const(*column_left); bool is_const_right = is_column_const(*column_right); ColumnPtr column_result = nullptr; if (is_const_left && is_const_right) { column_result = constant_constant(column_left, column_right, type_left, type_right, res_data_type, context->check_overflow_for_decimal()); } else if (is_const_left) { column_result = constant_vector(column_left, column_right, type_left, type_right, res_data_type, context->check_overflow_for_decimal()); } else if (is_const_right) { column_result = vector_constant(column_left, column_right, type_left, type_right, res_data_type, context->check_overflow_for_decimal()); } else { column_result = vector_vector(column_left, column_right, type_left, type_right, res_data_type, context->check_overflow_for_decimal()); } block.replace_by_position(result, std::move(column_result)); return Status::OK(); } private: ColumnPtr constant_constant(ColumnPtr column_left, ColumnPtr column_right, const typename Impl::DataTypeA* type_left, const typename Impl::DataTypeB* type_right, DataTypePtr res_data_type, bool check_overflow_for_decimal) const { const auto* column_left_ptr = assert_cast(column_left.get()); const auto* column_right_ptr = assert_cast(column_right.get()); DCHECK(column_left_ptr != nullptr && column_right_ptr != nullptr); ColumnPtr column_result = nullptr; if constexpr (result_is_decimal) { if constexpr (Impl::DataTypeA::PType == TYPE_DECIMALV2) { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); typename PrimitiveTypeTraits::CppType left_tmp; auto left_src = column_left_ptr->template get_value(); std::memcpy(&left_tmp, &left_src, sizeof(left_src)); typename PrimitiveTypeTraits::CppType right_tmp; auto right_src = column_right_ptr->template get_value(); std::memcpy(&right_tmp, &right_src, sizeof(right_src)); column_result = Impl::constant_constant( left_tmp, right_tmp, max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } else { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); typename PrimitiveTypeTraits::CppType left_tmp; auto left_src = column_left_ptr->template get_value(); std::memcpy(&left_tmp, &left_src, sizeof(left_src)); typename PrimitiveTypeTraits::CppType right_tmp; auto right_src = column_right_ptr->template get_value(); std::memcpy(&right_tmp, &right_src, sizeof(right_src)); column_result = Impl::constant_constant( left_tmp, right_tmp, max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } } else { typename PrimitiveTypeTraits::CppType left_tmp; auto left_src = column_left_ptr->template get_value(); std::memcpy(&left_tmp, &left_src, sizeof(left_src)); typename PrimitiveTypeTraits::CppType right_tmp; auto right_src = column_right_ptr->template get_value(); std::memcpy(&right_tmp, &right_src, sizeof(right_src)); column_result = Impl::constant_constant(left_tmp, right_tmp); } return ColumnConst::create(std::move(column_result), column_left->size()); } ColumnPtr vector_constant(ColumnPtr column_left, ColumnPtr column_right, const typename Impl::DataTypeA* type_left, const typename Impl::DataTypeB* type_right, DataTypePtr res_data_type, bool check_overflow_for_decimal) const { const auto* column_right_ptr = assert_cast(column_right.get()); DCHECK(column_right_ptr != nullptr); ColumnPtr res = nullptr; if constexpr (result_is_decimal) { if constexpr (Impl::DataTypeA::PType == TYPE_DECIMALV2) { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); typename PrimitiveTypeTraits::CppType tmp; auto src = column_right_ptr->template get_value(); std::memcpy(&tmp, &src, sizeof(src)); res = Impl::vector_constant(column_left->get_ptr(), tmp, max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } else { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); res = Impl::vector_constant( column_left->get_ptr(), column_right_ptr->template get_value(), max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } } else { res = Impl::vector_constant(column_left->get_ptr(), column_right_ptr->template get_value()); } return res; } ColumnPtr constant_vector(ColumnPtr column_left, ColumnPtr column_right, const typename Impl::DataTypeA* type_left, const typename Impl::DataTypeB* type_right, DataTypePtr res_data_type, bool check_overflow_for_decimal) const { const auto* column_left_ptr = assert_cast(column_left.get()); DCHECK(column_left_ptr != nullptr); ColumnPtr res = nullptr; if constexpr (result_is_decimal) { if constexpr (Impl::DataTypeA::PType == TYPE_DECIMALV2) { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); typename PrimitiveTypeTraits::CppType tmp; auto src = column_left_ptr->template get_value(); std::memcpy(&tmp, &src, sizeof(src)); res = Impl::constant_vector(tmp, column_right->get_ptr(), max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } else { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); typename PrimitiveTypeTraits::CppType tmp; auto src = column_left_ptr->template get_value(); std::memcpy(&tmp, &src, sizeof(src)); res = Impl::constant_vector(tmp, column_right->get_ptr(), max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } } else { res = Impl::constant_vector(column_left_ptr->template get_value(), column_right->get_ptr()); } return res; } ColumnPtr vector_vector(ColumnPtr column_left, ColumnPtr column_right, const typename Impl::DataTypeA* type_left, const typename Impl::DataTypeB* type_right, DataTypePtr res_data_type, bool check_overflow_for_decimal) const { ColumnPtr res = nullptr; if constexpr (result_is_decimal) { if constexpr (Impl::DataTypeA::PType == TYPE_DECIMALV2) { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); res = Impl::vector_vector( column_left->get_ptr(), column_right->get_ptr(), max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } else { if (!cast_type_to_either( remove_nullable(res_data_type).get(), [&](const auto& type_result) { auto max_and_multiplier = Impl::get_max_and_multiplier( type_left, type_right, type_result); res = Impl::vector_vector( column_left->get_ptr(), column_right->get_ptr(), max_and_multiplier.first, max_and_multiplier.second, type_result, check_overflow_for_decimal); return true; })) { throw Exception(ErrorCode::INTERNAL_ERROR, "Wrong type. Expected: Decimal, Actually: {}", type_to_string(res_data_type->get_primitive_type())); } } } else { res = Impl::vector_vector(column_left->get_ptr(), column_right->get_ptr()); } return res; } }; static const DecimalV2Value one(1, 0); struct DivideFloatingImpl { using ArgA = typename PrimitiveTypeTraits::CppType; using ArgB = typename PrimitiveTypeTraits::CppType; static constexpr PrimitiveType ArgAPType = TYPE_DOUBLE; static constexpr PrimitiveType ArgBPType = TYPE_DOUBLE; using ColumnType = typename PrimitiveTypeTraits::ColumnType; using DataTypeA = typename PrimitiveTypeTraits::DataType; using DataTypeB = typename PrimitiveTypeTraits::DataType; constexpr static bool need_replace_null_data_to_default = false; static DataTypes get_variadic_argument_types() { return {std::make_shared(), std::make_shared()}; } static void apply(const typename ColumnType::Container& a, ArgB b, typename ColumnType::Container& c, PaddedPODArray& null_map) { size_t size = c.size(); UInt8 is_null = b == 0; memset(null_map.data(), is_null, size); if (!is_null) { for (size_t i = 0; i < size; i++) { c[i] = (double)a[i] / (double)b; } } } static inline ArgA apply(ArgA a, ArgB b, UInt8& is_null) { is_null = b == 0; return a / (b + is_null); } static ColumnPtr constant_constant(ArgA a, ArgB b) { auto column_result = ColumnFloat64 ::create(1); auto null_map = ColumnUInt8::create(1, 0); column_result->get_element(0) = apply(a, b, null_map->get_element(0)); return ColumnNullable::create(std::move(column_result), std::move(null_map)); } static ColumnPtr vector_constant(ColumnPtr column_left, ArgB b) { const auto column_left_ptr = assert_cast(column_left.get()); auto column_result = ColumnFloat64::create(column_left->size()); DCHECK(column_left_ptr != nullptr); auto null_map = ColumnUInt8::create(column_left->size(), 0); apply(column_left_ptr->get_data(), b, column_result->get_data(), null_map->get_data()); return ColumnNullable::create(std::move(column_result), std::move(null_map)); } static ColumnPtr constant_vector(ArgA a, ColumnPtr column_right) { const auto column_right_ptr = assert_cast(column_right.get()); auto column_result = ColumnFloat64::create(column_right->size()); DCHECK(column_right_ptr != nullptr); auto null_map = ColumnUInt8::create(column_right->size(), 0); auto& b = column_right_ptr->get_data(); auto& c = column_result->get_data(); auto& n = null_map->get_data(); size_t size = b.size(); for (size_t i = 0; i < size; ++i) { c[i] = apply(a, b[i], n[i]); } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } static ColumnPtr vector_vector(ColumnPtr column_left, ColumnPtr column_right) { const auto* column_left_ptr = assert_cast(column_left.get()); const auto* column_right_ptr = assert_cast(column_right.get()); auto column_result = ColumnFloat64::create(column_left->size()); DCHECK(column_left_ptr != nullptr && column_right_ptr != nullptr); auto null_map = ColumnUInt8::create(column_result->size(), 0); auto& a = column_left_ptr->get_data(); auto& b = column_right_ptr->get_data(); auto& c = column_result->get_data(); auto& n = null_map->get_data(); size_t size = a.size(); for (size_t i = 0; i < size; ++i) { c[i] = apply(a[i], b[i], n[i]); } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } }; template struct DivideDecimalImpl { static_assert(is_decimal(TypeA) && is_decimal(TypeB)); static_assert((TypeA == TYPE_DECIMALV2 && TypeB == TYPE_DECIMALV2) || (TypeA != TYPE_DECIMALV2 && TypeB != TYPE_DECIMALV2)); using ArgA = typename PrimitiveTypeTraits::CppType; using ArgB = typename PrimitiveTypeTraits::CppType; static constexpr PrimitiveType ArgAPType = TypeA; static constexpr PrimitiveType ArgBPType = TypeB; using ArgNativeTypeA = typename PrimitiveTypeTraits::CppType::NativeType; using ArgNativeTypeB = typename PrimitiveTypeTraits::CppType::NativeType; using DataTypeA = typename PrimitiveTypeTraits::DataType; using DataTypeB = typename PrimitiveTypeTraits::DataType; using ColumnTypeA = typename PrimitiveTypeTraits::ColumnType; using ColumnTypeB = typename PrimitiveTypeTraits::ColumnType; constexpr static bool need_replace_null_data_to_default = true; static DataTypes get_variadic_argument_types() { return {std::make_shared::DataType>(), std::make_shared::DataType>()}; } static inline DecimalV2Value impl(DecimalV2Value a, DecimalV2Value b, UInt8& is_null) { is_null = b.is_zero(); return a / (is_null ? one : b); } template requires(is_decimal(ResultType)) static inline typename PrimitiveTypeTraits::CppType::NativeType impl( ArgNativeTypeA a, ArgNativeTypeB b, UInt8& is_null) { is_null = b == 0; return static_cast::CppType::NativeType>(a) / (b + is_null); } template requires(is_decimal(ResultType) && ResultType != TYPE_DECIMALV2) static ColumnPtr constant_constant( ArgA a, ArgB b, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { auto column_result = ColumnDecimal::create(1, res_data_type.get_scale()); auto null_map = ColumnUInt8::create(1, 0); if (check_overflow_for_decimal) { column_result->get_element(0) = typename PrimitiveTypeTraits::CppType(apply( a.value, b.value, null_map->get_element(0), max_result_number)); } else { column_result->get_element(0) = typename PrimitiveTypeTraits::CppType(apply( a.value, b.value, null_map->get_element(0), max_result_number)); } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(ResultType == TYPE_DECIMALV2) static ColumnPtr constant_constant( ArgA a, ArgB b, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { auto column_result = ColumnDecimal::create(1, res_data_type.get_scale()); auto null_map = ColumnUInt8::create(1, 0); if (check_overflow_for_decimal) { column_result->get_element(0) = typename PrimitiveTypeTraits::CppType(apply( a.value(), b.value(), null_map->get_element(0), max_result_number)); } else { column_result->get_element(0) = typename PrimitiveTypeTraits::CppType(apply( a.value(), b.value(), null_map->get_element(0), max_result_number)); } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(is_decimal(ResultType) && ResultType != TYPE_DECIMALV2) static ColumnPtr vector_constant( ColumnPtr column_left, ArgB b, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { const auto* column_left_ptr = assert_cast(column_left.get()); auto column_result = ColumnDecimal::create(column_left->size(), res_data_type.get_scale()); DCHECK(column_left_ptr != nullptr); auto null_map = ColumnUInt8::create(column_left->size(), 0); const auto& a = column_left_ptr->get_data().data(); const auto& c = column_result->get_data().data(); auto& n = null_map->get_data(); auto sz = column_left->size(); if (check_overflow_for_decimal) { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a[i], b, n[i], max_result_number)); } } else { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a[i], b, n[i], max_result_number)); } } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(ResultType == TYPE_DECIMALV2) static ColumnPtr vector_constant( ColumnPtr column_left, ArgB b, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { const auto* column_left_ptr = assert_cast(column_left.get()); auto column_result = ColumnDecimal::create(column_left->size(), res_data_type.get_scale()); DCHECK(column_left_ptr != nullptr); auto null_map = ColumnUInt8::create(column_left->size(), 0); const auto& a = column_left_ptr->get_data().data(); const auto& c = column_result->get_data().data(); auto& n = null_map->get_data(); auto sz = column_left->size(); if (check_overflow_for_decimal) { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a[i].value(), b.value(), n[i], max_result_number)); } } else { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a[i].value(), b.value(), n[i], max_result_number)); } } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(is_decimal(ResultType) && ResultType != TYPE_DECIMALV2) static ColumnPtr constant_vector( ArgA a, ColumnPtr column_right, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { const auto* column_right_ptr = assert_cast(column_right.get()); auto column_result = ColumnDecimal::create(column_right->size(), res_data_type.get_scale()); DCHECK(column_right_ptr != nullptr); auto null_map = ColumnUInt8::create(column_right->size(), 0); const auto& b = column_right_ptr->get_data().data(); const auto& c = column_result->get_data().data(); auto& n = null_map->get_data(); auto sz = column_right->size(); if (check_overflow_for_decimal) { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a, b[i], n[i], max_result_number)); } } else { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a, b[i], n[i], max_result_number)); } } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(ResultType == TYPE_DECIMALV2) static ColumnPtr constant_vector( ArgA a, ColumnPtr column_right, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { const auto* column_right_ptr = assert_cast(column_right.get()); auto column_result = ColumnDecimal::create(column_right->size(), res_data_type.get_scale()); DCHECK(column_right_ptr != nullptr); auto null_map = ColumnUInt8::create(column_right->size(), 0); const auto& b = column_right_ptr->get_data().data(); const auto& c = column_result->get_data().data(); auto& n = null_map->get_data(); auto sz = column_right->size(); if (check_overflow_for_decimal) { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a.value(), b[i].value(), n[i], max_result_number)); } } else { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a.value(), b[i].value(), n[i], max_result_number)); } } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(is_decimal(ResultType)) static ColumnPtr vector_vector( ColumnPtr column_left, ColumnPtr column_right, const typename PrimitiveTypeTraits::CppType& max_result_number, const typename PrimitiveTypeTraits::CppType& scale_diff_multiplier, const DataTypeDecimal& res_data_type, bool check_overflow_for_decimal) { const auto* column_left_ptr = assert_cast(column_left.get()); const auto* column_right_ptr = assert_cast(column_right.get()); auto column_result = ColumnDecimal::create(column_left->size(), res_data_type.get_scale()); DCHECK(column_left_ptr != nullptr && column_right_ptr != nullptr); // function divide, modulo and pmod auto null_map = ColumnUInt8::create(column_result->size(), 0); const auto& a = column_left_ptr->get_data().data(); const auto& b = column_right_ptr->get_data().data(); const auto& c = column_result->get_data().data(); auto& n = null_map->get_data(); auto sz = column_right->size(); if constexpr (TypeA == TYPE_DECIMALV2) { if (check_overflow_for_decimal) { for (size_t i = 0; i < sz; ++i) { c[i] = DecimalV2Value(apply(a[i].value(), b[i].value(), n[i], max_result_number)); } } else { for (size_t i = 0; i < sz; ++i) { c[i] = DecimalV2Value(apply(a[i].value(), b[i].value(), n[i], max_result_number)); } } } else { if (check_overflow_for_decimal) { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a[i], b[i], n[i], max_result_number)); } } else { for (size_t i = 0; i < sz; ++i) { c[i] = typename DataTypeDecimal::FieldType( apply(a[i], b[i], n[i], max_result_number)); } } } return ColumnNullable::create(std::move(column_result), std::move(null_map)); } template requires(is_decimal(ResultType)) static ALWAYS_INLINE typename PrimitiveTypeTraits::CppType::NativeType apply( ArgNativeTypeA a, ArgNativeTypeB b, UInt8& is_null, const typename PrimitiveTypeTraits::CppType& max_result_number) { if constexpr (TypeA == TYPE_DECIMALV2) { DecimalV2Value l(a); DecimalV2Value r(b); auto ans = impl(l, r, is_null); using ANS_TYPE = std::decay_t; if constexpr (check_overflow_for_decimal) { if constexpr (std::is_same_v) { if (ans.value() > max_result_number.value() || ans.value() < -max_result_number.value()) { throw Exception(ErrorCode::ARITHMETIC_OVERFLOW_ERRROR, "Arithmetic overflow: {} {} {} = {}, result type: {}", DecimalV2Value(a).to_string(), "divide", DecimalV2Value(b).to_string(), DecimalV2Value(ans).to_string(), type_to_string(ResultType)); } } else if constexpr (IsDecimalNumber) { if (ans.value > max_result_number.value || ans.value < -max_result_number.value) { throw Exception(ErrorCode::ARITHMETIC_OVERFLOW_ERRROR, "Arithmetic overflow: {} {} {} = {}, result type: {}", DecimalV2Value(a).to_string(), "divide", DecimalV2Value(b).to_string(), DecimalV2Value(ans).to_string(), type_to_string(ResultType)); } } else { if (ans > max_result_number.value || ans < -max_result_number.value) { throw Exception(ErrorCode::ARITHMETIC_OVERFLOW_ERRROR, "Arithmetic overflow: {} {} {} = {}, result type: {}", DecimalV2Value(a).to_string(), "divide", DecimalV2Value(b).to_string(), DecimalV2Value(ans).to_string(), type_to_string(ResultType)); } } } typename PrimitiveTypeTraits::CppType::NativeType result {}; memcpy(&result, &ans, std::min(sizeof(result), sizeof(ans))); return result; } else { return impl(a, b, is_null); } } template static std::pair::CppType, typename PrimitiveTypeTraits::CppType> get_max_and_multiplier(const DataTypeA* type_left, const DataTypeB* type_right, const DataTypeDecimal& type_result) { auto max_result_number = DataTypeDecimal::get_max_digits_number(type_result.get_precision()); auto orig_result_scale = type_left->get_scale() + type_right->get_scale(); auto result_scale = type_result.get_scale(); DCHECK(orig_result_scale >= result_scale); auto scale_diff_multiplier = DataTypeDecimal::get_scale_multiplier(orig_result_scale - result_scale); return {typename PrimitiveTypeTraits::CppType(max_result_number), typename PrimitiveTypeTraits::CppType(scale_diff_multiplier)}; } }; void register_function_divide(SimpleFunctionFactory& factory) { factory.register_function>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); factory.register_function>>(); } } // namespace doris