| 501 | } |
| 502 | |
| 503 | StringVal StringFunctions::Replace(FunctionContext* context, const StringVal& str, |
| 504 | const StringVal& pattern, const StringVal& replace) { |
| 505 | DCHECK_LE(str.len, StringVal::MAX_LENGTH); |
| 506 | DCHECK_LE(pattern.len, StringVal::MAX_LENGTH); |
| 507 | DCHECK_LE(replace.len, StringVal::MAX_LENGTH); |
| 508 | if (str.is_null || pattern.is_null || replace.is_null) return StringVal::null(); |
| 509 | if (pattern.len == 0 || pattern.len > str.len) return str; |
| 510 | |
| 511 | // StringSearch keeps a pointer to the StringValue object, so it must remain |
| 512 | // in scope if used. |
| 513 | StringSearch search; |
| 514 | StringValue needle; |
| 515 | const StringSearch *search_ptr; |
| 516 | const ReplaceContext* rptr = reinterpret_cast<ReplaceContext*> |
| 517 | (context->GetFunctionState(FunctionContext::FRAGMENT_LOCAL)); |
| 518 | if (UNLIKELY(rptr == nullptr)) { |
| 519 | needle = StringValue::FromStringVal(pattern); |
| 520 | search = StringSearch(&needle); |
| 521 | search_ptr = &search; |
| 522 | } else { |
| 523 | search_ptr = &rptr->search; |
| 524 | } |
| 525 | |
| 526 | const StringValue haystack = StringValue::FromStringVal(str); |
| 527 | int64_t match_pos = search_ptr->Search(&haystack); |
| 528 | |
| 529 | // No match? Skip everything. |
| 530 | if (match_pos < 0) return str; |
| 531 | |
| 532 | StringValue::SimpleString haystack_s = haystack.ToSimpleString(); |
| 533 | |
| 534 | DCHECK_GT(pattern.len, 0); |
| 535 | DCHECK_GE(haystack_s.len, pattern.len); |
| 536 | int buffer_space; |
| 537 | const int delta = replace.len - pattern.len; |
| 538 | // MAX_LENGTH is unsigned, so convert back to int to do correctly signed compare |
| 539 | DCHECK_LE(delta, static_cast<int>(StringVal::MAX_LENGTH) - 1); |
| 540 | if ((delta > 0 && delta < 128) && haystack_s.len <= 128) { |
| 541 | // Quick estimate for potential matches - this heuristic is needed to win |
| 542 | // over regexp_replace on expanding patterns. 128 is arbitrarily chosen so |
| 543 | // we can't massively over-estimate the buffer size. |
| 544 | int matches_possible = 0; |
| 545 | char c = pattern.ptr[0]; |
| 546 | for (int i = 0; i <= haystack_s.len - pattern.len; ++i) { |
| 547 | if (haystack_s.ptr[i] == c) ++matches_possible; |
| 548 | } |
| 549 | buffer_space = haystack_s.len + matches_possible * delta; |
| 550 | } else { |
| 551 | // Note - cannot overflow because pattern.len is at least one |
| 552 | static_assert(StringVal::MAX_LENGTH - 1 + StringVal::MAX_LENGTH <= |
| 553 | std::numeric_limits<decltype(buffer_space)>::max(), |
| 554 | "Buffer space computation can overflow"); |
| 555 | buffer_space = haystack_s.len + delta; |
| 556 | } |
| 557 | |
| 558 | StringVal result(context, buffer_space); |
| 559 | // result may be NULL if we went over MAX_LENGTH or the allocation failed. |
| 560 | if (UNLIKELY(result.is_null)) return result; |
nothing calls this directly
no test coverage detected