From 046e76b166174ac5867358b3b71b8b10ae3bb8ff Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Mon, 18 Nov 2024 15:05:56 +0800 Subject: [PATCH] This is an automated cherry-pick of #9615 Signed-off-by: ti-chi-bot --- dbms/src/Functions/FunctionsStringReplace.h | 228 +++++++++++++++--- dbms/src/Functions/FunctionsStringSearch.cpp | 52 ++-- dbms/src/Functions/GatherUtils/Algorithms.h | 26 ++ .../Functions/tests/gtest_strings_replace.cpp | 62 +++++ tests/fullstack-test/expr/replace.test | 40 +++ 5 files changed, 347 insertions(+), 61 deletions(-) create mode 100644 tests/fullstack-test/expr/replace.test diff --git a/dbms/src/Functions/FunctionsStringReplace.h b/dbms/src/Functions/FunctionsStringReplace.h index 352c5dd7bfe..6de4c7e5f83 100644 --- a/dbms/src/Functions/FunctionsStringReplace.h +++ b/dbms/src/Functions/FunctionsStringReplace.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include namespace DB @@ -47,33 +49,17 @@ class FunctionStringReplace : public IFunction return name; } +<<<<<<< HEAD size_t getNumberOfArguments() const override { return 0; } +======= + size_t getNumberOfArguments() const override { return 3; } +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) - bool isVariadic() const override { return true; } + bool isVariadic() const override { return false; } bool useDefaultImplementationForConstants() const override { return true; } - ColumnNumbers getArgumentsThatAreAlwaysConstant() const override - { - if constexpr (Impl::support_non_const_needle && Impl::support_non_const_replacement) - { - return {3, 4, 5}; - } - else if constexpr (Impl::support_non_const_needle) - { - return {2, 3, 4, 5}; - } - else if constexpr (Impl::support_non_const_replacement) - { - return {1, 3, 4, 5}; - } - else - { - return {1, 2, 3, 4, 5}; - } - } - void setCollator(const TiDB::TiDBCollatorPtr & collator_) override { collator = collator_; } DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { @@ -89,6 +75,7 @@ class FunctionStringReplace : public IFunction throw Exception("Illegal type " + arguments[2]->getName() + " of third argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); +<<<<<<< HEAD if (arguments.size() > 3 && !arguments[3]->isInteger()) throw Exception("Illegal type " + arguments[2]->getName() + " of forth argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); @@ -101,11 +88,14 @@ class FunctionStringReplace : public IFunction throw Exception("Illegal type " + arguments[2]->getName() + " of sixth argument of function " + getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); +======= +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) return std::make_shared(); } void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) const override { +<<<<<<< HEAD const ColumnPtr & column_src = block.getByPosition(arguments[0]).column; const ColumnPtr & column_needle = block.getByPosition(arguments[1]).column; const ColumnPtr & column_replacement = block.getByPosition(arguments[2]).column; @@ -120,18 +110,34 @@ class FunctionStringReplace : public IFunction Int64 pos = column_pos == nullptr ? 1 : typeid_cast(column_pos.get())->getInt(0); Int64 occ = column_occ == nullptr ? 0 : typeid_cast(column_occ.get())->getInt(0); String match_type = column_match_type == nullptr ? "" : typeid_cast(column_match_type.get())->getValue(); +======= + ColumnPtr column_src = block.getByPosition(arguments[0]).column; + ColumnPtr column_needle = block.getByPosition(arguments[1]).column; + ColumnPtr column_replacement = block.getByPosition(arguments[2]).column; +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) ColumnWithTypeAndName & column_result = block.getByPosition(result); bool needle_const = column_needle->isColumnConst(); bool replacement_const = column_replacement->isColumnConst(); - if (needle_const && replacement_const) + if (column_src->isColumnConst()) + { + executeImplConstHaystack( + column_src, + column_needle, + column_replacement, + needle_const, + replacement_const, + column_result); + } + else if (needle_const && replacement_const) { - executeImpl(column_src, column_needle, column_replacement, pos, occ, match_type, column_result); + executeImpl(column_src, column_needle, column_replacement, column_result); } else if (needle_const) { +<<<<<<< HEAD executeImplNonConstReplacement(column_src, column_needle, column_replacement, pos, occ, match_type, column_result); } else if (replacement_const) @@ -141,6 +147,17 @@ class FunctionStringReplace : public IFunction else { executeImplNonConstNeedleReplacement(column_src, column_needle, column_replacement, pos, occ, match_type, column_result); +======= + executeImplNonConstReplacement(column_src, column_needle, column_replacement, column_result); + } + else if (replacement_const) + { + executeImplNonConstNeedle(column_src, column_needle, column_replacement, column_result); + } + else + { + executeImplNonConstNeedleReplacement(column_src, column_needle, column_replacement, column_result); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) } } @@ -149,9 +166,6 @@ class FunctionStringReplace : public IFunction const ColumnPtr & column_src, const ColumnPtr & column_needle, const ColumnPtr & column_replacement, - Int64 pos, - Int64 occ, - const String & match_type, ColumnWithTypeAndName & column_result) const { const auto * c1_const = typeid_cast(column_needle.get()); @@ -162,13 +176,33 @@ class FunctionStringReplace : public IFunction if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vector(col->getChars(), col->getOffsets(), needle, replacement, pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vector( + col->getChars(), + col->getOffsets(), + needle, + replacement, + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorFixed(col->getChars(), col->getN(), needle, replacement, pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorFixed( + col->getChars(), + col->getN(), + needle, + replacement, + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else @@ -177,13 +211,73 @@ class FunctionStringReplace : public IFunction ErrorCodes::ILLEGAL_COLUMN); } + void executeImplConstHaystack( + const ColumnPtr & column_src, + const ColumnPtr & column_needle, + const ColumnPtr & column_replacement, + bool needle_const, + bool replacement_const, + ColumnWithTypeAndName & column_result) const + { + auto res_col = ColumnString::create(); + res_col->reserve(column_src->size()); + + RUNTIME_CHECK_MSG( + !needle_const || !replacement_const, + "should not got here when all argments of replace are constant"); + + const auto * column_src_const = checkAndGetColumnConst(column_src.get()); + RUNTIME_CHECK(column_src_const); + + using GatherUtils::ConstSource; + using GatherUtils::StringSource; + if (!needle_const && !replacement_const) + { + const auto * column_needle_string = checkAndGetColumn(column_needle.get()); + const auto * column_replacement_string = checkAndGetColumn(column_replacement.get()); + RUNTIME_CHECK(column_needle_string); + RUNTIME_CHECK(column_replacement_string); + + GatherUtils::replace( + ConstSource(*column_src_const), + StringSource(*column_needle_string), + StringSource(*column_replacement_string), + res_col); + } + else if (needle_const && !replacement_const) + { + const auto * column_needle_const = checkAndGetColumnConst(column_needle.get()); + const auto * column_replacement_string = checkAndGetColumn(column_replacement.get()); + RUNTIME_CHECK(column_needle_const); + RUNTIME_CHECK(column_replacement_string); + + GatherUtils::replace( + ConstSource(*column_src_const), + ConstSource(*column_needle_const), + StringSource(*column_replacement_string), + res_col); + } + else if (!needle_const && replacement_const) + { + const auto * column_needle_string = checkAndGetColumn(column_needle.get()); + const auto * column_replacement_const = checkAndGetColumnConst(column_replacement.get()); + RUNTIME_CHECK(column_needle_string); + RUNTIME_CHECK(column_replacement_const); + + GatherUtils::replace( + ConstSource(*column_src_const), + StringSource(*column_needle_string), + ConstSource(*column_replacement_const), + res_col); + } + + column_result.column = std::move(res_col); + } + void executeImplNonConstNeedle( const ColumnPtr & column_src, const ColumnPtr & column_needle, const ColumnPtr & column_replacement, - Int64 pos [[maybe_unused]], - Int64 occ [[maybe_unused]], - const String & match_type, ColumnWithTypeAndName & column_result) const { if constexpr (Impl::support_non_const_needle) @@ -195,13 +289,35 @@ class FunctionStringReplace : public IFunction if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorNonConstNeedle(col->getChars(), col->getOffsets(), col_needle->getChars(), col_needle->getOffsets(), replacement, pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorNonConstNeedle( + col->getChars(), + col->getOffsets(), + col_needle->getChars(), + col_needle->getOffsets(), + replacement, + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorFixedNonConstNeedle(col->getChars(), col->getN(), col_needle->getChars(), col_needle->getOffsets(), replacement, pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorFixedNonConstNeedle( + col->getChars(), + col->getN(), + col_needle->getChars(), + col_needle->getOffsets(), + replacement, + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else @@ -219,9 +335,6 @@ class FunctionStringReplace : public IFunction const ColumnPtr & column_src, const ColumnPtr & column_needle, const ColumnPtr & column_replacement, - Int64 pos [[maybe_unused]], - Int64 occ [[maybe_unused]], - const String & match_type, ColumnWithTypeAndName & column_result) const { if constexpr (Impl::support_non_const_replacement) @@ -233,13 +346,35 @@ class FunctionStringReplace : public IFunction if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorNonConstReplacement(col->getChars(), col->getOffsets(), needle, col_replacement->getChars(), col_replacement->getOffsets(), pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorNonConstReplacement( + col->getChars(), + col->getOffsets(), + needle, + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorFixedNonConstReplacement(col->getChars(), col->getN(), needle, col_replacement->getChars(), col_replacement->getOffsets(), pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorFixedNonConstReplacement( + col->getChars(), + col->getN(), + needle, + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else @@ -257,9 +392,6 @@ class FunctionStringReplace : public IFunction const ColumnPtr & column_src, const ColumnPtr & column_needle, const ColumnPtr & column_replacement, - Int64 pos [[maybe_unused]], - Int64 occ [[maybe_unused]], - const String & match_type, ColumnWithTypeAndName & column_result) const { if constexpr (Impl::support_non_const_needle && Impl::support_non_const_replacement) @@ -270,13 +402,37 @@ class FunctionStringReplace : public IFunction if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorNonConstNeedleReplacement(col->getChars(), col->getOffsets(), col_needle->getChars(), col_needle->getOffsets(), col_replacement->getChars(), col_replacement->getOffsets(), pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorNonConstNeedleReplacement( + col->getChars(), + col->getOffsets(), + col_needle->getChars(), + col_needle->getOffsets(), + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else if (const auto * col = checkAndGetColumn(column_src.get())) { auto col_res = ColumnString::create(); +<<<<<<< HEAD Impl::vectorFixedNonConstNeedleReplacement(col->getChars(), col->getN(), col_needle->getChars(), col_needle->getOffsets(), col_replacement->getChars(), col_replacement->getOffsets(), pos, occ, match_type, collator, col_res->getChars(), col_res->getOffsets()); +======= + Impl::vectorFixedNonConstNeedleReplacement( + col->getChars(), + col->getN(), + col_needle->getChars(), + col_needle->getOffsets(), + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) column_result.column = std::move(col_res); } else @@ -289,7 +445,5 @@ class FunctionStringReplace : public IFunction throw Exception("Argument at index 2 and 3 for function replace must be constant", ErrorCodes::ILLEGAL_COLUMN); } } - - TiDB::TiDBCollatorPtr collator{}; }; } // namespace DB diff --git a/dbms/src/Functions/FunctionsStringSearch.cpp b/dbms/src/Functions/FunctionsStringSearch.cpp index e15c3637b96..b5e60c79e61 100644 --- a/dbms/src/Functions/FunctionsStringSearch.cpp +++ b/dbms/src/Functions/FunctionsStringSearch.cpp @@ -780,6 +780,7 @@ struct ReplaceStringImpl /// support match type during the string search, used in regexp static const bool support_match_type = false; +<<<<<<< HEAD static void vector(const ColumnString::Chars_t & data, const ColumnString::Offsets & offsets, const std::string & needle, @@ -790,6 +791,15 @@ struct ReplaceStringImpl TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) +======= + static void vector( + const ColumnString::Chars_t & data, + const ColumnString::Offsets & offsets, + const std::string & needle, + const std::string & replacement, + ColumnString::Chars_t & res_data, + ColumnString::Offsets & res_offsets) +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) { const UInt8 * begin = &data[0]; const UInt8 * pos = begin; @@ -872,10 +882,6 @@ struct ReplaceStringImpl const ColumnString::Chars_t & needle_chars, const ColumnString::Offsets & needle_offsets, const std::string & replacement, - const Int64 & /* pos */, - const Int64 & /* occ */, - const std::string & /* match_type */, - TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) { @@ -946,10 +952,6 @@ struct ReplaceStringImpl const std::string & needle, const ColumnString::Chars_t & replacement_chars, const ColumnString::Offsets & replacement_offsets, - const Int64 & /* pos */, - const Int64 & /* occ */, - const std::string & /* match_type */, - TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) { @@ -1038,10 +1040,6 @@ struct ReplaceStringImpl const ColumnString::Offsets & needle_offsets, const ColumnString::Chars_t & replacement_chars, const ColumnString::Offsets & replacement_offsets, - const Int64 & /* pos */, - const Int64 & /* occ */, - const std::string & /* match_type */, - TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) { @@ -1109,6 +1107,7 @@ struct ReplaceStringImpl /// Note: this function converts fixed-length strings to variable-length strings /// and each variable-length string should ends with zero byte. +<<<<<<< HEAD static void vectorFixed(const ColumnString::Chars_t & data, size_t n, const std::string & needle, @@ -1119,6 +1118,15 @@ struct ReplaceStringImpl TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) +======= + static void vectorFixed( + const ColumnString::Chars_t & data, + size_t n, + const std::string & needle, + const std::string & replacement, + ColumnString::Chars_t & res_data, + ColumnString::Offsets & res_offsets) +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) { const UInt8 * begin = &data[0]; const UInt8 * pos = begin; @@ -1211,10 +1219,6 @@ struct ReplaceStringImpl const ColumnString::Chars_t & needle_chars, const ColumnString::Offsets & needle_offsets, const std::string & replacement, - const Int64 & /* pos */, - const Int64 & /* occ */, - const std::string & /* match_type */, - TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) { @@ -1286,10 +1290,6 @@ struct ReplaceStringImpl const std::string & needle, const ColumnString::Chars_t & replacement_chars, const ColumnString::Offsets & replacement_offsets, - const Int64 & /* pos */, - const Int64 & /* occ */, - const std::string & /* match_type */, - TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) { @@ -1388,10 +1388,6 @@ struct ReplaceStringImpl const ColumnString::Offsets & needle_offsets, const ColumnString::Chars_t & replacement_chars, const ColumnString::Offsets & replacement_offsets, - const Int64 & /* pos */, - const Int64 & /* occ */, - const std::string & /* match_type */, - TiDB::TiDBCollatorPtr /* collator */, ColumnString::Chars_t & res_data, ColumnString::Offsets & res_offsets) { @@ -1461,7 +1457,15 @@ struct ReplaceStringImpl } } +<<<<<<< HEAD static void constant(const std::string & data, const std::string & needle, const std::string & replacement, const Int64 & /* pos */, const Int64 & /* occ */, const std::string & /* match_type */, TiDB::TiDBCollatorPtr /* collator */, std::string & res_data) +======= + static void constant( + const std::string & data, + const std::string & needle, + const std::string & replacement, + std::string & res_data) +>>>>>>> 11ce13fffa (fix error when first argument of replace function is const (#9615)) { if (needle.empty()) { diff --git a/dbms/src/Functions/GatherUtils/Algorithms.h b/dbms/src/Functions/GatherUtils/Algorithms.h index 659238caa1c..b72801afb72 100644 --- a/dbms/src/Functions/GatherUtils/Algorithms.h +++ b/dbms/src/Functions/GatherUtils/Algorithms.h @@ -781,4 +781,30 @@ void resizeConstantSize(ArraySource && array_source, ValueSource && value_source } } +template +void replace( + HaystackSource && src_h, + NeedleSource && src_n, + ReplacementSource && src_r, + ColumnString::MutablePtr & res_col) +{ + while (!src_h.isEnd()) + { + const auto slice_h = src_h.getWhole(); + const auto slice_n = src_n.getWhole(); + const auto slice_r = src_r.getWhole(); + + const String str_h(reinterpret_cast(slice_h.data), slice_h.size); + const String str_n(reinterpret_cast(slice_n.data), slice_n.size); + const String str_r(reinterpret_cast(slice_r.data), slice_r.size); + String res; + Impl::constant(str_h, str_n, str_r, res); + res_col->insertData(res.data(), res.size()); + + src_h.next(); + src_n.next(); + src_r.next(); + } +} + } // namespace DB::GatherUtils diff --git a/dbms/src/Functions/tests/gtest_strings_replace.cpp b/dbms/src/Functions/tests/gtest_strings_replace.cpp index b9750e70070..9cc7cd60d8e 100644 --- a/dbms/src/Functions/tests/gtest_strings_replace.cpp +++ b/dbms/src/Functions/tests/gtest_strings_replace.cpp @@ -86,6 +86,13 @@ try toConst(""), toConst(" "))); + ASSERT_COLUMN_EQ( + createConstColumn(1, {" bc"}), + executeFunction("replaceAll", toConst("abc"), toConst("a"), toConst(" "))); + ASSERT_COLUMN_EQ( + createConstColumn(1, {""}), + executeFunction("replaceAll", toConst(""), toConst(""), toConst(" "))); + /// non-const needle and const replacement ASSERT_COLUMN_EQ( toVec({"hello", " e llo", "hello ", " ", "hello world"}), @@ -103,6 +110,14 @@ try toVec({" ", "w", "w", "www", " w"}), toConst("ww"))); + ASSERT_COLUMN_EQ( + toVec({" bc", "a c", "ab "}), + executeFunction( + "replaceAll", + createConstColumn(3, "abc"), + toVec({"a", "b", "c"}), + createConstColumn(3, " "))); + /// const needle and non-const replacement ASSERT_COLUMN_EQ( toVec({"hello", "xxxhxexllo", "helloxxxxxxxx", " ", "hello,,world"}), @@ -112,6 +127,14 @@ try toConst(" "), toVec({"", "x", "xx", " ", ","}))); + ASSERT_COLUMN_EQ( + toVec({"123", "456", "789"}), + executeFunction( + "replaceAll", + createConstColumn(3, "abc"), + createConstColumn(3, "abc"), + toVec({"123", "456", "789"}))); + /// non-const needle and non-const replacement ASSERT_COLUMN_EQ( toVec({"hello", " x e llo", "hello ", " ", "hello, world"}), @@ -120,6 +143,14 @@ try toVec({" hello ", " h e llo", "hello ", " ", "hello, world"}), toVec({" ", "h", "", "h", ","}), toVec({"", "x", "xx", " ", ","}))); + + ASSERT_COLUMN_EQ( + toVec({"1bc", "a2c", "ab3"}), + executeFunction( + "replaceAll", + createConstColumn(3, "abc"), + toVec({"a", "b", "c"}), + toVec({"1", "2", "3"}))); } CATCH @@ -143,6 +174,13 @@ try toConst("你"), toConst("您"))); + ASSERT_COLUMN_EQ( + createConstColumn(1, {"你你世界"}), + executeFunction("replaceAll", toConst("你好世界"), toConst("好"), toConst("你"))); + ASSERT_COLUMN_EQ( + createConstColumn(1, {" "}), + executeFunction("replaceAll", toConst("你好世界"), toConst("你好世界"), toConst(" "))); + /// non-const needle and const replacement ASSERT_COLUMN_EQ( toVec({" 你好 ", "你好", " ", "你 好 ", "你不好"}), @@ -160,6 +198,14 @@ try toVec({" ", " 你", "你好", " 你", "你好"}), toConst("x"))); + ASSERT_COLUMN_EQ( + toVec({" 好世界", "你好 界", "你 世界"}), + executeFunction( + "replaceAll", + createConstColumn(3, "你好世界"), + toVec({"你", "世", "好"}), + createConstColumn(3, " "))); + /// const needle and non-const replacement ASSERT_COLUMN_EQ( toVec({" 好 ", " 你 好", "你好好 你好好", " 你 好 ", "你好不好"}), @@ -169,6 +215,14 @@ try toConst("你"), toVec({"", " 你", "你好", " 你", "你好"}))); + ASSERT_COLUMN_EQ( + toVec({"你一二世界", "你天天世界", "你向上世界"}), + executeFunction( + "replaceAll", + createConstColumn(3, "你好世界"), + createConstColumn(3, "好"), + toVec({"一二", "天天", "向上"}))); + /// non-const needle and non-const replacement ASSERT_COLUMN_EQ( toVec({" 你好 ", " 你 你 你你 你好", "好 好", " 你好 ", "你不好"}), @@ -177,6 +231,14 @@ try toVec({" 你好 ", " 你 好", "你好 你好", "你 好 ", "你不好"}), toVec({"", " ", "你好", "你 ", "你好"}), toVec({" ", " 你", "好", " 你", "你好"}))); + + ASSERT_COLUMN_EQ( + toVec({"你好世好", "你好好界", "你学世界", "习好世界"}), + executeFunction( + "replaceAll", + createConstColumn(3, "你好世界"), + toVec({"界", "世", "好", "你"}), + toVec({"好", "好", "学", "习"}))); } CATCH diff --git a/tests/fullstack-test/expr/replace.test b/tests/fullstack-test/expr/replace.test new file mode 100644 index 00000000000..1f5c7f8a9c8 --- /dev/null +++ b/tests/fullstack-test/expr/replace.test @@ -0,0 +1,40 @@ +# Copyright 2024 PingCAP, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +mysql> drop table if exists test.t +mysql> create table test.t(c1 varchar(100), c2 varchar(100), c3 varchar(100)) +mysql> insert into test.t values('hello world', 'hello', '???') +mysql> alter table test.t set tiflash replica 1 +func> wait_table test t +mysql> set tidb_isolation_read_engines = 'tiflash'; set tidb_enforce_mpp=1; select replace(c1, c2, c3) from test.t +replace(c1, c2, c3) +??? world + +mysql> set tidb_isolation_read_engines = 'tiflash'; set tidb_enforce_mpp=1; select replace('hello world', c2, c3) from test.t +replace('hello world', c2, c3) +??? world + +mysql> set tidb_isolation_read_engines = 'tiflash'; set tidb_enforce_mpp=1; select replace('hello world', 'hello', '???') from test.t +replace('hello world', 'hello', '???') +??? world + +mysql> set tidb_isolation_read_engines = 'tiflash'; set tidb_enforce_mpp=1; select replace('hello world', c2, '???') from test.t +replace('hello world', c2, '???') +??? world + +mysql> set tidb_isolation_read_engines = 'tiflash'; set tidb_enforce_mpp=1; select replace('hello world', 'hello', c3) from test.t +replace('hello world', 'hello', c3) +??? world + +mysql> drop table if exists test.t