#include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int ILLEGAL_TYPE_OF_ARGUMENT; } class FunctionArrayHasAllAny : public IFunction { public: FunctionArrayHasAllAny(const Context & context_, bool all_, const char * name_) : context(context_), all(all_), name(name_) {} String getName() const override { return name; } bool isVariadic() const override { return false; } size_t getNumberOfArguments() const override { return 2; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { for (auto i : ext::range(0, arguments.size())) { auto array_type = typeid_cast(arguments[i].get()); if (!array_type) throw Exception("Argument " + std::to_string(i) + " for function " + getName() + " must be an array but it has type " + arguments[i]->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } return std::make_shared(); } void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override { size_t rows = input_rows_count; size_t num_args = arguments.size(); DataTypePtr common_type = nullptr; auto commonType = [&common_type, &block, &arguments]() { if (common_type == nullptr) { DataTypes data_types; data_types.reserve(arguments.size()); for (const auto & argument : arguments) data_types.push_back(block.getByPosition(argument).type); common_type = getLeastSupertype(data_types); } return common_type; }; Columns preprocessed_columns(num_args); for (size_t i = 0; i < num_args; ++i) { const auto & argument = block.getByPosition(arguments[i]); ColumnPtr preprocessed_column = argument.column; const auto argument_type = typeid_cast(argument.type.get()); const auto & nested_type = argument_type->getNestedType(); /// Converts Array(Nothing) or Array(Nullable(Nothing) to common type. Example: hasAll([Null, 1], [Null]) -> 1 if (typeid_cast(removeNullable(nested_type).get())) preprocessed_column = castColumn(argument, commonType(), context); preprocessed_columns[i] = std::move(preprocessed_column); } std::vector> sources; for (auto & argument_column : preprocessed_columns) { bool is_const = false; if (auto argument_column_const = typeid_cast(argument_column.get())) { is_const = true; argument_column = argument_column_const->getDataColumnPtr(); } if (auto argument_column_array = typeid_cast(argument_column.get())) sources.emplace_back(GatherUtils::createArraySource(*argument_column_array, is_const, rows)); else throw Exception{"Arguments for function " + getName() + " must be arrays.", ErrorCodes::LOGICAL_ERROR}; } auto result_column = ColumnUInt8::create(rows); auto result_column_ptr = typeid_cast(result_column.get()); GatherUtils::sliceHas(*sources[0], *sources[1], all, *result_column_ptr); block.getByPosition(result).column = std::move(result_column); } bool useDefaultImplementationForConstants() const override { return true; } private: const Context & context; bool all; const char * name; }; }