| // 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/array/arrayAggregation.cpp |
| // and modified by Doris |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "common/exception.h" |
| #include "common/status.h" |
| #include "olap/column_predicate.h" |
| #include "runtime/define_primitive_type.h" |
| #include "runtime/primitive_type.h" |
| #include "vec/aggregate_functions/aggregate_function.h" |
| #include "vec/aggregate_functions/aggregate_function_avg.h" |
| #include "vec/aggregate_functions/aggregate_function_min_max.h" |
| #include "vec/aggregate_functions/aggregate_function_product.h" |
| #include "vec/aggregate_functions/aggregate_function_simple_factory.h" |
| #include "vec/aggregate_functions/aggregate_function_sum.h" |
| #include "vec/aggregate_functions/helpers.h" |
| #include "vec/columns/column.h" |
| #include "vec/columns/column_array.h" |
| #include "vec/columns/column_decimal.h" |
| #include "vec/columns/column_nullable.h" |
| #include "vec/common/arena.h" |
| #include "vec/core/block.h" |
| #include "vec/core/column_numbers.h" |
| #include "vec/core/types.h" |
| #include "vec/data_types/data_type.h" |
| #include "vec/data_types/data_type_array.h" |
| #include "vec/data_types/data_type_nullable.h" |
| #include "vec/functions/array/function_array_join.h" |
| #include "vec/functions/array/function_array_mapped.h" |
| #include "vec/functions/function.h" |
| #include "vec/functions/simple_function_factory.h" |
| |
| namespace doris::vectorized { |
| |
| enum class AggregateOperation { MIN, MAX, SUM, AVERAGE, PRODUCT }; |
| |
| // For MIN/MAX, the type of result is the same as the type of elements, we can omit the |
| // template specialization. |
| template <AggregateOperation operation> |
| struct AggregateFunctionTraits; |
| |
| template <AggregateOperation operation> |
| requires(operation == AggregateOperation::MIN || operation == AggregateOperation::MAX) |
| struct AggregateFunctionTraits<operation> { |
| template <PrimitiveType Element> |
| struct TypeTraits { |
| static constexpr PrimitiveType ResultType = Element; |
| }; |
| }; |
| |
| template <> |
| struct AggregateFunctionTraits<AggregateOperation::SUM> { |
| template <PrimitiveType Element> |
| struct TypeTraits { |
| static constexpr PrimitiveType ResultType = |
| Element == TYPE_DECIMALV2 ? TYPE_DECIMALV2 |
| : is_float_or_double(Element) |
| ? TYPE_DOUBLE |
| : (Element == TYPE_LARGEINT ? TYPE_LARGEINT : TYPE_BIGINT); |
| using AggregateDataType = AggregateFunctionSumData<ResultType>; |
| using Function = AggregateFunctionSum<Element, ResultType, AggregateDataType>; |
| }; |
| }; |
| template <> |
| struct AggregateFunctionTraits<AggregateOperation::AVERAGE> { |
| template <PrimitiveType Element> |
| struct TypeTraits { |
| static constexpr PrimitiveType ResultType = |
| Element == TYPE_DECIMALV2 ? TYPE_DECIMALV2 : TYPE_DOUBLE; |
| using AggregateDataType = AggregateFunctionAvgData<ResultType>; |
| using Function = AggregateFunctionAvg<Element, ResultType, AggregateDataType>; |
| static_assert(std::is_same_v<typename PrimitiveTypeTraits<ResultType>::ColumnItemType, |
| typename Function::ResultType>, |
| "ResultType doesn't match."); |
| }; |
| }; |
| |
| template <> |
| struct AggregateFunctionTraits<AggregateOperation::PRODUCT> { |
| template <PrimitiveType Element> |
| struct TypeTraits { |
| static constexpr PrimitiveType ResultType = |
| Element == TYPE_DECIMALV2 ? TYPE_DECIMALV2 : Element; |
| using AggregateDataType = AggregateFunctionProductData<ResultType>; |
| using Function = AggregateFunctionProduct<Element, ResultType, AggregateDataType>; |
| }; |
| }; |
| |
| template <AggregateOperation AggOp, typename Derived> |
| struct ArrayAggregateFunctionCreator { |
| template <PrimitiveType T> |
| using Function = typename Derived::template TypeTraits<T>::Function; |
| |
| static auto create(const DataTypePtr& data_type_ptr, const AggregateFunctionAttr& attr) |
| -> AggregateFunctionPtr { |
| if constexpr (AggOp == AggregateOperation::MIN || AggOp == AggregateOperation::MAX) { |
| return creator_with_type_list< |
| TYPE_TINYINT, TYPE_SMALLINT, TYPE_INT, TYPE_BIGINT, TYPE_LARGEINT, TYPE_FLOAT, |
| TYPE_DOUBLE, TYPE_DECIMAL32, TYPE_DECIMAL64, TYPE_DECIMAL128I, |
| TYPE_DECIMAL256>::create<Function>(DataTypes {make_nullable(data_type_ptr)}, |
| true, attr); |
| } else { |
| return creator_with_type_list< |
| TYPE_TINYINT, TYPE_SMALLINT, TYPE_INT, TYPE_BIGINT, TYPE_LARGEINT, TYPE_FLOAT, |
| TYPE_DOUBLE>::create<Function>(DataTypes {make_nullable(data_type_ptr)}, true, |
| attr); |
| } |
| } |
| }; |
| |
| template <AggregateOperation operation> |
| struct ArrayAggregateImpl { |
| using column_type = ColumnArray; |
| using data_type = DataTypeArray; |
| |
| static bool _is_variadic() { return false; } |
| |
| static size_t _get_number_of_arguments() { return 1; } |
| |
| static bool skip_return_type_check() { return false; } |
| |
| static DataTypePtr get_return_type(const DataTypes& arguments) { |
| using Function = |
| ArrayAggregateFunctionCreator<operation, AggregateFunctionTraits<operation>>; |
| const DataTypeArray* data_type_array = |
| static_cast<const DataTypeArray*>(remove_nullable(arguments[0]).get()); |
| auto function = Function::create(data_type_array->get_nested_type(), |
| {.is_window_function = false, .column_names = {}}); |
| if (function) { |
| return function->get_return_type(); |
| } else { |
| throw doris::Exception(ErrorCode::INVALID_ARGUMENT, |
| "Unexpected type {} for aggregation {}", |
| data_type_array->get_nested_type()->get_name(), operation); |
| } |
| } |
| |
| static Status execute(Block& block, const ColumnNumbers& arguments, uint32_t result, |
| const DataTypeArray* data_type_array, const ColumnArray& array) { |
| ColumnPtr res; |
| DataTypePtr type = data_type_array->get_nested_type(); |
| const IColumn* data = array.get_data_ptr().get(); |
| |
| const auto& offsets = array.get_offsets(); |
| if constexpr (operation == AggregateOperation::MAX || |
| operation == AggregateOperation::MIN) { |
| // min/max can only be applied on ip type |
| if (execute_type<TYPE_IPV4>(res, type, data, offsets) || |
| execute_type<TYPE_IPV6>(res, type, data, offsets)) { |
| block.replace_by_position(result, std::move(res)); |
| return Status::OK(); |
| } |
| } |
| |
| if (execute_type<TYPE_BOOLEAN>(res, type, data, offsets) || |
| execute_type<TYPE_TINYINT>(res, type, data, offsets) || |
| execute_type<TYPE_SMALLINT>(res, type, data, offsets) || |
| execute_type<TYPE_INT>(res, type, data, offsets) || |
| execute_type<TYPE_BIGINT>(res, type, data, offsets) || |
| execute_type<TYPE_LARGEINT>(res, type, data, offsets) || |
| execute_type<TYPE_FLOAT>(res, type, data, offsets) || |
| execute_type<TYPE_DOUBLE>(res, type, data, offsets) || |
| execute_type<TYPE_DECIMAL32>(res, type, data, offsets) || |
| execute_type<TYPE_DECIMAL64>(res, type, data, offsets) || |
| execute_type<TYPE_DECIMAL128I>(res, type, data, offsets) || |
| execute_type<TYPE_DECIMAL256>(res, type, data, offsets) || |
| execute_type<TYPE_DATEV2>(res, type, data, offsets) || |
| execute_type<TYPE_DATETIMEV2>(res, type, data, offsets) || |
| execute_type<TYPE_TIMESTAMPTZ>(res, type, data, offsets) || |
| execute_type<TYPE_VARCHAR>(res, type, data, offsets)) { |
| block.replace_by_position(result, std::move(res)); |
| return Status::OK(); |
| } else { |
| return Status::RuntimeError("Unexpected column for aggregation: {}", data->get_name()); |
| } |
| } |
| |
| template <typename ColumnType, typename CreateColumnFunc> |
| static bool execute_type_impl(ColumnPtr& res_ptr, const DataTypePtr& type, const IColumn* data, |
| const ColumnArray::Offsets64& offsets, |
| CreateColumnFunc create_column_func) { |
| using Function = |
| ArrayAggregateFunctionCreator<operation, AggregateFunctionTraits<operation>>; |
| |
| const ColumnType* column = |
| data->is_nullable() |
| ? check_and_get_column<ColumnType>( |
| static_cast<const ColumnNullable*>(data)->get_nested_column()) |
| : check_and_get_column<ColumnType>(&*data); |
| if (!column) { |
| return false; |
| } |
| |
| ColumnPtr res_column = create_column_func(column); |
| res_column = make_nullable(res_column); |
| assert_cast<ColumnNullable&>(res_column->assume_mutable_ref()).reserve(offsets.size()); |
| |
| auto function = Function::create(type, {.is_window_function = false, .column_names = {}}); |
| auto guard = AggregateFunctionGuard(function.get()); |
| Arena arena; |
| auto nullable_column = make_nullable(data->get_ptr()); |
| const IColumn* columns[] = {nullable_column.get()}; |
| for (int64_t i = 0; i < offsets.size(); ++i) { |
| auto start = offsets[i - 1]; // -1 is ok. |
| auto end = offsets[i]; |
| bool is_empty = (start == end); |
| if (is_empty) { |
| res_column->assume_mutable()->insert_default(); |
| continue; |
| } |
| function->reset(guard.data()); |
| function->add_batch_range(start, end - 1, guard.data(), columns, arena, |
| data->is_nullable()); |
| function->insert_result_into(guard.data(), res_column->assume_mutable_ref()); |
| } |
| res_ptr = std::move(res_column); |
| return true; |
| } |
| |
| template <PrimitiveType Element> |
| static bool execute_type(ColumnPtr& res_ptr, const DataTypePtr& type, const IColumn* data, |
| const ColumnArray::Offsets64& offsets) { |
| if constexpr (is_string_type(Element)) { |
| if (operation == AggregateOperation::SUM || operation == AggregateOperation::PRODUCT || |
| operation == AggregateOperation::AVERAGE) { |
| return false; |
| } |
| |
| auto create_column = [](const ColumnString*) -> ColumnPtr { |
| return ColumnString::create(); |
| }; |
| |
| return execute_type_impl<ColumnString, decltype(create_column)>(res_ptr, type, data, |
| offsets, create_column); |
| } else { |
| if constexpr ((operation == AggregateOperation::SUM || |
| operation == AggregateOperation::PRODUCT || |
| operation == AggregateOperation::AVERAGE) && |
| (is_date_type(Element) || is_timestamptz_type(Element) || |
| is_decimalv3(Element))) { |
| return false; |
| } else { |
| using ColVecType = typename PrimitiveTypeTraits<Element>::ColumnType; |
| static constexpr PrimitiveType ResultType = AggregateFunctionTraits< |
| operation>::template TypeTraits<Element>::ResultType; |
| using ColVecResultType = typename PrimitiveTypeTraits<ResultType>::ColumnType; |
| |
| auto create_column = [](const ColVecType* column) -> ColumnPtr { |
| if constexpr (is_decimal(Element)) { |
| return ColVecResultType::create(0, column->get_scale()); |
| } else { |
| return ColVecResultType::create(); |
| } |
| }; |
| |
| return execute_type_impl<ColVecType, decltype(create_column)>( |
| res_ptr, type, data, offsets, create_column); |
| } |
| } |
| } |
| }; |
| |
| struct NameArrayMin { |
| static constexpr auto name = "array_min"; |
| }; |
| |
| template <> |
| struct ArrayAggregateFunctionCreator<AggregateOperation::MIN, |
| AggregateFunctionTraits<AggregateOperation::MIN>> { |
| static auto create(const DataTypePtr& data_type_ptr, const AggregateFunctionAttr& attr) |
| -> AggregateFunctionPtr { |
| return create_aggregate_function_single_value<AggregateFunctionMinData>( |
| NameArrayMin::name, {make_nullable(data_type_ptr)}, make_nullable(data_type_ptr), |
| true, attr); |
| } |
| }; |
| |
| struct NameArrayMax { |
| static constexpr auto name = "array_max"; |
| }; |
| |
| template <> |
| struct ArrayAggregateFunctionCreator<AggregateOperation::MAX, |
| AggregateFunctionTraits<AggregateOperation::MAX>> { |
| static auto create(const DataTypePtr& data_type_ptr, const AggregateFunctionAttr& attr) |
| -> AggregateFunctionPtr { |
| return create_aggregate_function_single_value<AggregateFunctionMaxData>( |
| NameArrayMax::name, {make_nullable(data_type_ptr)}, make_nullable(data_type_ptr), |
| true, attr); |
| } |
| }; |
| |
| struct NameArraySum { |
| static constexpr auto name = "array_sum"; |
| }; |
| |
| struct NameArrayAverage { |
| static constexpr auto name = "array_avg"; |
| }; |
| struct NameArrayProduct { |
| static constexpr auto name = "array_product"; |
| }; |
| |
| using FunctionArrayMin = |
| FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::MIN>, NameArrayMin>; |
| using FunctionArrayMax = |
| FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::MAX>, NameArrayMax>; |
| using FunctionArraySum = |
| FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::SUM>, NameArraySum>; |
| using FunctionArrayAverage = |
| FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::AVERAGE>, NameArrayAverage>; |
| using FunctionArrayProduct = |
| FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::PRODUCT>, NameArrayProduct>; |
| |
| using FunctionArrayJoin = FunctionArrayMapped<ArrayJoinImpl, NameArrayJoin>; |
| |
| template <AggregateOperation operation> |
| struct AggregateFunctionTraitsWithResultType; |
| |
| template <> |
| struct AggregateFunctionTraitsWithResultType<AggregateOperation::SUM> { |
| template <PrimitiveType InputType, PrimitiveType ResultType> |
| struct TypeTraits { |
| using AggregateDataType = AggregateFunctionSumData<ResultType>; |
| using Function = AggregateFunctionSum<InputType, ResultType, AggregateDataType>; |
| }; |
| }; |
| template <> |
| struct AggregateFunctionTraitsWithResultType<AggregateOperation::AVERAGE> { |
| template <PrimitiveType InputType, PrimitiveType ResultType> |
| struct TypeTraits { |
| using AggregateDataType = AggregateFunctionAvgData<ResultType>; |
| using Function = AggregateFunctionAvg<InputType, ResultType, AggregateDataType>; |
| }; |
| }; |
| template <> |
| struct AggregateFunctionTraitsWithResultType<AggregateOperation::PRODUCT> { |
| template <PrimitiveType InputType, PrimitiveType ResultType> |
| struct TypeTraits { |
| using AggregateDataType = AggregateFunctionProductData<ResultType>; |
| using Function = AggregateFunctionProduct<InputType, ResultType, AggregateDataType>; |
| }; |
| }; |
| template <typename Derived> |
| struct ArrayAggregateFunctionCreatorWithResultType { |
| template <PrimitiveType InputType, PrimitiveType ResultType> |
| using Function = typename Derived::template TypeTraits<InputType, ResultType>::Function; |
| |
| static auto create(const DataTypePtr& data_type_ptr, const DataTypePtr& result_type_ptr, |
| const AggregateFunctionAttr& attr) -> AggregateFunctionPtr { |
| return creator_with_type_list< |
| TYPE_DECIMAL32, TYPE_DECIMAL64, TYPE_DECIMAL128I, |
| TYPE_DECIMAL256>::creator_with_result_type<Function>("", |
| DataTypes {make_nullable( |
| data_type_ptr)}, |
| result_type_ptr, true, attr); |
| } |
| }; |
| template <AggregateOperation operation, PrimitiveType ResultType> |
| struct ArrayAggregateImplDecimalV3; |
| template <AggregateOperation operation, PrimitiveType ResultType> |
| requires(operation == AggregateOperation::SUM || operation == AggregateOperation::PRODUCT || |
| operation == AggregateOperation::AVERAGE) |
| struct ArrayAggregateImplDecimalV3<operation, ResultType> { |
| using column_type = ColumnArray; |
| using data_type = DataTypeArray; |
| |
| static bool _is_variadic() { return false; } |
| |
| static size_t _get_number_of_arguments() { return 1; } |
| |
| static bool skip_return_type_check() { return true; } |
| |
| static DataTypePtr get_return_type(const DataTypes& arguments) { |
| throw doris::Exception( |
| ErrorCode::NOT_IMPLEMENTED_ERROR, |
| "get_return_type is not implemented for ArrayAggregateImplDecimalV3"); |
| __builtin_unreachable(); |
| } |
| |
| static Status execute(Block& block, const ColumnNumbers& arguments, uint32_t result, |
| const DataTypePtr& result_type, const DataTypeArray* data_type_array, |
| const ColumnArray& array) { |
| ColumnPtr res; |
| DataTypePtr type = data_type_array->get_nested_type(); |
| const IColumn* data = array.get_data_ptr().get(); |
| |
| const auto& offsets = array.get_offsets(); |
| |
| if (execute_type<TYPE_DECIMAL32>(res, result_type, type, data, offsets) || |
| execute_type<TYPE_DECIMAL64>(res, result_type, type, data, offsets) || |
| execute_type<TYPE_DECIMAL128I>(res, result_type, type, data, offsets) || |
| execute_type<TYPE_DECIMAL256>(res, result_type, type, data, offsets)) { |
| block.replace_by_position(result, std::move(res)); |
| return Status::OK(); |
| } else { |
| return Status::RuntimeError("Unexpected column for aggregation: {}", data->get_name()); |
| } |
| } |
| |
| template <typename ColumnType, typename CreateColumnFunc> |
| static bool execute_type_impl(ColumnPtr& res_ptr, const DataTypePtr& result_type, |
| const DataTypePtr& type, const IColumn* data, |
| const ColumnArray::Offsets64& offsets, |
| CreateColumnFunc create_column_func) { |
| using Function = ArrayAggregateFunctionCreatorWithResultType< |
| AggregateFunctionTraitsWithResultType<operation>>; |
| |
| const ColumnType* column = |
| data->is_nullable() |
| ? check_and_get_column<ColumnType>( |
| static_cast<const ColumnNullable*>(data)->get_nested_column()) |
| : check_and_get_column<ColumnType>(&*data); |
| if (!column) { |
| return false; |
| } |
| |
| ColumnPtr res_column = create_column_func(column); |
| res_column = make_nullable(res_column); |
| assert_cast<ColumnNullable&>(res_column->assume_mutable_ref()).reserve(offsets.size()); |
| |
| auto function = Function::create(type, result_type, |
| {.is_window_function = false, .column_names = {}}); |
| auto guard = AggregateFunctionGuard(function.get()); |
| Arena arena; |
| auto nullable_column = make_nullable(data->get_ptr()); |
| const IColumn* columns[] = {nullable_column.get()}; |
| for (int64_t i = 0; i < offsets.size(); ++i) { |
| auto start = offsets[i - 1]; // -1 is ok. |
| auto end = offsets[i]; |
| bool is_empty = (start == end); |
| if (is_empty) { |
| res_column->assume_mutable()->insert_default(); |
| continue; |
| } |
| function->reset(guard.data()); |
| function->add_batch_range(start, end - 1, guard.data(), columns, arena, |
| data->is_nullable()); |
| function->insert_result_into(guard.data(), res_column->assume_mutable_ref()); |
| } |
| res_ptr = std::move(res_column); |
| return true; |
| } |
| |
| template <PrimitiveType Element> |
| static bool execute_type(ColumnPtr& res_ptr, const DataTypePtr& result_type, |
| const DataTypePtr& type, const IColumn* data, |
| const ColumnArray::Offsets64& offsets) { |
| using ColVecType = typename PrimitiveTypeTraits<Element>::ColumnType; |
| using ColVecResultType = typename PrimitiveTypeTraits<ResultType>::ColumnType; |
| |
| auto create_column = [](const ColVecType* column) -> ColumnPtr { |
| return ColVecResultType::create(0, column->get_scale()); |
| }; |
| |
| return execute_type_impl<ColVecType, decltype(create_column)>(res_ptr, result_type, type, |
| data, offsets, create_column); |
| } |
| }; |
| |
| template <typename Impl, typename Name> |
| class FunctionArrayAggDecimalV3 : public IFunction { |
| public: |
| static constexpr auto name = Name::name; |
| explicit FunctionArrayAggDecimalV3(DataTypePtr result_type) |
| : _result_type(std::move(result_type)) {} |
| |
| String get_name() const override { return name; } |
| Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, |
| uint32_t result, size_t input_rows_count) const override { |
| const auto& typed_column = block.get_by_position(arguments[0]); |
| auto ptr = typed_column.column->convert_to_full_column_if_const(); |
| const typename Impl::column_type* column_array; |
| if (ptr->is_nullable()) { |
| column_array = check_and_get_column<const typename Impl::column_type>( |
| assert_cast<const ColumnNullable*>(ptr.get())->get_nested_column_ptr().get()); |
| } else { |
| column_array = check_and_get_column<const typename Impl::column_type>(ptr.get()); |
| } |
| const auto* data_type_array = |
| assert_cast<const DataTypeArray*>(remove_nullable(typed_column.type).get()); |
| return Impl::execute(block, arguments, result, _result_type, data_type_array, |
| *column_array); |
| } |
| |
| bool is_variadic() const override { return Impl::_is_variadic(); } |
| |
| size_t get_number_of_arguments() const override { return Impl::_get_number_of_arguments(); } |
| |
| bool skip_return_type_check() const override { return Impl::skip_return_type_check(); } |
| |
| DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { |
| return Impl::get_return_type(arguments); |
| } |
| |
| private: |
| DataTypePtr _result_type; |
| }; |
| template <PrimitiveType ResultType> |
| struct ArraySumDecimalV3Attributes { |
| static_assert(is_decimalv3(ResultType)); |
| using AggregateDataType = AggregateFunctionSumData<ResultType>; |
| using Function = FunctionArrayAggDecimalV3< |
| ArrayAggregateImplDecimalV3<AggregateOperation::SUM, ResultType>, NameArraySum>; |
| }; |
| template <PrimitiveType ResultType> |
| using ArraySumDecimalV3 = typename ArraySumDecimalV3Attributes<ResultType>::Function; |
| |
| template <PrimitiveType ResultType> |
| struct ArrayAvgDecimalV3Attributes { |
| static_assert(is_decimalv3(ResultType)); |
| using AggregateDataType = AggregateFunctionAvgData<ResultType>; |
| using Function = FunctionArrayAggDecimalV3< |
| ArrayAggregateImplDecimalV3<AggregateOperation::AVERAGE, ResultType>, NameArrayAverage>; |
| }; |
| template <PrimitiveType ResultType> |
| using ArrayAvgDecimalV3 = typename ArrayAvgDecimalV3Attributes<ResultType>::Function; |
| |
| template <PrimitiveType ResultType> |
| struct ArrayProductDecimalV3Attributes { |
| static_assert(is_decimalv3(ResultType)); |
| using AggregateDataType = AggregateFunctionProductData<ResultType>; |
| using Function = FunctionArrayAggDecimalV3< |
| ArrayAggregateImplDecimalV3<AggregateOperation::PRODUCT, ResultType>, NameArrayProduct>; |
| }; |
| template <PrimitiveType ResultType> |
| using ArrayProductDecimalV3 = typename ArrayProductDecimalV3Attributes<ResultType>::Function; |
| void register_array_reduce_agg_functions(SimpleFunctionFactory& factory) { |
| { |
| ArrayAggFunctionCreator creator = [&](const DataTypePtr& result_type) { |
| if (is_decimalv3(result_type->get_primitive_type())) { |
| return DefaultFunctionBuilder::create_array_agg_function_decimalv3< |
| ArraySumDecimalV3>(result_type); |
| } else { |
| FunctionBuilderPtr func = |
| std::make_shared<DefaultFunctionBuilder>(FunctionArraySum::create()); |
| return func; |
| } |
| }; |
| factory.register_array_agg_function(NameArraySum::name, creator); |
| } |
| { |
| ArrayAggFunctionCreator creator = [&](const DataTypePtr& result_type) { |
| if (is_decimalv3(result_type->get_primitive_type())) { |
| return DefaultFunctionBuilder::create_array_agg_function_decimalv3< |
| ArrayAvgDecimalV3>(result_type); |
| } else { |
| FunctionBuilderPtr func = |
| std::make_shared<DefaultFunctionBuilder>(FunctionArrayAverage::create()); |
| return func; |
| } |
| }; |
| factory.register_array_agg_function(NameArrayAverage::name, creator); |
| } |
| { |
| ArrayAggFunctionCreator creator = [&](const DataTypePtr& result_type) { |
| if (is_decimalv3(result_type->get_primitive_type())) { |
| return DefaultFunctionBuilder::create_array_agg_function_decimalv3< |
| ArrayProductDecimalV3>(result_type); |
| } else { |
| FunctionBuilderPtr func = |
| std::make_shared<DefaultFunctionBuilder>(FunctionArrayProduct::create()); |
| return func; |
| } |
| }; |
| factory.register_array_agg_function(NameArrayProduct::name, creator); |
| } |
| } |
| |
| void register_function_array_aggregation(SimpleFunctionFactory& factory) { |
| factory.register_function<FunctionArrayMin>(); |
| factory.register_function<FunctionArrayMax>(); |
| factory.register_function<FunctionArrayJoin>(); |
| register_array_reduce_agg_functions(factory); |
| } |
| |
| } // namespace doris::vectorized |