From d431bcf3c73b500e8cc2995738e4f5a072ce47f0 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Tue, 14 Jul 2026 13:56:05 -0400 Subject: [PATCH 1/5] csup: fix panic in metadataValue --- csup/metadata.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/csup/metadata.go b/csup/metadata.go index 0f1adfcdf..7d2e95828 100644 --- a/csup/metadata.go +++ b/csup/metadata.go @@ -350,10 +350,14 @@ func metadataValue(cctx *Context, sctx *super.Context, b *scode.Builder, id ID, continue } min2, max2 := val.Deref("min"), val.Deref("max") - if min == nil || (min2 != nil && cmp(*min, *min2) > 0) { + if min == nil { + min, max = min2, max2 + continue + } + if cmp(*min, *min2) > 0 { min = new(min2.Copy()) } - if max == nil || (max2 != nil && cmp(*max, *max2) < 0) { + if cmp(*max, *max2) < 0 { max = new(max2.Copy()) } } From c6a1a16ba1eadff7cc74a5f9a6f8b3fc84d1c6bb Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Tue, 14 Jul 2026 16:47:08 -0400 Subject: [PATCH 2/5] add missing Value.Copy --- csup/metadata.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csup/metadata.go b/csup/metadata.go index 7d2e95828..63fddeb47 100644 --- a/csup/metadata.go +++ b/csup/metadata.go @@ -351,7 +351,8 @@ func metadataValue(cctx *Context, sctx *super.Context, b *scode.Builder, id ID, } min2, max2 := val.Deref("min"), val.Deref("max") if min == nil { - min, max = min2, max2 + min = new(min2.Copy()) + max = new(max2.Copy()) continue } if cmp(*min, *min2) > 0 { From 1e41d1b4979cf7d730c6058c51deab08b5715cda Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Tue, 14 Jul 2026 17:15:18 -0400 Subject: [PATCH 3/5] add mising nil check --- csup/metadata.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/csup/metadata.go b/csup/metadata.go index 63fddeb47..18727056d 100644 --- a/csup/metadata.go +++ b/csup/metadata.go @@ -351,8 +351,10 @@ func metadataValue(cctx *Context, sctx *super.Context, b *scode.Builder, id ID, } min2, max2 := val.Deref("min"), val.Deref("max") if min == nil { - min = new(min2.Copy()) - max = new(max2.Copy()) + if min2 != nil { + min = new(min2.Copy()) + max = new(max2.Copy()) + } continue } if cmp(*min, *min2) > 0 { From 20c879f5cfacb11ad55b5f249132473a1b219cb8 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Tue, 14 Jul 2026 17:24:33 -0400 Subject: [PATCH 4/5] simplify --- csup/metadata.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/csup/metadata.go b/csup/metadata.go index 18727056d..872b8a8db 100644 --- a/csup/metadata.go +++ b/csup/metadata.go @@ -342,33 +342,29 @@ func metadataValue(cctx *Context, sctx *super.Context, b *scode.Builder, id ID, return sctx.MustLookupTypeRecord(fields) case *Union: cmp := expr.NewValueCompareFn(order.Asc, order.NullsLast) + max, min := super.Null, super.Null var bb scode.Builder - var min, max *super.Value for _, id := range m.Values { val := newMetadataValue(cctx, sctx, &bb, id, projection) if val.IsNull() { continue } min2, max2 := val.Deref("min"), val.Deref("max") - if min == nil { - if min2 != nil { - min = new(min2.Copy()) - max = new(max2.Copy()) - } + if min2 == nil { continue } - if cmp(*min, *min2) > 0 { - min = new(min2.Copy()) + if min.IsNull() || cmp(min, *min2) > 0 { + min = min2.Copy() } - if cmp(*max, *max2) < 0 { - max = new(max2.Copy()) + if max.IsNull() || cmp(max, *max2) < 0 { + max = max2.Copy() } } - if min == nil { + if min.IsNull() { b.Append(nil) return super.TypeNull } - return metadataLeaf(sctx, b, *min, *max) + return metadataLeaf(sctx, b, min, max) case *Int: return metadataLeaf(sctx, b, super.NewInt(m.Typ, m.Min), super.NewInt(m.Typ, m.Max)) case *Uint: From 1b93edc908a401c5af5e7610e2d13ffa51628cf2 Mon Sep 17 00:00:00 2001 From: Noah Treuhaft Date: Tue, 14 Jul 2026 17:40:42 -0400 Subject: [PATCH 5/5] add test --- csup/object_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csup/object_test.go b/csup/object_test.go index 5fbbfc8e1..8768d1585 100644 --- a/csup/object_test.go +++ b/csup/object_test.go @@ -41,8 +41,8 @@ func TestObjectProjectMetadata(t *testing.T) { func TestObjectProjectMetadataForUnion(t *testing.T) { sctx := super.NewContext() supValues := []string{ - "{a:1::(int64|string),b?:2,c:3::(int64|null)}", - `{a:"s"::(int64|string),b?:_::int64,c:null::(int64|null)}`, + "{a:1::(int64|string),b?:2,c:3::(int64|null),d?:{e:4}}", + `{a:"s"::(int64|string),b?:_::int64,c:null::(int64|null),d?:_::{e:int64}}`, } builder := vector.NewDynamicValueBuilder() for _, s := range supValues { @@ -56,8 +56,8 @@ func TestObjectProjectMetadataForUnion(t *testing.T) { o, err := csup.NewObject(bytes.NewReader(csupBytes)) require.NoError(t, err) - p := field.NewProjection(field.DottedList("a,b,c")) + p := field.NewProjection(field.DottedList("a,b,c,d")) values := o.ProjectMetadata(super.NewContext(), p) require.Len(t, values, 1) - require.Equal(t, `{a:{min:1,max:"s"},b:{min:2,max:2},c:{min:3,max:3}}`, sup.FormatValue(values[0])) + require.Equal(t, `{a:{min:1,max:"s"},b:{min:2,max:2},c:{min:3,max:3},d:null}`, sup.FormatValue(values[0])) }