From 95fb61f37909d296898de0bdd20eabe192659870 Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Mon, 18 Nov 2024 15:05:56 +0800 Subject: [PATCH 1/2] This is an automated cherry-pick of #9615 Signed-off-by: ti-chi-bot --- dbms/src/Functions/FunctionsStringReplace.h | 365 ++++++++++++++++++ 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, 521 insertions(+), 24 deletions(-) create mode 100644 dbms/src/Functions/FunctionsStringReplace.h create mode 100644 tests/fullstack-test/expr/replace.test diff --git a/dbms/src/Functions/FunctionsStringReplace.h b/dbms/src/Functions/FunctionsStringReplace.h new file mode 100644 index 00000000000..5583239c027 --- /dev/null +++ b/dbms/src/Functions/FunctionsStringReplace.h @@ -0,0 +1,365 @@ +// Copyright 2023 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. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DB +{ + +namespace ErrorCodes +{ +extern const int ILLEGAL_COLUMN; +} // namespace ErrorCodes + +template +class FunctionStringReplace : 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 3; } + + bool isVariadic() const override { return false; } + bool useDefaultImplementationForConstants() const override { return true; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!arguments[0]->isStringOrFixedString()) + throw Exception( + "Illegal type " + arguments[0]->getName() + " of first argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (!arguments[1]->isStringOrFixedString()) + throw Exception( + "Illegal type " + arguments[1]->getName() + " of second argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + if (!arguments[2]->isStringOrFixedString()) + throw Exception( + "Illegal type " + arguments[2]->getName() + " of third argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result) const override + { + ColumnPtr column_src = block.getByPosition(arguments[0]).column; + ColumnPtr column_needle = block.getByPosition(arguments[1]).column; + ColumnPtr column_replacement = block.getByPosition(arguments[2]).column; + + ColumnWithTypeAndName & column_result = block.getByPosition(result); + + bool needle_const = column_needle->isColumnConst(); + bool replacement_const = column_replacement->isColumnConst(); + + 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, column_result); + } + else if (needle_const) + { + 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); + } + } + +private: + void executeImpl( + const ColumnPtr & column_src, + const ColumnPtr & column_needle, + const ColumnPtr & column_replacement, + ColumnWithTypeAndName & column_result) const + { + const auto * c1_const = typeid_cast(column_needle.get()); + const auto * c2_const = typeid_cast(column_replacement.get()); + auto needle = c1_const->getValue(); + auto replacement = c2_const->getValue(); + + if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vector( + col->getChars(), + col->getOffsets(), + needle, + replacement, + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorFixed( + col->getChars(), + col->getN(), + needle, + replacement, + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else + throw Exception( + "Illegal column " + column_src->getName() + " of first argument of function " + getName(), + 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, + ColumnWithTypeAndName & column_result) const + { + if constexpr (Impl::support_non_const_needle) + { + const auto * col_needle = typeid_cast(column_needle.get()); + const auto * col_replacement_const = typeid_cast(column_replacement.get()); + auto replacement = col_replacement_const->getValue(); + + if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorNonConstNeedle( + col->getChars(), + col->getOffsets(), + col_needle->getChars(), + col_needle->getOffsets(), + replacement, + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorFixedNonConstNeedle( + col->getChars(), + col->getN(), + col_needle->getChars(), + col_needle->getOffsets(), + replacement, + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else + throw Exception( + "Illegal column " + column_src->getName() + " of first argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + else + { + throw Exception("Argument at index 2 for function replace must be constant", ErrorCodes::ILLEGAL_COLUMN); + } + } + + void executeImplNonConstReplacement( + const ColumnPtr & column_src, + const ColumnPtr & column_needle, + const ColumnPtr & column_replacement, + ColumnWithTypeAndName & column_result) const + { + if constexpr (Impl::support_non_const_replacement) + { + const auto * col_needle_const = typeid_cast(column_needle.get()); + auto needle = col_needle_const->getValue(); + const auto * col_replacement = typeid_cast(column_replacement.get()); + + if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorNonConstReplacement( + col->getChars(), + col->getOffsets(), + needle, + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorFixedNonConstReplacement( + col->getChars(), + col->getN(), + needle, + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else + throw Exception( + "Illegal column " + column_src->getName() + " of first argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + else + { + throw Exception("Argument at index 3 for function replace must be constant", ErrorCodes::ILLEGAL_COLUMN); + } + } + + void executeImplNonConstNeedleReplacement( + const ColumnPtr & column_src, + const ColumnPtr & column_needle, + const ColumnPtr & column_replacement, + ColumnWithTypeAndName & column_result) const + { + if constexpr (Impl::support_non_const_needle && Impl::support_non_const_replacement) + { + const auto * col_needle = typeid_cast(column_needle.get()); + const auto * col_replacement = typeid_cast(column_replacement.get()); + + if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorNonConstNeedleReplacement( + col->getChars(), + col->getOffsets(), + col_needle->getChars(), + col_needle->getOffsets(), + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else if (const auto * col = checkAndGetColumn(column_src.get())) + { + auto col_res = ColumnString::create(); + Impl::vectorFixedNonConstNeedleReplacement( + col->getChars(), + col->getN(), + col_needle->getChars(), + col_needle->getOffsets(), + col_replacement->getChars(), + col_replacement->getOffsets(), + col_res->getChars(), + col_res->getOffsets()); + column_result.column = std::move(col_res); + } + else + throw Exception( + "Illegal column " + column_src->getName() + " of first argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } + else + { + throw Exception( + "Argument at index 2 and 3 for function replace must be constant", + ErrorCodes::ILLEGAL_COLUMN); + } + } +}; +} // namespace DB diff --git a/dbms/src/Functions/FunctionsStringSearch.cpp b/dbms/src/Functions/FunctionsStringSearch.cpp index e557efca3d4..fc7c0df9fd6 100644 --- a/dbms/src/Functions/FunctionsStringSearch.cpp +++ b/dbms/src/Functions/FunctionsStringSearch.cpp @@ -1097,6 +1097,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, @@ -1107,6 +1108,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; @@ -1189,10 +1199,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) { @@ -1263,10 +1269,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) { @@ -1355,10 +1357,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) { @@ -1426,6 +1424,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, @@ -1436,6 +1435,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; @@ -1528,10 +1536,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) { @@ -1603,10 +1607,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) { @@ -1705,10 +1705,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) { @@ -1778,7 +1774,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 From f59530093a9320460d2f2a3b69553097034408da Mon Sep 17 00:00:00 2001 From: guo-shaoge Date: Tue, 19 Nov 2024 11:44:02 +0800 Subject: [PATCH 2/2] fix Signed-off-by: guo-shaoge --- dbms/src/Functions/tests/gtest_strings_replace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Functions/tests/gtest_strings_replace.cpp b/dbms/src/Functions/tests/gtest_strings_replace.cpp index 9cc7cd60d8e..6f5eecd1555 100644 --- a/dbms/src/Functions/tests/gtest_strings_replace.cpp +++ b/dbms/src/Functions/tests/gtest_strings_replace.cpp @@ -236,7 +236,7 @@ try toVec({"你好世好", "你好好界", "你学世界", "习好世界"}), executeFunction( "replaceAll", - createConstColumn(3, "你好世界"), + createConstColumn(4, "你好世界"), toVec({"界", "世", "好", "你"}), toVec({"好", "好", "学", "习"}))); }