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

github-actions[bot] pushed a commit to branch cherry-pick-441e590b-to-branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git

commit 71bc106293ea9e9e94ad1388191d2b926f357956
Author: StormSpirit <[email protected]>
AuthorDate: Mon Sep 14 10:35:49 2026 +0800

    [#12915] fix(clickhouse): skip function-based index expressions on load 
(#12917)
    
    ### What changes were proposed in this pull request?
    
    This pull request stops the ClickHouse index metadata parser from
    recursively removing function wrappers. Direct column identifiers and
    tuples containing only identifiers retain their existing behavior, while
    function expressions such as `lower(name)` are rejected by the existing
    field validation and handled by the existing per-index warning-and-skip
    path.
    
    The previous wrapper-unwrapping behavior is retained in a
    sharding-key-specific helper so function-wrapped sharding keys such as
    `cityHash64(user_id)` remain unchanged. Unsupported index warnings
    retain the index, table, and type context without logging the raw
    expression, `type_full`, or parser exception.
    
    Bloom-filter parameter parsing remains outside this skip boundary, so
    malformed parameter metadata continues to fail with index context.
    
    Unit coverage verifies rejection of direct and nested function
    expressions, including hash functions, and mixed tuples, while retaining
    existing arithmetic-expression rejection and simple/tuple compatibility
    coverage. A focused ClickHouse integration test verifies that a native
    expression index remains present in the source DDL, is not exposed as a
    different column index, and is not recreated with changed semantics.
    
    ### Why are the changes needed?
    
    Gravitino's public `Index.fieldNames()` contract can represent column
    references but not arbitrary ClickHouse expressions. Reporting
    `lower(name)` as the field `name` fabricates metadata and causes
    load-to-create round trips to produce a semantically different index.
    Skipping the unsupported index preserves metadata correctness without
    adding a new expression API or SQL parser.
    
    Fix: #12915
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. Loading a ClickHouse table no longer exposes a function-based
    data-skipping index as a plain-column Gravitino index. Unsupported
    expression indexes are omitted with a warning while the table remains
    loadable. Simple identifier and identifier-only tuple indexes are
    unchanged, and no public API or property key is added or removed.
    
    ### How was this patch tested?
    
    - `./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:spotlessCheck
    --console=plain` - passed.
    - `./gradlew rat --console=plain` - passed.
    - `./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:test -PskipITs
    --console=plain` - passed with 100 tests, 0 skipped, 0 failures, and 0
    errors.
    - `./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:test --tests
    
'org.apache.gravitino.catalog.clickhouse.integration.test.CatalogClickHouseIT.testLoadExpressionIndexDoesNotFabricateColumnIndex'
    -PskipDockerTests=false --console=plain --no-daemon` - passed against
    ClickHouse 24.8.14 with 1 test, 0 skipped, 0 failures, and 0 errors.
    - `./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:test --tests
    
'org.apache.gravitino.catalog.clickhouse.integration.test.CatalogClickHouseClusterIT'
    -PskipDockerTests=false --console=plain --no-daemon` - passed against
    ClickHouse 24.8.14 with 19 tests, 0 skipped, 0 failures, and 0 errors.
    - `./gradlew :catalogs-contrib:catalog-jdbc-clickhouse:build -x test
    --console=plain` - passed.
    - `git diff --check` - passed.
    
    Signed-off-by: jiangxt2 <[email protected]>
    Co-authored-by: Qi Yu <[email protected]>
    # Conflicts:
    #       
catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
    #       
catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
---
 .../operations/ClickHouseTableOperations.java      |  24 ++++
 .../operations/ClickHouseTableSqlUtils.java        |  33 ++---
 .../integration/test/CatalogClickHouseIT.java      |  59 +++++++++
 .../operations/TestClickHouseTableOperations.java  |   4 +-
 .../TestClickHouseTableOperationsIndexParsing.java |  21 +++-
 .../TestClickHouseTableOperationsUnit.java         | 137 +++++++++++++++++++++
 6 files changed, 255 insertions(+), 23 deletions(-)

diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
index 835b6d9fa6..b01debdd50 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableOperations.java
@@ -1734,6 +1734,7 @@ public class ClickHouseTableOperations extends 
JdbcTableOperations {
           String expression = resultSet.getString("expr");
           long granularity = resultSet.getLong("granularity");
           try {
+<<<<<<< HEAD
             String[][] fields = parseIndexFields(expression);
             if (ArrayUtils.isEmpty(fields)) {
               continue;
@@ -1754,6 +1755,29 @@ public class ClickHouseTableOperations extends 
JdbcTableOperations {
                 databaseName,
                 tableName,
                 expression);
+=======
+            indexType = getClickHouseIndexType(type);
+          } catch (IllegalArgumentException ignored) {
+            LOG.warn(
+                "Skip unsupported data skipping index {} for {}.{} with 
unsupported type {}",
+                name,
+                databaseName,
+                tableName,
+                type);
+            continue;
+          }
+          try {
+            fields = parseIndexFields(expression);
+          } catch (IllegalArgumentException ignored) {
+            LOG.warn(
+                "Skip unsupported data skipping index {} for {}.{} with type 
{} because its "
+                    + "expression cannot be represented as index field names",
+                name,
+                databaseName,
+                tableName,
+                type);
+            continue;
+>>>>>>> 441e590b9 ([#12915] fix(clickhouse): skip function-based index 
expressions on load (#12917))
           }
         }
       }
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableSqlUtils.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableSqlUtils.java
index f90d607f23..9681c0d301 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableSqlUtils.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseTableSqlUtils.java
@@ -84,7 +84,7 @@ final class ClickHouseTableSqlUtils {
   }
 
   static List<String> extractShardingKeyColumns(String shardingKey) {
-    String normalized = normalizeIndexExpression(shardingKey);
+    String normalized = normalizeShardingKeyExpression(shardingKey);
     if (StringUtils.isBlank(normalized)) {
       return Collections.emptyList();
     }
@@ -136,23 +136,10 @@ final class ClickHouseTableSqlUtils {
   }
 
   static String normalizeIndexExpression(String expression) {
-    String trimmed = expression.trim();
-
-    boolean stripped = true;
-    String current = trimmed;
-    while (stripped) {
-      stripped = false;
-      Matcher matcher = FUNCTION_WRAPPER_PATTERN.matcher(current);
-      if (matcher.matches()) {
-        current = matcher.group(2).trim();
-        stripped = true;
-      }
-    }
+    String current = expression.trim();
 
     if (StringUtils.startsWithIgnoreCase(current, "tuple(") && 
StringUtils.endsWith(current, ")")) {
       current = current.substring("tuple(".length(), current.length() - 
1).trim();
-    } else if (StringUtils.equalsIgnoreCase(current, "tuple()")) {
-      current = "";
     }
 
     return current;
@@ -175,6 +162,22 @@ final class ClickHouseTableSqlUtils {
     return StringUtils.isNotBlank(identifier) && 
identifier.matches("^[a-zA-Z_][a-zA-Z0-9_]*$");
   }
 
+  private static String normalizeShardingKeyExpression(String expression) {
+    String current = expression.trim();
+
+    boolean stripped = true;
+    while (stripped) {
+      stripped = false;
+      Matcher matcher = FUNCTION_WRAPPER_PATTERN.matcher(current);
+      if (matcher.matches()) {
+        current = matcher.group(2).trim();
+        stripped = true;
+      }
+    }
+
+    return normalizeIndexExpression(current);
+  }
+
   private static Transform parsePartitionExpression(
       String expression, String originalPartitionKey) {
     String trimmedExpression = StringUtils.trim(expression);
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
index 45057b5eff..bd2cd475a5 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseIT.java
@@ -485,6 +485,65 @@ public class CatalogClickHouseIT extends BaseIT {
                         && Arrays.deepEquals(idx.fieldNames(), new String[][] 
{{"amount"}})));
   }
 
+  @Test
+  void testLoadExpressionIndexDoesNotFabricateColumnIndex() {
+    String sourceTableName = 
GravitinoITUtils.genRandomName("expression_index_source");
+    String recreatedTableName = 
GravitinoITUtils.genRandomName("expression_index_recreated");
+    clickhouseService.executeQuery(
+        String.format(
+            "CREATE TABLE `%s`.`%s` ("
+                + "id UInt64, "
+                + "name String, "
+                + "INDEX idx_name name TYPE minmax GRANULARITY 1, "
+                + "INDEX idx_lower lower(name) TYPE minmax GRANULARITY 1"
+                + ") ENGINE = MergeTree ORDER BY id",
+            schemaName, sourceTableName));
+
+    String sourceCreateSql =
+        clickhouseService.executeQueryForResult(
+            String.format("SHOW CREATE TABLE `%s`.`%s`", schemaName, 
sourceTableName));
+    String normalizedSourceCreateSql = sourceCreateSql.replace("`", 
"").replaceAll("\\s+", "");
+    Assertions.assertTrue(
+        StringUtils.containsIgnoreCase(
+            normalizedSourceCreateSql, "INDEXidx_lowerlower(name)TYPEminmax"),
+        "Source table should retain its expression index: " + sourceCreateSql);
+
+    TableCatalog tableCatalog = catalog.asTableCatalog();
+    Table loaded = tableCatalog.loadTable(NameIdentifier.of(schemaName, 
sourceTableName));
+    Index[] loadedIndexes = loaded.index();
+    Index loadedSimpleIndex =
+        Arrays.stream(loadedIndexes)
+            .filter(index -> "idx_name".equals(index.name()))
+            .findFirst()
+            .orElseThrow();
+    Assertions.assertEquals(Index.IndexType.DATA_SKIPPING_MINMAX, 
loadedSimpleIndex.type());
+    Assertions.assertArrayEquals(new String[][] {{"name"}}, 
loadedSimpleIndex.fieldNames());
+    Assertions.assertFalse(
+        Arrays.stream(loadedIndexes).anyMatch(index -> 
"idx_lower".equals(index.name())));
+
+    tableCatalog.createTable(
+        NameIdentifier.of(schemaName, recreatedTableName),
+        loaded.columns(),
+        loaded.comment(),
+        loaded.properties(),
+        loaded.partitioning(),
+        loaded.distribution(),
+        loaded.sortOrder(),
+        loaded.index());
+
+    String recreatedCreateSql =
+        clickhouseService.executeQueryForResult(
+            String.format("SHOW CREATE TABLE `%s`.`%s`", schemaName, 
recreatedTableName));
+    String normalizedRecreatedCreateSql =
+        recreatedCreateSql.replace("`", "").replaceAll("\\s+", "");
+    Assertions.assertTrue(
+        StringUtils.containsIgnoreCase(normalizedRecreatedCreateSql, 
"INDEXidx_namenametypeMINMAX"),
+        "Recreated table should retain the simple index: " + 
recreatedCreateSql);
+    Assertions.assertFalse(
+        StringUtils.containsIgnoreCase(normalizedRecreatedCreateSql, 
"idx_lower"),
+        "Recreated table must not contain a fabricated replacement index: " + 
recreatedCreateSql);
+  }
+
   @Test
   void testCreateAndLoadCompositePrimaryKey() {
     String table = GravitinoITUtils.genRandomName("composite_primary_key");
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
index 5f3fdbd8ea..fc476b4056 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperations.java
@@ -1357,8 +1357,8 @@ public class TestClickHouseTableOperations extends 
TestClickHouse {
     String[][] fields = ops.parseIndexFields("tuple(`c2`, `c3`)");
     Assertions.assertArrayEquals(new String[][] {{"c2"}, {"c3"}}, fields);
 
-    String[][] bloomFields = ops.parseIndexFields("bloom_filter(`c4`)");
-    Assertions.assertArrayEquals(new String[][] {{"c4"}}, bloomFields);
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
ops.parseIndexFields("bloom_filter(`c4`)"));
   }
 
   @Test
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsIndexParsing.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsIndexParsing.java
index 83ad206a7f..90fc4334ea 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsIndexParsing.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsIndexParsing.java
@@ -29,17 +29,23 @@ public class TestClickHouseTableOperationsIndexParsing {
     String[][] single = operations.parseIndexFields("col_1");
     Assertions.assertArrayEquals(new String[][] {{"col_1"}}, single);
 
+    String[][] quoted = operations.parseIndexFields("`quoted_col`");
+    Assertions.assertArrayEquals(new String[][] {{"quoted_col"}}, quoted);
+
     String[][] tuple = operations.parseIndexFields("tuple(`a`, b)");
     Assertions.assertArrayEquals(new String[][] {{"a"}, {"b"}}, tuple);
   }
 
   @Test
-  public void testParseFunctionWrappedExpression() {
-    String[][] bloom = 
operations.parseIndexFields("bloom_filter(cityHash64(user_id))");
-    Assertions.assertArrayEquals(new String[][] {{"user_id"}}, bloom);
-
-    String[][] nested = 
operations.parseIndexFields("minmax(lower(`tenant_id`))");
-    Assertions.assertArrayEquals(new String[][] {{"tenant_id"}}, nested);
+  public void testRejectFunctionWrappedExpression() {
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
operations.parseIndexFields("lower(name)"));
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> 
operations.parseIndexFields("bloom_filter(cityHash64(user_id))"));
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> operations.parseIndexFields("minmax(lower(`tenant_id`))"));
   }
 
   @Test
@@ -52,5 +58,8 @@ public class TestClickHouseTableOperationsIndexParsing {
   public void testUnsupportedExpression() {
     Assertions.assertThrows(
         IllegalArgumentException.class, () -> 
operations.parseIndexFields("cityHash64(id) % 16"));
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> operations.parseIndexFields("tuple(lower(name), id)"));
   }
 }
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
index 357d2783ee..da7762d11e 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/operations/TestClickHouseTableOperationsUnit.java
@@ -715,6 +715,143 @@ public class TestClickHouseTableOperationsUnit {
     Assertions.assertTrue(exception.getMessage().contains("balanced"));
   }
 
+<<<<<<< HEAD
+=======
+  @Test
+  void testGetIndexesFailsOnMalformedParameterizedIndexMetadata() throws 
Exception {
+    ExposedClickHouseTableOperations ops = newOps();
+
+    PreparedStatement primaryKeyStmt = Mockito.mock(PreparedStatement.class);
+    ResultSet primaryKeyRs = Mockito.mock(ResultSet.class);
+    PreparedStatement secondaryStmt = Mockito.mock(PreparedStatement.class);
+    ResultSet secondaryRs = Mockito.mock(ResultSet.class);
+
+    Mockito.when(primaryKeyRs.next()).thenReturn(false);
+    Mockito.when(primaryKeyStmt.executeQuery()).thenReturn(primaryKeyRs);
+    Mockito.when(secondaryRs.next()).thenReturn(true, false);
+    Mockito.when(secondaryStmt.executeQuery()).thenReturn(secondaryRs);
+    Mockito.when(secondaryRs.getString("name")).thenReturn("idx_bad");
+    Mockito.when(secondaryRs.getString("type")).thenReturn("ngrambf_v1");
+    Mockito.when(secondaryRs.getString("type_full")).thenReturn(null);
+    Mockito.when(secondaryRs.getString("expr")).thenReturn("col_1");
+    Mockito.when(secondaryRs.getLong("granularity")).thenReturn(1L);
+
+    Connection connection = Mockito.mock(Connection.class);
+    Mockito.when(connection.prepareStatement(Mockito.anyString()))
+        .thenReturn(primaryKeyStmt)
+        .thenReturn(secondaryStmt);
+
+    IllegalArgumentException exception =
+        Assertions.assertThrows(
+            IllegalArgumentException.class, () -> 
ops.callGetIndexes(connection, "db", "tbl"));
+    Assertions.assertTrue(exception.getMessage().contains("idx_bad"));
+    Assertions.assertTrue(exception.getMessage().contains("type_full"));
+  }
+
+  @Test
+  void testGetIndexesSkipsUnsupportedExpressionForParameterizedIndex() throws 
Exception {
+    ExposedClickHouseTableOperations ops = newOps();
+
+    PreparedStatement primaryKeyStmt = Mockito.mock(PreparedStatement.class);
+    ResultSet primaryKeyRs = Mockito.mock(ResultSet.class);
+    PreparedStatement secondaryStmt = Mockito.mock(PreparedStatement.class);
+    ResultSet secondaryRs = Mockito.mock(ResultSet.class);
+
+    Mockito.when(primaryKeyRs.next()).thenReturn(false);
+    Mockito.when(primaryKeyStmt.executeQuery()).thenReturn(primaryKeyRs);
+    Mockito.when(secondaryRs.next()).thenReturn(true, true, false);
+    Mockito.when(secondaryStmt.executeQuery()).thenReturn(secondaryRs);
+    Mockito.when(secondaryRs.getString("name")).thenReturn("idx_bad_expr", 
"idx_valid");
+    Mockito.when(secondaryRs.getString("type")).thenReturn("ngrambf_v1", 
"tokenbf_v1");
+    Mockito.when(secondaryRs.getString("type_full"))
+        .thenReturn("ngrambf_v1(3, 512, 3, 0)", "tokenbf_v1(256, 2, 0)");
+    Mockito.when(secondaryRs.getString("expr")).thenReturn("lower(col_1)", 
"col_2");
+    Mockito.when(secondaryRs.getLong("granularity")).thenReturn(1L, 1L);
+
+    Connection connection = Mockito.mock(Connection.class);
+    Mockito.when(connection.prepareStatement(Mockito.anyString()))
+        .thenReturn(primaryKeyStmt)
+        .thenReturn(secondaryStmt);
+
+    List<Index> indexes = ops.callGetIndexes(connection, "db", "tbl");
+
+    Assertions.assertEquals(1, indexes.size());
+    Assertions.assertEquals("idx_valid", indexes.get(0).name());
+    Assertions.assertEquals(Index.IndexType.DATA_SKIPPING_TOKENBFV1, 
indexes.get(0).type());
+    Assertions.assertArrayEquals(new String[][] {{"col_2"}}, 
indexes.get(0).fieldNames());
+    Assertions.assertEquals(
+        Map.of(
+            "bloom_filter_size", "256",
+            "hash_functions", "2",
+            "random_seed", "0"),
+        indexes.get(0).properties());
+  }
+
+  @Test
+  void testGetIndexesFallsBackWhenTypeFullColumnIsMissing() throws Exception {
+    ExposedClickHouseTableOperations ops = newOps();
+
+    PreparedStatement primaryKeyStmt = Mockito.mock(PreparedStatement.class);
+    ResultSet primaryKeyRs = Mockito.mock(ResultSet.class);
+    PreparedStatement modernSecondaryStmt = 
Mockito.mock(PreparedStatement.class);
+    PreparedStatement legacySecondaryStmt = 
Mockito.mock(PreparedStatement.class);
+    ResultSet legacySecondaryRs = Mockito.mock(ResultSet.class);
+
+    Mockito.when(primaryKeyRs.next()).thenReturn(false);
+    Mockito.when(primaryKeyStmt.executeQuery()).thenReturn(primaryKeyRs);
+    Mockito.when(modernSecondaryStmt.executeQuery())
+        .thenThrow(new SQLException("Unknown identifier 'type_full'"));
+    
Mockito.when(legacySecondaryStmt.executeQuery()).thenReturn(legacySecondaryRs);
+    Mockito.when(legacySecondaryRs.next()).thenReturn(true, false);
+    Mockito.when(legacySecondaryRs.getString("name")).thenReturn("idx_legacy");
+    
Mockito.when(legacySecondaryRs.getString("type")).thenReturn("ngrambf_v1(3, 
512, 3, 0)");
+    Mockito.when(legacySecondaryRs.getString("expr")).thenReturn("col_1");
+    Mockito.when(legacySecondaryRs.getLong("granularity")).thenReturn(1L);
+
+    Connection connection = Mockito.mock(Connection.class);
+    Mockito.when(connection.prepareStatement(Mockito.anyString()))
+        .thenReturn(primaryKeyStmt)
+        .thenReturn(modernSecondaryStmt)
+        .thenReturn(legacySecondaryStmt);
+
+    List<Index> indexes = ops.callGetIndexes(connection, "db", "tbl");
+
+    Assertions.assertEquals(1, indexes.size());
+    Assertions.assertEquals(Index.IndexType.DATA_SKIPPING_NGRAMBFV1, 
indexes.get(0).type());
+    Assertions.assertEquals(
+        Map.of(
+            "ngram_size", "3",
+            "bloom_filter_size", "512",
+            "hash_functions", "3",
+            "random_seed", "0"),
+        indexes.get(0).properties());
+  }
+
+  @Test
+  void testGetIndexesDoesNotFallbackForOtherSqlErrors() throws Exception {
+    ExposedClickHouseTableOperations ops = newOps();
+
+    PreparedStatement primaryKeyStmt = Mockito.mock(PreparedStatement.class);
+    ResultSet primaryKeyRs = Mockito.mock(ResultSet.class);
+    PreparedStatement secondaryStmt = Mockito.mock(PreparedStatement.class);
+    Mockito.when(primaryKeyRs.next()).thenReturn(false);
+    Mockito.when(primaryKeyStmt.executeQuery()).thenReturn(primaryKeyRs);
+    Mockito.when(secondaryStmt.executeQuery())
+        .thenThrow(new SQLException("Connection reset by peer"));
+
+    Connection connection = Mockito.mock(Connection.class);
+    Mockito.when(connection.prepareStatement(Mockito.anyString()))
+        .thenReturn(primaryKeyStmt)
+        .thenReturn(secondaryStmt);
+
+    GravitinoRuntimeException exception =
+        Assertions.assertThrows(
+            GravitinoRuntimeException.class, () -> 
ops.callGetIndexes(connection, "db", "tbl"));
+    Assertions.assertTrue(exception.getCause() instanceof SQLException);
+    Mockito.verify(connection, 
Mockito.times(2)).prepareStatement(Mockito.anyString());
+  }
+
+>>>>>>> 441e590b9 ([#12915] fix(clickhouse): skip function-based index 
expressions on load (#12917))
   private RenameMocks renameMocks(String storedComment, String engineFull) 
throws Exception {
     DataSource dataSource = Mockito.mock(DataSource.class);
     Connection connection = Mockito.mock(Connection.class);

Reply via email to