This is an automated email from the ASF dual-hosted git repository.
diqiu50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new dc29eef319 [#8634] feat(catalog-hive): support renaming table with new
database name (#11292)
dc29eef319 is described below
commit dc29eef319c2dba3795dc731a6e660c71c1e8708
Author: Andres Blanco <[email protected]>
AuthorDate: Wed Jun 17 23:14:51 2026 -0700
[#8634] feat(catalog-hive): support renaming table with new database name
(#11292)
### What changes were proposed in this pull request?
added check to see if a new schema is passed when renaming a hive table
and then move it to the new schema/database instead of just keeping it
in the old one. also made sure there were no compilation issues with
variables not being effectively final inside the hms client pool lambda.
### Why are the changes needed?
right now we don't support renaming hive tables into a different
database/schema. this PR fixes that so we can move tables across
databases in hive metastore during renames.
Fix: #8634
### Does this PR introduce _any_ user-facing change?
yes, users can now specify a new database name when renaming a table in
the hive catalog using the rename api.
### How was this patch tested?
Added a new `testCrossSchemaRename` integration test in
`TestHiveTable.java`. This test creates a secondary schema, creates a
table in the primary schema, issues a cross-schema rename command, and
explicitly verifies that the table is fully loadable from the new schema
and completely absent from the old schema.
---------
Co-authored-by: Copilot Autofix powered by AI
<[email protected]>
Co-authored-by: mchades <[email protected]>
Co-authored-by: Copilot <[email protected]>
---
.../catalog/hive/HiveCatalogOperations.java | 25 +++++++--
.../gravitino/catalog/hive/TestHiveTable.java | 46 ++++++++++++++++
.../hive/integration/test/CatalogHive2IT.java | 61 ++++++++++++++++++++++
3 files changed, 127 insertions(+), 5 deletions(-)
diff --git
a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogOperations.java
b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogOperations.java
index 1a474d4f53..99bcc1431d 100644
---
a/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogOperations.java
+++
b/catalogs/catalog-hive/src/main/java/org/apache/gravitino/catalog/hive/HiveCatalogOperations.java
@@ -699,12 +699,21 @@ public class HiveCatalogOperations
String newComment = currentTable.comment();
Map<String, String> updatedProperties = new
HashMap<>(currentTable.properties());
List<Column> updatedColumns = new
ArrayList<>(Arrays.asList(currentTable.columns()));
+ // Use the loaded table's database name as the default.
+ // If a new schema is explicitly requested during a rename, this will be
overwritten below.
+ String targetDatabaseName = currentTable.databaseName();
for (TableChange change : changes) {
if (change instanceof TableChange.RenameTable) {
TableChange.RenameTable rename = (TableChange.RenameTable) change;
- Preconditions.checkArgument(
- rename.getNewSchemaName().isEmpty(), "Does not support rename
schema yet");
+ if (rename.getNewSchemaName().isPresent()) {
+ String newSchemaName = rename.getNewSchemaName().get();
+ if (!schemaExists(NameIdentifier.of(schemaIdent.namespace(),
newSchemaName))) {
+ throw new NoSuchSchemaException("Schema %s does not exist",
newSchemaName);
+ }
+ // Move table to the new schema
+ targetDatabaseName = newSchemaName;
+ }
newTableName = rename.getNewName();
} else if (change instanceof TableChange.UpdateComment) {
newComment = ((TableChange.UpdateComment) change).getNewComment();
@@ -725,7 +734,12 @@ public class HiveCatalogOperations
HiveTable updatedTable =
buildAlteredHiveTable(
- currentTable, newTableName, newComment, updatedProperties,
updatedColumns);
+ currentTable,
+ newTableName,
+ newComment,
+ updatedProperties,
+ updatedColumns,
+ targetDatabaseName);
HiveTable finalUpdatedTable = updatedTable;
clientPool.run(
@@ -759,7 +773,8 @@ public class HiveCatalogOperations
String tableName,
String comment,
Map<String, String> properties,
- List<Column> columns) {
+ List<Column> columns,
+ String databaseName) {
HiveTable.Builder builder =
HiveTable.builder()
.withName(tableName)
@@ -770,7 +785,7 @@ public class HiveCatalogOperations
.withSortOrders(original.sortOrder())
.withPartitioning(original.partitioning())
.withCatalogName(original.catalogName())
- .withDatabaseName(original.databaseName());
+ .withDatabaseName(databaseName);
if (comment != null) {
builder.withComment(comment);
diff --git
a/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveTable.java
b/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveTable.java
index 99901eaa50..f2fc5188af 100644
---
a/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveTable.java
+++
b/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveTable.java
@@ -65,12 +65,15 @@ public class TestHiveTable extends MiniHiveMetastoreService
{
protected static final String HIVE_CATALOG_NAME = "test_catalog";
protected static final String HIVE_SCHEMA_NAME = "test_schema";
+ protected static final String HIVE_SCHEMA_NAME_NEW = HIVE_SCHEMA_NAME +
"_new";
protected static final String HIVE_COMMENT = "test_comment";
private static HiveCatalog hiveCatalog;
private static HiveCatalogOperations hiveCatalogOperations;
private static HiveSchema hiveSchema;
private static final NameIdentifier schemaIdent =
NameIdentifier.of(META_LAKE_NAME, HIVE_CATALOG_NAME, HIVE_SCHEMA_NAME);
+ private static final NameIdentifier newSchemaIdent =
+ NameIdentifier.of(META_LAKE_NAME, HIVE_CATALOG_NAME,
HIVE_SCHEMA_NAME_NEW);
@BeforeAll
public static void setup() {
@@ -81,6 +84,7 @@ public class TestHiveTable extends MiniHiveMetastoreService {
@AfterEach
public void resetSchema() {
+ hiveCatalogOperations.dropSchema(newSchemaIdent, true);
hiveCatalogOperations.dropSchema(schemaIdent, true);
hiveSchema = initHiveSchema();
}
@@ -576,6 +580,48 @@ public class TestHiveTable extends
MiniHiveMetastoreService {
Assertions.assertArrayEquals(createdTable.partitioning(),
alteredTable.partitioning());
}
+ @Test
+ public void testCrossSchemaRename() {
+ // Create a second schema to serve as the destination for the cross-schema
rename
+ hiveCatalogOperations.createSchema(newSchemaIdent, HIVE_COMMENT,
Maps.newHashMap());
+
+ // Create a table in the original schema
+ String originalTableName = genRandomName();
+ NameIdentifier tableIdentifier =
+ NameIdentifier.of(META_LAKE_NAME, hiveCatalog.name(),
hiveSchema.name(), originalTableName);
+ HiveColumn col1 =
+ HiveColumn.builder()
+ .withName("col_1")
+ .withType(Types.ByteType.get())
+ .withComment(HIVE_COMMENT)
+ .build();
+ hiveCatalogOperations.createTable(
+ tableIdentifier,
+ new Column[] {col1},
+ HIVE_COMMENT,
+ Maps.newHashMap(),
+ new Transform[0],
+ Distributions.NONE,
+ new SortOrder[0]);
+
+ // Alter the table to rename it and explicitly move it to the new schema
+ String newTableName = originalTableName + "_new";
+ hiveCatalogOperations.alterTable(
+ tableIdentifier, TableChange.rename(newTableName,
HIVE_SCHEMA_NAME_NEW));
+
+ // Verify the table is successfully loadable from the new schema
+ NameIdentifier newTableIdentifier =
+ NameIdentifier.of(META_LAKE_NAME, hiveCatalog.name(),
HIVE_SCHEMA_NAME_NEW, newTableName);
+
+
Assertions.assertTrue(hiveCatalogOperations.tableExists(newTableIdentifier));
+
+ // Verify the table is fully absent from the old schema
+ Assertions.assertFalse(hiveCatalogOperations.tableExists(tableIdentifier));
+ Assertions.assertFalse(
+ hiveCatalogOperations.tableExists(
+ NameIdentifier.of(tableIdentifier.namespace(), newTableName)));
+ }
+
@Test
public void testPurgeHiveTable() {
String hiveTableName = "test_hive_table";
diff --git
a/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/integration/test/CatalogHive2IT.java
b/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/integration/test/CatalogHive2IT.java
index 413ff82f58..121ab3a809 100644
---
a/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/integration/test/CatalogHive2IT.java
+++
b/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/integration/test/CatalogHive2IT.java
@@ -1396,6 +1396,67 @@ public class CatalogHive2IT extends BaseIT {
"please ensure that the type of the new column position is
compatible with the old one"));
}
+ @Test
+ public void testCrossSchemaTableRename() throws TException,
InterruptedException {
+ // Create a second schema to serve as the rename destination.
+ // No explicit location needed; HMS will use the default warehouse
directory.
+ String targetSchemaName = GravitinoITUtils.genRandomName(SCHEMA_PREFIX +
"_target");
+ Map<String, String> targetSchemaProperties = new HashMap<>();
+ targetSchemaProperties.put("key1", "val1");
+ targetSchemaProperties.put("key2", "val2");
+ catalog.asSchemas().createSchema(targetSchemaName, "target schema",
targetSchemaProperties);
+
+ // Create a table in the original schema
+ Column[] columns = createColumns();
+ NameIdentifier tableIdentifier = NameIdentifier.of(schemaName, tableName);
+ catalog
+ .asTableCatalog()
+ .createTable(
+ tableIdentifier,
+ columns,
+ TABLE_COMMENT,
+ createProperties(),
+ Transforms.EMPTY_TRANSFORM);
+
+ // Rename the table and move it to the target schema
+ String newTableName = GravitinoITUtils.genRandomName(TABLE_PREFIX +
"_renamed");
+ TableChange renameTableChange = TableChange.rename(newTableName,
targetSchemaName);
+ catalog.asTableCatalog().alterTable(tableIdentifier, renameTableChange);
+
+ // Verify the table is loadable from the new schema via Gravitino API
+ NameIdentifier newTableIdentifier = NameIdentifier.of(targetSchemaName,
newTableName);
+ Table loadedTable = catalog.asTableCatalog().loadTable(newTableIdentifier);
+ Assertions.assertNotNull(loadedTable);
+ Assertions.assertEquals(newTableName.toLowerCase(), loadedTable.name());
+
+ // Verify the table exists in the new schema directly from Hive Metastore
+ HiveTable hiveTable = loadHiveTable(targetSchemaName, newTableName);
+ Assertions.assertEquals(targetSchemaName.toLowerCase(),
hiveTable.databaseName());
+ Assertions.assertEquals(newTableName.toLowerCase(), hiveTable.name());
+
+ // Verify the table no longer exists in the old schema
+ Assertions.assertThrows(
+ NoSuchTableException.class, () ->
catalog.asTableCatalog().loadTable(tableIdentifier));
+ Assertions.assertFalse(hiveTableExists(schemaName, tableName));
+ Assertions.assertFalse(hiveTableExists(schemaName, newTableName));
+
+ // Test error case: rename to a non-existent schema should fail
+ String anotherTable = GravitinoITUtils.genRandomName(TABLE_PREFIX);
+ NameIdentifier anotherTableId = NameIdentifier.of(targetSchemaName,
anotherTable);
+ catalog
+ .asTableCatalog()
+ .createTable(
+ anotherTableId, columns, TABLE_COMMENT, createProperties(),
Transforms.EMPTY_TRANSFORM);
+
+ TableCatalog tableCatalog = catalog.asTableCatalog();
+ TableChange renameChange = TableChange.rename(anotherTable + "_moved",
"non_existent_schema");
+ Assertions.assertThrows(
+ NoSuchSchemaException.class, () ->
tableCatalog.alterTable(anotherTableId, renameChange));
+
+ // Clean up the target schema
+ catalog.asSchemas().dropSchema(targetSchemaName, true);
+ }
+
private void assertDefaultTableProperties(Table gravitinoReturnTable,
HiveTable actualTable) {
HiveTablePropertiesMetadata tablePropertiesMetadata = new
HiveTablePropertiesMetadata();
Assertions.assertEquals(