This is an automated email from the ASF dual-hosted git repository.

mchades 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 5259e9c5f6 [#10909] fix(client): Fix list/load inconsistency for 
schema and table names containing dots (#11597)
5259e9c5f6 is described below

commit 5259e9c5f63d2efe1dedb9d3a041ed21995d2735
Author: mchades <[email protected]>
AuthorDate: Thu Jun 11 17:13:29 2026 +0800

    [#10909] fix(client): Fix list/load inconsistency for schema and table 
names containing dots (#11597)
    
    ### What changes were proposed in this pull request?
    
    Fix the `list*`/`load*` inconsistency for MySQL schemas and tables whose
    names contain dots (e.g. a MySQL database named `db.v2` created
    externally with `` CREATE DATABASE `db.v2` ``).
    
    - `GenericSchema`: replace `MetadataObjects.of(String parent, String
    name, Type)` with `MetadataObjects.of(List, Type)`, consistent with
    `GenericFileset`, `GenericTopic`, and `GenericModel`.
    - `RelationalTable`: replace `MetadataObjects.parse(tableFullName(...),
    TABLE)` with `MetadataObjects.of(List, TABLE)`, and remove the
    now-unused `tableFullName()` helper and `DOT_JOINER` field.
    
    ### Why are the changes needed?
    
    Fix: #10909
    
    `MetadataObjects.of(String parent, String name, Type)` joins parent and
    name with `.` then re-parses by splitting on `.`. When `name` itself
    contains a dot (e.g. `"db.v2"`), the split produces too many segments
    and the length check throws `IllegalArgumentException`:
    
    ```
    IllegalArgumentException: If the type is SCHEMA, the length of names must 
be 2
      at GenericSchema.<init>(GenericSchema.java:48)
      at BaseSchemaCatalog.loadSchema(BaseSchemaCatalog.java:216)
    ```
    
    `listSchemas()` had already returned the dotted name successfully, so
    `loadSchema()` crashing breaks the `list*`/`load*` contract.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No API changes. Bug fix only: `loadSchema` and `loadTable` now correctly
    handle names containing dots, consistent with what
    `listSchemas`/`listTables` already returns.
    
    ### How was this patch tested?
    
    Added `testObjectNamesWithDots()` to `CatalogMysqlIT`
    (`@Tag("gravitino-docker-test")`). The test:
    1. Creates a MySQL database with a dot in its name directly via JDBC.
    2. Asserts `listSchemas()` returns that schema.
    3. Asserts `loadSchema()` succeeds for the same name.
    4. Creates a table in that schema directly via JDBC.
    5. Asserts `listTables()` returns the table.
    6. Asserts `loadTable()` succeeds for the same name.
    
    Co-authored-by: Copilot <[email protected]>
---
 .../mysql/integration/test/CatalogMysqlIT.java     | 46 ++++++++++++++++++++++
 .../org/apache/gravitino/client/GenericSchema.java |  3 +-
 .../apache/gravitino/client/RelationalTable.java   | 11 ++----
 3 files changed, 51 insertions(+), 9 deletions(-)

diff --git 
a/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
 
b/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
index 59a83b8e85..db9035d6c3 100644
--- 
a/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
+++ 
b/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlIT.java
@@ -2380,4 +2380,50 @@ public class CatalogMysqlIT extends BaseIT {
       }
     }
   }
+
+  @Test
+  void testObjectNamesWithDots() {
+    // Create a MySQL database with a dot in its name directly (bypassing 
Gravitino)
+    String dottedSchemaName = GravitinoITUtils.genRandomName("db") + ".nested";
+    mysqlService.executeQuery("CREATE DATABASE `" + dottedSchemaName + "`");
+    try {
+      // listSchemas should include the schema with dot in name
+      String[] listedSchemas = catalog.asSchemas().listSchemas();
+      Set<String> schemaNames = Sets.newHashSet(listedSchemas);
+      Assertions.assertTrue(
+          schemaNames.contains(dottedSchemaName),
+          "listSchemas should return schema with dot in name: " + 
dottedSchemaName);
+
+      // loadSchema must succeed for a name that appeared in listSchemas
+      Schema loadedSchema = catalog.asSchemas().loadSchema(dottedSchemaName);
+      Assertions.assertEquals(
+          dottedSchemaName,
+          loadedSchema.name(),
+          "loadSchema must succeed for schema that appeared in listSchemas");
+
+      // Create a table directly in MySQL (bypassing Gravitino, since dotted 
schema names are not
+      // allowed at creation time, but may exist externally)
+      String testTableName = GravitinoITUtils.genRandomName("test_table");
+      mysqlService.executeQuery(
+          "CREATE TABLE `" + dottedSchemaName + "`.`" + testTableName + "` (id 
INT)");
+
+      // listTables under the dotted schema should include the created table
+      NameIdentifier[] listedTables =
+          catalog.asTableCatalog().listTables(Namespace.of(dottedSchemaName));
+      Set<String> tableNames =
+          
Arrays.stream(listedTables).map(NameIdentifier::name).collect(Collectors.toSet());
+      Assertions.assertTrue(
+          tableNames.contains(testTableName), "listTables should return table 
under dotted schema");
+
+      // loadTable must succeed for a table that appeared in listTables
+      Table loadedTable =
+          
catalog.asTableCatalog().loadTable(NameIdentifier.of(dottedSchemaName, 
testTableName));
+      Assertions.assertEquals(
+          testTableName,
+          loadedTable.name(),
+          "loadTable must succeed for table that appeared in listTables");
+    } finally {
+      mysqlService.executeQuery("DROP DATABASE IF EXISTS `" + dottedSchemaName 
+ "`");
+    }
+  }
 }
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
index 79a90d3d4a..bbb5f84300 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericSchema.java
@@ -18,6 +18,7 @@
  */
 package org.apache.gravitino.client;
 
+import java.util.Arrays;
 import java.util.Map;
 import org.apache.gravitino.Audit;
 import org.apache.gravitino.MetadataObject;
@@ -45,7 +46,7 @@ class GenericSchema implements Schema, SupportsTags, 
SupportsRoles, SupportsPoli
   GenericSchema(SchemaDTO schemaDTO, RESTClient restClient, String metalake, 
String catalog) {
     this.schemaDTO = schemaDTO;
     MetadataObject schemaObject =
-        MetadataObjects.of(catalog, schemaDTO.name(), 
MetadataObject.Type.SCHEMA);
+        MetadataObjects.of(Arrays.asList(catalog, schemaDTO.name()), 
MetadataObject.Type.SCHEMA);
     this.objectTagOperations = new MetadataObjectTagOperations(metalake, 
schemaObject, restClient);
     this.objectRoleOperations =
         new MetadataObjectRoleOperations(metalake, schemaObject, restClient);
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
index 7a3dd671d9..fac38e76ac 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/RelationalTable.java
@@ -22,7 +22,6 @@ import static 
org.apache.gravitino.dto.util.DTOConverters.fromDTO;
 import static org.apache.gravitino.dto.util.DTOConverters.toDTO;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -81,8 +80,6 @@ class RelationalTable
         SupportsStatistics,
         SupportsPartitionStatistics {
 
-  private static final Joiner DOT_JOINER = Joiner.on(".");
-
   private final Table table;
 
   private final RESTClient restClient;
@@ -119,7 +116,9 @@ class RelationalTable
     this.restClient = restClient;
     this.table = fromDTO(tableDTO);
     MetadataObject tableObject =
-        MetadataObjects.parse(tableFullName(namespace, tableDTO.name()), 
MetadataObject.Type.TABLE);
+        MetadataObjects.of(
+            Arrays.asList(namespace.level(1), namespace.level(2), 
tableDTO.name()),
+            MetadataObject.Type.TABLE);
     this.objectTagOperations =
         new MetadataObjectTagOperations(namespace.level(0), tableObject, 
restClient);
     this.objectRoleOperations =
@@ -373,10 +372,6 @@ class RelationalTable
     return this;
   }
 
-  private static String tableFullName(Namespace tableNS, String tableName) {
-    return DOT_JOINER.join(tableNS.level(1), tableNS.level(2), tableName);
-  }
-
   @Override
   public String[] listTags() {
     return objectTagOperations.listTags();

Reply via email to