@@ -113,6 +113,14 @@ class FileScanTaskReaderTest : public TempFileTestBase {
113113 table_schema_->schema_id ());
114114 }
115115
116+ std::shared_ptr<Schema> RowLineageProjection () const {
117+ return std::make_shared<Schema>(
118+ std::vector<SchemaField>{SchemaField::MakeRequired (1 , " id" , int32 ()),
119+ MetadataColumns::kRowId ,
120+ MetadataColumns::kLastUpdatedSequenceNumber },
121+ table_schema_->schema_id ());
122+ }
123+
116124 Result<ExportedBatch> MakeBatch (const Schema& schema,
117125 const std::string& json_data) const {
118126 ICEBERG_ASSIGN_OR_RAISE (auto arrow_schema, MakeArrowSchema (schema));
@@ -409,17 +417,12 @@ TEST_F(FileScanTaskReaderTest, ReadLastUpdatedFromDataSeq) {
409417 data_file->first_row_id = 100L ;
410418 data_file->data_sequence_number = 5L ;
411419 FileScanTask task (data_file);
412- auto projected_schema = std::make_shared<Schema>(
413- std::vector<SchemaField>{SchemaField::MakeRequired (1 , " id" , int32 ()),
414- MetadataColumns::kRowId ,
415- MetadataColumns::kLastUpdatedSequenceNumber },
416- table_schema_->schema_id ());
417420
418421 FileScanTaskReader::Options options{
419422 .io = file_io_,
420423 .table_schema = table_schema_,
421424 .schemas = {table_schema_},
422- .projected_schema = projected_schema ,
425+ .projected_schema = RowLineageProjection () ,
423426 };
424427 ICEBERG_UNWRAP_OR_FAIL (auto reader, FileScanTaskReader::Make (std::move (options)));
425428 auto stream_result = reader->Open (task);
@@ -504,6 +507,80 @@ TEST_F(FileScanTaskReaderTest, OpenWithEqualityDeletesAddsAndPrunesDeleteOnlyCol
504507 ASSERT_NO_FATAL_FAILURE (VerifyStream (&stream, R"( [[1, "Foo"], [3, "Baz"]])" ));
505508}
506509
510+ TEST_F (FileScanTaskReaderTest, PositionDeletesPreserveRowLineage) {
511+ ICEBERG_UNWRAP_OR_FAIL (
512+ auto data_file,
513+ MakeDataFile (table_schema_,
514+ R"( [[1, "Foo", "blue"], [2, "Bar", "red"], [3, "Baz", "green"]])" ));
515+ data_file->first_row_id = 100 ;
516+ data_file->data_sequence_number = 5 ;
517+ ICEBERG_UNWRAP_OR_FAIL (
518+ auto pos_delete, MakePositionDeleteFile (CreateNewTempFilePathWithSuffix (" .parquet" ),
519+ {1 }, data_file->file_path ));
520+ FileScanTask task (data_file, {pos_delete});
521+
522+ FileScanTaskReader::Options options{
523+ .io = file_io_,
524+ .table_schema = table_schema_,
525+ .schemas = {table_schema_},
526+ .projected_schema = RowLineageProjection (),
527+ };
528+ ICEBERG_UNWRAP_OR_FAIL (auto reader, FileScanTaskReader::Make (std::move (options)));
529+ ICEBERG_UNWRAP_OR_FAIL (auto stream, reader->Open (task));
530+
531+ ASSERT_NO_FATAL_FAILURE (VerifyStream (&stream, R"( [[1, 100, 5], [3, 102, 5]])" ));
532+ }
533+
534+ TEST_F (FileScanTaskReaderTest, DeletionVectorDeletesPreserveRowLineage) {
535+ ICEBERG_UNWRAP_OR_FAIL (
536+ auto data_file,
537+ MakeDataFile (table_schema_,
538+ R"( [[1, "Foo", "blue"], [2, "Bar", "red"], [3, "Baz", "green"]])" ));
539+ data_file->first_row_id = 100 ;
540+ data_file->data_sequence_number = 5 ;
541+ ICEBERG_UNWRAP_OR_FAIL (
542+ auto deletion_vector,
543+ MakeDeletionVectorFile (CreateNewTempFilePathWithSuffix (" .puffin" ), {1 },
544+ data_file->file_path ));
545+ FileScanTask task (data_file, {deletion_vector});
546+
547+ FileScanTaskReader::Options options{
548+ .io = file_io_,
549+ .table_schema = table_schema_,
550+ .schemas = {table_schema_},
551+ .projected_schema = RowLineageProjection (),
552+ };
553+ ICEBERG_UNWRAP_OR_FAIL (auto reader, FileScanTaskReader::Make (std::move (options)));
554+ ICEBERG_UNWRAP_OR_FAIL (auto stream, reader->Open (task));
555+
556+ ASSERT_NO_FATAL_FAILURE (VerifyStream (&stream, R"( [[1, 100, 5], [3, 102, 5]])" ));
557+ }
558+
559+ TEST_F (FileScanTaskReaderTest, EqualityDeletesPreserveRowLineage) {
560+ ICEBERG_UNWRAP_OR_FAIL (
561+ auto data_file,
562+ MakeDataFile (table_schema_,
563+ R"( [[1, "Foo", "blue"], [2, "Bar", "red"], [3, "Baz", "green"]])" ));
564+ data_file->first_row_id = 100 ;
565+ data_file->data_sequence_number = 5 ;
566+ ICEBERG_UNWRAP_OR_FAIL (
567+ auto equality_delete,
568+ MakeEqualityDeleteFile (CreateNewTempFilePathWithSuffix (" .parquet" ), table_schema_,
569+ R"( [[0, "unused", "red"]])" , {3 }));
570+ FileScanTask task (data_file, {equality_delete});
571+
572+ FileScanTaskReader::Options options{
573+ .io = file_io_,
574+ .table_schema = table_schema_,
575+ .schemas = {table_schema_},
576+ .projected_schema = RowLineageProjection (),
577+ };
578+ ICEBERG_UNWRAP_OR_FAIL (auto reader, FileScanTaskReader::Make (std::move (options)));
579+ ICEBERG_UNWRAP_OR_FAIL (auto stream, reader->Open (task));
580+
581+ ASSERT_NO_FATAL_FAILURE (VerifyStream (&stream, R"( [[1, 100, 5], [3, 102, 5]])" ));
582+ }
583+
507584TEST_F (FileScanTaskReaderTest, OpenWithEqualityDeletesKeepsInputBatchWhenAllRowsAlive) {
508585 ICEBERG_UNWRAP_OR_FAIL (
509586 auto data_file,
0 commit comments