diff --git a/arrow/extensions/variant.go b/arrow/extensions/variant.go index fee2e046..55594696 100644 --- a/arrow/extensions/variant.go +++ b/arrow/extensions/variant.go @@ -225,6 +225,10 @@ func NewVariantType(storage arrow.DataType) (*VariantType, error) { dt = dt.(arrow.ExtensionType).StorageType() } + if dt.ID() == arrow.NULL { + return nil, fmt.Errorf("%w: typed_value field must not be null type", arrow.ErrInvalid) + } + if nt, ok := dt.(arrow.NestedType); ok { if !validNestedType(nt) { return nil, fmt.Errorf("%w: typed_value field must be a valid nested type, got %s", arrow.ErrInvalid, typedValueField.Type) @@ -295,7 +299,10 @@ func validStruct(s *arrow.StructType) bool { switch s.NumFields() { case 1: f := s.Field(0) - return (f.Name == "value" && isBinary(f.Type)) || f.Name == "typed_value" + if f.Name == "value" { + return isBinary(f.Type) + } + return f.Name == "typed_value" && f.Type.ID() != arrow.NULL case 2: valField, ok := s.FieldByName("value") if !ok || !valField.Nullable || !isBinary(valField.Type) { @@ -311,7 +318,7 @@ func validStruct(s *arrow.StructType) bool { return validNestedType(nt) } - return true + return typedField.Type.ID() != arrow.NULL default: return false } diff --git a/arrow/extensions/variant_test.go b/arrow/extensions/variant_test.go index a39fd513..e4917746 100644 --- a/arrow/extensions/variant_test.go +++ b/arrow/extensions/variant_test.go @@ -83,6 +83,11 @@ func TestVariantExtensionType(t *testing.T) { arrow.Field{Name: "metadata", Type: arrow.BinaryTypes.String, Nullable: false}, arrow.Field{Name: "value", Type: arrow.BinaryTypes.Binary, Nullable: false}), "metadata field must be non-nullable binary type, got utf8"}, + {arrow.StructOf( + arrow.Field{Name: "metadata", Type: arrow.BinaryTypes.Binary, Nullable: false}, + arrow.Field{Name: "value", Type: arrow.BinaryTypes.Binary, Nullable: true}, + arrow.Field{Name: "typed_value", Type: arrow.Null, Nullable: true}), + "typed_value field must not be null type"}, } for _, tt := range tests { @@ -113,6 +118,11 @@ func TestVariantExtensionBadNestedTypes(t *testing.T) { ), Nullable: false})}, {"empty struct elem", arrow.StructOf( arrow.Field{Name: "foobar", Type: arrow.StructOf(), Nullable: false})}, + {"null typed_value in shredded field", arrow.StructOf( + arrow.Field{Name: "foobar", Type: arrow.StructOf( + arrow.Field{Name: "value", Type: arrow.BinaryTypes.Binary, Nullable: true}, + arrow.Field{Name: "typed_value", Type: arrow.Null, Nullable: true}, + ), Nullable: false})}, {"non-nullable two elem struct", arrow.StructOf( arrow.Field{Name: "foobar", Type: arrow.StructOf( arrow.Field{Name: "value", Type: arrow.BinaryTypes.Binary, Nullable: true},