@@ -34,9 +34,22 @@ namespace iceberg {
3434
3535namespace {
3636
37+ const std::string& TaskFilePath (const std::shared_ptr<ChangelogScanTask>& task) {
38+ if (auto added = std::dynamic_pointer_cast<AddedRowsScanTask>(task)) {
39+ return added->data_file ()->file_path ;
40+ }
41+ if (auto deleted = std::dynamic_pointer_cast<DeletedDataFileScanTask>(task)) {
42+ return deleted->data_file ()->file_path ;
43+ }
44+
45+ static const std::string empty_path;
46+ return empty_path;
47+ }
48+
3749// / \brief Sort changelog scan tasks for deterministic ordering.
3850// / Sorts by change_ordinal, then by operation type name, then by file path.
39- void SortTasks (std::vector<std::shared_ptr<ChangelogScanTask>>& tasks) {
51+ template <typename TaskType>
52+ void SortTasks (std::vector<std::shared_ptr<TaskType>>& tasks) {
4053 std::ranges::sort (tasks, [](const auto & t1, const auto & t2) {
4154 if (t1->change_ordinal () != t2->change_ordinal ()) {
4255 return t1->change_ordinal () < t2->change_ordinal ();
@@ -45,7 +58,8 @@ void SortTasks(std::vector<std::shared_ptr<ChangelogScanTask>>& tasks) {
4558 return static_cast <uint8_t >(t1->operation ()) <
4659 static_cast <uint8_t >(t2->operation ());
4760 }
48- return t1->data_file ()->file_path < t2->data_file ()->file_path ;
61+ return TaskFilePath (std::static_pointer_cast<ChangelogScanTask>(t1)) <
62+ TaskFilePath (std::static_pointer_cast<ChangelogScanTask>(t2));
4963 });
5064}
5165
@@ -94,8 +108,10 @@ TEST_P(IncrementalChangelogScanTest, DataFilters) {
94108 EXPECT_EQ (t1->change_ordinal (), 1 );
95109 EXPECT_EQ (t1->commit_snapshot_id (), 2000L );
96110 EXPECT_EQ (t1->operation (), ChangelogOperation::kInsert );
97- EXPECT_EQ (t1->data_file ()->file_path , " /path/to/file_b.parquet" );
98- EXPECT_TRUE (t1->delete_files ().empty ());
111+ auto insert_t1 = std::dynamic_pointer_cast<AddedRowsScanTask>(t1);
112+ ASSERT_NE (insert_t1, nullptr );
113+ EXPECT_EQ (insert_t1->data_file ()->file_path , " /path/to/file_b.parquet" );
114+ EXPECT_TRUE (insert_t1->delete_files ().empty ());
99115}
100116
101117TEST_P (IncrementalChangelogScanTest, Overwrites) {
@@ -130,16 +146,20 @@ TEST_P(IncrementalChangelogScanTest, Overwrites) {
130146 EXPECT_EQ (t1->change_ordinal (), 0 );
131147 EXPECT_EQ (t1->commit_snapshot_id (), 2000L );
132148 EXPECT_EQ (t1->operation (), ChangelogOperation::kInsert );
133- EXPECT_EQ (t1->data_file ()->file_path , " /path/to/file_a2.parquet" );
134- EXPECT_TRUE (t1->delete_files ().empty ());
149+ auto insert_t1 = std::dynamic_pointer_cast<AddedRowsScanTask>(t1);
150+ ASSERT_NE (insert_t1, nullptr );
151+ EXPECT_EQ (insert_t1->data_file ()->file_path , " /path/to/file_a2.parquet" );
152+ EXPECT_TRUE (insert_t1->delete_files ().empty ());
135153
136154 // Second task: deleted file (DELETE operation)
137155 auto t2 = tasks[1 ];
138156 EXPECT_EQ (t2->change_ordinal (), 0 );
139157 EXPECT_EQ (t2->commit_snapshot_id (), 2000L );
140158 EXPECT_EQ (t2->operation (), ChangelogOperation::kDelete );
141- EXPECT_EQ (t2->data_file ()->file_path , " /path/to/file_a.parquet" );
142- EXPECT_TRUE (t2->delete_files ().empty ());
159+ auto delete_t2 = std::dynamic_pointer_cast<DeletedDataFileScanTask>(t2);
160+ ASSERT_NE (delete_t2, nullptr );
161+ EXPECT_EQ (delete_t2->data_file ()->file_path , " /path/to/file_a.parquet" );
162+ EXPECT_TRUE (delete_t2->existing_deletes ().empty ());
143163}
144164
145165TEST_P (IncrementalChangelogScanTest, DuplicatedManifests) {
@@ -190,10 +210,14 @@ TEST_P(IncrementalChangelogScanTest, DuplicatedManifests) {
190210 ASSERT_EQ (tasks.size (), 2 );
191211 SortTasks (tasks);
192212
193- EXPECT_EQ (tasks[0 ]->data_file ()->file_path , " /path/to/file_a.parquet" );
213+ auto insert_t1 = std::dynamic_pointer_cast<AddedRowsScanTask>(tasks[0 ]);
214+ ASSERT_NE (insert_t1, nullptr );
215+ EXPECT_EQ (insert_t1->data_file ()->file_path , " /path/to/file_a.parquet" );
194216 EXPECT_EQ (tasks[0 ]->commit_snapshot_id (), 1000L );
195217
196- EXPECT_EQ (tasks[1 ]->data_file ()->file_path , " /path/to/file_b.parquet" );
218+ auto insert_t2 = std::dynamic_pointer_cast<AddedRowsScanTask>(tasks[1 ]);
219+ ASSERT_NE (insert_t2, nullptr );
220+ EXPECT_EQ (insert_t2->data_file ()->file_path , " /path/to/file_b.parquet" );
197221 EXPECT_EQ (tasks[1 ]->commit_snapshot_id (), 2000L );
198222}
199223
@@ -225,8 +249,10 @@ TEST_P(IncrementalChangelogScanTest, FileDeletes) {
225249 EXPECT_EQ (t1->change_ordinal (), 0 );
226250 EXPECT_EQ (t1->commit_snapshot_id (), 2000L );
227251 EXPECT_EQ (t1->operation (), ChangelogOperation::kDelete );
228- EXPECT_EQ (t1->data_file ()->file_path , " /path/to/file_a.parquet" );
229- EXPECT_TRUE (t1->delete_files ().empty ());
252+ auto delete_t1 = std::dynamic_pointer_cast<DeletedDataFileScanTask>(t1);
253+ ASSERT_NE (delete_t1, nullptr );
254+ EXPECT_EQ (delete_t1->data_file ()->file_path , " /path/to/file_a.parquet" );
255+ EXPECT_TRUE (delete_t1->existing_deletes ().empty ());
230256}
231257
232258TEST_P (IncrementalChangelogScanTest, ExistingEntriesInNewDataManifestsAreIgnored) {
@@ -278,8 +304,10 @@ TEST_P(IncrementalChangelogScanTest, ExistingEntriesInNewDataManifestsAreIgnored
278304 EXPECT_EQ (t1->change_ordinal (), 0 );
279305 EXPECT_EQ (t1->commit_snapshot_id (), 3000L );
280306 EXPECT_EQ (t1->operation (), ChangelogOperation::kInsert );
281- EXPECT_EQ (t1->data_file ()->file_path , " /path/to/file_c.parquet" );
282- EXPECT_TRUE (t1->delete_files ().empty ());
307+ auto insert_t1 = std::dynamic_pointer_cast<AddedRowsScanTask>(t1);
308+ ASSERT_NE (insert_t1, nullptr );
309+ EXPECT_EQ (insert_t1->data_file ()->file_path , " /path/to/file_c.parquet" );
310+ EXPECT_TRUE (insert_t1->delete_files ().empty ());
283311}
284312
285313TEST_P (IncrementalChangelogScanTest, DataFileRewrites) {
@@ -330,13 +358,17 @@ TEST_P(IncrementalChangelogScanTest, DataFileRewrites) {
330358 EXPECT_EQ (t1->change_ordinal (), 0 );
331359 EXPECT_EQ (t1->commit_snapshot_id (), 1000L );
332360 EXPECT_EQ (t1->operation (), ChangelogOperation::kInsert );
333- EXPECT_EQ (t1->data_file ()->file_path , " /path/to/file_a.parquet" );
361+ auto insert_t1 = std::dynamic_pointer_cast<AddedRowsScanTask>(t1);
362+ ASSERT_NE (insert_t1, nullptr );
363+ EXPECT_EQ (insert_t1->data_file ()->file_path , " /path/to/file_a.parquet" );
334364
335365 auto t2 = tasks[1 ];
336366 EXPECT_EQ (t2->change_ordinal (), 1 );
337367 EXPECT_EQ (t2->commit_snapshot_id (), 2000L );
338368 EXPECT_EQ (t2->operation (), ChangelogOperation::kInsert );
339- EXPECT_EQ (t2->data_file ()->file_path , " /path/to/file_b.parquet" );
369+ auto insert_t2 = std::dynamic_pointer_cast<AddedRowsScanTask>(t2);
370+ ASSERT_NE (insert_t2, nullptr );
371+ EXPECT_EQ (insert_t2->data_file ()->file_path , " /path/to/file_b.parquet" );
340372}
341373
342374TEST_P (IncrementalChangelogScanTest, ManifestRewritesAreIgnored) {
@@ -393,19 +425,25 @@ TEST_P(IncrementalChangelogScanTest, ManifestRewritesAreIgnored) {
393425 EXPECT_EQ (t1->change_ordinal (), 0 );
394426 EXPECT_EQ (t1->commit_snapshot_id (), 1000L );
395427 EXPECT_EQ (t1->operation (), ChangelogOperation::kInsert );
396- EXPECT_EQ (t1->data_file ()->file_path , " /path/to/file_a.parquet" );
428+ auto insert_t1 = std::dynamic_pointer_cast<AddedRowsScanTask>(t1);
429+ ASSERT_NE (insert_t1, nullptr );
430+ EXPECT_EQ (insert_t1->data_file ()->file_path , " /path/to/file_a.parquet" );
397431
398432 auto t2 = tasks[1 ];
399433 EXPECT_EQ (t2->change_ordinal (), 1 );
400434 EXPECT_EQ (t2->commit_snapshot_id (), 2000L );
401435 EXPECT_EQ (t2->operation (), ChangelogOperation::kInsert );
402- EXPECT_EQ (t2->data_file ()->file_path , " /path/to/file_b.parquet" );
436+ auto insert_t2 = std::dynamic_pointer_cast<AddedRowsScanTask>(t2);
437+ ASSERT_NE (insert_t2, nullptr );
438+ EXPECT_EQ (insert_t2->data_file ()->file_path , " /path/to/file_b.parquet" );
403439
404440 auto t3 = tasks[2 ];
405441 EXPECT_EQ (t3->change_ordinal (), 2 );
406442 EXPECT_EQ (t3->commit_snapshot_id (), 4000L );
407443 EXPECT_EQ (t3->operation (), ChangelogOperation::kInsert );
408- EXPECT_EQ (t3->data_file ()->file_path , " /path/to/file_c.parquet" );
444+ auto insert_t3 = std::dynamic_pointer_cast<AddedRowsScanTask>(t3);
445+ ASSERT_NE (insert_t3, nullptr );
446+ EXPECT_EQ (insert_t3->data_file ()->file_path , " /path/to/file_c.parquet" );
409447}
410448
411449TEST_P (IncrementalChangelogScanTest, DeleteFilesAreNotSupported) {
0 commit comments