| 152 | } |
| 153 | |
| 154 | std::unique_ptr<IDataType::SubstreamData> IDataType::getSubcolumnData( |
| 155 | std::string_view subcolumn_name, |
| 156 | const SubstreamData & data, |
| 157 | size_t initial_array_level, |
| 158 | bool throw_if_null) |
| 159 | { |
| 160 | std::unique_ptr<IDataType::SubstreamData> res; |
| 161 | /// Track whether res was set by an exact name match, so that exact matches |
| 162 | /// always take priority over prefix (dynamic subcolumn) matches. |
| 163 | /// This matters when e.g. JSON has typed paths "a" (Array(JSON)) and "a.b" (Int64): |
| 164 | /// without this, the prefix match on "a" would fire first (sorted order) and |
| 165 | /// the exact match on "a.b" would be skipped because res is already set. |
| 166 | bool res_from_exact_match = false; |
| 167 | |
| 168 | ISerialization::StreamCallback callback_with_data = [&](const auto & subpath) |
| 169 | { |
| 170 | for (size_t i = 0; i < subpath.size(); ++i) |
| 171 | { |
| 172 | size_t prefix_len = i + 1; |
| 173 | if (!subpath[i].visited && ISerialization::hasSubcolumnForPath(subpath, prefix_len)) |
| 174 | { |
| 175 | auto name = ISerialization::getSubcolumnNameForStream(subpath, prefix_len, false, initial_array_level); |
| 176 | /// Create data from path only if it's requested subcolumn. |
| 177 | /// Use the first exact match to be consistent with ColumnsDescription::addSubcolumns |
| 178 | /// which also keeps the first subcolumn when there are name collisions |
| 179 | /// (e.g. "null" can match both Nullable's null-map and a Tuple element named "null"). |
| 180 | /// Exact matches always take priority over prefix matches regardless of iteration order. |
| 181 | if (name == subcolumn_name && !res_from_exact_match) |
| 182 | { |
| 183 | res = std::make_unique<SubstreamData>(ISerialization::createFromPath(subpath, prefix_len)); |
| 184 | res_from_exact_match = true; |
| 185 | } |
| 186 | /// Check if this subcolumn is a prefix of requested subcolumn and it can create dynamic subcolumns. |
| 187 | /// Only use prefix matches when no exact match has been found. |
| 188 | else if (!res_from_exact_match && subcolumn_name.starts_with(name + ".") && subpath[i].data.type && subpath[i].data.type->hasDynamicSubcolumnsData()) |
| 189 | { |
| 190 | auto dynamic_subcolumn_name = subcolumn_name.substr(name.size() + 1); |
| 191 | auto dynamic_subcolumn_data = subpath[i].data.type->getDynamicSubcolumnData( |
| 192 | dynamic_subcolumn_name, |
| 193 | subpath[i].data, |
| 194 | initial_array_level + ISerialization::getArrayLevel(subpath, prefix_len), |
| 195 | false); |
| 196 | if (dynamic_subcolumn_data) |
| 197 | { |
| 198 | /// Create requested subcolumn using dynamic subcolumn data. |
| 199 | auto tmp_subpath = subpath; |
| 200 | if (tmp_subpath[i].creator) |
| 201 | { |
| 202 | dynamic_subcolumn_data->type = tmp_subpath[i].creator->create(dynamic_subcolumn_data->type); |
| 203 | dynamic_subcolumn_data->column = tmp_subpath[i].creator->create(dynamic_subcolumn_data->column); |
| 204 | dynamic_subcolumn_data->serialization = tmp_subpath[i].creator->create(dynamic_subcolumn_data->serialization, dynamic_subcolumn_data->type); |
| 205 | } |
| 206 | |
| 207 | tmp_subpath[i].data = *dynamic_subcolumn_data; |
| 208 | res = std::make_unique<SubstreamData>(ISerialization::createFromPath(tmp_subpath, prefix_len)); |
| 209 | } |
| 210 | } |
| 211 | } |
nothing calls this directly
no test coverage detected