#pragma once #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 FunctionArrayPush : public IFunction { public: FunctionArrayPush(bool push_front_, const char * name_) : push_front(push_front_), name(name_) {} String getName() const override { return name; } bool isVariadic() const override { return false; } size_t getNumberOfArguments() const override { return 2; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } 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(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "First argument for function {} must be an array but it has type {}.", getName(), arguments[0]->getName()); auto nested_type = array_type->getNestedType(); DataTypes types = {nested_type, arguments[1]}; return std::make_shared(getLeastSupertype(types)); } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type, size_t input_rows_count) const override { if (return_type->onlyNull()) return return_type->createColumnConstWithDefaultValue(input_rows_count); auto result_column = return_type->createColumn(); auto array_column = arguments[0].column; auto appended_column = arguments[1].column; if (!arguments[0].type->equals(*return_type)) array_column = castColumn(arguments[0], return_type); const DataTypePtr & return_nested_type = typeid_cast(*return_type).getNestedType(); if (!arguments[1].type->equals(*return_nested_type)) appended_column = castColumn(arguments[1], return_nested_type); std::unique_ptr array_source; std::unique_ptr value_source; size_t size = array_column->size(); bool is_const = false; if (const auto * const_array_column = typeid_cast(array_column.get())) { is_const = true; array_column = const_array_column->getDataColumnPtr(); } if (const auto * argument_column_array = typeid_cast(array_column.get())) array_source = GatherUtils::createArraySource(*argument_column_array, is_const, size); else throw Exception(ErrorCodes::LOGICAL_ERROR, "First arguments for function {} must be array.", getName()); bool is_appended_const = false; if (const auto * const_appended_column = typeid_cast(appended_column.get())) { is_appended_const = true; appended_column = const_appended_column->getDataColumnPtr(); } value_source = GatherUtils::createValueSource(*appended_column, is_appended_const, size); auto sink = GatherUtils::createArraySink(typeid_cast(*result_column), size); GatherUtils::push(*array_source, *value_source, *sink, push_front); return result_column; } bool useDefaultImplementationForConstants() const override { return true; } bool useDefaultImplementationForNulls() const override { return false; } private: bool push_front; const char * name; }; }