| 1276 | } |
| 1277 | |
| 1278 | StringVal StringFunctions::ConcatWs(FunctionContext* context, const StringVal& sep, |
| 1279 | int num_children, const StringVal* strs) { |
| 1280 | DCHECK_GE(num_children, 1); |
| 1281 | DCHECK(strs != nullptr); |
| 1282 | if (sep.is_null) return StringVal::null(); |
| 1283 | |
| 1284 | // Loop once to compute valid start index, final string size and valid string object |
| 1285 | // count. |
| 1286 | int32_t valid_num_children = 0; |
| 1287 | int32_t valid_start_index = -1; |
| 1288 | int64_t total_size = 0; |
| 1289 | for (int32_t i = 0; i < num_children; ++i) { |
| 1290 | if (strs[i].is_null) continue; |
| 1291 | |
| 1292 | if (valid_start_index == -1) { |
| 1293 | valid_start_index = i; |
| 1294 | // Calculate the space required by first valid string object. |
| 1295 | total_size += strs[i].len; |
| 1296 | } else { |
| 1297 | // Calculate the space required by subsequent valid string object. |
| 1298 | total_size += sep.len + strs[i].len; |
| 1299 | } |
| 1300 | // Record the count of valid string object. |
| 1301 | valid_num_children++; |
| 1302 | } |
| 1303 | |
| 1304 | if (total_size > StringVal::MAX_LENGTH) { |
| 1305 | context->SetError(Substitute(ERROR_CHARACTER_LIMIT_EXCEEDED, |
| 1306 | "Concatenated string length", |
| 1307 | PrettyPrinter::Print(StringVal::MAX_LENGTH, TUnit::BYTES)).c_str()); |
| 1308 | return StringVal::null(); |
| 1309 | } |
| 1310 | |
| 1311 | // If all data are invalid, or data size is zero, return empty string. |
| 1312 | if (valid_start_index < 0 || total_size <= 0) { |
| 1313 | return StringVal(); |
| 1314 | } |
| 1315 | DCHECK_GT(valid_num_children, 0); |
| 1316 | |
| 1317 | // Pass through if there's only one argument. |
| 1318 | if (valid_num_children == 1) return strs[valid_start_index]; |
| 1319 | |
| 1320 | // Reserve space needed by final result. |
| 1321 | StringVal result(context, total_size); |
| 1322 | if (UNLIKELY(result.is_null)) return StringVal::null(); |
| 1323 | |
| 1324 | // Loop to append the data. |
| 1325 | uint8_t* ptr = result.ptr; |
| 1326 | Ubsan::MemCpy(ptr, strs[valid_start_index].ptr, strs[valid_start_index].len); |
| 1327 | ptr += strs[valid_start_index].len; |
| 1328 | for (int32_t i = valid_start_index + 1; i < num_children; ++i) { |
| 1329 | if (strs[i].is_null) continue; |
| 1330 | Ubsan::MemCpy(ptr, sep.ptr, sep.len); |
| 1331 | ptr += sep.len; |
| 1332 | Ubsan::MemCpy(ptr, strs[i].ptr, strs[i].len); |
| 1333 | ptr += strs[i].len; |
| 1334 | } |
| 1335 | return result; |
nothing calls this directly
no test coverage detected