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

yuqi1129 pushed a commit to branch issue_11027
in repository https://gitbox.apache.org/repos/asf/gravitino.git

commit 77081b94dab1dd1e33fdd5da29d2fab8709846a5
Author: yuqi <[email protected]>
AuthorDate: Tue May 26 22:00:56 2026 +0800

    fix(lance): Improve schema refresh robustness and test coverage
    
    - Change LOG.debug to LOG.warn for dataset load failures in loadTable
      so silent fallbacks are visible in production logs
    - Add defensive try-catch in schemaRefreshMode() to handle invalid
      enum values gracefully instead of propagating IllegalArgumentException
    - Add test for empty-schema table refresh in DECLARED_ONLY mode
    - Add test for graceful fallback when openDataset fails
    
    Co-Authored-By: Claude Opus 4.7 <[email protected]>
---
 .../lakehouse/lance/LanceTableOperations.java      | 16 +++++--
 .../lakehouse/lance/TestLanceTableOperations.java  | 56 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 5 deletions(-)

diff --git 
a/catalogs/catalog-lakehouse-generic/src/main/java/org/apache/gravitino/catalog/lakehouse/lance/LanceTableOperations.java
 
b/catalogs/catalog-lakehouse-generic/src/main/java/org/apache/gravitino/catalog/lakehouse/lance/LanceTableOperations.java
index e529385572..c9d955f52d 100644
--- 
a/catalogs/catalog-lakehouse-generic/src/main/java/org/apache/gravitino/catalog/lakehouse/lance/LanceTableOperations.java
+++ 
b/catalogs/catalog-lakehouse-generic/src/main/java/org/apache/gravitino/catalog/lakehouse/lance/LanceTableOperations.java
@@ -152,7 +152,7 @@ public class LanceTableOperations extends 
ManagedTableOperations {
       }
       columns = extractColumns(dataset.getSchema());
     } catch (Exception e) {
-      LOG.debug(
+      LOG.warn(
           "Failed to load Lance schema from location {} for table {}. Return 
stored metadata.",
           location,
           ident,
@@ -414,10 +414,16 @@ public class LanceTableOperations extends 
ManagedTableOperations {
   }
 
   private SchemaRefreshMode schemaRefreshMode() {
-    return 
Optional.ofNullable(catalogProperties.get(LanceConstants.LANCE_SCHEMA_REFRESH_MODE))
-        .map(mode -> mode.trim().replace('-', '_').toUpperCase())
-        .map(SchemaRefreshMode::valueOf)
-        .orElse(SchemaRefreshMode.DECLARED_ONLY);
+    String raw = 
catalogProperties.get(LanceConstants.LANCE_SCHEMA_REFRESH_MODE);
+    if (StringUtils.isBlank(raw)) {
+      return SchemaRefreshMode.DECLARED_ONLY;
+    }
+    try {
+      return SchemaRefreshMode.valueOf(raw.trim().replace('-', 
'_').toUpperCase());
+    } catch (IllegalArgumentException e) {
+      LOG.warn("Unknown schema refresh mode '{}', falling back to 
DECLARED_ONLY", raw);
+      return SchemaRefreshMode.DECLARED_ONLY;
+    }
   }
 
   private boolean isDeclaredOnly(Table table) {
diff --git 
a/catalogs/catalog-lakehouse-generic/src/test/java/org/apache/gravitino/catalog/lakehouse/lance/TestLanceTableOperations.java
 
b/catalogs/catalog-lakehouse-generic/src/test/java/org/apache/gravitino/catalog/lakehouse/lance/TestLanceTableOperations.java
index 617c7bb777..1b20195ae3 100644
--- 
a/catalogs/catalog-lakehouse-generic/src/test/java/org/apache/gravitino/catalog/lakehouse/lance/TestLanceTableOperations.java
+++ 
b/catalogs/catalog-lakehouse-generic/src/test/java/org/apache/gravitino/catalog/lakehouse/lance/TestLanceTableOperations.java
@@ -274,6 +274,62 @@ public class TestLanceTableOperations {
         .update(eq(ident), eq(TableEntity.class), eq(Entity.EntityType.TABLE), 
any());
   }
 
+  @Test
+  public void testLoadEmptySchemaTableRefreshesFromDataset() throws Exception {
+    NameIdentifier ident = NameIdentifier.of("schema", "table");
+    String location = tempDir.resolve("empty-schema-table").toString();
+    TableEntity tableEntity =
+        tableEntity(ident, List.of(), Map.of(Table.PROPERTY_LOCATION, 
location));
+    when(store.get(eq(ident), eq(Entity.EntityType.TABLE), 
eq(TableEntity.class)))
+        .thenReturn(tableEntity);
+    when(idGenerator.nextId()).thenReturn(10L, 11L);
+    when(store.update(eq(ident), eq(TableEntity.class), 
eq(Entity.EntityType.TABLE), any()))
+        .thenAnswer(
+            invocation -> {
+              @SuppressWarnings("unchecked")
+              Function<TableEntity, TableEntity> updater = 
invocation.getArgument(3);
+              return updater.apply(tableEntity);
+            });
+
+    Dataset dataset = mock(Dataset.class);
+    when(dataset.getSchema())
+        .thenReturn(
+            new org.apache.arrow.vector.types.pojo.Schema(
+                List.of(Field.nullable("col1", new ArrowType.Utf8()))));
+    when(dataset.version()).thenReturn(5L);
+    Mockito.doReturn(dataset).when(lanceTableOps).openDataset(location, 
Map.of());
+
+    Table loadedTable =
+        PrincipalUtils.doAs(new UserPrincipal("tester"), () -> 
lanceTableOps.loadTable(ident));
+
+    Assertions.assertEquals(1, loadedTable.columns().length);
+    Assertions.assertEquals("col1", loadedTable.columns()[0].name());
+    Assertions.assertEquals(Types.StringType.get(), 
loadedTable.columns()[0].dataType());
+    Assertions.assertEquals("5", 
loadedTable.properties().get(LANCE_TABLE_VERSION));
+  }
+
+  @Test
+  public void testLoadTableFallsBackWhenDatasetOpenFails() throws Exception {
+    NameIdentifier ident = NameIdentifier.of("schema", "table");
+    String location = tempDir.resolve("broken-table").toString();
+    TableEntity tableEntity =
+        tableEntity(
+            ident,
+            List.of(),
+            Map.of(Table.PROPERTY_LOCATION, location, LANCE_TABLE_DECLARED, 
"true"));
+    when(store.get(eq(ident), eq(Entity.EntityType.TABLE), 
eq(TableEntity.class)))
+        .thenReturn(tableEntity);
+    Mockito.doThrow(new RuntimeException("dataset not found"))
+        .when(lanceTableOps)
+        .openDataset(location, Map.of());
+
+    Table loadedTable = lanceTableOps.loadTable(ident);
+
+    Assertions.assertEquals(0, loadedTable.columns().length);
+    verify(store, never())
+        .update(eq(ident), eq(TableEntity.class), eq(Entity.EntityType.TABLE), 
any());
+  }
+
   @Test
   public void testHandleLanceTableChangeRespectsOrder() {
     Table table = mock(Table.class);

Reply via email to