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

yuqi4733 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 f4836e1f93 [#5657] feat(trino-connector): Support mysql JSON type 
(#7446)
f4836e1f93 is described below

commit f4836e1f933c86e76de31c0e28376828d11404d4
Author: qbhan <[email protected]>
AuthorDate: Wed Jul 2 11:09:08 2025 +0800

    [#5657] feat(trino-connector): Support mysql JSON type (#7446)
    
    <!--
    1. Title: [#<issue>] <type>(<scope>): <subject>
       Examples:
         - "[#123] feat(operator): support xxx"
         - "[#233] fix: check null before access result in xxx"
         - "[MINOR] refactor: fix typo in variable name"
         - "[MINOR] docs: fix typo in README"
         - "[#255] test: fix flaky test NameOfTheTest"
       Reference: https://www.conventionalcommits.org/en/v1.0.0/
    2. If the PR is unfinished, please mark this PR as draft.
    -->
    
    ### What changes were proposed in this pull request?
    Support mysql JSON type with Trino.
    
    ### Why are the changes needed?
    
    Fix: #5657
    
    ### Does this PR introduce _any_ user-facing change?
    no
    
    ### How was this patch tested?
    local integration-test
---
 .../testsets/jdbc-mysql/00006_datatype.sql         | 34 ++++++++++++----------
 .../testsets/jdbc-mysql/00006_datatype.txt         | 10 ++++---
 .../jdbc/mysql/MySQLDataTypeTransformer.java       | 12 ++++++++
 .../trino/connector/util/json/JsonCodec.java       | 27 +++++++++++++++++
 .../jdbc/mysql/TestMySQLDataTypeTransformer.java   | 10 +++++++
 5 files changed, 73 insertions(+), 20 deletions(-)

diff --git 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.sql
 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.sql
index 383f7766f5..c266405130 100644
--- 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.sql
+++ 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.sql
@@ -18,17 +18,18 @@ CREATE TABLE tb01 (
     f13 DATE,
     f14 TIME,
     f15 TIMESTAMP,
-    f16 TIMESTAMP WITH TIME ZONE
+    f16 TIMESTAMP WITH TIME ZONE,
+    f17 JSON
 );
 
 SHOW CREATE TABLE tb01;
 
-INSERT INTO tb01 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
+INSERT INTO tb01 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
 VALUES ('Sample text 1', 'Text1', x'65', 123.456, 7.89, 12.34, FALSE, 1, 100, 
1000, 1000, 100000, DATE '2024-01-01',
-        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC');
+        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC', JSON '{"x" : 300, "y" : "AFRICA", "z" : null}');
 
-INSERT INTO tb01 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
-VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
NULL, NULL, NULL, NULl, NULl);
+INSERT INTO tb01 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
+VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
NULL, NULL, NULL, NULl, NULl, NULL);
 
 select * from tb01 order by f1;
 
@@ -48,29 +49,30 @@ CREATE TABLE tb02 (
     f13 DATE NOT NULL ,
     f14 TIME NOT NULL ,
     f15 TIMESTAMP NOT NULL,
-    f16 TIMESTAMP WITH TIME ZONE NOT NULL
+    f16 TIMESTAMP WITH TIME ZONE NOT NULL,
+    f17 JSON NOT NULL
 );
 
 show create table tb02;
 
-INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
+INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
 VALUES ('Sample text 1', 'Text1', x'65', 123.456, 7.89, 12.34, FALSE, 1, 100, 
1000, 1000, 100000, DATE '2024-01-01',
-        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC');
+        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC', JSON '{"x" : 300, "y" : "AFRICA", "z" : null}');
 
-INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
-VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
NULL, NULL, NULL, NULL, NULL);
+INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
+VALUES (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
NULL, NULL, NULL, NULL, NULL, NULL);
 
-INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
+INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
 VALUES ('Sample text 1', NULL, x'65', 123.456, 7.89, 12.34, FALSE, 1, 100, 
1000, 1000, 100000, DATE '2024-01-01',
-        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC');
+        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC', JSON '{"x" : 300, "y" : "AFRICA", "z" : null}');
 
-INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
+INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
 VALUES ('Sample text 1', 'same3', x'65', 123.456, 7.89, 12.34, FALSE, 1, 100, 
1000, 1000, NULl, DATE '2024-01-01',
-        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC');
+        TIME '08:00:00', TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP 
'2024-01-01 08:00:00 UTC', JSON '{"x" : 300, "y" : "AFRICA", "z" : null}');
 
-INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16)
+INSERT INTO tb02 (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, 
f15, f16, f17)
 VALUES ('Sample text 1', 'same9', x'65', 123.456, 7.89, 12.34, FALSE, 1, 100, 
1000, 1000, 1992382342, DATE '2024-01-01',
-        NULL, TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP '2024-01-01 08:00:00 
UTC');
+        NULL, TIMESTAMP '2024-01-01 08:00:00', TIMESTAMP '2024-01-01 08:00:00 
UTC', JSON '{}');
 
 drop table tb01;
 
diff --git 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.txt
 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.txt
index 91267178cf..b7658af842 100644
--- 
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.txt
+++ 
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-mysql/00006_datatype.txt
@@ -20,7 +20,8 @@ CREATE TABLE
    f13 date,
    f14 time(0),
    f15 timestamp(0),
-   f16 timestamp(0) with time zone
+   f16 timestamp(0) with time zone,
+   f17 json
 )
 COMMENT ''
 WITH (
@@ -31,8 +32,8 @@ INSERT: 1 row
 
 INSERT: 1 row
 
-"Sample text 1","Text1               
","65","123.456","7.89","12.34","false","1","100","1000","1000","100000","2024-01-01","08:00:00","2024-01-01
 08:00:00","2024-01-01 08:00:00 UTC"
-"","","","","","","","","","","","","","","",""
+"Sample text 1","Text1               
","65","123.456","7.89","12.34","false","1","100","1000","1000","100000","2024-01-01","08:00:00","2024-01-01
 08:00:00","2024-01-01 08:00:00 UTC","{""x"":300,""y"":""AFRICA"",""z"":null}"
+"","","","","","","","","","","","","","","","",""
 
 CREATE TABLE
 
@@ -52,7 +53,8 @@ CREATE TABLE
    f13 date NOT NULL,
    f14 time(0) NOT NULL,
    f15 timestamp(0) NOT NULL,
-   f16 timestamp(0) with time zone NOT NULL
+   f16 timestamp(0) with time zone NOT NULL,
+   f17 json NOT NULL
 )
 COMMENT ''
 WITH (
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLDataTypeTransformer.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLDataTypeTransformer.java
index f926467cfb..089311e6a4 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLDataTypeTransformer.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/MySQLDataTypeTransformer.java
@@ -21,6 +21,7 @@ package 
org.apache.gravitino.trino.connector.catalog.jdbc.mysql;
 
 import io.trino.spi.TrinoException;
 import io.trino.spi.type.CharType;
+import io.trino.spi.type.StandardTypes;
 import io.trino.spi.type.TimeType;
 import io.trino.spi.type.TimestampType;
 import io.trino.spi.type.TimestampWithTimeZoneType;
@@ -29,6 +30,7 @@ import org.apache.gravitino.rel.types.Type.Name;
 import org.apache.gravitino.rel.types.Types;
 import org.apache.gravitino.trino.connector.GravitinoErrorCode;
 import org.apache.gravitino.trino.connector.util.GeneralDataTypeTransformer;
+import org.apache.gravitino.trino.connector.util.json.JsonCodec;
 
 /** Type transformer between MySQL and Trino */
 public class MySQLDataTypeTransformer extends GeneralDataTypeTransformer {
@@ -39,6 +41,9 @@ public class MySQLDataTypeTransformer extends 
GeneralDataTypeTransformer {
   // https://dev.mysql.com/doc/refman/8.0/en/char.html
   private static final int MYSQL_VARCHAR_LENGTH_LIMIT = 16383;
 
+  public static final io.trino.spi.type.Type JSON_TYPE =
+      JsonCodec.getJsonType(MySQLDataTypeTransformer.class.getClassLoader());
+
   @Override
   public io.trino.spi.type.Type getTrinoType(Type type) {
     if (type.name() == Name.STRING) {
@@ -52,6 +57,11 @@ public class MySQLDataTypeTransformer extends 
GeneralDataTypeTransformer {
       }
     } else if (Name.TIME == type.name()) {
       return TimeType.TIME_SECONDS;
+    } else if (Name.EXTERNAL == type.name()) {
+      String catalogString = ((Types.ExternalType) type).catalogString();
+      if (StandardTypes.JSON.equalsIgnoreCase(catalogString)) {
+        return JSON_TYPE;
+      }
     }
 
     return super.getTrinoType(type);
@@ -94,6 +104,8 @@ public class MySQLDataTypeTransformer extends 
GeneralDataTypeTransformer {
                 + MYSQL_VARCHAR_LENGTH_LIMIT);
       }
       return Types.VarCharType.of(length);
+    } else if (typeClass == JSON_TYPE.getClass()) {
+      return Types.ExternalType.of(StandardTypes.JSON);
     }
 
     return super.getGravitinoType(type);
diff --git 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/json/JsonCodec.java
 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/json/JsonCodec.java
index edf0f69ebf..4f0f21c3b4 100644
--- 
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/json/JsonCodec.java
+++ 
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/json/JsonCodec.java
@@ -39,6 +39,7 @@ import io.trino.spi.connector.ConnectorInsertTableHandle;
 import io.trino.spi.connector.ConnectorSplit;
 import io.trino.spi.connector.ConnectorTableHandle;
 import io.trino.spi.connector.ConnectorTransactionHandle;
+import io.trino.spi.type.StandardTypes;
 import io.trino.spi.type.Type;
 import io.trino.spi.type.TypeManager;
 import io.trino.spi.type.TypeSignature;
@@ -52,6 +53,7 @@ import 
org.apache.gravitino.trino.connector.GravitinoConnectorPluginManager;
  */
 public class JsonCodec {
   private static ObjectMapper mapper;
+  private static Type jsonType;
 
   private static ObjectMapper buildMapper(ClassLoader classLoader) {
     try {
@@ -64,6 +66,17 @@ public class JsonCodec {
     }
   }
 
+  private static Type buildJsonType(ClassLoader classLoader) {
+    try {
+      ClassLoader appClassLoader =
+          
GravitinoConnectorPluginManager.instance(classLoader).getAppClassloader();
+      TypeManager typeManager = createTypeManager(appClassLoader);
+      return typeManager.getType(new TypeSignature(StandardTypes.JSON));
+    } catch (Exception e) {
+      throw new TrinoException(GRAVITINO_RUNTIME_ERROR, "Failed to build 
JsonType", e);
+    }
+  }
+
   static TypeManager createTypeManager(ClassLoader classLoader) {
     try {
       Class internalTypeManagerClass = 
classLoader.loadClass("io.trino.type.InternalTypeManager");
@@ -220,4 +233,18 @@ public class JsonCodec {
       return mapper;
     }
   }
+
+  public static Type getJsonType(ClassLoader classLoader) {
+    if (jsonType != null) {
+      return jsonType;
+    }
+
+    synchronized (JsonCodec.class) {
+      if (jsonType != null) {
+        return jsonType;
+      }
+      jsonType = buildJsonType(classLoader);
+      return jsonType;
+    }
+  }
 }
diff --git 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/TestMySQLDataTypeTransformer.java
 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/TestMySQLDataTypeTransformer.java
index b5203e831f..7e2048a028 100644
--- 
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/TestMySQLDataTypeTransformer.java
+++ 
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/catalog/jdbc/mysql/TestMySQLDataTypeTransformer.java
@@ -19,6 +19,8 @@
 
 package org.apache.gravitino.trino.connector.catalog.jdbc.mysql;
 
+import static 
org.apache.gravitino.trino.connector.catalog.jdbc.mysql.MySQLDataTypeTransformer.JSON_TYPE;
+
 import io.trino.spi.TrinoException;
 import org.apache.gravitino.rel.types.Type;
 import org.apache.gravitino.rel.types.Types;
@@ -100,4 +102,12 @@ public class TestMySQLDataTypeTransformer {
         generalDataTypeTransformer.getTrinoType(unsignBigintType),
         io.trino.spi.type.DecimalType.createDecimalType(20, 0));
   }
+
+  @Test
+  public void testGravitinoExternalJsonTypeToTrinoType() {
+    GeneralDataTypeTransformer generalDataTypeTransformer = new 
MySQLDataTypeTransformer();
+
+    Type jsonType = Types.ExternalType.of("json");
+    Assertions.assertEquals(generalDataTypeTransformer.getTrinoType(jsonType), 
JSON_TYPE);
+  }
 }

Reply via email to