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

Code before:
      ::arrow::schema({::arrow::field("outer", type, /*nullable=*/true)}), {outer_array});

  auto write_props = WriterProperties::Builder().write_batch_size(4)->build();

  std::shared_ptr<Table> actual;
  DoRoundtrip(expected, /*row_group_size=*/outer_array->length(), &actual, write_props);
  ::arrow::AssertTablesEqual(*expected, *actual, /*same_chunk_layout=*/false);
}

TEST(TestArrowReaderAdHoc, OldDataPageV2) {
  // ARROW-17100
#ifndef ARROW_WITH_SNAPPY
  GTEST_SKIP() << "Test requires Snappy compression";
#endif
  const char* c_root = std::getenv("ARROW_TEST_DATA");
  if (!c_root) {
    GTEST_SKIP() << "ARROW_TEST_DATA not set.";
  }
  std::stringstream ss;
  ss << c_root << "/"
     << "parquet/ARROW-17100.parquet";
  std::string path = ss.str();
  TryReadDataFile(path);
}

class TestArrowReaderAdHocSparkAndHvr
    : public ::testing::TestWithParam<
          std::tuple<std::string, std::shared_ptr<DataType>>> {};

TEST_P(TestArrowReaderAdHocSparkAndHvr, ReadDecimals) {
  std::string path(test::get_data_dir());

  std::string filename;
  std::shared_ptr<DataType> decimal_type;
  std::tie(filename, decimal_type) = GetParam();

  path += "/" + filename;
  ASSERT_GT(path.size(), 0);

  auto pool = ::arrow::default_memory_pool();

  std::unique_ptr<FileReader> arrow_reader;
  ASSERT_OK_NO_THROW(
      FileReader::Make(pool, ParquetFileReader::OpenFile(path, false), &arrow_reader));
  std::shared_ptr<::arrow::Table> table;
  ASSERT_OK_NO_THROW(arrow_reader->ReadTable(&table));

  std::shared_ptr<::arrow::Schema> schema;
  ASSERT_OK_NO_THROW(arrow_reader->GetSchema(&schema));
  ASSERT_EQ(1, schema->num_fields());
  ASSERT_TRUE(schema->field(0)->type()->Equals(*decimal_type));

Review comment (suggestion):
This feature is supported by parquet-java via a writer flag `parquet.avro.write-old-list-structure`: https://github.com/apache/parquet-java/blob/08a4e7e6279f8c3b8558bd294fee4489a96d0db1/parquet-avro/src/main/java/org/apache/parquet/avro/AvroWriteSupport.java#L69 so I don't think we need to add a test file to parquet-testing repo.

Instead, I added a roundtrip test to create the file by C++ Parquet writer and then read it via the C++ Arrow Parquet reader. Does it look good to you? @pitrou @mapleFU 


Code after:
      ::arrow::schema({::arrow::field("outer", type, /*nullable=*/true)}), {outer_array});

  auto write_props = WriterProperties::Builder().write_batch_size(4)->build();

  std::shared_ptr<Table> actual;
  DoRoundtrip(expected, /*row_group_size=*/outer_array->length(), &actual, write_props);
  ::arrow::AssertTablesEqual(*expected, *actual, /*same_chunk_layout=*/false);
}

TEST(TestArrowReaderAdHoc, OldDataPageV2) {
  // ARROW-17100
#ifndef ARROW_WITH_SNAPPY
  GTEST_SKIP() << "Test requires Snappy compression";
#endif
  const char* c_root = std::getenv("ARROW_TEST_DATA");
  if (!c_root) {
    GTEST_SKIP() << "ARROW_TEST_DATA not set.";
  }
  std::stringstream ss;
  ss << c_root << "/"
     << "parquet/ARROW-17100.parquet";
  std::string path = ss.str();
  TryReadDataFile(path);
}

TEST(TestArrowReaderAdHoc, LegacyTwoLevelList) {
  auto VerifyData = [](std::unique_ptr<ParquetFileReader> file_reader) {
    // Expected Parquet schema of legacy two-level encoding
    constexpr std::string_view kExpectedLegacyList =
        "required group field_id=-1 a (List) {\n"
        "  repeated group field_id=-1 array (List) {\n"
        "    repeated int32 field_id=-1 array;\n"
        "  }\n"
        "}\n";

    // Expected Arrow schema and data
    auto arrow_inner_list =
        field("array", list(field("array", ::arrow::int32(), /*nullable=*/false)),
              /*nullable=*/false);
    auto arrow_outer_list = list(arrow_inner_list);
    auto arrow_schema =
        ::arrow::schema({field("a", arrow_outer_list, /*nullable=*/false)});
    auto expected_table = TableFromJSON(arrow_schema, {R"([[[[1,2],[3,4]]]])"});

    // Verify Parquet schema
    auto root_group = file_reader->metadata()->schema()->group_node();
    ASSERT_EQ(1, root_group->field_count());
    std::stringstream nodeStr;
    PrintSchema(root_group->field(0).get(), nodeStr);
    ASSERT_EQ(kExpectedLegacyList, nodeStr.str());