#pragma once #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; } enum class LeastGreatest { Least, Greatest }; template class FunctionLeastGreatestGeneric : public IFunction { public: static constexpr auto name = kind == LeastGreatest::Least ? "least" : "greatest"; static FunctionPtr create(const Context &) { return std::make_shared>(); } private: String getName() const override { return name; } size_t getNumberOfArguments() const override { return 0; } bool isVariadic() const override { return true; } bool useDefaultImplementationForConstants() const override { return true; } DataTypePtr getReturnTypeImpl(const DataTypes & types) const override { if (types.empty()) throw Exception("Function " + getName() + " cannot be called without arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); return getLeastSupertype(types); } void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override { size_t num_arguments = arguments.size(); if (1 == num_arguments) { block.getByPosition(result).column = block.getByPosition(arguments[0]).column; return; } auto result_type = block.getByPosition(result).type; Columns converted_columns(num_arguments); for (size_t arg = 0; arg < num_arguments; ++arg) converted_columns[arg] = castColumn(block.getByPosition(arguments[arg]), result_type)->convertToFullColumnIfConst(); auto result_column = result_type->createColumn(); result_column->reserve(input_rows_count); for (size_t row_num = 0; row_num < input_rows_count; ++row_num) { size_t best_arg = 0; for (size_t arg = 1; arg < num_arguments; ++arg) { auto cmp_result = converted_columns[arg]->compareAt(row_num, row_num, *converted_columns[best_arg], 1); if constexpr (kind == LeastGreatest::Least) { if (cmp_result < 0) best_arg = arg; } else { if (cmp_result > 0) best_arg = arg; } } result_column->insertFrom(*converted_columns[best_arg], row_num); } block.getByPosition(result).column = std::move(result_column); } }; template class LeastGreatestOverloadResolver : public IFunctionOverloadResolverImpl { public: static constexpr auto name = kind == LeastGreatest::Least ? "least" : "greatest"; static FunctionOverloadResolverImplPtr create(const Context & context) { return std::make_unique>(context); } explicit LeastGreatestOverloadResolver(const Context & context_) : context(context_) {} String getName() const override { return name; } size_t getNumberOfArguments() const override { return 0; } bool isVariadic() const override { return true; } FunctionBaseImplPtr build(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type) const override { DataTypes argument_types; /// More efficient specialization for two numeric arguments. if (arguments.size() == 2 && isNumber(arguments[0].type) && isNumber(arguments[1].type)) return std::make_unique(SpecializedFunction::create(context), argument_types, return_type); return std::make_unique( FunctionLeastGreatestGeneric::create(context), argument_types, return_type); } DataTypePtr getReturnType(const DataTypes & types) const override { if (types.empty()) throw Exception("Function " + getName() + " cannot be called without arguments", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH); return getLeastSupertype(types); } private: const Context & context; }; }