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(

Reply via email to