| 511 | } |
| 512 | |
| 513 | NamesAndTypesList convertToSubcolumns(const NamesAndTypesList & names_and_types) |
| 514 | { |
| 515 | auto nested_types = getSubcolumnsOfNested(names_and_types); |
| 516 | auto res = names_and_types; |
| 517 | |
| 518 | for (auto & name_type : res) |
| 519 | { |
| 520 | if (!isArray(name_type.type)) |
| 521 | continue; |
| 522 | |
| 523 | auto split = splitName(name_type.name); |
| 524 | if (split.second.empty()) |
| 525 | continue; |
| 526 | |
| 527 | if (name_type.isSubcolumn()) |
| 528 | { |
| 529 | /// If this is a subcolumn (e.g. `c0.c2.null` — subcolumn `null` of `c0.c2`) |
| 530 | /// and its parent column is part of a Nested group, remap it to be a subcolumn |
| 531 | /// of the Nested type (e.g. subcolumn `c2.null` of Nested `c0`). |
| 532 | /// This ensures the Nested serialization is used, which handles shared offsets correctly. |
| 533 | auto name_in_storage = name_type.getNameInStorage(); |
| 534 | auto storage_split = splitName(name_in_storage); |
| 535 | if (!storage_split.second.empty()) |
| 536 | { |
| 537 | auto it = nested_types.find(storage_split.first); |
| 538 | if (it != nested_types.end()) |
| 539 | { |
| 540 | auto new_subcolumn = concatenateName(storage_split.second, name_type.getSubcolumnName()); |
| 541 | if (auto subcolumn_type = it->second->tryGetSubcolumnType(new_subcolumn)) |
| 542 | name_type = NameAndTypePair{storage_split.first, new_subcolumn, it->second, subcolumn_type}; |
| 543 | } |
| 544 | } |
| 545 | continue; |
| 546 | } |
| 547 | |
| 548 | auto it = nested_types.find(split.first); |
| 549 | if (it != nested_types.end()) |
| 550 | name_type = NameAndTypePair{split.first, split.second, it->second, it->second->getSubcolumnType(split.second)}; |
| 551 | } |
| 552 | |
| 553 | return res; |
| 554 | } |
| 555 | |
| 556 | |
| 557 | void validateArraySizes(const Block & block) |