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 <[email protected]>
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 == "" {