#include #include #include #include #include #include #include namespace DB { using namespace GatherUtils; namespace ErrorCodes { extern const int ILLEGAL_COLUMN; extern const int ILLEGAL_TYPE_OF_ARGUMENT; } struct NameStartsWith { static constexpr auto name = "startsWith"; }; struct NameEndsWith { static constexpr auto name = "endsWith"; }; template class FunctionStartsEndsWith : public IFunction { public: static constexpr auto name = Name::name; static FunctionPtr create(const Context &) { return std::make_shared(); } String getName() const override { return name; } size_t getNumberOfArguments() const override { return 2; } bool useDefaultImplementationForConstants() const override { return true; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { if (!isStringOrFixedString(arguments[0])) throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); if (!isStringOrFixedString(arguments[1])) throw Exception("Illegal type " + arguments[1]->getName() + " of argument of function " + 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 { const IColumn * haystack_column = block.getByPosition(arguments[0]).column.get(); const IColumn * needle_column = block.getByPosition(arguments[1]).column.get(); auto col_res = ColumnVector::create(); typename ColumnVector::Container & vec_res = col_res->getData(); vec_res.resize(input_rows_count); if (const ColumnString * haystack = checkAndGetColumn(haystack_column)) dispatch(StringSource(*haystack), needle_column, vec_res); else if (const ColumnFixedString * haystack = checkAndGetColumn(haystack_column)) dispatch(FixedStringSource(*haystack), needle_column, vec_res); else if (const ColumnConst * haystack = checkAndGetColumnConst(haystack_column)) dispatch>(ConstSource(*haystack), needle_column, vec_res); else if (const ColumnConst * haystack = checkAndGetColumnConst(haystack_column)) dispatch>(ConstSource(*haystack), needle_column, vec_res); else throw Exception("Illegal combination of columns as arguments of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); block.getByPosition(result).column = std::move(col_res); } private: template void dispatch(HaystackSource haystack_source, const IColumn * needle_column, PaddedPODArray & res_data) const { if (const ColumnString * needle = checkAndGetColumn(needle_column)) execute(haystack_source, StringSource(*needle), res_data); else if (const ColumnFixedString * needle = checkAndGetColumn(needle_column)) execute(haystack_source, FixedStringSource(*needle), res_data); else if (const ColumnConst * needle = checkAndGetColumnConst(needle_column)) execute>(haystack_source, ConstSource(*needle), res_data); else if (const ColumnConst * needle = checkAndGetColumnConst(needle_column)) execute>(haystack_source, ConstSource(*needle), res_data); else throw Exception("Illegal combination of columns as arguments of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); } template static void execute(HaystackSource haystack_source, NeedleSource needle_source, PaddedPODArray & res_data) { size_t row_num = 0; while (!haystack_source.isEnd()) { auto haystack = haystack_source.getWhole(); auto needle = needle_source.getWhole(); if (needle.size > haystack.size) { res_data[row_num] = false; } else { if constexpr (std::is_same_v) { res_data[row_num] = StringRef(haystack.data, needle.size) == StringRef(needle.data, needle.size); } else /// endsWith { res_data[row_num] = StringRef(haystack.data + haystack.size - needle.size, needle.size) == StringRef(needle.data, needle.size); } } haystack_source.next(); needle_source.next(); ++row_num; } } }; }