#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO include this last because of a broken roaring header. See the comment // inside. #include namespace DB { namespace ErrorCodes { extern const int ILLEGAL_TYPE_OF_ARGUMENT; extern const int LOGICAL_ERROR; } /** Bitmap functions. * Build a bitmap from integer array: * bitmapBuild: integer[] -> bitmap * * Convert bitmap to integer array: * bitmapToArray: bitmap -> integer[] * * Return the smallest value in the set: * bitmapMin: bitmap -> integer * * Return the greatest value in the set: * bitmapMax: bitmap -> integer * * Return subset in specified range (not include the range_end): * bitmapSubsetInRange: bitmap,integer,integer -> bitmap * * Return subset of the smallest `limit` values in set which is no smaller than `range_start`. * bitmapSubsetLimit: bitmap,integer,integer -> bitmap * * Transform an array of values in a bitmap to another array of values, the result is a new bitmap. * bitmapTransform: bitmap,integer[],integer[] -> bitmap * * Two bitmap and calculation: * bitmapAnd: bitmap,bitmap -> bitmap * * Two bitmap or calculation: * bitmapOr: bitmap,bitmap -> bitmap * * Two bitmap xor calculation: * bitmapXor: bitmap,bitmap -> bitmap * * Two bitmap andnot calculation: * bitmapAndnot: bitmap,bitmap -> bitmap * * Return bitmap cardinality: * bitmapCardinality: bitmap -> integer * * Two bitmap and calculation, return cardinality: * bitmapAndCardinality: bitmap,bitmap -> integer * * Two bitmap or calculation, return cardinality: * bitmapOrCardinality: bitmap,bitmap -> integer * * Two bitmap xor calculation, return cardinality: * bitmapXorCardinality: bitmap,bitmap -> integer * * Two bitmap andnot calculation, return cardinality: * bitmapAndnotCardinality: bitmap,bitmap -> integer * * Determine if a bitmap contains the given integer: * bitmapContains: bitmap,integer -> bool * * Judge if a bitmap is superset of the another one: * bitmapHasAll: bitmap,bitmap -> bool * * Judge if the intersection of two bitmap is nonempty: * bitmapHasAny: bitmap,bitmap -> bool */ template class FunctionBitmapBuildImpl : public IFunction { public: static constexpr auto name = Name::name; static FunctionPtr create(ContextPtr) { return std::make_shared(); } String getName() const override { return name; } bool isVariadic() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } size_t getNumberOfArguments() const override { return 1; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (arguments[0]->onlyNull()) return arguments[0]; const auto * array_type = typeid_cast(arguments[0].get()); if (!array_type) throw Exception( "First argument for function " + getName() + " must be an array but it has type " + arguments[0]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); auto nested_type = array_type->getNestedType(); DataTypes argument_types = {nested_type}; Array params_row; AggregateFunctionProperties properties; AggregateFunctionPtr bitmap_function; WhichDataType which(nested_type); if (which.isUInt8()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isUInt16()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isUInt32()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isUInt64()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isInt8()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isInt16()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isInt32()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else if (which.isInt64()) bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); else throw Exception( "Unexpected type " + array_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return std::make_shared(bitmap_function, argument_types, params_row); } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /* input_rows_count */) const override { const IDataType * from_type = arguments[0].type.get(); const auto * array_type = typeid_cast(from_type); const auto & nested_type = array_type->getNestedType(); DataTypes argument_types = {nested_type}; WhichDataType which(nested_type); if (which.isUInt8()) return executeBitmapData(argument_types, arguments); else if (which.isUInt16()) return executeBitmapData(argument_types, arguments); else if (which.isUInt32()) return executeBitmapData(argument_types, arguments); else if (which.isUInt64()) return executeBitmapData(argument_types, arguments); else if (which.isInt8()) return executeBitmapData(argument_types, arguments); else if (which.isInt16()) return executeBitmapData(argument_types, arguments); else if (which.isInt32()) return executeBitmapData(argument_types, arguments); else if (which.isInt64()) return executeBitmapData(argument_types, arguments); else throw Exception( "Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } private: template ColumnPtr executeBitmapData(DataTypes & argument_types, const ColumnsWithTypeAndName & arguments) const { // input data const ColumnArray * array = typeid_cast(arguments[0].column.get()); const ColumnPtr & mapped = array->getDataPtr(); const ColumnArray::Offsets & offsets = array->getOffsets(); const ColumnVector * column = checkAndGetColumn>(&*mapped); const typename ColumnVector::Container & input_data = column->getData(); // output data Array params_row; AggregateFunctionProperties properties; AggregateFunctionPtr bitmap_function = AggregateFunctionFactory::instance().get( AggregateFunctionGroupBitmapData::name(), argument_types, params_row, properties); auto col_to = ColumnAggregateFunction::create(bitmap_function); col_to->reserve(offsets.size()); size_t pos = 0; for (size_t i = 0; i < offsets.size(); ++i) { col_to->insertDefault(); AggregateFunctionGroupBitmapData & bitmap_data = *reinterpret_cast *>(col_to->getData()[i]); for (; pos < offsets[i]; ++pos) { bitmap_data.rbs.add(input_data[pos]); } } return col_to; } }; template class FunctionBitmapToArrayImpl : public IFunction { public: static constexpr auto name = Name::name; static FunctionPtr create(ContextPtr) { return std::make_shared(); } String getName() const override { return name; } bool isVariadic() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } size_t getNumberOfArguments() const override { return 1; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { const DataTypeAggregateFunction * bitmap_type = typeid_cast(arguments[0].get()); if (!(bitmap_type && bitmap_type->getFunctionName() =="groupBitmap")) throw Exception( "First argument for function " + getName() + " must be a bitmap but it has type " + arguments[0]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); const DataTypePtr data_type = bitmap_type->getArgumentsDataTypes()[0]; return std::make_shared(data_type); } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override { // input data const auto & return_type = result_type; auto res_ptr = return_type->createColumn(); ColumnArray & res = assert_cast(*res_ptr); IColumn & res_data = res.getData(); ColumnArray::Offsets & res_offsets = res.getOffsets(); const IDataType * from_type = arguments[0].type.get(); const DataTypeAggregateFunction * aggr_type = typeid_cast(from_type); WhichDataType which(aggr_type->getArgumentsDataTypes()[0]); if (which.isUInt8()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isUInt16()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isUInt32()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isUInt64()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isInt8()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isInt16()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isInt32()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else if (which.isInt64()) executeIntType(arguments, input_rows_count, res_data, res_offsets); else throw Exception( "Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return res_ptr; } private: using ToType = UInt64; template void executeIntType( const ColumnsWithTypeAndName & arguments, size_t input_rows_count, IColumn & res_data_col, ColumnArray::Offsets & res_offsets) const { const ColumnAggregateFunction * column = typeid_cast(arguments[0].column.get()); PaddedPODArray & res_data = typeid_cast &>(res_data_col).getData(); ColumnArray::Offset res_offset = 0; for (size_t i = 0; i < input_rows_count; ++i) { const AggregateFunctionGroupBitmapData & bitmap_data_1 = *reinterpret_cast *>(column->getData()[i]); UInt64 count = bitmap_data_1.rbs.rb_to_array(res_data); res_offset += count; res_offsets.emplace_back(res_offset); } } }; template class FunctionBitmapSubset : public IFunction { public: static constexpr auto name = Impl::name; static FunctionPtr create(ContextPtr) { return std::make_shared>(); } String getName() const override { return name; } bool isVariadic() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } size_t getNumberOfArguments() const override { return 3; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { const DataTypeAggregateFunction * bitmap_type = typeid_cast(arguments[0].get()); if (!(bitmap_type && bitmap_type->getFunctionName() == "groupBitmap")) throw Exception( "First argument for function " + getName() + " must be a bitmap but it has type " + arguments[0]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); for (size_t i = 1; i < 3; ++i) { WhichDataType which(arguments[i].get()); if (!(which.isUInt8() || which.isUInt16() || which.isUInt32() || which.isUInt64())) { throw Exception( "The second and third arguments for function " + getName() + " must be one of [UInt8, UInt16, UInt32, UInt64] but one of them has type " + arguments[1]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } } return arguments[0]; } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { const IDataType * from_type = arguments[0].type.get(); const DataTypeAggregateFunction * aggr_type = typeid_cast(from_type); WhichDataType which(aggr_type->getArgumentsDataTypes()[0]); if (which.isUInt8()) return executeIntType(arguments, input_rows_count); else if (which.isUInt16()) return executeIntType(arguments, input_rows_count); else if (which.isUInt32()) return executeIntType(arguments, input_rows_count); else if (which.isUInt64()) return executeIntType(arguments, input_rows_count); else if (which.isInt8()) return executeIntType(arguments, input_rows_count); else if (which.isInt16()) return executeIntType(arguments, input_rows_count); else if (which.isInt32()) return executeIntType(arguments, input_rows_count); else if (which.isInt64()) return executeIntType(arguments, input_rows_count); else throw Exception( "Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } private: using ToType = UInt64; template ColumnPtr executeIntType(const ColumnsWithTypeAndName & arguments, size_t input_rows_count) const { const IColumn * column_ptrs[3]; bool is_column_const[3]; const ColumnAggregateFunction * col_agg_func; const PaddedPODArray * container0; const PaddedPODArray * container1, * container2; ColumnPtr column_holder[2]; for (size_t i = 0; i < 3; ++i) { if (i > 0) { column_holder[i - 1] = castColumn(arguments[i], std::make_shared()); column_ptrs[i] = column_holder[i-1].get(); } else { column_ptrs[i] = arguments[i].column.get(); } is_column_const[i] = isColumnConst(*column_ptrs[i]); } if (is_column_const[0]) col_agg_func = typeid_cast(typeid_cast(column_ptrs[0])->getDataColumnPtr().get()); else col_agg_func = typeid_cast(column_ptrs[0]); container0 = &col_agg_func->getData(); if (is_column_const[1]) container1 = &typeid_cast(typeid_cast(column_ptrs[1])->getDataColumnPtr().get())->getData(); else container1 = &typeid_cast(column_ptrs[1])->getData(); if (is_column_const[2]) container2 = &typeid_cast(typeid_cast(column_ptrs[2])->getDataColumnPtr().get())->getData(); else container2 = &typeid_cast(column_ptrs[2])->getData(); auto col_to = ColumnAggregateFunction::create(col_agg_func->getAggregateFunction()); col_to->reserve(input_rows_count); for (size_t i = 0; i < input_rows_count; ++i) { AggregateDataPtr data_ptr_0 = is_column_const[0] ? (*container0)[0] : (*container0)[i]; const AggregateFunctionGroupBitmapData & bitmap_data_0 = *reinterpret_cast*>(data_ptr_0); const UInt64 range_start = is_column_const[1] ? (*container1)[0] : (*container1)[i]; const UInt64 range_end = is_column_const[2] ? (*container2)[0] : (*container2)[i]; col_to->insertDefault(); AggregateFunctionGroupBitmapData & bitmap_data_2 = *reinterpret_cast *>(col_to->getData()[i]); Impl::apply(bitmap_data_0, range_start, range_end, bitmap_data_2); } return col_to; } }; struct BitmapSubsetInRangeImpl { public: static constexpr auto name = "bitmapSubsetInRange"; template static void apply( const AggregateFunctionGroupBitmapData & bitmap_data_0, UInt64 range_start, UInt64 range_end, AggregateFunctionGroupBitmapData & bitmap_data_2) { bitmap_data_0.rbs.rb_range(range_start, range_end, bitmap_data_2.rbs); } }; struct BitmapSubsetLimitImpl { public: static constexpr auto name = "bitmapSubsetLimit"; template static void apply( const AggregateFunctionGroupBitmapData & bitmap_data_0, UInt64 range_start, UInt64 range_end, AggregateFunctionGroupBitmapData & bitmap_data_2) { bitmap_data_0.rbs.rb_limit(range_start, range_end, bitmap_data_2.rbs); } }; struct BitmapSubsetOffsetLimitImpl { public: static constexpr auto name = "subBitmap"; template static void apply( const AggregateFunctionGroupBitmapData & bitmap_data_0, UInt64 range_start, UInt64 range_end, AggregateFunctionGroupBitmapData & bitmap_data_2) { bitmap_data_0.rbs.rb_offset_limit(range_start, range_end, bitmap_data_2.rbs); } }; using FunctionBitmapSubsetInRange = FunctionBitmapSubset; using FunctionBitmapSubsetLimit = FunctionBitmapSubset; using FunctionBitmapSubsetOffsetLimit = FunctionBitmapSubset; class FunctionBitmapTransform : public IFunction { public: static constexpr auto name = "bitmapTransform"; static FunctionPtr create(ContextPtr) { return std::make_shared(); } String getName() const override { return name; } bool isVariadic() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } size_t getNumberOfArguments() const override { return 3; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { const DataTypeAggregateFunction * bitmap_type = typeid_cast(arguments[0].get()); if (!(bitmap_type && bitmap_type->getFunctionName() == "groupBitmap")) throw Exception( "First argument for function " + getName() + " must be a bitmap but it has type " + arguments[0]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); for (size_t i = 0; i < 2; ++i) { const auto * array_type = typeid_cast(arguments[i + 1].get()); String msg = "The second and third arguments for function " + getName() + " must be an one of [Array(UInt8), Array(UInt16), Array(UInt32), Array(UInt64)] but one of them has type " + arguments[i + 1]->getName() + "."; if (!array_type) throw Exception(msg, ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); auto nested_type = array_type->getNestedType(); WhichDataType which(nested_type); if (!(which.isUInt8() || which.isUInt16() || which.isUInt32() || which.isUInt64())) throw Exception(msg, ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } return arguments[0]; } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { const IDataType * from_type = arguments[0].type.get(); const DataTypeAggregateFunction * aggr_type = typeid_cast(from_type); WhichDataType which(aggr_type->getArgumentsDataTypes()[0]); if (which.isUInt8()) return executeIntType(arguments, input_rows_count); else if (which.isUInt16()) return executeIntType(arguments, input_rows_count); else if (which.isUInt32()) return executeIntType(arguments, input_rows_count); else if (which.isUInt64()) return executeIntType(arguments, input_rows_count); else if (which.isInt8()) return executeIntType(arguments, input_rows_count); else if (which.isInt16()) return executeIntType(arguments, input_rows_count); else if (which.isInt32()) return executeIntType(arguments, input_rows_count); else if (which.isInt64()) return executeIntType(arguments, input_rows_count); else throw Exception( "Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } private: using ToType = UInt64; template ColumnPtr executeIntType(const ColumnsWithTypeAndName & arguments, size_t input_rows_count) const { const IColumn * column_ptrs[3]; bool is_column_const[3]; const ColumnAggregateFunction * col_agg_func; const PaddedPODArray * container0; const ColumnArray * array1; const ColumnArray * array2; ColumnPtr column_holder[2]; for (size_t i = 0; i < 3; ++i) { if (i > 0) { auto array_type = std::make_shared(std::make_shared()); column_holder[i - 1] = castColumn(arguments[i], array_type); column_ptrs[i] = column_holder[i-1].get(); } else { column_ptrs[i] = arguments[i].column.get(); } is_column_const[i] = isColumnConst(*column_ptrs[i]); } if (is_column_const[0]) { col_agg_func = typeid_cast(typeid_cast(column_ptrs[0])->getDataColumnPtr().get()); } else { col_agg_func = typeid_cast(column_ptrs[0]); } container0 = &col_agg_func->getData(); if (is_column_const[1]) array1 = typeid_cast(typeid_cast(column_ptrs[1])->getDataColumnPtr().get()); else array1 = typeid_cast(column_ptrs[1]); const ColumnArray::Offsets & from_offsets = array1->getOffsets(); const ColumnVector::Container & from_container = typeid_cast *>(&array1->getData())->getData(); if (is_column_const[2]) array2 = typeid_cast(typeid_cast(column_ptrs[2])->getDataColumnPtr().get()); else array2 = typeid_cast(column_ptrs[2]); const ColumnArray::Offsets & to_offsets = array2->getOffsets(); const ColumnVector::Container & to_container = typeid_cast *>(&array2->getData())->getData(); auto col_to = ColumnAggregateFunction::create(col_agg_func->getAggregateFunction()); col_to->reserve(input_rows_count); size_t from_start; size_t from_end; size_t to_start; size_t to_end; for (size_t i = 0; i < input_rows_count; ++i) { AggregateDataPtr data_ptr_0 = is_column_const[0] ? (*container0)[0] : (*container0)[i]; const AggregateFunctionGroupBitmapData & bitmap_data_0 = *reinterpret_cast *>(data_ptr_0); if (is_column_const[1]) { from_start = 0; from_end = from_container.size(); } else { from_start = i == 0 ? 0 : from_offsets[i - 1]; from_end = from_offsets[i]; } if (is_column_const[2]) { to_start = 0; to_end = to_container.size(); } else { to_start = i == 0 ? 0 : to_offsets[i - 1]; to_end = to_offsets[i]; } if (from_end - from_start != to_end - to_start) throw Exception("From array size and to array size mismatch", ErrorCodes::LOGICAL_ERROR); col_to->insertDefault(); AggregateFunctionGroupBitmapData & bitmap_data_2 = *reinterpret_cast *>(col_to->getData()[i]); bitmap_data_2.rbs.merge(bitmap_data_0.rbs); bitmap_data_2.rbs.rb_replace(&from_container[from_start], &to_container[to_start], from_end - from_start); } return col_to; } }; template class FunctionBitmapSelfCardinalityImpl : public IFunction { public: static constexpr auto name = Impl::name; static FunctionPtr create(ContextPtr) { return std::make_shared>(); } String getName() const override { return name; } bool isVariadic() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } size_t getNumberOfArguments() const override { return 1; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { const auto * bitmap_type = typeid_cast(arguments[0].get()); if (!(bitmap_type && bitmap_type->getFunctionName() == "groupBitmap")) throw Exception( "First argument for function " + getName() + " must be a bitmap but it has type " + arguments[0]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return std::make_shared>(); } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { auto col_to = ColumnVector::create(input_rows_count); typename ColumnVector::Container & vec_to = col_to->getData(); const IDataType * from_type = arguments[0].type.get(); const DataTypeAggregateFunction * aggr_type = typeid_cast(from_type); WhichDataType which(aggr_type->getArgumentsDataTypes()[0]); if (which.isUInt8()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isUInt16()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isUInt32()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isUInt64()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt8()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt16()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt32()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt64()) executeIntType(arguments, input_rows_count, vec_to); else throw Exception( "Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return col_to; } private: using ToType = UInt64; template void executeIntType( const ColumnsWithTypeAndName & arguments, size_t input_rows_count, typename ColumnVector::Container & vec_to) const { const ColumnAggregateFunction * column = typeid_cast(arguments[0].column.get()); for (size_t i = 0; i < input_rows_count; ++i) { const AggregateFunctionGroupBitmapData & bitmap_data = *reinterpret_cast *>(column->getData()[i]); vec_to[i] = Impl::apply(bitmap_data); } } }; struct BitmapCardinalityImpl { public: static constexpr auto name = "bitmapCardinality"; template static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data) { return bitmap_data.rbs.size(); } }; struct BitmapMinImpl { public: static constexpr auto name = "bitmapMin"; template static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data) { return bitmap_data.rbs.rb_min(); } }; struct BitmapMaxImpl { public: static constexpr auto name = "bitmapMax"; template static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data) { return bitmap_data.rbs.rb_max(); } }; template struct BitmapAndCardinalityImpl { using ReturnType = UInt64; static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data_1, const AggregateFunctionGroupBitmapData & bitmap_data_2) { // roaring_bitmap_and_cardinality( rb1, rb2 ); return bitmap_data_1.rbs.rb_and_cardinality(bitmap_data_2.rbs); } }; template struct BitmapOrCardinalityImpl { using ReturnType = UInt64; static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data_1, const AggregateFunctionGroupBitmapData & bitmap_data_2) { // return roaring_bitmap_or_cardinality( rb1, rb2 ); return bitmap_data_1.rbs.rb_or_cardinality(bitmap_data_2.rbs); } }; template struct BitmapXorCardinalityImpl { using ReturnType = UInt64; static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data_1, const AggregateFunctionGroupBitmapData & bitmap_data_2) { // return roaring_bitmap_xor_cardinality( rb1, rb2 ); return bitmap_data_1.rbs.rb_xor_cardinality(bitmap_data_2.rbs); } }; template struct BitmapAndnotCardinalityImpl { using ReturnType = UInt64; static UInt64 apply(const AggregateFunctionGroupBitmapData & bitmap_data_1, const AggregateFunctionGroupBitmapData & bitmap_data_2) { // roaring_bitmap_andnot_cardinality( rb1, rb2 ); return bitmap_data_1.rbs.rb_andnot_cardinality(bitmap_data_2.rbs); } }; template struct BitmapHasAllImpl { using ReturnType = UInt8; static UInt8 apply(const AggregateFunctionGroupBitmapData & bitmap_data_1, const AggregateFunctionGroupBitmapData & bitmap_data_2) { return bitmap_data_1.rbs.rb_is_subset(bitmap_data_2.rbs); } }; template struct BitmapHasAnyImpl { using ReturnType = UInt8; static UInt8 apply(const AggregateFunctionGroupBitmapData & bitmap_data_1, const AggregateFunctionGroupBitmapData & bitmap_data_2) { return bitmap_data_1.rbs.rb_intersect(bitmap_data_2.rbs); } }; class FunctionBitmapContains : public IFunction { public: static constexpr auto name = "bitmapContains"; static FunctionPtr create(ContextPtr) { return std::make_shared(); } String getName() const override { return name; } bool isVariadic() const override { return false; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } size_t getNumberOfArguments() const override { return 2; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { const auto * bitmap_type0 = typeid_cast(arguments[0].get()); if (!(bitmap_type0 && bitmap_type0->getFunctionName() == "groupBitmap")) throw Exception( "First argument for function " + getName() + " must be a bitmap but it has type " + arguments[0]->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); WhichDataType which(arguments[1].get()); if (!which.isNativeInt() && !which.isNativeUInt()) throw Exception( "Second argument for function " + getName() + " must be an native integer type but it has type " + arguments[1]->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return std::make_shared>(); } bool useDefaultImplementationForConstants() const override { return true; } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { auto col_to = ColumnVector::create(input_rows_count); typename ColumnVector::Container & vec_to = col_to->getData(); const IDataType * from_type = arguments[0].type.get(); const DataTypeAggregateFunction * aggr_type = typeid_cast(from_type); WhichDataType which(aggr_type->getArgumentsDataTypes()[0]); if (which.isUInt8()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isUInt16()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isUInt32()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isUInt64()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt8()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt16()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt32()) executeIntType(arguments, input_rows_count, vec_to); else if (which.isInt64()) executeIntType(arguments, input_rows_count, vec_to); else throw Exception( "Unexpected type " + from_type->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); return col_to; } private: template void executeIntType( const ColumnsWithTypeAndName & arguments, size_t input_rows_count, typename ColumnVector::Container & vec_to) const { const IColumn * column_ptrs[2]; bool is_column_const[2]; const PaddedPODArray * container0; const PaddedPODArray * container1; column_ptrs[0] = arguments[0].column.get(); is_column_const[0] = isColumnConst(*column_ptrs[0]); if (is_column_const[0]) container0 = &typeid_cast(typeid_cast(column_ptrs[0])->getDataColumnPtr().get())->getData(); else container0 = &typeid_cast(column_ptrs[0])->getData(); // we can always cast the second column to ColumnUInt64 auto uint64_column = castColumn(arguments[1], std::make_shared()); column_ptrs[1] = uint64_column.get(); is_column_const[1] = isColumnConst(*column_ptrs[1]); if (is_column_const[1]) container1 = &typeid_cast(typeid_cast(column_ptrs[1])->getDataColumnPtr().get())->getData(); else container1 = &typeid_cast(column_ptrs[1])->getData(); for (size_t i = 0; i < input_rows_count; ++i) { AggregateDataPtr data_ptr_0 = is_column_const[0] ? (*container0)[0] : (*container0)[i]; const UInt64 data1 = is_column_const[1] ? (*container1)[0] : (*container1)[i]; const AggregateFunctionGroupBitmapData & bitmap_data_0 = *reinterpret_cast *>(data_ptr_0); vec_to[i] = bitmap_data_0.rbs.rb_contains(data1); } } }; template