Apache Iceberg version
main @ 035fc1e
Query engine
None — engine-agnostic, core variant shredding API
Please describe the bug
ShreddedObject.put(field, value) does not clear a prior remove(field) marker, so after remove() then put() on the same field, get()/fieldNames()/numFields() report the field as missing while writeTo() still serializes it with the new value.
See ShreddedObject.put(String, VariantValue) (core/src/main/java/org/apache/iceberg/variants/ShreddedObject.java line 92-100).
get() short-circuits on removedFields.contains(field) (line 102-106) and nameSet() removes removedFields from the name set (line 64-74); SerializationState builds its field list from shreddedFields, which put() already updated.
Steps to reproduce
ShreddedObject o = new ShreddedObject(metadata)
o.put("a", value1)
o.remove("a") — o.get("a") returns null.
o.put("a", value2) — expected: o.get("a") returns value2.
Actual: o.get("a") still returns null, and o.numFields()/o.fieldNames() exclude "a".
o.writeTo(buffer, 0) — the serialized bytes contain "a" with value2, contradicting step 4.
Additional context
Fix: clear the removedFields marker in put().
Apache Iceberg version
main @ 035fc1e
Query engine
None — engine-agnostic, core variant shredding API
Please describe the bug
ShreddedObject.put(field, value)does not clear a priorremove(field)marker, so afterremove()thenput()on the same field,get()/fieldNames()/numFields()report the field as missing whilewriteTo()still serializes it with the new value.See
ShreddedObject.put(String, VariantValue)(core/src/main/java/org/apache/iceberg/variants/ShreddedObject.javaline 92-100).get()short-circuits onremovedFields.contains(field)(line 102-106) andnameSet()removesremovedFieldsfrom the name set (line 64-74);SerializationStatebuilds its field list fromshreddedFields, whichput()already updated.Steps to reproduce
ShreddedObject o = new ShreddedObject(metadata)o.put("a", value1)o.remove("a")—o.get("a")returnsnull.o.put("a", value2)— expected:o.get("a")returnsvalue2.Actual:
o.get("a")still returnsnull, ando.numFields()/o.fieldNames()exclude"a".o.writeTo(buffer, 0)— the serialized bytes contain"a"withvalue2, contradicting step 4.Additional context
Fix: clear the
removedFieldsmarker input().