Skip to content

Commit 4bf7ae6

Browse files
authored
fix: field name mismatch when alter table rename caused by FieldMappingReader (#274)
1 parent 0dafd41 commit 4bf7ae6

2 files changed

Lines changed: 50 additions & 0 deletions

File tree

src/paimon/core/io/field_mapping_reader.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ FieldMappingReader::FieldMappingReader(int32_t field_count,
6565
if (non_partition_info_.cast_executors[i] != nullptr) {
6666
need_casting_ = true;
6767
}
68+
// Field name change (RENAME COLUMN) also requires mapping: data schema
69+
// carries the file's physical name while read schema carries the
70+
// post-rename logical name. If we skipped mapping, the inner reader's
71+
// batch would be passed through with the old physical name and the
72+
// consumer's name-based lookup against the read schema would fail.
73+
if (non_partition_info_.non_partition_data_schema[i].Name() !=
74+
non_partition_info_.non_partition_read_schema[i].Name()) {
75+
need_mapping_ = true;
76+
}
6877
}
6978
}
7079

src/paimon/core/io/field_mapping_reader_test.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,47 @@ TEST_F(FieldMappingReaderTest, TestReadWithSchemaEvolutionWithRenameAndModifyTyp
597597
CheckResult(read_schema, /*predicate=*/nullptr, expect_data);
598598
}
599599

600+
TEST_F(FieldMappingReaderTest, TestReadWithSchemaEvolutionPureRename) {
601+
// Regression: pure RENAME (same field ids, same types, identity order, no
602+
// partition / non-exist) used to leave need_mapping_ false, taking the
603+
// FieldMappingReader PASSTHRU path. The inner reader's batch was emitted
604+
// unchanged carrying the file's physical column names, so a consumer that
605+
// looked columns up by name against the read schema (post-rename logical
606+
// names) failed to find them.
607+
608+
// File schema: physical names f0, f1
609+
std::vector<DataField> data_fields = {DataField(0, arrow::field("f0", arrow::utf8())),
610+
DataField(1, arrow::field("f1", arrow::int32()))};
611+
auto data_schema = DataField::ConvertDataFieldsToArrowSchema(data_fields);
612+
auto data_array = std::dynamic_pointer_cast<arrow::StructArray>(
613+
arrow::ipc::internal::json::ArrayFromJSON(arrow::struct_({data_schema->fields()}),
614+
R"([
615+
["Alice", 1],
616+
["Bob", 2],
617+
["Carol", 3]
618+
])")
619+
.ValueOrDie());
620+
621+
// Read schema: same field ids, RENAMED names, same types, identity order
622+
std::vector<DataField> read_fields = {DataField(0, arrow::field("name_new", arrow::utf8())),
623+
DataField(1, arrow::field("age_new", arrow::int32()))};
624+
auto read_schema = DataField::ConvertDataFieldsToArrowSchema(read_fields);
625+
626+
// Expected output uses the post-rename names; verifies mapping actually
627+
// ran (PASSTHRU would keep f0/f1 and Equals would fail).
628+
auto expected = std::dynamic_pointer_cast<arrow::StructArray>(
629+
arrow::ipc::internal::json::ArrayFromJSON(arrow::struct_({read_schema->fields()}),
630+
R"([
631+
["Alice", 1],
632+
["Bob", 2],
633+
["Carol", 3]
634+
])")
635+
.ValueOrDie());
636+
637+
CheckResult(data_schema, data_array, read_schema, /*predicate=*/nullptr,
638+
/*partition_keys=*/{}, BinaryRow::EmptyRow(), expected);
639+
}
640+
600641
TEST_F(FieldMappingReaderTest, TestReadWithSchemaEvolutionWithRenameAndModifyTypeAndPredicate) {
601642
// field_0 and field_3 are rename and modify type
602643
// result is not filtered by predicate, as DOUBLE->STRING alter table does not support predicate

0 commit comments

Comments
 (0)