-
Notifications
You must be signed in to change notification settings - Fork 213
fix(table): reject nil uuid assignment updates #1329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -902,13 +902,17 @@ func (b *MetadataBuilder) RemoveSnapshotRef(name string) error { | |
| return nil | ||
| } | ||
|
|
||
| func (b *MetadataBuilder) SetUUID(uuid uuid.UUID) error { | ||
| if b.uuid == uuid { | ||
| func (b *MetadataBuilder) SetUUID(newUUID uuid.UUID) error { | ||
| if newUUID == uuid.Nil { | ||
| return fmt.Errorf("%w: cannot set uuid to nil", iceberg.ErrInvalidArgument) | ||
| } | ||
|
|
||
| if b.uuid == newUUID { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional / possibly out of scope: Java's assignUUID enforces a second invariant beyond non-nul, "Cannot reassign uuid", i.e. once a non-nil UUID is set you can't change it to a different one. Here SetUUID |
||
| return nil | ||
| } | ||
|
|
||
| b.updates = append(b.updates, NewAssignUUIDUpdate(uuid)) | ||
| b.uuid = uuid | ||
| b.updates = append(b.updates, NewAssignUUIDUpdate(newUUID)) | ||
| b.uuid = newUUID | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2317,6 +2317,30 @@ func TestSetFormatVersionPreservesExistingUUID(t *testing.T) { | |
| require.Equal(t, existingUUID, meta.TableUUID()) | ||
| } | ||
|
|
||
| func TestSetUUIDRejectsNil(t *testing.T) { | ||
| builder := builderWithoutChanges(2) | ||
| originalUUID := builder.uuid | ||
|
|
||
| err := builder.SetUUID(uuid.Nil) | ||
| require.ErrorIs(t, err, iceberg.ErrInvalidArgument) | ||
| require.False(t, builder.HasChanges()) | ||
| require.Equal(t, originalUUID, builder.uuid) | ||
|
|
||
| meta, err := builder.Build() | ||
| require.NoError(t, err) | ||
| require.Equal(t, originalUUID, meta.TableUUID()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The whole design rests on |
||
| } | ||
|
|
||
| func TestNewMetadataWithUUIDGeneratesUUIDForNil(t *testing.T) { | ||
| tableSchema := schema() | ||
| partSpec := partitionSpec() | ||
| order := sortOrder() | ||
|
|
||
| meta, err := NewMetadataWithUUID(&tableSchema, &partSpec, order, "s3://bucket/test/location", nil, uuid.Nil) | ||
| require.NoError(t, err) | ||
| require.NotEqual(t, uuid.Nil, meta.TableUUID()) | ||
| } | ||
|
|
||
| func TestSetFormatVersionDowngradeNotAllowed(t *testing.T) { | ||
| builder := builderWithoutChanges(2) | ||
| err := builder.SetFormatVersion(1) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, routing the guard through SetUUID means the assign-uuid update path (updates.go:177 -> SetUUID) is covered by the same check, so no second guard is needed. And the uuid -> newUUID rename is actually required here, since the old
uuidparam shadowed the package anduuid.Nilwasn't referenceable. Matches Java's assignUUID precondition too.