@@ -538,13 +538,20 @@ class ListReader : public ColumnReaderImpl {
538538 return item_reader_->LoadBatch (number_of_records);
539539 }
540540
541+ virtual ::arrow::Result<std::shared_ptr<ChunkedArray>> AssembleArray (
542+ std::shared_ptr<ArrayData> data) {
543+ std::shared_ptr<Array> result = ::arrow::MakeArray (data);
544+ return std::make_shared<ChunkedArray>(result);
545+ }
546+
541547 Status BuildArray (int64_t length_upper_bound,
542548 std::shared_ptr<ChunkedArray>* out) override {
543549 const int16_t * def_levels;
544550 const int16_t * rep_levels;
545551 int64_t num_levels;
546552 RETURN_NOT_OK (item_reader_->GetDefLevels (&def_levels, &num_levels));
547553 RETURN_NOT_OK (item_reader_->GetRepLevels (&rep_levels, &num_levels));
554+
548555 std::shared_ptr<ResizableBuffer> validity_buffer;
549556 ::parquet::internal::ValidityBitmapInputOutput validity_io;
550557 validity_io.values_read_upper_bound = length_upper_bound;
@@ -576,6 +583,7 @@ class ListReader : public ColumnReaderImpl {
576583 if (validity_buffer != nullptr ) {
577584 RETURN_NOT_OK (
578585 validity_buffer->Resize (BitUtil::BytesForBits (validity_io.values_read )));
586+ validity_buffer->ZeroPadding ();
579587 }
580588 ARROW_ASSIGN_OR_RAISE (std::shared_ptr<ArrayData> item_chunk, ChunksToSingle (**out));
581589
@@ -586,8 +594,7 @@ class ListReader : public ColumnReaderImpl {
586594 /* length=*/ validity_io.values_read , std::move (buffers),
587595 std::vector<std::shared_ptr<ArrayData>>{item_chunk}, validity_io.null_count );
588596
589- std::shared_ptr<Array> result = ::arrow::MakeArray (data);
590- *out = std::make_shared<ChunkedArray>(result);
597+ ARROW_ASSIGN_OR_RAISE (*out, AssembleArray (std::move (data)));
591598 return Status::OK ();
592599 }
593600
@@ -600,6 +607,32 @@ class ListReader : public ColumnReaderImpl {
600607 std::unique_ptr<ColumnReaderImpl> item_reader_;
601608};
602609
610+ class PARQUET_NO_EXPORT FixedSizeListReader : public ListReader<int32_t > {
611+ public:
612+ FixedSizeListReader (std::shared_ptr<ReaderContext> ctx, std::shared_ptr<Field> field,
613+ ::parquet::internal::LevelInfo level_info,
614+ std::unique_ptr<ColumnReaderImpl> child_reader)
615+ : ListReader(std::move(ctx), std::move(field), level_info,
616+ std::move (child_reader)) {}
617+ ::arrow::Result<std::shared_ptr<ChunkedArray>> AssembleArray (
618+ std::shared_ptr<ArrayData> data) final {
619+ DCHECK_EQ (data->buffers .size (), 2 );
620+ DCHECK_EQ (field ()->type ()->id (), ::arrow::Type::FIXED_SIZE_LIST );
621+ const auto & type = checked_cast<::arrow::FixedSizeListType&>(*field ()->type ());
622+ const int32_t * offsets = reinterpret_cast <const int32_t *>(data->buffers [1 ]->data ());
623+ for (int x = 1 ; x <= data->length ; x++) {
624+ int32_t size = offsets[x] - offsets[x - 1 ];
625+ if (size != type.list_size ()) {
626+ return Status::Invalid (" Expected all lists to be of size=" , type.list_size (),
627+ " but index " , x, " had size=" , size);
628+ }
629+ }
630+ data->buffers .resize (1 );
631+ std::shared_ptr<Array> result = ::arrow::MakeArray (data);
632+ return std::make_shared<ChunkedArray>(result);
633+ }
634+ };
635+
603636class PARQUET_NO_EXPORT StructReader : public ColumnReaderImpl {
604637 public:
605638 explicit StructReader (std::shared_ptr<ReaderContext> ctx,
@@ -714,6 +747,7 @@ Status StructReader::BuildArray(int64_t length_upper_bound,
714747 // Ensure all values are initialized.
715748 if (null_bitmap) {
716749 RETURN_NOT_OK (null_bitmap->Resize (BitUtil::BytesForBits (validity_io.values_read )));
750+ null_bitmap->ZeroPadding ();
717751 }
718752
719753 END_PARQUET_CATCH_EXCEPTIONS
@@ -770,16 +804,36 @@ Status GetReader(const SchemaField& field, const std::shared_ptr<Field>& arrow_f
770804 std::unique_ptr<FileColumnIterator> input (
771805 ctx->iterator_factory (field.column_index , ctx->reader ));
772806 out->reset (new LeafReader (ctx, arrow_field, std::move (input), field.level_info ));
773- } else if (type_id == ::arrow::Type::LIST ) {
807+ } else if (type_id == ::arrow::Type::LIST || type_id == ::arrow::Type::MAP ||
808+ type_id == ::arrow::Type::FIXED_SIZE_LIST ||
809+ type_id == ::arrow::Type::LARGE_LIST ) {
810+ auto list_field = arrow_field;
774811 auto child = &field.children [0 ];
775812 std::unique_ptr<ColumnReaderImpl> child_reader;
776813 RETURN_NOT_OK (GetReader (*child, ctx, &child_reader));
777814 if (child_reader == nullptr ) {
778815 *out = nullptr ;
779816 return Status::OK ();
780817 }
781- out->reset (new ListReader<int32_t >(ctx, arrow_field, field.level_info ,
782- std::move (child_reader)));
818+ if (type_id == ::arrow::Type::LIST ||
819+ type_id == ::arrow::Type::MAP ) { // Map can be reconstructed as list of structs.
820+ if (type_id == ::arrow::Type::MAP &&
821+ child_reader->field ()->type ()->num_fields () != 2 ) {
822+ // This case applies if either key or value is filtered.
823+ list_field = list_field->WithType (::arrow::list (child_reader->field ()));
824+ }
825+ out->reset (new ListReader<int32_t >(ctx, list_field, field.level_info ,
826+ std::move (child_reader)));
827+ } else if (type_id == ::arrow::Type::LARGE_LIST ) {
828+ out->reset (new ListReader<int64_t >(ctx, list_field, field.level_info ,
829+ std::move (child_reader)));
830+
831+ } else if (type_id == ::arrow::Type::FIXED_SIZE_LIST ) {
832+ out->reset (new FixedSizeListReader (ctx, list_field, field.level_info ,
833+ std::move (child_reader)));
834+ } else {
835+ return Status::UnknownError (" Unknown list type: " , field.field ->ToString ());
836+ }
783837 } else if (type_id == ::arrow::Type::STRUCT ) {
784838 std::vector<std::shared_ptr<Field>> child_fields;
785839 std::vector<std::unique_ptr<ColumnReaderImpl>> child_readers;
0 commit comments