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 7d54df627a [#7809] feat(trino-connector): Support create table with 
index info with MySQL (#7810)
7d54df627a is described below

commit 7d54df627af575a400e017f6ed175beb7477d634
Author: qbhan <[email protected]>
AuthorDate: Wed Jul 30 15:56:22 2025 +0800

    [#7809] feat(trino-connector): Support create table with index info with 
MySQL (#7810)
    
    ### What changes were proposed in this pull request?
    Support create mysql table with index info in Trino like this:
    ```sql
    CREATE TABLE 
gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key (
       key1 integer NOT NULL,
       key2 integer,
       col1 integer
    )
    COMMENT ''
    WITH (
       engine = 'InnoDB',
       primary_key = ARRAY['key1'],
       unique_key = ARRAY['unique_key1:key2']
    )
    ```
    
    ### Why are the changes needed?
    Fix: #7809
    
    ### Does this PR introduce _any_ user-facing change?
    no
    
    ### How was this patch tested?
    local tests
---
 docs/trino-connector/catalog-mysql.md              |  32 +++-
 .../docker-script/init/mysql/init.sql              |  63 -------
 .../testsets/jdbc-mysql/00010_show_index.sql       | 185 ++++++++++++++++++++-
 .../testsets/jdbc-mysql/00010_show_index.txt       |  44 +++++
 .../catalog/CatalogConnectorMetadata.java          |   3 +-
 .../catalog/jdbc/mysql/MySQLMetadataAdapter.java   |  76 ++++++++-
 .../catalog/jdbc/mysql/MySQLPropertyMeta.java      |  51 ++++++
 .../trino/connector/metadata/GravitinoTable.java   |  22 +++
 .../trino/connector/GravitinoMockServer.java       |   1 +
 9 files changed, 400 insertions(+), 77 deletions(-)

diff --git a/docs/trino-connector/catalog-mysql.md 
b/docs/trino-connector/catalog-mysql.md
index 131aabdbee..1dd6ea869b 100644
--- a/docs/trino-connector/catalog-mysql.md
+++ b/docs/trino-connector/catalog-mysql.md
@@ -16,7 +16,7 @@ To connect to MySQL, you need:
 
 ## Create table
 
-At present, the Apache Gravitino Trino connector only supports basic MySQL 
table creation statements, which involve fields, null allowances, and comments. 
However, it does not support advanced features like primary keys, indexes, 
default values, and auto-increment.
+At present, the Apache Gravitino Trino connector only supports basic MySQL 
table creation statements, which involve fields, null allowances, comments, 
primary keys and indexes. However, it does not support advanced features like 
default values and auto-increment.
 
 The Gravitino Trino connector does not support `CREATE TABLE AS SELECT`.
 
@@ -36,7 +36,16 @@ Currently, it doesn't support certain query optimizations, 
such as indexes and p
 
 ## Table and Schema properties
 
-MySQL's tables and schemas cannot support properties.
+MySQL's schemas cannot support properties.
+
+The following are supported MySQL table properties:
+
+| Property name                      | Type   | Default Value  | Description   
                                                                                
                                          | Required | Since Version |
+|------------------------------------|--------|----------------|-----------------------------------------------------------------------------------------------------------------------------------------|----------|---------------|
+| engine                             | string | InnoDB         | The engine 
that MySQL table uses.                                                          
                                             | No       | 0.4.0         |
+| auto_increment_offset              | string | (none)         | The auto 
increment offset for the table.                                                 
                                               | No       | 0.4.0         |
+| primary_key                        | list   | (none)         | The primary 
keys for the table, can choose multi columns as the table primary key. All key 
columns must be defined as `NOT NULL`.       | No       | 1.0.0         |
+| unique_key                         | list   | (none)         | The unique 
keys for the table, can choose multi columns for multi unique key. Each unique 
key should be defined as `keyName:col1,col2`. | No       | 1.0.0         |
 
 ## Basic usage examples
 
@@ -116,6 +125,25 @@ salary int
 );
 ```
 
+Create a new table named `table_index` in schema `mysql_test.database_01` with 
primary keys and indexes.
+
+```sql
+CREATE TABLE mysql_test.database_01.table_index (
+   key1 integer NOT NULL,
+   key2 integer,
+   key3 integer,
+   key4 integer,
+   key5 integer NOT NULL,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key5','key1'],
+   unique_key = ARRAY['unique_key1:key2','unique_key2:key4,key3']
+);
+```
+
 ### Writing data
 
 Insert data into the table `table_01`:
diff --git a/integration-test-common/docker-script/init/mysql/init.sql 
b/integration-test-common/docker-script/init/mysql/init.sql
index b6535b27cf..8848b0f23d 100644
--- a/integration-test-common/docker-script/init/mysql/init.sql
+++ b/integration-test-common/docker-script/init/mysql/init.sql
@@ -118,66 +118,3 @@ INSERT INTO gt_mysql_test_all_type.demo (
     ST_GeomFromText('POINT(10 20)'),        -- point_col
     ST_GeomFromText('LINESTRING(0 0, 10 10)') -- geometry_col
 );
-CREATE DATABASE gt_mysql_test_index;
-CREATE TABLE gt_mysql_test_index.demo_with_one_primary_key
-(
-    key1 INT PRIMARY KEY,
-    col1 INT
-);
-CREATE TABLE gt_mysql_test_index.demo_with_two_primary_key
-(
-    key1 INT,
-    key2 INT,
-    col1 INT,
-    primary key (key2, key1)
-);
-CREATE TABLE gt_mysql_test_index.demo_with_one_unique_key
-(
-    key1 INT,
-    col1 INT,
-    unique key unique_key1 (key1)
-);
-CREATE TABLE gt_mysql_test_index.demo_with_one_unique_key_1
-(
-    key1 INT,
-    key2 INT,
-    col1 INT,
-    unique key unique_key1 (key2, key1)
-);
-CREATE TABLE gt_mysql_test_index.demo_with_two_unique_key
-(
-    key1 INT,
-    key2 INT,
-    col1 INT,
-    unique key unique_key1 (key1),
-    unique key unique_key2 (key2)
-);
-CREATE TABLE gt_mysql_test_index.demo_with_two_unique_key_1
-(
-    key1 INT,
-    key2 INT,
-    key3 INT,
-    col1 INT,
-    unique key unique_key1 (key1),
-    unique key unique_key2 (key3, key2)
-);
-CREATE TABLE gt_mysql_test_index.demo_with_primary_key_and_unique_key
-(
-    key1 INT,
-    key2 INT,
-    col1 INT,
-    primary key (key1),
-    unique key unique_key1 (key2)
-);
-CREATE TABLE gt_mysql_test_index.demo_with_primary_key_and_unique_key_1
-(
-    key1 INT,
-    key2 INT,
-    key3 INT,
-    key4 INT,
-    key5 INT,
-    col1 INT,
-    primary key (key5, key1),
-    unique key unique_key1 (key2),
-    unique key unique_key2 (key4, key3)
-);
\ No newline at end of file
diff --git 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.sql
 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.sql
index 7f7d8ae1e3..5c78a9e99f 100644
--- 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.sql
+++ 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.sql
@@ -1,16 +1,183 @@
--- Table create by integration-test-common/docker-script/init/mysql/init.sql
-show create table gt_mysql_test_index.demo_with_one_primary_key;
+CREATE SCHEMA gt_mysql.gt_mysql_test_index;
 
-show create table gt_mysql_test_index.demo_with_two_primary_key;
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_primary_key (
+   key1 integer NOT NULL,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key1']
+);
 
-show create table gt_mysql_test_index.demo_with_one_unique_key;
+SHOW CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_primary_key;
 
-show create table gt_mysql_test_index.demo_with_one_unique_key_1;
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_one_primary_key;
 
-show create table gt_mysql_test_index.demo_with_two_unique_key;
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_primary_key (
+   key1 integer NOT NULL,
+   key2 integer NOT NULL,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key2','key1']
+);
 
-show create table gt_mysql_test_index.demo_with_two_unique_key_1;
+SHOW CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_primary_key;
 
-show create table gt_mysql_test_index.demo_with_primary_key_and_unique_key;
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_two_primary_key;
 
-show create table gt_mysql_test_index.demo_with_primary_key_and_unique_key_1;
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key (
+   key1 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   unique_key = ARRAY['unique_key1:key1']
+);
+
+SHOW CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key;
+
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key;
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key_1 (
+   key1 integer,
+   key2 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   unique_key = ARRAY['unique_key1:key2,key1']
+);
+
+SHOW CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key_1;
+
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key_1;
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key (
+   key1 integer,
+   key2 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   unique_key = ARRAY['unique_key1:key1','unique_key2:key2']
+);
+
+SHOW CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key;
+
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key;
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key_1 (
+   key1 integer,
+   key2 integer,
+   key3 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   unique_key = ARRAY['unique_key1:key1','unique_key2:key3,key2']
+);
+
+SHOW CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key_1;
+
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key_1;
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key 
(
+   key1 integer NOT NULL,
+   key2 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key1'],
+   unique_key = ARRAY['unique_key1:key2']
+);
+
+SHOW CREATE TABLE 
gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key;
+
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key;
+
+CREATE TABLE 
gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key_1 (
+   key1 integer NOT NULL,
+   key2 integer,
+   key3 integer,
+   key4 integer,
+   key5 integer NOT NULL,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key5','key1'],
+   unique_key = ARRAY['unique_key1:key2','unique_key2:key4,key3']
+);
+
+SHOW CREATE TABLE 
gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key_1;
+
+DROP TABLE gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key_1;
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_invalid_primary_key (
+   key1 integer NOT NULL,
+   key2 integer,
+   key3 integer,
+   key4 integer,
+   key5 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key5','key1']
+);
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_invalid_primary_key_1 (
+   key1 integer NOT NULL,
+   key2 integer,
+   key3 integer,
+   key4 integer,
+   key5 integer,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   primary_key = ARRAY['key6','key1']
+);
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_invalid_unique_key (
+   key1 integer NOT NULL,
+   key2 integer,
+   key3 integer,
+   key4 integer,
+   key5 integer NOT NULL,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   unique_key = ARRAY['unique_key1:key7','unique_key2:key4,key3']
+);
+
+CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_invalid_unique_key (
+   key1 integer NOT NULL,
+   key2 integer,
+   key3 integer,
+   key4 integer,
+   key5 integer NOT NULL,
+   col1 integer
+)
+COMMENT ''
+WITH (
+   engine = 'InnoDB',
+   unique_key = ARRAY['unique_key1:']
+);
+
+DROP SCHEMA gt_mysql.gt_mysql_test_index;
diff --git 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.txt
 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.txt
index b7bdaf167c..5494904300 100644
--- 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.txt
+++ 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00010_show_index.txt
@@ -1,3 +1,7 @@
+CREATE SCHEMA
+
+CREATE TABLE
+
 "CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_primary_key (
    key1 integer NOT NULL,
    col1 integer
@@ -8,6 +12,10 @@ WITH (
    primary_key = ARRAY['key1']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_primary_key (
    key1 integer NOT NULL,
    key2 integer NOT NULL,
@@ -19,6 +27,10 @@ WITH (
    primary_key = ARRAY['key2','key1']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key (
    key1 integer,
    col1 integer
@@ -29,6 +41,10 @@ WITH (
    unique_key = ARRAY['unique_key1:key1']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_one_unique_key_1 (
    key1 integer,
    key2 integer,
@@ -40,6 +56,10 @@ WITH (
    unique_key = ARRAY['unique_key1:key2,key1']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key (
    key1 integer,
    key2 integer,
@@ -51,6 +71,10 @@ WITH (
    unique_key = ARRAY['unique_key1:key1','unique_key2:key2']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE gt_mysql.gt_mysql_test_index.demo_with_two_unique_key_1 (
    key1 integer,
    key2 integer,
@@ -63,6 +87,10 @@ WITH (
    unique_key = ARRAY['unique_key1:key1','unique_key2:key3,key2']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE 
gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key (
    key1 integer NOT NULL,
    key2 integer,
@@ -75,6 +103,10 @@ WITH (
    unique_key = ARRAY['unique_key1:key2']
 )"
 
+DROP TABLE
+
+CREATE TABLE
+
 "CREATE TABLE 
gt_mysql.gt_mysql_test_index.demo_with_primary_key_and_unique_key_1 (
    key1 integer NOT NULL,
    key2 integer,
@@ -89,3 +121,15 @@ WITH (
    primary_key = ARRAY['key5','key1'],
    unique_key = ARRAY['unique_key1:key2','unique_key2:key4,key3']
 )"
+
+DROP TABLE
+
+<QUERY_FAILED> Primary key must be NOT NULL in MySQL
+
+<QUERY_FAILED> Column 'key6' specified in property 'primary_key' doesn't exist 
in table
+
+<QUERY_FAILED> Column 'key7' specified in property 'unique_key' doesn't exist 
in table
+
+<QUERY_FAILED> Invalid unique key define: unique_key1:
+
+DROP SCHEMA
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorMetadata.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorMetadata.java
index 945c7ee22a..a66bd2aed6 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorMetadata.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/CatalogConnectorMetadata.java
@@ -171,7 +171,8 @@ public class CatalogConnectorMetadata {
           table.getProperties(),
           table.getPartitioning(),
           table.getDistribution(),
-          table.getSortOrders());
+          table.getSortOrders(),
+          table.getIndexes());
     } catch (NoSuchSchemaException e) {
       throw new TrinoException(
           GravitinoErrorCode.GRAVITINO_SCHEMA_NOT_EXISTS, 
SCHEMA_DOES_NOT_EXIST_MSG, e);
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLMetadataAdapter.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLMetadataAdapter.java
index f28941a23d..614600889c 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLMetadataAdapter.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLMetadataAdapter.java
@@ -18,11 +18,19 @@
  */
 package org.apache.gravitino.trino.connector.catalog.jdbc.mysql;
 
+import static io.trino.spi.StandardErrorCode.INVALID_TABLE_PROPERTY;
+import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
+import static java.lang.String.format;
 import static 
org.apache.gravitino.trino.connector.catalog.jdbc.mysql.MySQLPropertyMeta.TABLE_PRIMARY_KEY;
 import static 
org.apache.gravitino.trino.connector.catalog.jdbc.mysql.MySQLPropertyMeta.TABLE_UNIQUE_KEY;
+import static 
org.apache.gravitino.trino.connector.catalog.jdbc.mysql.MySQLPropertyMeta.getPrimaryKey;
+import static 
org.apache.gravitino.trino.connector.catalog.jdbc.mysql.MySQLPropertyMeta.getUniqueKey;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import io.trino.spi.TrinoException;
 import io.trino.spi.connector.ColumnMetadata;
 import io.trino.spi.connector.ConnectorTableMetadata;
 import io.trino.spi.connector.SchemaTableName;
@@ -32,10 +40,12 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.gravitino.catalog.property.PropertyConverter;
 import org.apache.gravitino.rel.indexes.Index;
+import org.apache.gravitino.rel.indexes.Indexes;
 import 
org.apache.gravitino.trino.connector.catalog.CatalogConnectorMetadataAdapter;
 import org.apache.gravitino.trino.connector.metadata.GravitinoColumn;
 import org.apache.gravitino.trino.connector.metadata.GravitinoTable;
@@ -80,11 +90,19 @@ public class MySQLMetadataAdapter extends 
CatalogConnectorMetadataAdapter {
     String tableName = 
tableMetadata.getTableSchema().getTable().getTableName();
     String schemaName = 
tableMetadata.getTableSchema().getTable().getSchemaName();
     String comment = tableMetadata.getComment().orElse("");
-    Map<String, String> properties = 
toGravitinoTableProperties(tableMetadata.getProperties());
+    Map<String, Object> tableProperties = tableMetadata.getProperties();
+    Map<String, String> properties = 
toGravitinoTableProperties(tableProperties);
+
+    Set<String> primaryKeyList = getPrimaryKey(tableProperties);
+    Map<String, Set<String>> uniqueKeyMap = getUniqueKey(tableProperties);
 
     List<GravitinoColumn> columns = new ArrayList<>();
+    ImmutableSet.Builder<String> columnNamesBuilder = ImmutableSet.builder();
     for (int i = 0; i < tableMetadata.getColumns().size(); i++) {
       ColumnMetadata column = tableMetadata.getColumns().get(i);
+      if (primaryKeyList.contains(column.getName()) && column.isNullable()) {
+        throw new TrinoException(NOT_SUPPORTED, "Primary key must be NOT NULL 
in MySQL");
+      }
       boolean autoIncrement =
           (boolean) 
column.getProperties().getOrDefault(MySQLPropertyMeta.AUTO_INCREMENT, false);
 
@@ -97,9 +115,63 @@ public class MySQLMetadataAdapter extends 
CatalogConnectorMetadataAdapter {
               column.isNullable(),
               autoIncrement,
               column.getProperties()));
+      columnNamesBuilder.add(column.getName());
+    }
+
+    Index[] indexes = buildIndexes(primaryKeyList, uniqueKeyMap, 
columnNamesBuilder.build());
+
+    return new GravitinoTable(schemaName, tableName, columns, comment, 
properties, indexes);
+  }
+
+  private static Index[] buildIndexes(
+      Set<String> primaryKeyList, Map<String, Set<String>> uniqueKeyMap, 
Set<String> columnNames) {
+    ImmutableList.Builder<Index> builder = ImmutableList.builder();
+    if (!primaryKeyList.isEmpty()) {
+      builder.add(convertPrimaryKey(primaryKeyList, columnNames));
+    }
+
+    if (!uniqueKeyMap.isEmpty()) {
+      builder.addAll(convertUniqueKey(uniqueKeyMap, columnNames));
+    }
+
+    List<Index> indexList = builder.build();
+    return indexList.toArray(new Index[indexList.size()]);
+  }
+
+  private static Index convertPrimaryKey(Set<String> primaryKeys, Set<String> 
columnNames) {
+    for (String primaryKeyColumn : primaryKeys) {
+      if (!columnNames.contains(primaryKeyColumn)) {
+        throw new TrinoException(
+            INVALID_TABLE_PROPERTY,
+            format(
+                "Column '%s' specified in property '%s' doesn't exist in 
table",
+                primaryKeyColumn, TABLE_PRIMARY_KEY));
+      }
+    }
+    return Indexes.createMysqlPrimaryKey(convertIndexFieldNames(primaryKeys));
+  }
+
+  private static List<Index> convertUniqueKey(
+      Map<String, Set<String>> uniqueKeys, Set<String> columnNames) {
+    ImmutableList.Builder<Index> builder = ImmutableList.builder();
+    for (String uniqueKey : uniqueKeys.keySet()) {
+      Set<String> uniqueKeyColumns = uniqueKeys.get(uniqueKey);
+      for (String uniqueKeyColumn : uniqueKeyColumns) {
+        if (!columnNames.contains(uniqueKeyColumn)) {
+          throw new TrinoException(
+              INVALID_TABLE_PROPERTY,
+              format(
+                  "Column '%s' specified in property '%s' doesn't exist in 
table",
+                  uniqueKeyColumn, TABLE_UNIQUE_KEY));
+        }
+      }
+      builder.add(Indexes.unique(uniqueKey, 
convertIndexFieldNames(uniqueKeyColumns)));
     }
+    return builder.build();
+  }
 
-    return new GravitinoTable(schemaName, tableName, columns, comment, 
properties);
+  private static String[][] convertIndexFieldNames(Set<String> fieldNames) {
+    return fieldNames.stream().map(colName -> new String[] 
{colName}).toArray(String[][]::new);
   }
 
   @Override
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLPropertyMeta.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLPropertyMeta.java
index 8682d2acd0..8ebe1dd7db 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLPropertyMeta.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLPropertyMeta.java
@@ -23,10 +23,16 @@ import static 
io.trino.spi.session.PropertyMetadata.booleanProperty;
 import static io.trino.spi.session.PropertyMetadata.stringProperty;
 import static io.trino.spi.type.VarcharType.VARCHAR;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import io.trino.jdbc.$internal.guava.collect.ImmutableMap;
 import io.trino.spi.session.PropertyMetadata;
 import io.trino.spi.type.ArrayType;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.apache.gravitino.trino.connector.catalog.HasPropertyMeta;
 
 /**
@@ -79,4 +85,49 @@ public class MySQLPropertyMeta implements HasPropertyMeta {
   public List<PropertyMetadata<?>> getColumnPropertyMetadata() {
     return COLUMN_PROPERTY_META;
   }
+
+  /**
+   * Extract primary key from table properties
+   *
+   * @param tableProperties table properties
+   * @return primary key list
+   */
+  public static Set<String> getPrimaryKey(Map<String, Object> tableProperties) 
{
+    Preconditions.checkArgument(tableProperties != null, "tableProperties is 
null");
+    ImmutableSet.Builder<String> primaryKeyBuilder = new 
ImmutableSet.Builder<>();
+
+    if (tableProperties.containsKey(TABLE_PRIMARY_KEY)) {
+      primaryKeyBuilder.addAll((List<String>) 
tableProperties.get(TABLE_PRIMARY_KEY));
+    }
+
+    return primaryKeyBuilder.build();
+  }
+
+  /**
+   * Extract unique key from table properties
+   *
+   * @param tableProperties table properties
+   * @return unique key list
+   */
+  public static Map<String, Set<String>> getUniqueKey(Map<String, Object> 
tableProperties) {
+    Preconditions.checkArgument(tableProperties != null, "tableProperties is 
null");
+    ImmutableMap.Builder<String, Set<String>> uniqueKeyMapBuilder = new 
ImmutableMap.Builder<>();
+
+    if (tableProperties.containsKey(TABLE_UNIQUE_KEY)) {
+      List<String> uniqueKeyList = (List<String>) 
tableProperties.get(TABLE_UNIQUE_KEY);
+      Splitter uniqueKeyDefSplitter = 
Splitter.on(':').trimResults().omitEmptyStrings();
+      Splitter columnSplitter = 
Splitter.on(',').trimResults().omitEmptyStrings();
+
+      for (String uniqueKeyDef : uniqueKeyList) {
+        List<String> uniqueKeyDefSplit = 
uniqueKeyDefSplitter.splitToList(uniqueKeyDef);
+        Preconditions.checkArgument(
+            uniqueKeyDefSplit.size() == 2, "Invalid unique key define: %s", 
uniqueKeyDef);
+        uniqueKeyMapBuilder.put(
+            uniqueKeyDefSplit.get(0),
+            
ImmutableSet.copyOf(columnSplitter.splitToList(uniqueKeyDefSplit.get(1))));
+      }
+    }
+
+    return uniqueKeyMapBuilder.build();
+  }
 }
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/metadata/GravitinoTable.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/metadata/GravitinoTable.java
index 9a27b2efb7..6b4869f174 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/metadata/GravitinoTable.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/metadata/GravitinoTable.java
@@ -90,11 +90,33 @@ public class GravitinoTable {
       List<GravitinoColumn> columns,
       String comment,
       Map<String, String> properties) {
+    this(schemaName, tableName, columns, comment, properties, new Index[0]);
+  }
+
+  /**
+   * Constructs a new GravitinoTable with the specified schema name, table 
name, columns, comment,
+   * properties and indexes.
+   *
+   * @param schemaName the schema name
+   * @param tableName the table name
+   * @param columns the columns
+   * @param comment the comment
+   * @param properties the properties
+   * @param indexes the indexes
+   */
+  public GravitinoTable(
+      String schemaName,
+      String tableName,
+      List<GravitinoColumn> columns,
+      String comment,
+      Map<String, String> properties,
+      Index[] indexes) {
     this.schemaName = schemaName;
     this.tableName = tableName;
     this.columns = columns;
     this.comment = comment;
     this.properties = properties;
+    this.indexes = indexes;
   }
 
   /**
diff --git 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/GravitinoMockServer.java
 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/GravitinoMockServer.java
index 172d48962c..05172dcc53 100644
--- 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/GravitinoMockServer.java
+++ 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/GravitinoMockServer.java
@@ -355,6 +355,7 @@ public class GravitinoMockServer implements AutoCloseable {
             anyMap(),
             any(),
             any(),
+            any(),
             any()))
         .thenAnswer(
             new Answer<Table>() {

Reply via email to