You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ze...@apache.org on 2026/07/23 18:12:26 UTC

(arrow-go) branch main updated: fix(parquet/variant): handle empty metadata keys (#985)

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 2bc506ad fix(parquet/variant): handle empty metadata keys (#985)
2bc506ad is described below

commit 2bc506ad7db7138e012001f4897629de543d8879
Author: Minh Vu <vu...@gmail.com>
AuthorDate: Thu Jul 23 20:12:21 2026 +0200

    fix(parquet/variant): handle empty metadata keys (#985)
    
    ### Rationale for this change
    
    Variant metadata may contain an empty object key. `Metadata.KeyAt`
    validates the dictionary index, then previously took the address of the
    key's first byte. That panics when the key is empty.
    
    ### What changes are included in this PR?
    
    Use `unsafe.SliceData` for the existing zero-copy byte-to-string
    conversion so zero-length keys are handled safely. Add a builder-based
    regression covering both `KeyAt` and `IdFor`.
    
    ### Are these changes tested?
    
    Yes:
    
    - `go test ./parquet/variant`
    - `go test -race -count=1 ./parquet/variant`
    
    ### Are there any user-facing changes?
    
    `Metadata.KeyAt` now returns an empty string for a valid empty key
    instead of panicking. There is no API change.
---
 parquet/variant/variant.go      |  3 ++-
 parquet/variant/variant_test.go | 16 ++++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/parquet/variant/variant.go b/parquet/variant/variant.go
index 0e8a904b..25eacd43 100644
--- a/parquet/variant/variant.go
+++ b/parquet/variant/variant.go
@@ -258,7 +258,8 @@ func (m Metadata) KeyAt(id uint32) (string, error) {
 			id, len(m.keys))
 	}
 
-	return unsafe.String(&m.keys[id][0], len(m.keys[id])), nil
+	key := m.keys[id]
+	return unsafe.String(unsafe.SliceData(key), len(key)), nil
 }
 
 // IdFor returns the dictionary IDs for the given key.
diff --git a/parquet/variant/variant_test.go b/parquet/variant/variant_test.go
index b2f55339..649a719c 100644
--- a/parquet/variant/variant_test.go
+++ b/parquet/variant/variant_test.go
@@ -122,6 +122,22 @@ func TestBasicRead(t *testing.T) {
 	})
 }
 
+func TestMetadataEmptyKey(t *testing.T) {
+	var b variant.Builder
+	start := b.Offset()
+	fields := []variant.FieldEntry{b.NextField(start, "")}
+	require.NoError(t, b.AppendNull())
+	require.NoError(t, b.FinishObject(start, fields))
+	value, err := b.Build()
+	require.NoError(t, err)
+	metadata := value.Metadata()
+
+	key, err := metadata.KeyAt(0)
+	require.NoError(t, err)
+	assert.Empty(t, key)
+	assert.Equal(t, []uint32{0}, metadata.IdFor(""))
+}
+
 func loadVariant(t *testing.T, test string) variant.Value {
 	dir := getVariantDir()
 	if dir == "" {