|
54 | 54 | namespace starrocks { |
55 | 55 | // A regex to match any regex pattern is equivalent to a substring search. |
56 | 56 | static const RE2 SUBSTRING_RE(R"((?:\.\*)*([^\.\^\{\[\(\|\)\]\}\+\*\?\$\\]+)(?:\.\*)*)", re2::RE2::Quiet); |
| 57 | +// A strict fixed literal regex contains only normal characters without any regex special characters. |
| 58 | +static const RE2 FIXED_LITERAL_RE(R"(^[^\.\^\{\[\(\|\)\]\}\+\*\?\$\\]+$)", re2::RE2::Quiet); |
57 | 59 |
|
58 | 60 | #define THROW_RUNTIME_ERROR_IF_EXCEED_LIMIT(col, func_name) \ |
59 | 61 | if (UNLIKELY(col->capacity_limit_reached())) { \ |
@@ -3114,8 +3116,10 @@ Status StringFunctions::regexp_replace_prepare(FunctionContext* context, Functio |
3114 | 3116 | state->pattern = pattern_str; |
3115 | 3117 |
|
3116 | 3118 | std::string search_string; |
| 3119 | + |
3117 | 3120 | if (pattern_str.size() && RE2::FullMatch(pattern_str, SUBSTRING_RE, &search_string)) { |
3118 | 3121 | state->use_hyperscan = true; |
| 3122 | + state->use_hyperscan_vec = RE2::FullMatch(pattern_str, FIXED_LITERAL_RE, &search_string); |
3119 | 3123 | state->size_of_pattern = pattern.size; |
3120 | 3124 | std::string re_pattern(pattern.data, pattern.size); |
3121 | 3125 | RETURN_IF_ERROR(hs_compile_and_alloc_scratch(re_pattern, state, context, pattern)); |
@@ -3586,35 +3590,36 @@ static StatusOr<ColumnPtr> hyperscan_vec_evaluate(const BinaryColumn* src, Strin |
3586 | 3590 | raw::make_room(&dst_offsets, num_rows + 1); |
3587 | 3591 | dst_bytes.reserve(data_count()); |
3588 | 3592 |
|
3589 | | - // copy data |
| 3593 | + // copy data row by row with replacements applied |
3590 | 3594 | char* cursor = reinterpret_cast<char*>(dst_bytes.data()); |
3591 | | - size_t last_to = 0; |
3592 | | - for (const auto& info : match_info_chain_in_one_row.info_chain) { |
3593 | | - strings::memcpy_inlined(cursor, data + last_to, info.from - last_to); |
3594 | | - cursor += info.from - last_to; |
3595 | | - strings::memcpy_inlined(cursor, rpl_value.data(), rpl_value.size()); |
3596 | | - cursor += rpl_value.size(); |
3597 | | - last_to = info.to; |
3598 | | - } |
3599 | | - strings::memcpy_inlined(cursor, data + last_to, src_value_size - last_to); |
3600 | | - |
3601 | | - // split offset |
3602 | 3595 | size_t match_index = 0; |
3603 | | - dst_offsets[0] = 0; |
3604 | 3596 | size_t match_size = match_info_chain_in_one_row.info_chain.size(); |
| 3597 | + dst_offsets[0] = 0; |
| 3598 | + |
3605 | 3599 | for (size_t i = 0; i < num_rows; i++) { |
3606 | | - size_t from = src_offsets[i]; |
3607 | | - size_t to = src_offsets[i + 1]; |
3608 | | - size_t dis = to - from; |
3609 | | - DCHECK(match_index == match_size || match_info_chain_in_one_row.info_chain[match_index].to > from); |
3610 | | - while (match_index < match_size && match_info_chain_in_one_row.info_chain[match_index].from >= from && |
3611 | | - match_info_chain_in_one_row.info_chain[match_index].to <= to) { |
3612 | | - dis -= match_info_chain_in_one_row.info_chain[match_index].to - |
3613 | | - match_info_chain_in_one_row.info_chain[match_index].from; |
3614 | | - dis += rpl_value.size(); |
| 3600 | + size_t row_start = src_offsets[i]; |
| 3601 | + size_t row_end = src_offsets[i + 1]; |
| 3602 | + size_t last_to = row_start; |
| 3603 | + |
| 3604 | + // Process all matches in this row |
| 3605 | + while (match_index < match_size && match_info_chain_in_one_row.info_chain[match_index].from >= row_start && |
| 3606 | + match_info_chain_in_one_row.info_chain[match_index].to <= row_end) { |
| 3607 | + const auto& info = match_info_chain_in_one_row.info_chain[match_index]; |
| 3608 | + // Copy data before the match |
| 3609 | + strings::memcpy_inlined(cursor, data + last_to, info.from - last_to); |
| 3610 | + cursor += info.from - last_to; |
| 3611 | + // Copy replacement |
| 3612 | + strings::memcpy_inlined(cursor, rpl_value.data(), rpl_value.size()); |
| 3613 | + cursor += rpl_value.size(); |
| 3614 | + last_to = info.to; |
3615 | 3615 | match_index++; |
3616 | 3616 | } |
3617 | | - dst_offsets[i + 1] = dst_offsets[i] + dis; |
| 3617 | + // Copy remaining data in this row |
| 3618 | + strings::memcpy_inlined(cursor, data + last_to, row_end - last_to); |
| 3619 | + cursor += row_end - last_to; |
| 3620 | + |
| 3621 | + // Calculate offset for this row |
| 3622 | + dst_offsets[i + 1] = cursor - reinterpret_cast<char*>(dst_bytes.data()); |
3618 | 3623 | } |
3619 | 3624 | DCHECK(match_index == match_size); |
3620 | 3625 | DCHECK(dst_offsets.back() == data_count()); |
@@ -3723,7 +3728,7 @@ StatusOr<ColumnPtr> StringFunctions::regexp_replace(FunctionContext* context, co |
3723 | 3728 |
|
3724 | 3729 | if (state->const_pattern) { |
3725 | 3730 | if (state->use_hyperscan) { |
3726 | | - if (columns[2]->is_constant() && context->state()->enable_hyperscan_vec()) { |
| 3731 | + if (columns[2]->is_constant() && context->state()->enable_hyperscan_vec() && state->use_hyperscan_vec) { |
3727 | 3732 | return regexp_replace_use_hyperscan_vec(state, columns); |
3728 | 3733 | } else { |
3729 | 3734 | return regexp_replace_use_hyperscan(state, columns); |
|
0 commit comments