Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

functions: Fix replace not working for const src #9536

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion dbms/src/Functions/FunctionsStringReplace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions dbms/src/Functions/FunctionsStringSearch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */,
Expand Down
32 changes: 31 additions & 1 deletion dbms/src/Functions/tests/gtest_strings_replace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ class StringReplace : public DB::tests::FunctionTest
return createColumn<Nullable<String>>(v);
}

ColumnWithTypeAndName toConst(const String & s) { return createConstColumn<Nullable<String>>(1, s); }
ColumnWithTypeAndName toConst(const String & s, size_t size = 1)
{
return createConstColumn<Nullable<String>>(size, s);
}
};

TEST_F(StringReplace, string_replace_all_unit_Test)
Expand Down Expand Up @@ -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

Expand Down