@@ -402,6 +402,36 @@ class RealtimeWriteInteTest : public ::testing::Test {
402402 return CollectedReadResult{std::move (reader), std::move (result)};
403403 }
404404
405+ void ReadPlanWithSchemaAndCheck (const std::shared_ptr<Plan>& plan,
406+ const std::shared_ptr<RealtimeContext>& realtime_context,
407+ const std::shared_ptr<arrow::Schema>& read_schema,
408+ const std::string& expected_json) const {
409+ std::unique_ptr<ArrowSchema> c_read_schema = std::make_unique<ArrowSchema>();
410+ ASSERT_TRUE (arrow::ExportSchema (*read_schema, c_read_schema.get ()).ok ());
411+ ReadContextBuilder read_builder (table_path_);
412+ read_builder.SetOptions (options_)
413+ .SetReadSchema (std::move (c_read_schema))
414+ .WithRealtimeContext (realtime_context)
415+ .WithMemoryPool (pool_);
416+ ASSERT_OK_AND_ASSIGN (std::unique_ptr<ReadContext> read_context, read_builder.Finish ());
417+ ASSERT_OK_AND_ASSIGN (std::unique_ptr<TableRead> table_read,
418+ TableRead::Create (std::move (read_context)));
419+ ASSERT_OK_AND_ASSIGN (std::unique_ptr<BatchReader> reader,
420+ table_read->CreateReader (plan->Splits ()));
421+ ASSERT_OK_AND_ASSIGN (std::shared_ptr<arrow::ChunkedArray> result,
422+ ReadResultCollector::CollectResult (reader.get ()));
423+
424+ arrow::FieldVector result_fields = {arrow::field (" _VALUE_KIND" , arrow::int8 ())};
425+ result_fields.insert (result_fields.end (), read_schema->fields ().begin (),
426+ read_schema->fields ().end ());
427+ std::shared_ptr<arrow::Array> expected =
428+ arrow::ipc::internal::json::ArrayFromJSON (arrow::struct_ (result_fields), expected_json)
429+ .ValueOrDie ();
430+ ASSERT_NE (nullptr , result);
431+ ASSERT_TRUE (std::make_shared<arrow::ChunkedArray>(expected)->Equals (*result))
432+ << result->ToString ();
433+ }
434+
405435 Result<std::vector<Row>> ReadRows (
406436 const std::shared_ptr<RealtimeContext>& realtime_context) const {
407437 PAIMON_ASSIGN_OR_RAISE (std::shared_ptr<Plan> plan,
@@ -1522,6 +1552,56 @@ TEST_F(RealtimeWriteInteTest, TestUnionReadAfterColumnRename) {
15221552 ASSERT_OK (second_writer->Close ());
15231553}
15241554
1555+ TEST_F (RealtimeWriteInteTest, TestUnionReadWithNestedStructProjection) {
1556+ std::shared_ptr<arrow::DataType> address_type =
1557+ arrow::struct_ ({arrow::field (" city" , arrow::utf8 ()), arrow::field (" zip" , arrow::int64 ())});
1558+ std::shared_ptr<arrow::DataType> profile_type = arrow::struct_ (
1559+ {arrow::field (" name" , arrow::utf8 ()), arrow::field (" address" , address_type)});
1560+ fields_ = {arrow::field (" id" , arrow::int64 ()), arrow::field (" profile" , profile_type),
1561+ arrow::field (" pt" , arrow::utf8 ())};
1562+ schema_ = arrow::schema (fields_);
1563+ CreateTable (/* partition_keys=*/ {});
1564+
1565+ ASSERT_OK_AND_ASSIGN (std::shared_ptr<RealtimeContext> realtime_context,
1566+ RealtimeContext::Create ());
1567+ ASSERT_OK_AND_ASSIGN (std::unique_ptr<FileStoreWrite> writer,
1568+ CreateRealtimeWriter (realtime_context));
1569+ ASSERT_OK_AND_ASSIGN (std::unique_ptr<RecordBatch> disk_batch,
1570+ MakeUnpartitionedBatchFromJson (R"( [
1571+ [0, ["disk-0", ["hangzhou", 310000]], "p0"],
1572+ [1, ["disk-1", ["shanghai", 200000]], "p0"]
1573+ ])" ));
1574+ ASSERT_OK (writer->Write (std::move (disk_batch)));
1575+ ASSERT_OK_AND_ASSIGN (std::vector<RealtimeCommitProgress> disk_commits,
1576+ writer->PrepareCommitWithProgress (/* commit_identifier=*/ 0 ));
1577+ ASSERT_OK_AND_ASSIGN (int64_t disk_snapshot_id, Commit (disk_commits, /* commit_identifier=*/ 0 ));
1578+ ASSERT_OK (writer->RefreshCommittedSnapshot (disk_snapshot_id));
1579+
1580+ ASSERT_OK_AND_ASSIGN (std::unique_ptr<RecordBatch> memory_batch,
1581+ MakeUnpartitionedBatchFromJson (R"( [
1582+ [2, ["memory-2", ["beijing", 100000]], "p0"],
1583+ [3, ["memory-3", ["shenzhen", 518000]], "p0"]
1584+ ])" ));
1585+ ASSERT_OK (writer->Write (std::move (memory_batch)));
1586+
1587+ ASSERT_OK_AND_ASSIGN (std::shared_ptr<Plan> plan,
1588+ CreatePlan (realtime_context, /* predicate=*/ nullptr ));
1589+ std::shared_ptr<arrow::DataType> projected_address_type =
1590+ arrow::struct_ ({arrow::field (" city" , arrow::utf8 ())});
1591+ std::shared_ptr<arrow::DataType> projected_profile_type =
1592+ arrow::struct_ ({arrow::field (" address" , projected_address_type)});
1593+ std::shared_ptr<arrow::Schema> projected_schema = arrow::schema (
1594+ {arrow::field (" id" , arrow::int64 ()), arrow::field (" profile" , projected_profile_type),
1595+ arrow::field (" pt" , arrow::utf8 ())});
1596+ ReadPlanWithSchemaAndCheck (plan, realtime_context, projected_schema, R"( [
1597+ [0, 0, [["hangzhou"]], "p0"],
1598+ [0, 1, [["shanghai"]], "p0"],
1599+ [0, 2, [["beijing"]], "p0"],
1600+ [0, 3, [["shenzhen"]], "p0"]
1601+ ])" );
1602+ ASSERT_OK (writer->Close ());
1603+ }
1604+
15251605TEST_F (RealtimeWriteInteTest, TestRefreshCommittedSnapshotReclaimsMemory) {
15261606 CreateTable (/* partition_keys=*/ {});
15271607 ASSERT_OK_AND_ASSIGN (std::shared_ptr<RealtimeContext> realtime_context,
0 commit comments