badalprasadsingh commented on code in PR #2511:
URL: https://github.com/apache/iceberg-go/pull/2511#discussion_r4534609189


##########
name_mapping.go:
##########
@@ -352,13 +354,18 @@ func (n indexedNameMappingAccessor) indexFields(field 
*MappedField) {
        for i := range field.Fields {
                mappedField := &field.Fields[i]
                for _, name := range mappedField.Names {
-                       if _, exists := fieldsByName[name]; !exists {
-                               fieldsByName[name] = mappedField
+                       if existing, ok := fieldsByName[name]; ok && existing 
!= mappedField {
+                               return fmt.Errorf("%w: duplicate name mapping 
%q", ErrInvalidSchema, name)

Review Comment:
   nit: the error gives only the name, so a nested duplicate such as element is 
hard to find in a large mapping. Adding both field IDs helps, and your 
ErrorContains checks still pass:
   
   ```go
   return fmt.Errorf("%w: duplicate name mapping %q (field IDs %d and %d)", 
ErrInvalidSchema, name, existing.ID(), mappedField.ID())
   ```



##########
name_mapping.go:
##########
@@ -352,13 +354,18 @@ func (n indexedNameMappingAccessor) indexFields(field 
*MappedField) {
        for i := range field.Fields {
                mappedField := &field.Fields[i]
                for _, name := range mappedField.Names {
-                       if _, exists := fieldsByName[name]; !exists {
-                               fieldsByName[name] = mappedField
+                       if existing, ok := fieldsByName[name]; ok && existing 
!= mappedField {

Review Comment:
   scans of files without field ids now fail on these mappings, where today the 
first entry silently wins
   
   iceberg-ava fails too, but users will see a new error, so I'd add a bullet 
under "Unreleased compatibility notes" in `website/src/releases.md`, like the 
identifier-field one



##########
name_mapping_test.go:
##########
@@ -117,6 +117,74 @@ func TestApplyNameMappingUsesAlias(t *testing.T) {
        assert.Equal(t, 1, result.Field(0).ID)
 }
 
+func TestApplyNameMappingRejectsDuplicateAliases(t *testing.T) {
+       schema := iceberg.NewSchema(0,
+               iceberg.NestedField{ID: 100, Name: "shared", Type: 
iceberg.PrimitiveTypes.String},
+       )
+       mapping := iceberg.NameMapping{
+               {FieldID: new(1), Names: []string{"original", "shared"}},
+               {FieldID: new(2), Names: []string{"shared"}},
+       }
+
+       result, err := iceberg.ApplyNameMapping(schema, mapping)
+       require.Nil(t, result)
+       require.ErrorIs(t, err, iceberg.ErrInvalidSchema)
+       assert.ErrorContains(t, err, `duplicate name mapping "shared"`)
+}
+
+func TestApplyNameMappingRejectsDuplicateNestedAliases(t *testing.T) {
+       schema := iceberg.NewSchema(0,
+               iceberg.NestedField{
+                       ID: 100, Name: "parent",
+                       Type: &iceberg.StructType{FieldList: 
[]iceberg.NestedField{
+                               {ID: 101, Name: "shared", Type: 
iceberg.PrimitiveTypes.String},
+                       }},
+               },
+       )
+       mapping := iceberg.NameMapping{
+               {FieldID: new(1), Names: []string{"parent"}, Fields: 
[]iceberg.MappedField{
+                       {FieldID: new(2), Names: []string{"original", 
"shared"}},
+                       {FieldID: new(3), Names: []string{"shared"}},
+               }},
+       }
+
+       result, err := iceberg.ApplyNameMapping(schema, mapping)
+       require.Nil(t, result)
+       require.ErrorIs(t, err, iceberg.ErrInvalidSchema)
+       assert.ErrorContains(t, err, `duplicate name mapping "shared"`)
+}
+
+func TestApplyNameMappingAllowsSameNestedNameInDifferentStructs(t *testing.T) {

Review Comment:
   no test covers the `existing != mappedField` exemption, so removing it would 
go unnoticed: accept a field that lists its own name twice (names is a set) -> 
add an allow case



##########
name_mapping.go:
##########
@@ -529,7 +536,11 @@ func (n *nameMapProjectVisitor) Variant(v VariantType, 
variantPartner *MappedFie
 
 func ApplyNameMapping(schemaWithoutIDs *Schema, nameMapping NameMapping) 
(*Schema, error) {
        partner := &MappedField{Fields: nameMapping}
-       accessor := newIndexedNameMappingAccessor(partner)
+       accessor, err := newIndexedNameMappingAccessor(partner)
+       if err != nil {
+               return nil, err
+       }

Review Comment:
   P1 (not new here): two mapping entries with the same field id still crash 
reads, if a file has both columns, NewSchema  panics in a scan go-routine and 
kills the process. 
   
   as this PR validates mappings, better: return an error too (or file an issue 
and raise a follow-up pr).
   
   ```go
   fields := top.Type.(*StructType).FieldList
   if err := checkDuplicateFieldIDs(nil, fields); err != nil {
        return nil, err
   }
   return NewSchema(schemaWithoutIDs.ID, fields...), nil
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to