This is an automated email from the ASF dual-hosted git repository.
laskoviymishka pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new 6693e2f3b refactor(catalog)!: rename PurgeableTable to
PurgeableCatalog (#2305)
6693e2f3b is described below
commit 6693e2f3b4896a2edef68abbbdec356d184875c4
Author: Minh Vu <[email protected]>
AuthorDate: Sun Oct 25 19:05:56 2026 +0100
refactor(catalog)!: rename PurgeableTable to PurgeableCatalog (#2305)
---
catalog/catalog.go | 15 +++++++--------
catalog/example_multi_table_transaction_test.go | 2 ++
catalog/glue/glue.go | 2 +-
catalog/hadoop/hadoop.go | 2 +-
catalog/hive/hive.go | 2 +-
catalog/multi_table_transaction_test.go | 2 ++
catalog/rest/rest.go | 2 +-
catalog/sql/sql.go | 2 +-
catalog/sql/sql_test.go | 11 ++---------
cmd/iceberg/drop_test.go | 4 ++++
cmd/iceberg/main.go | 10 +---------
cmd/iceberg/properties_test.go | 4 ++++
cmd/iceberg/upgrade_rollback_test.go | 4 ++++
website/src/releases.md | 1 +
14 files changed, 32 insertions(+), 31 deletions(-)
diff --git a/catalog/catalog.go b/catalog/catalog.go
index d5bda95dc..6bd810d2b 100644
--- a/catalog/catalog.go
+++ b/catalog/catalog.go
@@ -121,6 +121,9 @@ func NewCreateViewCfg() CreateViewCfg {
type Catalog interface {
io.Closer
+ // PurgeableCatalog provides the mandatory physical table deletion API.
+ PurgeableCatalog
+
// CatalogType returns the type of the catalog.
CatalogType() Type
@@ -180,13 +183,9 @@ type TransactionalCatalog interface {
CommitTransaction(ctx context.Context, commits []table.TableCommit)
error
}
-// PurgeableTable is an optional interface that catalogs can implement
-// to support physical table deletion (catalog entry + underlying files).
-// Callers should check for this capability via a type assertion:
-//
-// if purger, ok := cat.(catalog.PurgeableTable); ok {
-// err := purger.PurgeTable(ctx, ident)
-// }
+// PurgeableCatalog is the small table purge interface embedded by Catalog.
+// Every Catalog must support PurgeTable, which removes the catalog entry and
+// performs best-effort physical file deletion.
//
// For REST catalogs the purge is delegated server-side. For client-side
// catalogs (SQL, Glue, Hive, Hadoop) the table is first dropped from
@@ -199,7 +198,7 @@ type TransactionalCatalog interface {
// Any file-deletion, directory walk, or listing errors encountered are logged
// as warnings, and the operation succeeds (returns nil) so that the catalog
drop
// remains the single source of truth.
-type PurgeableTable interface {
+type PurgeableCatalog interface {
PurgeTable(ctx context.Context, identifier table.Identifier) error
}
diff --git a/catalog/example_multi_table_transaction_test.go
b/catalog/example_multi_table_transaction_test.go
index 5a8614b58..7188d87a1 100644
--- a/catalog/example_multi_table_transaction_test.go
+++ b/catalog/example_multi_table_transaction_test.go
@@ -64,6 +64,8 @@ func (c *exampleCatalog) CommitTable(context.Context,
table.Identifier, []table.
func (c *exampleCatalog) DropTable(context.Context, table.Identifier) error {
return nil }
+func (c *exampleCatalog) PurgeTable(context.Context, table.Identifier) error {
return nil }
+
func (c *exampleCatalog) RenameTable(context.Context, table.Identifier,
table.Identifier) (*table.Table, error) {
return nil, nil
}
diff --git a/catalog/glue/glue.go b/catalog/glue/glue.go
index 5341340cd..9e70b0153 100644
--- a/catalog/glue/glue.go
+++ b/catalog/glue/glue.go
@@ -154,7 +154,7 @@ type glueAPI interface {
UpdateDatabase(ctx context.Context, params *glue.UpdateDatabaseInput,
optFns ...func(*glue.Options)) (*glue.UpdateDatabaseOutput, error)
}
-var _ catalog.PurgeableTable = (*Catalog)(nil)
+var _ catalog.Catalog = (*Catalog)(nil)
type Catalog struct {
glueSvc glueAPI
diff --git a/catalog/hadoop/hadoop.go b/catalog/hadoop/hadoop.go
index fc277687a..822126bf1 100644
--- a/catalog/hadoop/hadoop.go
+++ b/catalog/hadoop/hadoop.go
@@ -184,7 +184,7 @@ func validateIdentifierParts(ident table.Identifier,
identifierName, componentNa
// Catalog is a filesystem-based Iceberg catalog that requires no external
// metastore. All state lives on disk as directories and versioned JSON
// metadata files. Currently only local filesystem paths are supported.
-var _ catalog.PurgeableTable = (*Catalog)(nil)
+var _ catalog.Catalog = (*Catalog)(nil)
type Catalog struct {
name string
diff --git a/catalog/hive/hive.go b/catalog/hive/hive.go
index d460c2191..3354affa0 100644
--- a/catalog/hive/hive.go
+++ b/catalog/hive/hive.go
@@ -51,7 +51,7 @@ func init() {
}))
}
-var _ catalog.PurgeableTable = (*Catalog)(nil)
+var _ catalog.Catalog = (*Catalog)(nil)
type Catalog struct {
client HiveClient
diff --git a/catalog/multi_table_transaction_test.go
b/catalog/multi_table_transaction_test.go
index 88ddc42ec..03c3be089 100644
--- a/catalog/multi_table_transaction_test.go
+++ b/catalog/multi_table_transaction_test.go
@@ -81,6 +81,8 @@ func (s *fullStubCatalog) CommitTable(context.Context,
table.Identifier, []table
func (s *fullStubCatalog) DropTable(context.Context, table.Identifier) error {
return nil }
+func (s *fullStubCatalog) PurgeTable(context.Context, table.Identifier) error
{ return nil }
+
func (s *fullStubCatalog) RenameTable(context.Context, table.Identifier,
table.Identifier) (*table.Table, error) {
return nil, nil
}
diff --git a/catalog/rest/rest.go b/catalog/rest/rest.go
index 7e2eb7602..933392372 100644
--- a/catalog/rest/rest.go
+++ b/catalog/rest/rest.go
@@ -897,7 +897,7 @@ func toProps(o *options) iceberg.Properties {
return props
}
-var _ catalog.PurgeableTable = (*Catalog)(nil)
+var _ catalog.Catalog = (*Catalog)(nil)
type Catalog struct {
baseURI *url.URL
diff --git a/catalog/sql/sql.go b/catalog/sql/sql.go
index 1b1e216b0..6eaaef4db 100644
--- a/catalog/sql/sql.go
+++ b/catalog/sql/sql.go
@@ -382,7 +382,7 @@ func isRetryableSerializableError(err error) bool {
strings.Contains(msg, "ORA-00060")
}
-var _ catalog.PurgeableTable = (*Catalog)(nil)
+var _ catalog.Catalog = (*Catalog)(nil)
type Catalog struct {
db *bun.DB
diff --git a/catalog/sql/sql_test.go b/catalog/sql/sql_test.go
index 889c9609d..c2250d7c7 100644
--- a/catalog/sql/sql_test.go
+++ b/catalog/sql/sql_test.go
@@ -1565,11 +1565,7 @@ func (s *SqliteCatalogTestSuite) TestPurgeTable() {
s.Require().NoError(err)
s.Require().NoError(os.WriteFile(metaLoc, newMetaBytes, 0o644))
- // Assert that the catalog implements PurgeableTable
- purger, ok := any(tt.cat).(catalog.PurgeableTable)
- s.Require().True(ok, "catalog must implement PurgeableTable")
-
- s.NoError(purger.PurgeTable(context.Background(), tt.tblID))
+ s.NoError(tt.cat.PurgeTable(context.Background(), tt.tblID))
// The table catalog entry should be gone
_, err = tt.cat.LoadTable(context.Background(), tt.tblID)
@@ -1640,10 +1636,7 @@ func (s *SqliteCatalogTestSuite)
TestPurgeTableGCDisabled() {
metaLoc := strings.TrimPrefix(tbl.MetadataLocation(), "file://")
s.FileExists(metaLoc)
- purger, ok := any(tt.cat).(catalog.PurgeableTable)
- s.Require().True(ok, "catalog must implement PurgeableTable")
-
- s.NoError(purger.PurgeTable(context.Background(), tt.tblID))
+ s.NoError(tt.cat.PurgeTable(context.Background(), tt.tblID))
// The table catalog entry should be gone
_, err = tt.cat.LoadTable(context.Background(), tt.tblID)
diff --git a/cmd/iceberg/drop_test.go b/cmd/iceberg/drop_test.go
index ca4723c1b..aa141be4b 100644
--- a/cmd/iceberg/drop_test.go
+++ b/cmd/iceberg/drop_test.go
@@ -70,6 +70,10 @@ func (m *mockCatalogForDrop) DropTable(ctx context.Context,
identifier table.Ide
return m.dropErr
}
+func (m *mockCatalogForDrop) PurgeTable(context.Context, table.Identifier)
error {
+ return errors.New("catalog does not support purge")
+}
+
func (m *mockCatalogForDrop) RenameTable(ctx context.Context, from, to
table.Identifier) (*table.Table, error) {
return nil, nil
}
diff --git a/cmd/iceberg/main.go b/cmd/iceberg/main.go
index 0e6ac1bc1..47adb4a34 100644
--- a/cmd/iceberg/main.go
+++ b/cmd/iceberg/main.go
@@ -615,15 +615,7 @@ func runDrop(ctx context.Context, output Output, cat
catalog.Catalog, cmd *DropC
ident := catalog.ToIdentifier(cmd.Table.Identifier)
if cmd.Table.Purge {
- purger, ok := cat.(catalog.PurgeableTable)
- if !ok {
- output.Error(fmt.Errorf("catalog %s does not
support purge", cat.CatalogType()))
- osExit(1)
-
- return
- }
-
- if err := purger.PurgeTable(ctx, ident); err != nil {
+ if err := cat.PurgeTable(ctx, ident); err != nil {
output.Error(err)
osExit(1)
diff --git a/cmd/iceberg/properties_test.go b/cmd/iceberg/properties_test.go
index ebaec58f2..fb812fb90 100644
--- a/cmd/iceberg/properties_test.go
+++ b/cmd/iceberg/properties_test.go
@@ -65,6 +65,10 @@ func (m *mockCatalogForProperties)
DropTable(context.Context, table.Identifier)
panic("DropTable must not be called")
}
+func (m *mockCatalogForProperties) PurgeTable(context.Context,
table.Identifier) error {
+ panic("PurgeTable must not be called")
+}
+
func (m *mockCatalogForProperties) RenameTable(context.Context,
table.Identifier, table.Identifier) (*table.Table, error) {
panic("RenameTable must not be called")
}
diff --git a/cmd/iceberg/upgrade_rollback_test.go
b/cmd/iceberg/upgrade_rollback_test.go
index 0774c7f28..2dec3923a 100644
--- a/cmd/iceberg/upgrade_rollback_test.go
+++ b/cmd/iceberg/upgrade_rollback_test.go
@@ -431,6 +431,10 @@ func (p *panicCatalog) DropTable(context.Context,
table.Identifier) error {
panic("DropTable must not be called")
}
+func (p *panicCatalog) PurgeTable(context.Context, table.Identifier) error {
+ panic("PurgeTable must not be called")
+}
+
func (p *panicCatalog) RenameTable(context.Context, table.Identifier,
table.Identifier) (*table.Table, error) {
panic("RenameTable must not be called")
}
diff --git a/website/src/releases.md b/website/src/releases.md
index e0d398b74..b83a6a6ef 100644
--- a/website/src/releases.md
+++ b/website/src/releases.md
@@ -42,6 +42,7 @@ Per-release notes (highlights, breaking changes,
contributors) are published on
### Unreleased compatibility notes
+- **Table purge is required on catalogs.** The `catalog.Catalog` interface now
embeds `catalog.PurgeableCatalog`; every custom catalog implementation must
provide `PurgeTable(ctx, identifier) error`. The narrow
`catalog.PurgeableTable` interface is renamed to `catalog.PurgeableCatalog`.
Built-in purge behavior is unchanged.
- **Unify statistics blob types with Puffin.** Replace `table.BlobType` with
`puffin.BlobType` when constructing `table.BlobMetadata`. Replace
`table.BlobTypeApacheDatasketchesThetaV1` with
`puffin.BlobTypeDataSketchesTheta` and `table.BlobTypeDeletionVectorV1` with
`puffin.BlobTypeDeletionVector`. Use `puffin.BlobType.IsKnown()` to identify
the types defined by the Puffin specification; the redundant
`table.BlobType.IsValid()` method is removed. Unknown non-empty blob type names
still r [...]
- **View representation field uses the Go SQL initialism.** Replace
`view.Representation.Sql` with `view.Representation.SQL`. Serialized view
metadata still uses the `sql` JSON field.
- **Orphan cleanup results now expose only `OrphanFiles`.** Replace
`result.OrphanFileLocations` with `result.OrphanFiles` (each entry has `Path`
and `SizeBytes`). `OrphanCleanupPlan.Files()` still provides path-only lists
during planning.