This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git


The following commit(s) were added to refs/heads/main by this push:
     new cf49e3e5 fix(ipc): preserve map child field metadata (#809)
cf49e3e5 is described below

commit cf49e3e5437dc104d76924e6f43da982e01c29f3
Author: Dima Kuznetsov <[email protected]>
AuthorDate: Tue May 12 19:16:32 2026 +0300

    fix(ipc): preserve map child field metadata (#809)
    
    ### Rationale for this change
    
    IPC deserialization of `MapType` reconstructed map key/value children
    from only their data types, which dropped field-level metadata on the
    key and value fields. This could silently lose metadata such as field
    IDs after an IPC schema round-trip.
    
    ### What changes are included in this PR?
    
    The IPC metadata reader now reconstructs `MapType` using
    `arrow.MapOfFields(...)` with the already-deserialized key and value
    fields, preserving their metadata and nullability.
    
    A regression test was added to verify that map key/value field metadata,
    item nullability, and `KeysSorted` survive an IPC schema round-trip.
    
    ### Are these changes tested?
    
    Yes - unit test included.
    
    ### Are there any user-facing changes?
    
    Yes - IPC schema deserialization now preserves field-level metadata on
    MapType key and value children.
---
 arrow/ipc/metadata.go      |  3 +--
 arrow/ipc/metadata_test.go | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/arrow/ipc/metadata.go b/arrow/ipc/metadata.go
index 91f37af7..c139f95e 100644
--- a/arrow/ipc/metadata.go
+++ b/arrow/ipc/metadata.go
@@ -843,8 +843,7 @@ func concreteTypeFromFB(typ flatbuf.Type, data 
flatbuffers.Table, children []arr
 
                var dt flatbuf.Map
                dt.Init(data.Bytes, data.Pos)
-               ret := arrow.MapOf(pairType.Field(0).Type, 
pairType.Field(1).Type)
-               ret.SetItemNullable(pairType.Field(1).Nullable)
+               ret := arrow.MapOfFields(pairType.Field(0), pairType.Field(1))
                ret.KeysSorted = dt.KeysSorted()
                return ret, nil
 
diff --git a/arrow/ipc/metadata_test.go b/arrow/ipc/metadata_test.go
index 64898890..ac8820dc 100644
--- a/arrow/ipc/metadata_test.go
+++ b/arrow/ipc/metadata_test.go
@@ -86,6 +86,47 @@ func TestRWSchema(t *testing.T) {
        }
 }
 
+func TestMapFieldMetadataRoundTrip(t *testing.T) {
+       keyMeta := arrow.NewMetadata([]string{"my.key.id"}, []string{"100"})
+       itemMeta := arrow.NewMetadata([]string{"my.item.id"}, []string{"200"})
+
+       mapType := arrow.MapOfFields(
+               arrow.Field{Name: "key", Type: arrow.BinaryTypes.String, 
Metadata: keyMeta},
+               arrow.Field{Name: "value", Type: arrow.PrimitiveTypes.Int32, 
Nullable: true, Metadata: itemMeta},
+       )
+       mapType.KeysSorted = true
+       schema := arrow.NewSchema([]arrow.Field{
+               {Name: "m", Type: mapType, Nullable: true},
+       }, nil)
+
+       var buf bytes.Buffer
+       w := NewWriter(&buf, WithSchema(schema), 
WithAllocator(memory.DefaultAllocator))
+       if err := w.Close(); err != nil {
+               t.Fatal(err)
+       }
+
+       r, err := NewReader(bytes.NewReader(buf.Bytes()), 
WithAllocator(memory.DefaultAllocator))
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer r.Release()
+
+       roundTripped := r.Schema()
+       if !roundTripped.Equal(schema) {
+               t.Fatalf("schema mismatch after IPC round-trip:\ngot:  
%s\nwant: %s", roundTripped, schema)
+       }
+
+       rtMap := roundTripped.Field(0).Type.(*arrow.MapType)
+       if got, ok := rtMap.KeyField().Metadata.GetValue("my.key.id"); !ok || 
got != "100" {
+               t.Fatalf("key field metadata lost after IPC round-trip: got 
keys=%v", rtMap.KeyField().Metadata.Keys())
+       }
+       if got, ok := rtMap.ItemField().Metadata.GetValue("my.item.id"); !ok || 
got != "200" {
+               t.Fatalf("item field metadata lost after IPC round-trip: got 
keys=%v", rtMap.ItemField().Metadata.Keys())
+       }
+       assert.True(t, rtMap.ItemField().Nullable)
+       assert.True(t, rtMap.KeysSorted)
+}
+
 func TestRWFooter(t *testing.T) {
        for _, tc := range []struct {
                schema *arrow.Schema

Reply via email to