| 1424 | } |
| 1425 | |
| 1426 | void AggregateFunctions::StringConcatMerge(FunctionContext* ctx, |
| 1427 | const StringVal& src, StringVal* result) { |
| 1428 | if (src.is_null) return; |
| 1429 | const int header_len = sizeof(StringConcatHeader); |
| 1430 | if (result->is_null) { |
| 1431 | AllocBuffer(ctx, result, header_len); |
| 1432 | if (UNLIKELY(result->is_null)) { |
| 1433 | DCHECK(!ctx->impl()->state()->GetQueryStatus().ok()); |
| 1434 | return; |
| 1435 | } |
| 1436 | // Copy the header from the first intermediate value. |
| 1437 | *reinterpret_cast<StringConcatHeader*>(result->ptr) = |
| 1438 | *reinterpret_cast<StringConcatHeader*>(src.ptr); |
| 1439 | } |
| 1440 | // Append the string portion of the intermediate src to result (omit src's header). |
| 1441 | unsigned buf_len = src.len - header_len; |
| 1442 | unsigned new_len = result->len + buf_len; |
| 1443 | if (LIKELY(new_len <= StringVal::MAX_LENGTH)) { |
| 1444 | uint8_t* ptr = ctx->Reallocate(result->ptr, new_len); |
| 1445 | if (LIKELY(ptr != NULL)) { |
| 1446 | memcpy(ptr + result->len, src.ptr + header_len, buf_len); |
| 1447 | result->ptr = ptr; |
| 1448 | result->len = new_len; |
| 1449 | } else { |
| 1450 | DCHECK(!ctx->impl()->state()->GetQueryStatus().ok()); |
| 1451 | } |
| 1452 | } else { |
| 1453 | ctx->SetError(Substitute(ERROR_CONCATENATED_STRING_MAX_SIZE_REACHED, |
| 1454 | PrettyPrinter::Print(StringVal::MAX_LENGTH, TUnit::BYTES)).c_str()); |
| 1455 | } |
| 1456 | } |
| 1457 | |
| 1458 | StringVal AggregateFunctions::StringConcatFinalize(FunctionContext* ctx, |
| 1459 | const StringVal& src) { |
nothing calls this directly
no test coverage detected