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

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

commit 6dba8fa20c209858b628e8e7a42d37c23f355104
Author: StormSpirit <[email protected]>
AuthorDate: Fri Jul 10 08:55:38 2026 +0800

    [#11912] feat(clickhouse): support set data skipping index type (#11916)
    
    ### What changes were proposed in this pull request?
    
    - Add set data skipping index type to the Index API
    - Support set index in CREATE TABLE, ALTER TABLE, and table loading
    - Refactor index DDL generation into a shared helper
    
    ### Why are the changes needed?
    
    Fix: #11912
    
    The ClickHouse catalog only supports minmax and bloom_filter skip
    indexes. Tables with set indexes load without error but index metadata
    is silently dropped, and explicit creation attempts fail. The set index
    type has no required parameters (unlike ngrambf_v1/tokenbf_v1), making
    it safe to add without a parameter-passing mechanism.
    
    ### Does this PR introduce any user-facing change?
    
    Yes. ClickHouse tables with set data skipping indexes can now be created
    and loaded through Gravitino with index metadata preserved.
    
    ### How was this patch tested?
    
    **Unit tests** (`TestClickHouseTableOperations`):
    - `testGetClickHouseIndexType`: verifies index type string-to-enum
    mapping (minmax, bloom_filter, set)
    
    **Integration tests** (`CatalogClickHouseIT`):
    - `testCreateAndLoadWithPartitionSortAndIndexes`: extended with SET
    index create/load round-trip
    - `testAlterTableAddIndexWithSetIndex`: ALTER TABLE ADD INDEX with SET
    type
    
    Both test classes require `-PskipDockerTests=false` to run.
    
    ---------
    
    Signed-off-by: jiangxt2 <[email protected]>
---
 .../org/apache/gravitino/rel/indexes/Index.java    |  3 +
 .../catalog/clickhouse/ClickHouseConstants.java    |  3 +
 .../operations/ClickHouseTableOperations.java      | 66 +++++++++++++++++-----
 .../test/CatalogClickHouseClusterIT.java           | 18 ++++++
 .../integration/test/CatalogClickHouseIT.java      | 45 +++++++++++++--
 .../operations/TestClickHouseTableOperations.java  | 40 +++++++++++++
 docs/jdbc-clickhouse-catalog.md                    |  3 +-
 7 files changed, 157 insertions(+), 21 deletions(-)

diff --git a/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java 
b/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
index d299683889..9f725c19cc 100644
--- a/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
+++ b/api/src/main/java/org/apache/gravitino/rel/indexes/Index.java
@@ -129,5 +129,8 @@ public interface Index {
 
     /** Bloom filter data skipping index */
     DATA_SKIPPING_BLOOM_FILTER,
+
+    /** Set data skipping index */
+    DATA_SKIPPING_SET,
   }
 }
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
index 38428e82aa..a2fca9f7b7 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/ClickHouseConstants.java
@@ -57,5 +57,8 @@ public class ClickHouseConstants {
 
     // The name of the data skipping index type for bloom filter index in 
clickhouse.
     public static final String DATA_SKIPPING_BLOOM_FILTER = "bloom_filter";
+
+    // The name of the data skipping index type for set index in clickhouse.
+    public static final String DATA_SKIPPING_SET = "set";
   }
 }
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 118eed0989..688483a9ce 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
@@ -20,6 +20,7 @@ package org.apache.gravitino.catalog.clickhouse.operations;
 
 import static 
org.apache.gravitino.catalog.clickhouse.ClickHouseConstants.IndexConstants.DATA_SKIPPING_BLOOM_FILTER;
 import static 
org.apache.gravitino.catalog.clickhouse.ClickHouseConstants.IndexConstants.DATA_SKIPPING_MINMAX_VALUE;
+import static 
org.apache.gravitino.catalog.clickhouse.ClickHouseConstants.IndexConstants.DATA_SKIPPING_SET;
 import static 
org.apache.gravitino.catalog.clickhouse.ClickHouseTablePropertiesMetadata.CLICKHOUSE_ENGINE_KEY;
 import static 
org.apache.gravitino.catalog.clickhouse.ClickHouseTablePropertiesMetadata.ENGINE_PROPERTY_ENTRY;
 import static 
org.apache.gravitino.catalog.clickhouse.ClickHouseTablePropertiesMetadata.GRAVITINO_ENGINE_KEY;
@@ -483,23 +484,27 @@ public class ClickHouseTableOperations extends 
JdbcTableOperations {
           sqlBuilder.append(" PRIMARY KEY (").append(fieldStr).append(")");
           break;
         case DATA_SKIPPING_MINMAX:
-          Preconditions.checkArgument(
-              StringUtils.isNotBlank(index.name()), "Data skipping index name 
must not be blank");
           // The GRANULARITY value is always 1 here currently as we can't set 
it by Index: there is
           // no field for it.
           // TODO(yuqi) add a properties field to Index to support user 
defined GRANULARITY value.
-          sqlBuilder.append(
-              " INDEX %s %s TYPE minmax GRANULARITY 1"
-                  .formatted(quoteIdentifier(index.name()), fieldStr));
+          sqlBuilder
+              .append(" ")
+              .append(buildDataSkippingIndexDdl(index.name(), fieldStr, 
"minmax", 1));
           break;
         case DATA_SKIPPING_BLOOM_FILTER:
           // The GRANULARITY value is always 3 here currently.
           // TODO(yuqi) add a properties field to Index to support user 
defined GRANULARITY value.
-          Preconditions.checkArgument(
-              StringUtils.isNotBlank(index.name()), "Data skipping index name 
must not be blank");
-          sqlBuilder.append(
-              " INDEX %s %s TYPE bloom_filter GRANULARITY 3"
-                  .formatted(quoteIdentifier(index.name()), fieldStr));
+          sqlBuilder
+              .append(" ")
+              .append(buildDataSkippingIndexDdl(index.name(), fieldStr, 
"bloom_filter", 3));
+          break;
+        case DATA_SKIPPING_SET:
+          // The max unique values (N) is always 0 (unlimited) here currently 
as we can't set it
+          // by Index: there is no field for it. ClickHouse requires set(N) 
syntax.
+          // TODO(yuqi) add a properties field to Index to support user 
defined max unique values.
+          sqlBuilder
+              .append(" ")
+              .append(buildDataSkippingIndexDdl(index.name(), fieldStr, 
"set(0)", 1));
           break;
         default:
           throw new IllegalArgumentException(
@@ -871,12 +876,16 @@ public class ClickHouseTableOperations extends 
JdbcTableOperations {
     String fieldStr = getIndexFieldStr(addIndex.getFieldNames());
     switch (addIndex.getType()) {
       case DATA_SKIPPING_MINMAX:
-        return "ADD INDEX %s %s TYPE minmax GRANULARITY 1"
-            .formatted(quoteIdentifier(addIndex.getName()), fieldStr);
+        return "ADD " + buildDataSkippingIndexDdl(addIndex.getName(), 
fieldStr, "minmax", 1);
 
       case DATA_SKIPPING_BLOOM_FILTER:
-        return "ADD INDEX %s %s TYPE bloom_filter GRANULARITY 3"
-            .formatted(quoteIdentifier(addIndex.getName()), fieldStr);
+        return "ADD " + buildDataSkippingIndexDdl(addIndex.getName(), 
fieldStr, "bloom_filter", 3);
+
+      case DATA_SKIPPING_SET:
+        // The max unique values (N) is always 0 (unlimited) here currently as 
we can't set it
+        // by Index: there is no field for it. ClickHouse requires set(N) 
syntax.
+        // TODO(yuqi) add a properties field to Index to support user defined 
max unique values.
+        return "ADD " + buildDataSkippingIndexDdl(addIndex.getName(), 
fieldStr, "set(0)", 1);
 
       case PRIMARY_KEY:
         throw new UnsupportedOperationException(
@@ -1333,7 +1342,19 @@ public class ClickHouseTableOperations extends 
JdbcTableOperations {
     return secondaryIndexes;
   }
 
-  private Index.IndexType getClickHouseIndexType(String rawType) {
+  /**
+   * Maps a ClickHouse data skipping index type string to the corresponding 
Gravitino {@link
+   * Index.IndexType}. Returns {@code DATA_SKIPPING_MINMAX} for blank/null 
input (ClickHouse
+   * default). Also handles the {@code set(N)} parameterized format that some 
ClickHouse versions
+   * may return from {@code system.data_skipping_indices}.
+   *
+   * @param rawType the index type string from ClickHouse metadata (e.g. 
"minmax", "bloom_filter",
+   *     "set", "set(0)")
+   * @return the corresponding Gravitino IndexType
+   * @throws IllegalArgumentException if the type is not supported
+   */
+  @VisibleForTesting
+  Index.IndexType getClickHouseIndexType(String rawType) {
     if (StringUtils.isBlank(rawType)) {
       return Index.IndexType.DATA_SKIPPING_MINMAX;
     }
@@ -1343,11 +1364,26 @@ public class ClickHouseTableOperations extends 
JdbcTableOperations {
         return Index.IndexType.DATA_SKIPPING_MINMAX;
       case DATA_SKIPPING_BLOOM_FILTER:
         return Index.IndexType.DATA_SKIPPING_BLOOM_FILTER;
+      case DATA_SKIPPING_SET:
+        return Index.IndexType.DATA_SKIPPING_SET;
       default:
+        // ClickHouse may return "set(N)" with parameter in some versions;
+        // match on prefix to handle both "set" and "set(N)" formats.
+        if (rawType.startsWith(DATA_SKIPPING_SET + "(")) {
+          return Index.IndexType.DATA_SKIPPING_SET;
+        }
         throw new IllegalArgumentException("Unsupported data skipping index 
type: " + rawType);
     }
   }
 
+  private String buildDataSkippingIndexDdl(
+      String indexName, String fieldStr, String typeName, int granularity) {
+    Preconditions.checkArgument(
+        StringUtils.isNotBlank(indexName), "Data skipping index name must not 
be blank");
+    return "INDEX %s %s TYPE %s GRANULARITY %d"
+        .formatted(quoteIdentifier(indexName), fieldStr, typeName, 
granularity);
+  }
+
   private StringBuilder appendColumnDefinition(JdbcColumn column, 
StringBuilder sqlBuilder) {
     // Add Nullable data type
     String dataType = typeConverter.fromGravitino(column.dataType());
diff --git 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
index 48d6ee8f89..7cfdde2b7b 100644
--- 
a/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
+++ 
b/catalogs-contrib/catalog-jdbc-clickhouse/src/test/java/org/apache/gravitino/catalog/clickhouse/integration/test/CatalogClickHouseClusterIT.java
@@ -506,6 +506,24 @@ public class CatalogClickHouseClusterIT extends BaseIT {
         Arrays.stream(loaded.index())
             .anyMatch(index -> Objects.equals(index.name(), "idx_col_1_new")));
 
+    tableCatalog.alterTable(
+        tableIdentifier,
+        TableChange.addIndex(
+            Index.IndexType.DATA_SKIPPING_SET, "idx_col_2_set", new String[][] 
{{"col_2"}}));
+    loaded = tableCatalog.loadTable(tableIdentifier);
+    Assertions.assertTrue(
+        Arrays.stream(loaded.index())
+            .anyMatch(
+                index ->
+                    Objects.equals(index.name(), "idx_col_2_set")
+                        && index.type() == Index.IndexType.DATA_SKIPPING_SET
+                        && Arrays.deepEquals(index.fieldNames(), new 
String[][] {{"col_2"}})));
+    tableCatalog.alterTable(tableIdentifier, 
TableChange.deleteIndex("idx_col_2_set", false));
+    loaded = tableCatalog.loadTable(tableIdentifier);
+    Assertions.assertFalse(
+        Arrays.stream(loaded.index())
+            .anyMatch(index -> Objects.equals(index.name(), "idx_col_2_set")));
+
     RuntimeException autoIncrementTrueException =
         Assertions.assertThrows(
             RuntimeException.class,
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 4da92f33e1..a1f64dacda 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
@@ -510,7 +510,9 @@ public class CatalogClickHouseIT extends BaseIT {
         new Index[] {
           Indexes.primary(Indexes.DEFAULT_PRIMARY_KEY_NAME, new String[][] 
{{"user_id"}}),
           Indexes.of(
-              Index.IndexType.DATA_SKIPPING_MINMAX, "idx_amount", new 
String[][] {{"amount"}})
+              Index.IndexType.DATA_SKIPPING_MINMAX, "idx_amount", new 
String[][] {{"amount"}}),
+          Indexes.of(
+              Index.IndexType.DATA_SKIPPING_SET, "idx_userid_set", new 
String[][] {{"user_id"}})
         };
 
     catalog
@@ -555,6 +557,13 @@ public class CatalogClickHouseIT extends BaseIT {
                 idx ->
                     idx.type() == Index.IndexType.DATA_SKIPPING_MINMAX
                         && Arrays.deepEquals(idx.fieldNames(), new String[][] 
{{"amount"}})));
+    Assertions.assertTrue(
+        Arrays.stream(loadedIndexes)
+            .anyMatch(
+                idx ->
+                    idx.type() == Index.IndexType.DATA_SKIPPING_SET
+                        && idx.name().equals("idx_userid_set")
+                        && Arrays.deepEquals(idx.fieldNames(), new String[][] 
{{"user_id"}})));
   }
 
   @Test
@@ -1335,7 +1344,8 @@ public class CatalogClickHouseIT extends BaseIT {
         };
     Index[] indexes =
         new Index[] {
-          Indexes.of(Index.IndexType.DATA_SKIPPING_MINMAX, "idx_note", new 
String[][] {{"note"}})
+          Indexes.of(Index.IndexType.DATA_SKIPPING_MINMAX, "idx_note", new 
String[][] {{"note"}}),
+          Indexes.of(Index.IndexType.DATA_SKIPPING_SET, "idx_note_set", new 
String[][] {{"note"}})
         };
     TableCatalog tableCatalog = catalog.asTableCatalog();
     tableCatalog.createTable(
@@ -1353,12 +1363,18 @@ public class CatalogClickHouseIT extends BaseIT {
     tableCatalog.alterTable(
         tableIdentifier,
         TableChange.updateColumnComment(new String[] {"score"}, "score column 
changed"));
-    tableCatalog.alterTable(tableIdentifier, 
TableChange.deleteIndex("idx_note", false));
+    tableCatalog.alterTable(
+        tableIdentifier,
+        TableChange.deleteIndex("idx_note", false),
+        TableChange.deleteIndex("idx_note_set", false));
     Table loaded = tableCatalog.loadTable(tableIdentifier);
     Assertions.assertTrue(loaded.columns()[1].nullable());
     Assertions.assertEquals("score column changed", 
loaded.columns()[1].comment());
     Assertions.assertFalse(
         Arrays.stream(loaded.index()).anyMatch(index -> 
Objects.equals(index.name(), "idx_note")));
+    Assertions.assertFalse(
+        Arrays.stream(loaded.index())
+            .anyMatch(index -> Objects.equals(index.name(), "idx_note_set")));
 
     Assertions.assertDoesNotThrow(
         () ->
@@ -1417,7 +1433,8 @@ public class CatalogClickHouseIT extends BaseIT {
           Indexes.of(
               Index.IndexType.DATA_SKIPPING_BLOOM_FILTER,
               "idx_note_bloom",
-              new String[][] {{"note"}})
+              new String[][] {{"note"}}),
+          Indexes.of(Index.IndexType.DATA_SKIPPING_SET, "idx_score_set", new 
String[][] {{"score"}})
         };
     TableCatalog tableCatalog = catalog.asTableCatalog();
     tableCatalog.createTable(
@@ -1434,15 +1451,27 @@ public class CatalogClickHouseIT extends BaseIT {
         tableIdentifier,
         TableChange.addIndex(
             Index.IndexType.DATA_SKIPPING_MINMAX, "idx_new", new String[][] 
{{"score"}}));
+    tableCatalog.alterTable(
+        tableIdentifier,
+        TableChange.addIndex(
+            Index.IndexType.DATA_SKIPPING_SET, "idx_new_set", new String[][] 
{{"note"}}));
     Table loaded = tableCatalog.loadTable(tableIdentifier);
     Assertions.assertTrue(
         Arrays.stream(loaded.index()).anyMatch(index -> 
Objects.equals(index.name(), "idx_new")));
+    Assertions.assertTrue(
+        Arrays.stream(loaded.index())
+            .anyMatch(
+                index ->
+                    Objects.equals(index.name(), "idx_new_set")
+                        && index.type() == Index.IndexType.DATA_SKIPPING_SET));
 
     tableCatalog.alterTable(
         tableIdentifier,
         TableChange.deleteIndex("idx_score_minmax", false),
         TableChange.deleteIndex("idx_note_bloom", false),
-        TableChange.deleteIndex("idx_new", false));
+        TableChange.deleteIndex("idx_score_set", false),
+        TableChange.deleteIndex("idx_new", false),
+        TableChange.deleteIndex("idx_new_set", false));
     loaded = tableCatalog.loadTable(tableIdentifier);
     Assertions.assertFalse(
         Arrays.stream(loaded.index())
@@ -1450,8 +1479,14 @@ public class CatalogClickHouseIT extends BaseIT {
     Assertions.assertFalse(
         Arrays.stream(loaded.index())
             .anyMatch(index -> Objects.equals(index.name(), 
"idx_note_bloom")));
+    Assertions.assertFalse(
+        Arrays.stream(loaded.index())
+            .anyMatch(index -> Objects.equals(index.name(), "idx_score_set")));
     Assertions.assertFalse(
         Arrays.stream(loaded.index()).anyMatch(index -> 
Objects.equals(index.name(), "idx_new")));
+    Assertions.assertFalse(
+        Arrays.stream(loaded.index())
+            .anyMatch(index -> Objects.equals(index.name(), "idx_new_set")));
 
     RuntimeException autoIncrementTrueException =
         Assertions.assertThrows(
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 946a1a3027..3a54b45812 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
@@ -1099,6 +1099,7 @@ public class TestClickHouseTableOperations extends 
TestClickHouse {
           Indexes.primary(Indexes.DEFAULT_PRIMARY_KEY_NAME, new String[][] 
{{"c1"}}),
           Indexes.of(IndexType.DATA_SKIPPING_MINMAX, "idx_c2", new String[][] 
{{"c2"}}),
           Indexes.of(IndexType.DATA_SKIPPING_BLOOM_FILTER, "idx_c3", new 
String[][] {{"c3"}}),
+          Indexes.of(IndexType.DATA_SKIPPING_SET, "idx_c4", new String[][] 
{{"c2"}}),
         };
 
     String sql =
@@ -1115,6 +1116,7 @@ public class TestClickHouseTableOperations extends 
TestClickHouse {
     Assertions.assertTrue(sql.contains("PARTITION BY `c1`"));
     Assertions.assertTrue(sql.contains("INDEX `idx_c2` `c2` TYPE minmax 
GRANULARITY 1"));
     Assertions.assertTrue(sql.contains("INDEX `idx_c3` `c3` TYPE bloom_filter 
GRANULARITY 3"));
+    Assertions.assertTrue(sql.contains("INDEX `idx_c4` `c2` TYPE set(0) 
GRANULARITY 1"));
   }
 
   @Test
@@ -1380,6 +1382,15 @@ public class TestClickHouseTableOperations extends 
TestClickHouse {
     Assertions.assertTrue(
         bloomSql.contains("ADD INDEX `idx_bf` `c2` TYPE bloom_filter 
GRANULARITY 3"));
 
+    String setSql =
+        ops.buildAlterSql(
+            "db",
+            "tbl",
+            new TableChange[] {
+              TableChange.addIndex(IndexType.DATA_SKIPPING_SET, "idx_set", new 
String[][] {{"c2"}})
+            });
+    Assertions.assertTrue(setSql.contains("ADD INDEX `idx_set` `c2` TYPE 
set(0) GRANULARITY 1"));
+
     Assertions.assertThrows(
         IllegalArgumentException.class,
         () ->
@@ -1402,6 +1413,35 @@ public class TestClickHouseTableOperations extends 
TestClickHouse {
                 }));
   }
 
+  @Test
+  public void testGetClickHouseIndexType() {
+    StubClickHouseTableOperations ops = new StubClickHouseTableOperations();
+    ops.initialize(
+        null,
+        new ClickHouseExceptionConverter(),
+        new ClickHouseTypeConverter(),
+        new ClickHouseColumnDefaultValueConverter(),
+        new HashMap<>());
+
+    // Exact matches
+    Assertions.assertEquals(IndexType.DATA_SKIPPING_MINMAX, 
ops.getClickHouseIndexType("minmax"));
+    Assertions.assertEquals(
+        IndexType.DATA_SKIPPING_BLOOM_FILTER, 
ops.getClickHouseIndexType("bloom_filter"));
+    Assertions.assertEquals(IndexType.DATA_SKIPPING_SET, 
ops.getClickHouseIndexType("set"));
+
+    // set(N) variants — ClickHouse may return type with parameter in some 
versions
+    Assertions.assertEquals(IndexType.DATA_SKIPPING_SET, 
ops.getClickHouseIndexType("set(0)"));
+    Assertions.assertEquals(IndexType.DATA_SKIPPING_SET, 
ops.getClickHouseIndexType("set(100)"));
+
+    // Blank/null defaults to MINMAX
+    Assertions.assertEquals(IndexType.DATA_SKIPPING_MINMAX, 
ops.getClickHouseIndexType(""));
+    Assertions.assertEquals(IndexType.DATA_SKIPPING_MINMAX, 
ops.getClickHouseIndexType(null));
+
+    // Unsupported type
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
ops.getClickHouseIndexType("unknown_type"));
+  }
+
   @Test
   public void testAlterTableNullabilityValidationFails() {
     StubClickHouseTableOperations ops = new StubClickHouseTableOperations();
diff --git a/docs/jdbc-clickhouse-catalog.md b/docs/jdbc-clickhouse-catalog.md
index b6859cdaf1..4075ff2b38 100644
--- a/docs/jdbc-clickhouse-catalog.md
+++ b/docs/jdbc-clickhouse-catalog.md
@@ -172,7 +172,7 @@ See [Manage Relational Metadata Using 
Gravitino](./manage-relational-metadata-us
 | Mapping             | Gravitino table maps to a ClickHouse table             
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
   |
 | Engines             | **MergeTree family** (`MergeTree` default, 
`ReplacingMergeTree`, `SummingMergeTree`, `AggregatingMergeTree`, 
`CollapsingMergeTree`, `VersionedCollapsingMergeTree`, `GraphiteMergeTree`): 
fully supported, data persists across restarts. **Log family** (`TinyLog`, 
`StripeLog`, `Log`): supported, data and table definition persist across 
restarts. **`Null`**: supported, table persists, data is always discarded by 
design. **`Set`**: supported, table definition persists.  [...]
 | Ordering/Partition  | MergeTree-family requires exactly one `ORDER BY` 
column; only single-column identity `PARTITION BY` is supported on MergeTree 
engines. Other engines reject `ORDER BY`/`PARTITION BY`.                        
                                                                                
                                                                                
                                                                                
            |
-| Indexes             | Primary key; data-skipping indexes 
`DATA_SKIPPING_MINMAX` and `DATA_SKIPPING_BLOOM_FILTER` (fixed granularities).  
                                                                                
                                                                                
                                                                                
                                                                                
                       |
+| Indexes             | Primary key; data-skipping indexes 
`DATA_SKIPPING_MINMAX`, `DATA_SKIPPING_BLOOM_FILTER`, and `DATA_SKIPPING_SET` 
(fixed granularities).                                                          
                                                                                
                                                                                
                                                                                
                         |
 | Distribution        | Gravitino enforces `Distributions.NONE`; no custom 
distribution strategies.                                                        
                                                                                
                                                                                
                                                                                
                                                                                
       |
 | Column defaults     | Supported.                                             
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
   |
 | Unsupported         | Engine change after creation; removing table 
properties; auto-increment columns.                                             
                                                                                
                                                                                
                                                                                
                                                                                
             |
@@ -242,6 +242,7 @@ If you need Gravitino to manage an existing cluster 
database or table, recreate
 - Data-skipping indexes:
   - `DATA_SKIPPING_MINMAX` (`GRANULARITY` fixed to 1)
   - `DATA_SKIPPING_BLOOM_FILTER` (`GRANULARITY` fixed to 3)
+  - `DATA_SKIPPING_SET` (`GRANULARITY` fixed to 1)
 
 ### Partitioning, Sorting, and Distribution
 

Reply via email to