#pragma once #include #include #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"; }; DECLARE_MULTITARGET_CODE( template class FunctionStartsEndsWith : public IFunction { public: static constexpr auto name = Name::name; 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(); } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override { const IColumn * haystack_column = arguments[0].column.get(); const IColumn * needle_column = 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_fixed = checkAndGetColumn(haystack_column)) dispatch(FixedStringSource(*haystack_fixed), needle_column, vec_res); else if (const ColumnConst * haystack_const = checkAndGetColumnConst(haystack_column)) dispatch>(ConstSource(*haystack_const), needle_column, vec_res); else if (const ColumnConst * haystack_const_fixed = checkAndGetColumnConst(haystack_column)) dispatch>(ConstSource(*haystack_const_fixed), needle_column, vec_res); else throw Exception("Illegal combination of columns as arguments of function " + getName(), ErrorCodes::ILLEGAL_COLUMN); return 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_fixed = checkAndGetColumn(needle_column)) execute(haystack_source, FixedStringSource(*needle_fixed), res_data); else if (const ColumnConst * needle_const = checkAndGetColumnConst(needle_column)) execute>(haystack_source, ConstSource(*needle_const), res_data); else if (const ColumnConst * needle_const_fixed = checkAndGetColumnConst(needle_column)) execute>(haystack_source, ConstSource(*needle_const_fixed), 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; } } }; ) // DECLARE_MULTITARGET_CODE template class FunctionStartsEndsWith : public TargetSpecific::Default::FunctionStartsEndsWith { public: explicit FunctionStartsEndsWith(ContextPtr context) : selector(context) { selector.registerImplementation>(); #if USE_MULTITARGET_CODE selector.registerImplementation>(); selector.registerImplementation>(); selector.registerImplementation>(); selector.registerImplementation>(); #endif } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override { return selector.selectAndExecute(arguments, result_type, input_rows_count); } static FunctionPtr create(ContextPtr context) { return std::make_shared>(context); } private: ImplementationSelector selector; }; }