Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,21 @@ public DeregisterTableResponse deregisterTable(String tableId, String delimiter)
"Table not found: " + tableId, CommonUtil.formatCurrentStackTrace(), tableId);
}
Map<String, String> properties = t.properties();
// TODO Support real deregister API.

// Verify the table is external before deregistering. For non-external (managed) tables,
// dropTable would delete the underlying Lance data, violating the deregister contract
// ("It will not delete the underlying lance data"). The TableCatalog interface does not
// expose a metadata-only removal path, so we fail fast rather than risk silent data loss.
boolean external =
Optional.ofNullable(properties.get(Table.PROPERTY_EXTERNAL))
.map(Boolean::parseBoolean)
.orElse(false);
if (!external) {
throw new UnsupportedOperationException(
"deregisterTable only supports external tables, but table " + tableId + " is managed");
}

// External tables: dropTable removes catalog metadata only, preserving Lance data.
boolean result = catalog.asTableCatalog().dropTable(tableIdentifier);
if (!result) {
throw new TableNotFoundException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@

import static org.apache.gravitino.lance.common.utils.LanceConstants.LANCE_TABLE_VERSION;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.lance.common.ops.gravitino.GravitinoLanceNamespaceWrapper;
import org.apache.gravitino.lance.common.ops.gravitino.GravitinoLanceTableAlterHandler.AlterColumnsGravitinoLance;
import org.apache.gravitino.lance.common.ops.gravitino.GravitinoLanceTableAlterHandler.DropColumns;
import org.apache.gravitino.lance.common.ops.gravitino.GravitinoLanceTableOperations;
import org.apache.gravitino.rel.Table;
import org.apache.gravitino.rel.TableCatalog;
import org.apache.gravitino.rel.TableChange;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -92,4 +98,32 @@ void testAlterColumnsHandlerRejectsUnsupportedFields() {
Assertions.assertEquals(
"Only RENAME alteration is supported currently.", exception.getMessage());
}

@Test
void testDeregisterTableRejectsManagedTable() {
// Mock a managed table (no PROPERTY_EXTERNAL=true)
Table managedTable = Mockito.mock(Table.class);
Mockito.when(managedTable.properties()).thenReturn(new HashMap<>());

TableCatalog tableCatalog = Mockito.mock(TableCatalog.class);
Mockito.when(tableCatalog.loadTable(Mockito.any(NameIdentifier.class)))
.thenReturn(managedTable);

Catalog catalog = Mockito.mock(Catalog.class);
Mockito.when(catalog.asTableCatalog()).thenReturn(tableCatalog);

GravitinoLanceNamespaceWrapper wrapper = Mockito.mock(GravitinoLanceNamespaceWrapper.class);
Mockito.when(wrapper.loadAndValidateLakehouseCatalog(Mockito.anyString())).thenReturn(catalog);

GravitinoLanceTableOperations ops = new GravitinoLanceTableOperations(wrapper);

UnsupportedOperationException exception =
Assertions.assertThrows(
UnsupportedOperationException.class,
() -> ops.deregisterTable("catalog.schema.table", "."));
Assertions.assertTrue(exception.getMessage().contains("only supports external tables"));

// Verify dropTable was never called — the guard must reject before reaching the catalog layer.
Mockito.verify(tableCatalog, Mockito.never()).dropTable(Mockito.any());
}
}
Loading