Repository: apache/arrow
File: cpp/src/parquet/column_writer_test.cc (C++)

Code before:

  std::shared_ptr<TypedColumnReader<Int32Type>> BuildReader(int64_t num_rows) {
    EXPECT_OK_AND_ASSIGN(auto buffer, sink_->Finish());
    auto source = std::make_shared<::arrow::io::BufferReader>(buffer);
    ReaderProperties reader_properties;
    std::unique_ptr<PageReader> page_reader = PageReader::Open(
        std::move(source), num_rows, Compression::UNCOMPRESSED, reader_properties);
    std::shared_ptr<ColumnReader> reader =
        ColumnReader::Make(schema_descriptor_.get(), std::move(page_reader));
    return std::static_pointer_cast<TypedColumnReader<Int32Type>>(reader);
  }

 protected:
  std::shared_ptr<ColumnDescriptor> schema_descriptor_;
  std::shared_ptr<::arrow::io::BufferOutputStream> sink_;
  std::shared_ptr<WriterProperties> writer_properties_;
  std::unique_ptr<ColumnChunkMetaDataBuilder> metadata_;
};

TEST_F(TestArrowWriteSerialize, AllNulls) {
  std::shared_ptr<::arrow::Buffer> null_bitmap;
  ASSERT_OK_AND_ASSIGN(null_bitmap, ::arrow::AllocateBitmap(100));
  // Set all bits to 0 (null)
  ::arrow::bit_util::SetBitsTo(null_bitmap->mutable_data(), 0, 100, false);

  std::shared_ptr<::arrow::Buffer> data_buffer = nullptr;

  auto array_data =
      ::arrow::ArrayData::Make(::arrow::int8(), 100, {null_bitmap, data_buffer}, 100);
  auto array = ::arrow::MakeArray(array_data);

  auto typed_writer = this->BuildWriter();

  std::vector<int16_t> def_levels(100, 0);
  std::vector<int16_t> rep_levels(100, 0);

  auto arrow_writer_properties = default_arrow_writer_properties();
  ArrowWriteContext ctx(::arrow::default_memory_pool(), arrow_writer_properties.get());

  ASSERT_OK(typed_writer->WriteArrow(def_levels.data(), rep_levels.data(), 100, *array,
                                     &ctx, true));

  typed_writer->Close();

  auto typed_reader = this->BuildReader(100);
  int64_t values_read = 0;
  std::vector<int16_t> def_levels_out(100);
  std::vector<int16_t> rep_levels_out(100);
  std::vector<int32_t> values_out(100);

  int64_t rows_read = typed_reader->ReadBatch(

Review comment (bug):
Please correct me if I was wrong. I think the Arrow spec is vague on whether the value buffer can be null if all values are null. It also escapes the `Array::Validate` check as in https://github.com/apache/arrow/blob/abbcd53007e613d8ece3e4abcdbae9ba2f4c618f/cpp/src/arrow/array/validate.cc#L505-L507.

If this violates the spec, is it better to fix `Array::Validate()` and calls it before calling `functor.Serialize()`?

Code after:
    WriterProperties::Builder properties_builder;
    if (column_properties.encoding() == Encoding::PLAIN_DICTIONARY ||
        column_properties.encoding() == Encoding::RLE_DICTIONARY) {
      properties_builder.enable_dictionary();
    } else {
      properties_builder.disable_dictionary();
      properties_builder.encoding(column_properties.encoding());
    }
    auto path = this->schema_.Column(0)->path();
    if (column_properties.bloom_filter_enabled()) {
      properties_builder.enable_bloom_filter(path,
                                             *column_properties.bloom_filter_options());
    } else {
      properties_builder.disable_bloom_filter(path);
    }
    this->writer_properties_ = properties_builder.build();

    this->metadata_ =
        ColumnChunkMetaDataBuilder::Make(this->writer_properties_, this->descr_);
    auto pager = PageWriter::Open(this->sink_, column_properties.compression(),
                                  this->metadata_.get());

    builder_ = BloomFilterBuilder::Make(&this->schema_, this->writer_properties_.get());
    builder_->AppendRowGroup();
    bloom_filter_ = builder_->CreateBloomFilter(/*column_ordinal=*/0);

    return std::dynamic_pointer_cast<TypedColumnWriter<TestType>>(
        ColumnWriter::Make(this->metadata_.get(), std::move(pager),
                           this->writer_properties_.get(), bloom_filter_));
  }

  std::unique_ptr<BloomFilterBuilder> builder_;
  BloomFilter* bloom_filter_{nullptr};  // Will be created and owned by `builder_`.
};

// Note: BooleanType is excluded.
using TestBloomFilterTypes = ::testing::Types<Int32Type, Int64Type, Int96Type, FloatType,
                                              DoubleType, ByteArrayType, FLBAType>;

TYPED_TEST_SUITE(TestBloomFilterWriter, TestBloomFilterTypes);

TYPED_TEST(TestBloomFilterWriter, Basic) {
  this->GenerateData(SMALL_SIZE);

  ColumnProperties column_properties;
  column_properties.set_bloom_filter_options(BloomFilterOptions{SMALL_SIZE, 0.05});

  auto writer = this->BuildWriter(SMALL_SIZE, column_properties);
  writer->WriteBatch(this->values_.size(), nullptr, nullptr, this->values_ptr_);
  writer->Close();