Skip to content
Merged
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
49 changes: 33 additions & 16 deletions dbms/src/TiDB/Collation/Collator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,44 +134,60 @@ template <typename Collator>
void Pattern<Collator>::tryCompileAsciiCi(const std::string & pattern, char escape)
{
is_ascii_ci_pattern = false;
const auto unsigned_escape = static_cast<unsigned char>(escape);
// Can't handle non-ASCII escape
if (escape < 0)
if (unsigned_escape >= weight_ascii_ci.size())
{
return;
}
ascii_ci_pattern.clear();
ascii_ci_pattern.reserve(pattern.length());

auto last_tp = MatchType::Match;
for (size_t i = 0; i < pattern.length(); i++)
{
auto c = pattern[i];
// Can't handle non-ASCII character
if (c < 0)
{
return;
}
auto c = static_cast<unsigned char>(pattern[i]);
MatchType tp;

if (c == escape)
if (c == unsigned_escape)
{
tp = MatchType::Match;
if (i < pattern.length() - 1)
{
// use next char to match
c = pattern[++i];
c = static_cast<unsigned char>(pattern[++i]);
}
else
{
// use `escape` to match
}
}
else if (c == '_')
{
tp = MatchType::One;
}
else if (c == '%')
{
if (i > 0 && pattern[i - 1] == '%')
// Only keep one '%' for continuous unescaped '%'s
if (last_tp == MatchType::Any)
{
continue;
}
tp = MatchType::Any;
}
else
{
tp = MatchType::Match;
}

// Can't handle non-ASCII characters
if (c >= weight_ascii_ci.size())
{
return;
}

ascii_ci_pattern.push_back(weight_ascii_ci[c]);
last_tp = tp;
}
is_ascii_ci_pattern = true;
}
Expand Down Expand Up @@ -300,12 +316,13 @@ int Pattern<Collator>::tryMatchAsciiCi(const char * s, size_t length) const
}
else
{
// Can't handle non-ASCII escape
if (s[str_idx] < 0)
// Can't handle non-ASCII characters
if (static_cast<unsigned char>(s[str_idx]) >= weight_ascii_ci.size())
{
return -1;
}
if ((match_types[p_idx] == Match && weight_ascii_ci[s[str_idx]] == ascii_ci_pattern[p_idx])
if ((match_types[p_idx] == Match
&& weight_ascii_ci[static_cast<unsigned char>(s[str_idx])] == ascii_ci_pattern[p_idx])
|| match_types[p_idx] == One)
{
p_idx++;
Expand Down Expand Up @@ -340,13 +357,13 @@ int Pattern<Collator>::tryMatchAsciiCi(const char * s, size_t length) const
{ // Fast forward to the first match position
while (str_idx < length)
{
// Can't handle non-ASCII escape
if (s[str_idx] < 0)
// Can't handle non-ASCII characters
if (static_cast<unsigned char>(s[str_idx]) >= weight_ascii_ci.size())
{
return -1;
}

if (weight_ascii_ci[s[str_idx]] != ascii_ci_pattern[p_idx_after_any])
if (weight_ascii_ci[static_cast<unsigned char>(s[str_idx])] != ascii_ci_pattern[p_idx_after_any])
{
str_idx = ++backtrack_idx;
}
Expand Down
43 changes: 43 additions & 0 deletions dbms/src/TiDB/tests/gtest_tidb_collator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ const typename CollatorCases::PatternCase CollatorCases::pattern_cases[] = {
{"中国", {false, false, false, false, false, false, false}},
{"中国中", {true, true, true, true, true, true, true}},
{"", {false, false, false, false, false, false, false}}}},
{"%报告%",
{{"报告", {true, true, true, true, true, true, true}},
{"测试报告完成", {true, true, true, true, true, true, true}},
{"报表", {false, false, false, false, false, false, false}},
{"", {false, false, false, false, false, false, false}}}},
{"A%",
{{"a", {false, false, true, false, true, true, false}},
{"aaa", {false, false, true, false, true, true, false}},
Expand Down Expand Up @@ -275,6 +280,44 @@ const typename CollatorCases::PatternCase CollatorCases::pattern_cases[] = {
{"1234567910", {true, true, true, true, true, true, true}},
},
},
{
"a\\%%b", // escaped '%' followed by wildcard '%'
{
{"a%b", {true, true, true, true, true, true, true}},
{"a%foob", {true, true, true, true, true, true, true}},
{"a%x", {false, false, false, false, false, false, false}},
{"afoob", {false, false, false, false, false, false, false}},
},
},
{
"a%%b", // test consecutive '%' deduplication - two '%'s
{
{"ab", {true, true, true, true, true, true, true}},
{"axb", {true, true, true, true, true, true, true}},
{"a123b", {true, true, true, true, true, true, true}},
{"a", {false, false, false, false, false, false, false}},
},
},
{
"a%%%b", // test consecutive '%' deduplication - three '%'s
{
{"ab", {true, true, true, true, true, true, true}},
{"axb", {true, true, true, true, true, true, true}},
{"a456b", {true, true, true, true, true, true, true}},
{"", {false, false, false, false, false, false, false}},
},
},
{
"a\\%%%b", // escaped '%' followed by two wildcard '%'s (dedup to one)
{
{"a%b", {true, true, true, true, true, true, true}},
{"a%xb", {true, true, true, true, true, true, true}},
{"a%123b", {true, true, true, true, true, true, true}},
{"a%x", {false, false, false, false, false, false, false}},
{"a%123c", {false, false, false, false, false, false, false}},
{"ab", {false, false, false, false, false, false, false}},
},
},
{
"%__", // test match from end
{
Expand Down