|
20 | 20 | #include "iceberg/avro/avro_reader.h" |
21 | 21 |
|
22 | 22 | #include <memory> |
| 23 | +#include <vector> |
23 | 24 |
|
24 | 25 | #include <arrow/array/builder_base.h> |
25 | 26 | #include <arrow/c/bridge.h> |
| 27 | +#include <arrow/extension_type.h> |
26 | 28 | #include <arrow/filesystem/filesystem.h> |
27 | 29 | #include <arrow/record_batch.h> |
28 | 30 | #include <arrow/result.h> |
|
42 | 44 | #include "iceberg/metadata_columns.h" |
43 | 45 | #include "iceberg/name_mapping.h" |
44 | 46 | #include "iceberg/schema_internal.h" |
| 47 | +#include "iceberg/util/checked_cast.h" |
45 | 48 | #include "iceberg/util/macros.h" |
46 | 49 |
|
47 | 50 | namespace iceberg::avro { |
@@ -209,6 +212,63 @@ struct ReadContext { |
209 | 212 | std::shared_ptr<::arrow::ArrayBuilder> builder_; |
210 | 213 | }; |
211 | 214 |
|
| 215 | +std::shared_ptr<::arrow::DataType> StorageTypeForBuilder( |
| 216 | + const std::shared_ptr<::arrow::DataType>& type); |
| 217 | + |
| 218 | +std::shared_ptr<::arrow::Field> StorageFieldForBuilder( |
| 219 | + const std::shared_ptr<::arrow::Field>& field) { |
| 220 | + return ::arrow::field(field->name(), StorageTypeForBuilder(field->type()), |
| 221 | + field->nullable(), field->metadata()); |
| 222 | +} |
| 223 | + |
| 224 | +// Arrow cannot construct builders for arrow.uuid extension arrays yet, so build |
| 225 | +// with the UUID storage type while keeping the public schema unchanged. |
| 226 | +std::shared_ptr<::arrow::DataType> StorageTypeForBuilder( |
| 227 | + const std::shared_ptr<::arrow::DataType>& type) { |
| 228 | + switch (type->id()) { |
| 229 | + case ::arrow::Type::EXTENSION: { |
| 230 | + const auto& extension_type = |
| 231 | + internal::checked_cast<const ::arrow::ExtensionType&>(*type); |
| 232 | + if (extension_type.extension_name() == kArrowUuidExtensionName) { |
| 233 | + return extension_type.storage_type(); |
| 234 | + } |
| 235 | + return type; |
| 236 | + } |
| 237 | + case ::arrow::Type::STRUCT: { |
| 238 | + const auto& struct_type = internal::checked_cast<const ::arrow::StructType&>(*type); |
| 239 | + std::vector<std::shared_ptr<::arrow::Field>> fields; |
| 240 | + fields.reserve(struct_type.num_fields()); |
| 241 | + for (const auto& field : struct_type.fields()) { |
| 242 | + fields.emplace_back(StorageFieldForBuilder(field)); |
| 243 | + } |
| 244 | + return ::arrow::struct_(std::move(fields)); |
| 245 | + } |
| 246 | + case ::arrow::Type::LIST: { |
| 247 | + const auto& list_type = internal::checked_cast<const ::arrow::ListType&>(*type); |
| 248 | + return ::arrow::list(StorageFieldForBuilder(list_type.value_field())); |
| 249 | + } |
| 250 | + case ::arrow::Type::LARGE_LIST: { |
| 251 | + const auto& list_type = |
| 252 | + internal::checked_cast<const ::arrow::LargeListType&>(*type); |
| 253 | + return ::arrow::large_list(StorageFieldForBuilder(list_type.value_field())); |
| 254 | + } |
| 255 | + case ::arrow::Type::FIXED_SIZE_LIST: { |
| 256 | + const auto& list_type = |
| 257 | + internal::checked_cast<const ::arrow::FixedSizeListType&>(*type); |
| 258 | + return ::arrow::fixed_size_list(StorageFieldForBuilder(list_type.value_field()), |
| 259 | + list_type.list_size()); |
| 260 | + } |
| 261 | + case ::arrow::Type::MAP: { |
| 262 | + const auto& map_type = internal::checked_cast<const ::arrow::MapType&>(*type); |
| 263 | + return ::arrow::map(StorageTypeForBuilder(map_type.key_type()), |
| 264 | + StorageFieldForBuilder(map_type.item_field()), |
| 265 | + map_type.keys_sorted()); |
| 266 | + } |
| 267 | + default: |
| 268 | + return type; |
| 269 | + } |
| 270 | +} |
| 271 | + |
212 | 272 | } // namespace |
213 | 273 |
|
214 | 274 | // TODO(gang.wu): collect basic reader metrics |
@@ -349,7 +409,8 @@ class AvroReader::Impl { |
349 | 409 | context_->arrow_schema_ = import_result.MoveValueUnsafe(); |
350 | 410 |
|
351 | 411 | auto arrow_struct_type = |
352 | | - std::make_shared<::arrow::StructType>(context_->arrow_schema_->fields()); |
| 412 | + internal::checked_pointer_cast<::arrow::StructType>(StorageTypeForBuilder( |
| 413 | + std::make_shared<::arrow::StructType>(context_->arrow_schema_->fields()))); |
353 | 414 | auto builder_result = ::arrow::MakeBuilder(arrow_struct_type); |
354 | 415 | if (!builder_result.ok()) { |
355 | 416 | return InvalidSchema("Failed to make the arrow builder: {}", |
|
0 commit comments