diff --git a/dbms/src/Functions/FunctionsStringReplace.h b/dbms/src/Functions/FunctionsStringReplace.h index 604c2479bb0..9ef7987fcd1 100644 --- a/dbms/src/Functions/FunctionsStringReplace.h +++ b/dbms/src/Functions/FunctionsStringReplace.h @@ -122,10 +122,16 @@ class FunctionStringReplace : public IFunction ColumnWithTypeAndName & column_result = block.getByPosition(result); + bool src_const = column_src->isColumnConst(); bool needle_const = column_needle->isColumnConst(); bool replacement_const = column_replacement->isColumnConst(); - if (needle_const && replacement_const) + if (src_const) + { + // Rare cases + executeFallbackImpl(column_src, column_needle, column_replacement, pos, occ, match_type, column_result); + } + else if (needle_const && replacement_const) { executeImpl(column_src, column_needle, column_replacement, pos, occ, match_type, column_result); } @@ -165,6 +171,34 @@ class FunctionStringReplace : public IFunction } private: + // No vectorized acceleration. Just a general enough implementation suitable + // for all kind of input columns. + void executeFallbackImpl( + const ColumnPtr & column_src, + const ColumnPtr & column_needle, + const ColumnPtr & column_replacement, + Int64 pos, + Int64 occ, + const String & match_type, + ColumnWithTypeAndName & column_result) const + { + auto col_res = ColumnString::create(); + col_res->reserve(column_src->size()); + + for (size_t i = 0; i < column_src->size(); ++i) + { + String result; + const auto data = column_src->getDataAt(i).toStringView(); + const auto needle = column_needle->getDataAt(i).toStringView(); + const auto replacement = column_replacement->getDataAt(i).toStringView(); + Impl::constant(data, needle, replacement, pos, occ, match_type, collator, result); + + col_res->insertData(result.data(), result.size()); + } + + column_result.column = std::move(col_res); + } + void executeImpl( const ColumnPtr & column_src, const ColumnPtr & column_needle, diff --git a/dbms/src/Functions/FunctionsStringSearch.cpp b/dbms/src/Functions/FunctionsStringSearch.cpp index 5b5318bcc30..e994611947d 100644 --- a/dbms/src/Functions/FunctionsStringSearch.cpp +++ b/dbms/src/Functions/FunctionsStringSearch.cpp @@ -1495,9 +1495,9 @@ struct ReplaceStringImpl } static void constant( - const std::string & data, - const std::string & needle, - const std::string & replacement, + const std::string_view data, + const std::string_view needle, + const std::string_view replacement, const Int64 & /* pos */, const Int64 & /* occ */, const std::string & /* match_type */, diff --git a/dbms/src/Functions/tests/gtest_strings_replace.cpp b/dbms/src/Functions/tests/gtest_strings_replace.cpp index 4615d634e5f..f68861ff911 100644 --- a/dbms/src/Functions/tests/gtest_strings_replace.cpp +++ b/dbms/src/Functions/tests/gtest_strings_replace.cpp @@ -43,7 +43,10 @@ class StringReplace : public DB::tests::FunctionTest return createColumn>(v); } - ColumnWithTypeAndName toConst(const String & s) { return createConstColumn>(1, s); } + ColumnWithTypeAndName toConst(const String & s, size_t size = 1) + { + return createConstColumn>(size, s); + } }; TEST_F(StringReplace, string_replace_all_unit_Test) @@ -104,6 +107,33 @@ try toVec({" hello ", " h e llo", "hello ", " ", "hello, world"}), toVec({" ", "h", "", "h", ","}), toVec({"", "x", "xx", " ", ","}))); + + /// const src replacement + ASSERT_COLUMN_EQ( + toVec({"Good Night", "Bad Afternoon", "Good Afterwhile"}), + executeFunction( + "replaceAll", + toConst("Good Afternoon", 3), + toVec({"Afternoon", "Good", "noon"}), + toVec({"Night", "Bad", "while"}))); + + /// const src and needle replacement + ASSERT_COLUMN_EQ( + toVec({"Good Night", "Good Bad", "Good while"}), + executeFunction( + "replaceAll", + toConst("Good Afternoon", 3), + toConst("Afternoon", 3), + toVec({"Night", "Bad", "while"}))); + + /// const src and replace replacement + ASSERT_COLUMN_EQ( + toVec({"Good Night", "Night Afternoon", "Good AfterNight"}), + executeFunction( + "replaceAll", + toConst("Good Afternoon", 3), + toVec({"Afternoon", "Good", "noon"}), + toConst("Night", 3))); } CATCH