| // 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. |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| #include <functional> |
| #include <memory> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "common/status.h" |
| #include "util/bitmap_value.h" |
| #include "vec/aggregate_functions/aggregate_function.h" |
| #include "vec/columns/column.h" |
| #include "vec/columns/column_complex.h" |
| #include "vec/columns/column_nullable.h" |
| #include "vec/columns/column_vector.h" |
| #include "vec/common/assert_cast.h" |
| #include "vec/core/block.h" |
| #include "vec/core/column_numbers.h" |
| #include "vec/core/column_with_type_and_name.h" |
| #include "vec/core/types.h" |
| #include "vec/data_types/data_type.h" |
| #include "vec/data_types/data_type_bitmap.h" |
| #include "vec/data_types/data_type_nullable.h" |
| #include "vec/data_types/data_type_number.h" |
| #include "vec/functions/function.h" |
| #include "vec/functions/simple_function_factory.h" |
| |
| namespace doris { |
| class FunctionContext; |
| } // namespace doris |
| |
| namespace doris::vectorized { |
| |
| // currently only bitmap_or and bitmap_or_count will call this function, |
| // other bitmap functions will use default implementation for nulls |
| #define BITMAP_OR_NULLABLE(nullable, input_rows_count, res, op) \ |
| const auto& nested_col_ptr = nullable->get_nested_column_ptr(); \ |
| const auto* __restrict null_map_data = nullable->get_null_map_data().data(); \ |
| const auto& mid_data = assert_cast<const ColumnBitmap*>(nested_col_ptr.get())->get_data(); \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| if (!null_map_data[row]) { \ |
| res[row] op mid_data[row]; \ |
| } \ |
| } |
| |
| #define BITMAP_FUNCTION_VARIADIC(CLASS, FUNCTION_NAME, OP) \ |
| struct CLASS { \ |
| static constexpr auto name = #FUNCTION_NAME; \ |
| using ResultDataType = DataTypeBitMap; \ |
| static Status vector_vector(ColumnPtr argument_columns[], size_t col_size, \ |
| size_t input_rows_count, std::vector<BitmapValue>& res, \ |
| IColumn* res_nulls) { \ |
| std::vector<const ColumnUInt8::value_type*> null_map_datas(col_size); \ |
| int nullable_cols_count = 0; \ |
| ColumnUInt8::value_type* __restrict res_nulls_data = nullptr; \ |
| if (res_nulls) { \ |
| res_nulls_data = assert_cast<ColumnUInt8*>(res_nulls)->get_data().data(); \ |
| } \ |
| if (auto* nullable = check_and_get_column<ColumnNullable>(*argument_columns[0])) { \ |
| null_map_datas[nullable_cols_count++] = nullable->get_null_map_data().data(); \ |
| BITMAP_OR_NULLABLE(nullable, input_rows_count, res, =); \ |
| } else { \ |
| const auto& mid_data = \ |
| assert_cast<const ColumnBitmap*>(argument_columns[0].get())->get_data(); \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| res[row] = mid_data[row]; \ |
| } \ |
| } \ |
| for (size_t col = 1; col < col_size; ++col) { \ |
| if (auto* nullable = \ |
| check_and_get_column<ColumnNullable>(*argument_columns[col])) { \ |
| null_map_datas[nullable_cols_count++] = nullable->get_null_map_data().data(); \ |
| BITMAP_OR_NULLABLE(nullable, input_rows_count, res, OP); \ |
| } else { \ |
| const auto& col_data = \ |
| assert_cast<const ColumnBitmap*>(argument_columns[col].get()) \ |
| ->get_data(); \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| res[row] OP col_data[row]; \ |
| } \ |
| } \ |
| } \ |
| if (res_nulls_data && nullable_cols_count == col_size) { \ |
| const auto* null_map_data = null_map_datas[0]; \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| res_nulls_data[row] = null_map_data[row]; \ |
| } \ |
| for (int i = 1; i < nullable_cols_count; ++i) { \ |
| null_map_data = null_map_datas[i]; \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| res_nulls_data[row] &= null_map_data[row]; \ |
| } \ |
| } \ |
| } \ |
| return Status::OK(); \ |
| } \ |
| } |
| |
| #define BITMAP_FUNCTION_COUNT_VARIADIC(CLASS, FUNCTION_NAME, OP) \ |
| struct CLASS { \ |
| static constexpr auto name = #FUNCTION_NAME; \ |
| using ResultDataType = DataTypeInt64; \ |
| using TData = std::vector<BitmapValue>; \ |
| using ResTData = typename ColumnInt64::Container; \ |
| static Status vector_vector(ColumnPtr argument_columns[], size_t col_size, \ |
| size_t input_rows_count, ResTData& res, IColumn* res_nulls) { \ |
| TData vals; \ |
| if (auto* nullable = check_and_get_column<ColumnNullable>(*argument_columns[0])) { \ |
| vals.resize(input_rows_count); \ |
| BITMAP_OR_NULLABLE(nullable, input_rows_count, vals, =); \ |
| } else { \ |
| vals = assert_cast<const ColumnBitmap*>(argument_columns[0].get())->get_data(); \ |
| } \ |
| for (size_t col = 1; col < col_size; ++col) { \ |
| if (auto* nullable = \ |
| check_and_get_column<ColumnNullable>(*argument_columns[col])) { \ |
| BITMAP_OR_NULLABLE(nullable, input_rows_count, vals, OP); \ |
| } else { \ |
| const auto& col_data = \ |
| assert_cast<const ColumnBitmap*>(argument_columns[col].get()) \ |
| ->get_data(); \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| vals[row] OP col_data[row]; \ |
| } \ |
| } \ |
| } \ |
| for (size_t row = 0; row < input_rows_count; ++row) { \ |
| res[row] = vals[row].cardinality(); \ |
| } \ |
| return Status::OK(); \ |
| } \ |
| } |
| |
| BITMAP_FUNCTION_VARIADIC(BitmapOr, bitmap_or, |=); |
| BITMAP_FUNCTION_VARIADIC(BitmapAnd, bitmap_and, &=); |
| BITMAP_FUNCTION_VARIADIC(BitmapXor, bitmap_xor, ^=); |
| BITMAP_FUNCTION_COUNT_VARIADIC(BitmapOrCount, bitmap_or_count, |=); |
| BITMAP_FUNCTION_COUNT_VARIADIC(BitmapAndCount, bitmap_and_count, &=); |
| BITMAP_FUNCTION_COUNT_VARIADIC(BitmapXorCount, bitmap_xor_count, ^=); |
| |
| Status execute_bitmap_op_count_null_to_zero( |
| FunctionContext* context, Block& block, const ColumnNumbers& arguments, uint32_t result, |
| size_t input_rows_count, |
| const std::function<Status(FunctionContext*, Block&, const ColumnNumbers&, size_t, size_t)>& |
| exec_impl_func); |
| |
| template <typename Impl> |
| class FunctionBitMapVariadic : public IFunction { |
| public: |
| static constexpr auto name = Impl::name; |
| |
| static FunctionPtr create() { return std::make_shared<FunctionBitMapVariadic>(); } |
| |
| String get_name() const override { return name; } |
| |
| size_t get_number_of_arguments() const override { return 0; } |
| |
| bool is_variadic() const override { return true; } |
| |
| DataTypePtr get_return_type_impl(const DataTypes& arguments) const override { |
| using ResultDataType = typename Impl::ResultDataType; |
| if (std::is_same_v<Impl, BitmapOr> || is_count()) { |
| bool return_nullable = false; |
| // result is nullable only when any columns is nullable for bitmap_or and bitmap_or_count |
| for (size_t i = 0; i < arguments.size(); ++i) { |
| if (arguments[i]->is_nullable()) { |
| return_nullable = true; |
| break; |
| } |
| } |
| auto result_type = std::make_shared<ResultDataType>(); |
| return return_nullable ? make_nullable(result_type) : result_type; |
| } else { |
| return std::make_shared<ResultDataType>(); |
| } |
| } |
| |
| bool use_default_implementation_for_nulls() const override { |
| // result is null only when all columns is null for bitmap_or. |
| // for count functions, result is always not null, and if the bitmap op result is null, |
| // the count is 0 |
| return !static_cast<bool>(std::is_same_v<Impl, BitmapOr> || is_count()); |
| } |
| |
| Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments, |
| uint32_t result, size_t input_rows_count) const override { |
| if (std::is_same_v<Impl, BitmapAndCount> || std::is_same_v<Impl, BitmapXorCount>) { |
| auto impl_func = [&](FunctionContext* context, Block& block, |
| const ColumnNumbers& arguments, uint32_t result, |
| size_t input_rows_count) { |
| return execute_impl_internal(context, block, arguments, result, input_rows_count); |
| }; |
| return execute_bitmap_op_count_null_to_zero(context, block, arguments, result, |
| input_rows_count, impl_func); |
| } else { |
| return execute_impl_internal(context, block, arguments, result, input_rows_count); |
| } |
| } |
| |
| Status execute_impl_internal(FunctionContext* context, Block& block, |
| const ColumnNumbers& arguments, uint32_t result, |
| size_t input_rows_count) const { |
| size_t argument_size = arguments.size(); |
| std::vector<ColumnPtr> argument_columns(argument_size); |
| |
| for (size_t i = 0; i < argument_size; ++i) { |
| argument_columns[i] = |
| block.get_by_position(arguments[i]).column->convert_to_full_column_if_const(); |
| } |
| |
| using ResultDataType = typename Impl::ResultDataType; //DataTypeBitMap or DataTypeInt64 |
| using ColVecResult = std::conditional_t<is_complex_v<ResultDataType::PType>, |
| ColumnComplexType<ResultDataType::PType>, |
| ColumnVector<ResultDataType::PType>>; |
| typename ColVecResult::MutablePtr col_res = nullptr; |
| |
| typename ColumnUInt8::MutablePtr col_res_nulls; |
| auto& result_info = block.get_by_position(result); |
| // special case for bitmap_or and bitmap_or_count |
| if (!use_default_implementation_for_nulls() && result_info.type->is_nullable()) { |
| col_res_nulls = ColumnUInt8::create(input_rows_count, 0); |
| } |
| |
| col_res = ColVecResult::create(); |
| |
| auto& vec_res = col_res->get_data(); |
| vec_res.resize(input_rows_count); |
| |
| RETURN_IF_ERROR(Impl::vector_vector(argument_columns.data(), argument_size, |
| input_rows_count, vec_res, col_res_nulls.get())); |
| if (!use_default_implementation_for_nulls() && result_info.type->is_nullable()) { |
| block.replace_by_position( |
| result, ColumnNullable::create(std::move(col_res), std::move(col_res_nulls))); |
| } else { |
| block.replace_by_position(result, std::move(col_res)); |
| } |
| return Status::OK(); |
| } |
| |
| private: |
| bool is_count() const { |
| return (std::is_same_v<Impl, BitmapOrCount> || std::is_same_v<Impl, BitmapAndCount> || |
| std::is_same_v<Impl, BitmapXorCount>); |
| } |
| }; |
| |
| using FunctionBitmapOr = FunctionBitMapVariadic<BitmapOr>; |
| using FunctionBitmapXor = FunctionBitMapVariadic<BitmapXor>; |
| using FunctionBitmapAnd = FunctionBitMapVariadic<BitmapAnd>; |
| using FunctionBitmapOrCount = FunctionBitMapVariadic<BitmapOrCount>; |
| using FunctionBitmapAndCount = FunctionBitMapVariadic<BitmapAndCount>; |
| using FunctionBitmapXorCount = FunctionBitMapVariadic<BitmapXorCount>; |
| |
| void register_function_bitmap_variadic(SimpleFunctionFactory& factory) { |
| factory.register_function<FunctionBitmapOr>(); |
| factory.register_function<FunctionBitmapXor>(); |
| factory.register_function<FunctionBitmapAnd>(); |
| factory.register_function<FunctionBitmapOrCount>(); |
| factory.register_function<FunctionBitmapAndCount>(); |
| factory.register_function<FunctionBitmapXorCount>(); |
| } |
| } // namespace doris::vectorized |