matrixorigin / matrixorigin/matrixone
[Bug]: iceberg_register_access leaves catalog with no supported drop path
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 311
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 768
Description
## Description
After the supported `CALL iceberg_register_access` path creates principal and residency metadata, `DROP ICEBERG CATALOG` is permanently blocked even when all external table mappings have been removed. There is no unregister or cascade SQL surface, and direct DELETE from the catalog tables is privilege denied, so the catalog cannot be cleaned up through supported SQL.
## Environment
- Branch: `main`
- Commit: `8e616a693458652cc26b3c4be45c6602dff298d4`
- Deployment: local single-CN Iceberg profile with Nessie REST catalog and MinIO
## Steps to reproduce
```sql
CREATE ICEBERG CATALOG ice_drop_block
WITH (
'type'='rest',
'uri'='http://127.0.0.1:19120/iceberg',
'warehouse'='s3://mo-iceberg/warehouse',
'auth_mode'='none'
);
CALL iceberg_register_access(
'ice_drop_block',
'scope=cluster,account_id=0,external_principal=ci-local,endpoint=localhost,region=us-east-1,bucket=mo-iceberg'
);
DROP ICEBERG CATALOG ice_drop_block;
```
## Actual behavior
DROP fails with:
```text
ERROR 20301 (HY000): invalid input: iceberg catalog ice_drop_block still has dependent metadata: principal mappings, residency policies
```
The catalog has zero table mappings but one principal row and one residency-policy row. Trying to delete those rows directly from `mo_catalog.mo_iceberg_principal_map` / `mo_iceberg_residency_policy` as `moadmin` is rejected with `do not have privilege to execute the statement`.
## Expected behavior
A supported lifecycle must exist to unregister access metadata and then drop the catalog, or `DROP ICEBERG CATALOG` must provide an explicit supported cascade/cleanup form. A catalog created and configured through public SQL must not become undeletable.
## Stability and controls
- Reproducer: 3/3 independent catalog names.
- State check: all three had `0` table mappings, `1` principal mapping, and `1` residency policy when DROP failed.
- Control: a catalog created with the same options but without `iceberg_register_access` dropped successfully and left zero catalog rows.
- Failure atomicity: rejected DROP retained the catalog and both dependencies consistently.
## Evidence
```text
control_remaining 0
third_dependencies 1 1
ice_drop_block_1 mappings=0 principals=1 policies=1
ice_drop_block_2 mappings=0 principals=1 policies=1
ice_drop_block_3 mappings=0 principals=1 policies=1
```
## Code analysis
`pkg/frontend/iceberg_call.go` implements only `iceberg_register_access`, which upserts `mo_iceberg_principal_map` and `mo_iceberg_residency_policy`. No corresponding unregister path exists. `pkg/frontend/iceberg.go::handleDropIcebergCatalog` treats both tables as blocking dependencies and returns before deleting the catalog. The public lifecycle therefore has an entry operation but no exit operation.
## Regression coverage
After the fix, add a local Iceberg E2E/BVT lifecycle case covering create catalog, register access, create/drop mapping, unregister or explicit cascade cleanup, drop catalog, and zero residual rows in all catalog-owned metadata tables. Also assert ordinary DROP without the explicit cleanup form remains atomic when live table mappings exist.
## Related
- #27199 is about HTTPS validation ordering and is not a duplicate.
- Discovered while executing `test/iceberg/iceberg_e2e_local.go` and inspecting `mo_iceberg_*` lifecycle metadata.
Contributor guide
Assessment
This issue has not been assessed yet.