Skip to content
Merged
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
30 changes: 29 additions & 1 deletion src/iceberg/catalog/memory/in_memory_catalog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,35 @@ Status InMemoryCatalog::DropTable(const TableIdentifier& identifier, bool purge)
Status InMemoryCatalog::RenameTable(const TableIdentifier& from,
const TableIdentifier& to) {
std::unique_lock lock(mutex_);
return NotImplemented("rename table");

// Renaming a table to itself is a no-op.
if (from == to) {
return {};
}

// Verify the source table exists.
ICEBERG_ASSIGN_OR_RAISE(auto from_exists, root_namespace_->TableExists(from));
if (!from_exists) {
return NoSuchTable("Source table does not exist: {}", from);
}

// Verify the destination table does not already exist.
ICEBERG_ASSIGN_OR_RAISE(auto to_exists, root_namespace_->TableExists(to));
if (to_exists) {
return AlreadyExists("Destination table already exists: {}", to);
}

// Get the metadata location from the source table.
ICEBERG_ASSIGN_OR_RAISE(auto metadata_location,
root_namespace_->GetTableMetadataLocation(from));

// Register the destination with the same metadata location.
ICEBERG_RETURN_UNEXPECTED(root_namespace_->RegisterTable(to, metadata_location));

// Unregister the source table.
ICEBERG_RETURN_UNEXPECTED(root_namespace_->UnregisterTable(from));

return {};
}

Result<std::shared_ptr<Table>> InMemoryCatalog::LoadTable(
Expand Down
43 changes: 43 additions & 0 deletions src/iceberg/test/in_memory_catalog_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,49 @@ TEST_F(InMemoryCatalogTest, DropTable) {
EXPECT_THAT(result, IsOk());
}

TEST_F(InMemoryCatalogTest, RenameTable) {
// Create a table first.
TableIdentifier ident{.ns = {}, .name = "t1"};
auto schema = std::make_shared<Schema>(
std::vector<SchemaField>{SchemaField::MakeRequired(1, "x", int64())},
/*schema_id=*/1);
auto spec = PartitionSpec::Unpartitioned();
auto sort_order = SortOrder::Unsorted();

ICEBERG_UNWRAP_OR_FAIL(
auto table, catalog_->CreateTable(ident, schema, spec, sort_order,
GenerateTestTableLocation(ident.name), {}));

// Rename to itself is a no-op.
EXPECT_THAT(catalog_->RenameTable(ident, ident), IsOk());

// Rename non-existent source table.
TableIdentifier nonexist{.ns = {}, .name = "nonexist"};
EXPECT_THAT(catalog_->RenameTable(nonexist, ident), IsError(ErrorKind::kNoSuchTable));

// Rename to an existing destination table.
TableIdentifier ident2{.ns = {}, .name = "t2"};
ICEBERG_UNWRAP_OR_FAIL(
auto table2, catalog_->CreateTable(ident2, schema, spec, sort_order,
GenerateTestTableLocation(ident2.name), {}));
EXPECT_THAT(catalog_->RenameTable(ident, ident2), IsError(ErrorKind::kAlreadyExists));

// Drop ident2 to clear the destination, then rename.
EXPECT_THAT(catalog_->DropTable(ident2, /*purge=*/false), IsOk());

// Rename ident -> ident2.
TableIdentifier renamed{.ns = {}, .name = "t2"};
EXPECT_THAT(catalog_->RenameTable(ident, renamed), IsOk());
EXPECT_THAT(catalog_->TableExists(ident), HasValue(::testing::Eq(false)));
EXPECT_THAT(catalog_->TableExists(renamed), HasValue(::testing::Eq(true)));

// Load the renamed table to verify it's intact.
auto loaded = catalog_->LoadTable(renamed);
ASSERT_THAT(loaded, IsOk());
EXPECT_EQ(loaded.value()->name().name, "t2");
EXPECT_EQ(loaded.value()->uuid(), table->uuid());
}

TEST_F(InMemoryCatalogTest, Namespace) {
Namespace ns{.levels = {"n1", "n2"}};
std::unordered_map<std::string, std::string> properties = {{"prop1", "val1"},
Expand Down
Loading