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 a4023593e0 [#8215] connector(trino/flink): Support for reading/writing
time precision (#8216)
a4023593e0 is described below
commit a4023593e07c1d7c2591e5b23a7cefdb20fd4355
Author: predator4ann <[email protected]>
AuthorDate: Fri Sep 5 20:41:51 2025 +0800
[#8215] connector(trino/flink): Support for reading/writing time precision
(#8216)
### Why are the changes needed?
Fix: #8215
### Does this PR introduce _any_ user-facing change?
No
### How was this patch tested?
UT already added.
---------
Signed-off-by: zacsun <[email protected]>
---
.../gravitino/flink/connector/utils/TypeUtils.java | 53 +++++++++++--
.../flink/connector/utils/TestTypeUtils.java | 90 ++++++++++++++++++++--
.../testsets/jdbc-postgresql/00006_datatype.txt | 14 ++--
.../catalog/hive/HiveDataTypeTransformer.java | 17 ++++
.../iceberg/IcebergDataTypeTransformer.java | 9 +++
.../jdbc/mysql/MySQLDataTypeTransformer.java | 9 +++
.../postgresql/PostgreSQLDataTypeTransformer.java | 40 ++++++++--
.../connector/util/GeneralDataTypeTransformer.java | 47 +++++++++--
.../connector/util/TestDataTypeTransformer.java | 6 +-
9 files changed, 249 insertions(+), 36 deletions(-)
diff --git
a/flink-connector/flink/src/main/java/org/apache/gravitino/flink/connector/utils/TypeUtils.java
b/flink-connector/flink/src/main/java/org/apache/gravitino/flink/connector/utils/TypeUtils.java
index 8766bea836..3ce11846d7 100644
---
a/flink-connector/flink/src/main/java/org/apache/gravitino/flink/connector/utils/TypeUtils.java
+++
b/flink-connector/flink/src/main/java/org/apache/gravitino/flink/connector/utils/TypeUtils.java
@@ -36,6 +36,13 @@ import org.apache.gravitino.rel.types.Types;
public class TypeUtils {
+ // Flink supports time/timestamp precision from 0 to 9 (nanosecond
precision).
+ // @see
+ //
https://nightlies.apache.org/flink/flink-docs-release-2.1/docs/dev/table/types/#date-and-time
+ protected static final int FLINK_SECONDS_PRECISION = 0;
+ protected static final int FLINK_MICROS_PRECISION = 6;
+ protected static final int FLINK_NANOS_PRECISION = 9;
+
private TypeUtils() {}
public static Type toGravitinoType(LogicalType logicalType) {
@@ -68,9 +75,15 @@ public class TypeUtils {
case DATE:
return Types.DateType.get();
case TIME_WITHOUT_TIME_ZONE:
- return Types.TimeType.get();
+ org.apache.flink.table.types.logical.TimeType timeType =
+ (org.apache.flink.table.types.logical.TimeType) logicalType;
+ int timePrecision = timeType.getPrecision();
+ return Types.TimeType.of(timePrecision);
case TIMESTAMP_WITHOUT_TIME_ZONE:
- return Types.TimestampType.withoutTimeZone();
+ org.apache.flink.table.types.logical.TimestampType timestampType =
+ (org.apache.flink.table.types.logical.TimestampType) logicalType;
+ int timestampPrecision = timestampType.getPrecision();
+ return Types.TimestampType.withoutTimeZone(timestampPrecision);
case INTERVAL_YEAR_MONTH:
return Types.IntervalYearType.get();
case INTERVAL_DAY_TIME:
@@ -78,8 +91,15 @@ public class TypeUtils {
case FLOAT:
return Types.FloatType.get();
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ org.apache.flink.table.types.logical.LocalZonedTimestampType
localZonedTimestampType =
+ (org.apache.flink.table.types.logical.LocalZonedTimestampType)
logicalType;
+ int localZonedPrecision = localZonedTimestampType.getPrecision();
+ return Types.TimestampType.withTimeZone(localZonedPrecision);
case TIMESTAMP_WITH_TIME_ZONE:
- return Types.TimestampType.withTimeZone();
+ org.apache.flink.table.types.logical.ZonedTimestampType
zonedTimestampType =
+ (org.apache.flink.table.types.logical.ZonedTimestampType)
logicalType;
+ int zonedPrecision = zonedTimestampType.getPrecision();
+ return Types.TimestampType.withTimeZone(zonedPrecision);
case ARRAY:
ArrayType arrayType = (ArrayType) logicalType;
Type elementType = toGravitinoType(arrayType.getElementType());
@@ -155,10 +175,20 @@ public class TypeUtils {
return DataTypes.DATE();
case TIMESTAMP:
Types.TimestampType timestampType = (Types.TimestampType)
gravitinoType;
+ int precision = FLINK_MICROS_PRECISION;
+ if (timestampType.hasPrecisionSet()) {
+ precision = timestampType.precision();
+ if (precision < FLINK_SECONDS_PRECISION || precision >
FLINK_NANOS_PRECISION) {
+ throw new UnsupportedOperationException(
+ "Unsupported timestamp precision for Flink: "
+ + precision
+ + ". Flink supports precision from 0 to 9.");
+ }
+ }
if (timestampType.hasTimeZone()) {
- return DataTypes.TIMESTAMP_LTZ();
+ return DataTypes.TIMESTAMP_LTZ(precision);
} else {
- return DataTypes.TIMESTAMP();
+ return DataTypes.TIMESTAMP(precision);
}
case LIST:
Types.ListType listType = (Types.ListType) gravitinoType;
@@ -188,7 +218,18 @@ public class TypeUtils {
case NULL:
return DataTypes.NULL();
case TIME:
- return DataTypes.TIME();
+ Types.TimeType timeType = (Types.TimeType) gravitinoType;
+ int timePrecision = FLINK_SECONDS_PRECISION;
+ if (timeType.hasPrecisionSet()) {
+ timePrecision = timeType.precision();
+ if (timePrecision < FLINK_SECONDS_PRECISION || timePrecision >
FLINK_NANOS_PRECISION) {
+ throw new UnsupportedOperationException(
+ "Unsupported time precision for Flink: "
+ + timePrecision
+ + ". Flink supports precision from 0 to 9.");
+ }
+ }
+ return DataTypes.TIME(timePrecision);
case INTERVAL_YEAR:
return DataTypes.INTERVAL(DataTypes.YEAR());
case INTERVAL_DAY:
diff --git
a/flink-connector/flink/src/test/java/org/apache/gravitino/flink/connector/utils/TestTypeUtils.java
b/flink-connector/flink/src/test/java/org/apache/gravitino/flink/connector/utils/TestTypeUtils.java
index 8a9297cb51..438e5fbe37 100644
---
a/flink-connector/flink/src/test/java/org/apache/gravitino/flink/connector/utils/TestTypeUtils.java
+++
b/flink-connector/flink/src/test/java/org/apache/gravitino/flink/connector/utils/TestTypeUtils.java
@@ -69,13 +69,13 @@ public class TestTypeUtils {
Assertions.assertEquals(Types.ByteType.get(),
TypeUtils.toGravitinoType(new TinyIntType()));
Assertions.assertEquals(Types.ShortType.get(),
TypeUtils.toGravitinoType(new SmallIntType()));
Assertions.assertEquals(
- Types.TimestampType.withoutTimeZone(), TypeUtils.toGravitinoType(new
TimestampType()));
+ Types.TimestampType.withoutTimeZone(6), TypeUtils.toGravitinoType(new
TimestampType()));
Assertions.assertEquals(
- Types.TimestampType.withTimeZone(), TypeUtils.toGravitinoType(new
ZonedTimestampType()));
+ Types.TimestampType.withTimeZone(6), TypeUtils.toGravitinoType(new
ZonedTimestampType()));
Assertions.assertEquals(
- Types.TimestampType.withTimeZone(),
+ Types.TimestampType.withTimeZone(6),
TypeUtils.toGravitinoType(new LocalZonedTimestampType()));
- Assertions.assertEquals(Types.TimeType.get(),
TypeUtils.toGravitinoType(new TimeType()));
+ Assertions.assertEquals(Types.TimeType.of(0),
TypeUtils.toGravitinoType(new TimeType()));
Assertions.assertEquals(
Types.IntervalDayType.get(),
TypeUtils.toGravitinoType(
@@ -132,11 +132,10 @@ public class TestTypeUtils {
Assertions.assertEquals(DataTypes.BYTES(),
TypeUtils.toFlinkType(Types.BinaryType.get()));
Assertions.assertEquals(DataTypes.BINARY(10),
TypeUtils.toFlinkType(Types.FixedType.of(10)));
Assertions.assertEquals(
- DataTypes.TIMESTAMP(6),
TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone()));
+ DataTypes.TIMESTAMP(6),
TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone(6)));
Assertions.assertEquals(
- DataTypes.TIMESTAMP_WITH_LOCAL_TIME_ZONE(6),
- TypeUtils.toFlinkType(Types.TimestampType.withTimeZone()));
- Assertions.assertEquals(DataTypes.TIME(),
TypeUtils.toFlinkType(Types.TimeType.get()));
+ DataTypes.TIMESTAMP_LTZ(6),
TypeUtils.toFlinkType(Types.TimestampType.withTimeZone(6)));
+ Assertions.assertEquals(DataTypes.TIME(0),
TypeUtils.toFlinkType(Types.TimeType.of(0)));
Assertions.assertEquals(
DataTypes.INTERVAL(DataTypes.DAY()),
TypeUtils.toFlinkType(Types.IntervalDayType.get()));
Assertions.assertEquals(
@@ -164,4 +163,79 @@ public class TestTypeUtils {
UnsupportedOperationException.class,
() -> TypeUtils.toFlinkType(Types.UnparsedType.of("unknown")));
}
+
+ @Test
+ public void testTimePrecisionConversion() {
+ // TIME
+ Assertions.assertEquals(Types.TimeType.of(0),
TypeUtils.toGravitinoType(new TimeType(0)));
+ Assertions.assertEquals(Types.TimeType.of(3),
TypeUtils.toGravitinoType(new TimeType(3)));
+ Assertions.assertEquals(Types.TimeType.of(6),
TypeUtils.toGravitinoType(new TimeType(6)));
+ Assertions.assertEquals(Types.TimeType.of(9),
TypeUtils.toGravitinoType(new TimeType(9)));
+
+ // Test converting back
+ Assertions.assertEquals(DataTypes.TIME(0),
TypeUtils.toFlinkType(Types.TimeType.of(0)));
+ Assertions.assertEquals(DataTypes.TIME(3),
TypeUtils.toFlinkType(Types.TimeType.of(3)));
+ Assertions.assertEquals(DataTypes.TIME(6),
TypeUtils.toFlinkType(Types.TimeType.of(6)));
+ Assertions.assertEquals(DataTypes.TIME(9),
TypeUtils.toFlinkType(Types.TimeType.of(9)));
+ }
+
+ @Test
+ public void testTimestampPrecisionConversion() {
+ // TIMESTAMP without timezone
+ Assertions.assertEquals(
+ Types.TimestampType.withoutTimeZone(0), TypeUtils.toGravitinoType(new
TimestampType(0)));
+ Assertions.assertEquals(
+ Types.TimestampType.withoutTimeZone(3), TypeUtils.toGravitinoType(new
TimestampType(3)));
+ Assertions.assertEquals(
+ Types.TimestampType.withoutTimeZone(6), TypeUtils.toGravitinoType(new
TimestampType(6)));
+ Assertions.assertEquals(
+ Types.TimestampType.withoutTimeZone(9), TypeUtils.toGravitinoType(new
TimestampType(9)));
+
+ // TIMESTAMP with timezone (LocalZoned)
+ Assertions.assertEquals(
+ Types.TimestampType.withTimeZone(0),
+ TypeUtils.toGravitinoType(new LocalZonedTimestampType(0)));
+ Assertions.assertEquals(
+ Types.TimestampType.withTimeZone(3),
+ TypeUtils.toGravitinoType(new LocalZonedTimestampType(3)));
+ Assertions.assertEquals(
+ Types.TimestampType.withTimeZone(6),
+ TypeUtils.toGravitinoType(new LocalZonedTimestampType(6)));
+ Assertions.assertEquals(
+ Types.TimestampType.withTimeZone(9),
+ TypeUtils.toGravitinoType(new LocalZonedTimestampType(9)));
+
+ // Test converting back
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP(0),
TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone(0)));
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP(3),
TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone(3)));
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP(6),
TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone(6)));
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP(9),
TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone(9)));
+
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP_LTZ(0),
TypeUtils.toFlinkType(Types.TimestampType.withTimeZone(0)));
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP_LTZ(3),
TypeUtils.toFlinkType(Types.TimestampType.withTimeZone(3)));
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP_LTZ(6),
TypeUtils.toFlinkType(Types.TimestampType.withTimeZone(6)));
+ Assertions.assertEquals(
+ DataTypes.TIMESTAMP_LTZ(9),
TypeUtils.toFlinkType(Types.TimestampType.withTimeZone(9)));
+ }
+
+ @Test
+ public void testInvalidPrecisionHandling() {
+ Assertions.assertThrows(
+ UnsupportedOperationException.class, () ->
TypeUtils.toFlinkType(Types.TimeType.of(10)));
+
+ Assertions.assertThrows(
+ UnsupportedOperationException.class,
+ () -> TypeUtils.toFlinkType(Types.TimestampType.withoutTimeZone(10)));
+
+ Assertions.assertThrows(
+ UnsupportedOperationException.class,
+ () -> TypeUtils.toFlinkType(Types.TimestampType.withTimeZone(10)));
+ }
}
diff --git
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-postgresql/00006_datatype.txt
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-postgresql/00006_datatype.txt
index 36c36db470..e37cbee1a5 100644
---
a/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-postgresql/00006_datatype.txt
+++
b/trino-connector/integration-test/src/test/resources/trino-ci-testset/testsets/jdbc-postgresql/00006_datatype.txt
@@ -17,9 +17,9 @@ CREATE TABLE
f11 integer,
f12 bigint,
f13 date,
- f14 time(6),
- f15 timestamp(6),
- f16 timestamp(6) with time zone
+ f14 time(3),
+ f15 timestamp(3),
+ f16 timestamp(3) with time zone
)
COMMENT ''"
@@ -27,7 +27,7 @@ INSERT: 1 row
INSERT: 1 row
-"Sample text 1","Text1
","65","123.456","7.89","12.34","false","100","1000","1000","100000","2024-01-01","08:00:00.000000","2024-01-01
08:00:00.000000","2024-01-01 08:00:00.000000 UTC"
+"Sample text 1","Text1
","65","123.456","7.89","12.34","false","100","1000","1000","100000","2024-01-01","08:00:00.000","2024-01-01
08:00:00.000","2024-01-01 08:00:00.000 UTC"
"","","","","","","","","","","","","","",""
CREATE TABLE
@@ -45,9 +45,9 @@ CREATE TABLE
f11 integer NOT NULL,
f12 bigint NOT NULL,
f13 date NOT NULL,
- f14 time(6) NOT NULL,
- f15 timestamp(6) NOT NULL,
- f16 timestamp(6) with time zone NOT NULL
+ f14 time(3) NOT NULL,
+ f15 timestamp(3) NOT NULL,
+ f16 timestamp(3) with time zone NOT NULL
)
COMMENT ''"
diff --git
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/hive/HiveDataTypeTransformer.java
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/hive/HiveDataTypeTransformer.java
index f047f61d5e..a01d3fe3ac 100644
---
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/hive/HiveDataTypeTransformer.java
+++
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/hive/HiveDataTypeTransformer.java
@@ -20,6 +20,7 @@
package org.apache.gravitino.trino.connector.catalog.hive;
import io.trino.spi.TrinoException;
+import io.trino.spi.type.TimestampType;
import io.trino.spi.type.VarcharType;
import org.apache.gravitino.rel.types.Type;
import org.apache.gravitino.rel.types.Types;
@@ -39,6 +40,8 @@ public class HiveDataTypeTransformer extends
GeneralDataTypeTransformer {
throw new TrinoException(
GravitinoErrorCode.GRAVITINO_UNSUPPORTED_GRAVITINO_DATATYPE,
"Unsupported gravitino datatype: " + type);
+ } else if (Type.Name.TIMESTAMP == type.name()) {
+ return TimestampType.TIMESTAMP_MILLIS;
}
return super.getTrinoType(type);
}
@@ -72,6 +75,20 @@ public class HiveDataTypeTransformer extends
GeneralDataTypeTransformer {
}
return Types.FixedCharType.of(charType.getLength());
+ } else if
(io.trino.spi.type.TimestampType.class.isAssignableFrom(typeClass)) {
+ // When creating a table in Hive, the timestamp data type only supports
timestamp and
+ // timestamp(3)
+ // with the precision being 3 (milliseconds precision)
+ io.trino.spi.type.TimestampType timestampType =
(io.trino.spi.type.TimestampType) type;
+ int precision = timestampType.getPrecision();
+ if (precision != TRINO_MILLIS_PRECISION) {
+ throw new TrinoException(
+ GravitinoErrorCode.GRAVITINO_ILLEGAL_ARGUMENT,
+ "Incorrect timestamp precision for timestamp("
+ + precision
+ + "), the configured precision is MILLISECONDS;");
+ }
+ return Types.TimestampType.withoutTimeZone();
}
return super.getGravitinoType(type);
diff --git
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/iceberg/IcebergDataTypeTransformer.java
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/iceberg/IcebergDataTypeTransformer.java
index 2c4fa12f8f..042a61f3a1 100644
---
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/iceberg/IcebergDataTypeTransformer.java
+++
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/iceberg/IcebergDataTypeTransformer.java
@@ -49,6 +49,15 @@ public class IcebergDataTypeTransformer extends
GeneralDataTypeTransformer {
"Iceberg does not support the datatype VARCHAR with length");
}
return Types.StringType.get();
+ } else if (io.trino.spi.type.TimeType.class.isAssignableFrom(typeClass)) {
+ // Iceberg only supports time type with microsecond (6) precision
+ return Types.TimeType.of(TRINO_MICROS_PRECISION);
+ } else if
(io.trino.spi.type.TimestampType.class.isAssignableFrom(typeClass)) {
+ // Iceberg only supports timestamp type (without time zone) with
microsecond (6) precision
+ return Types.TimestampType.withoutTimeZone(TRINO_MICROS_PRECISION);
+ } else if
(io.trino.spi.type.TimestampWithTimeZoneType.class.isAssignableFrom(typeClass))
{
+ // Iceberg only supports timestamp with time zone type with microsecond
(6) precision
+ return Types.TimestampType.withTimeZone(TRINO_MICROS_PRECISION);
}
return super.getGravitinoType(type);
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 920793d2e9..b6ecf8696d 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
@@ -103,6 +103,15 @@ public class MySQLDataTypeTransformer extends
GeneralDataTypeTransformer {
return Types.VarCharType.of(length);
} else if (typeClass == JSON_TYPE.getClass()) {
return
Types.ExternalType.of(MySQLExternalDataType.JSON.getMysqlTypeName());
+ } else if (io.trino.spi.type.TimeType.class.isAssignableFrom(typeClass)) {
+ // MySQL only supports time type with second (0) precision
+ return Types.TimeType.of(TRINO_SECONDS_PRECISION);
+ } else if
(io.trino.spi.type.TimestampType.class.isAssignableFrom(typeClass)) {
+ // MySQL only supports timestamp type (without time zone) with second
(0) precision
+ return Types.TimestampType.withoutTimeZone(TRINO_SECONDS_PRECISION);
+ } else if
(io.trino.spi.type.TimestampWithTimeZoneType.class.isAssignableFrom(typeClass))
{
+ // MySQL only supports timestamp with time zone type with second (0)
precision
+ return Types.TimestampType.withTimeZone(TRINO_SECONDS_PRECISION);
}
return super.getGravitinoType(type);
diff --git
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/postgresql/PostgreSQLDataTypeTransformer.java
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/postgresql/PostgreSQLDataTypeTransformer.java
index 0134fbacc8..cd04413e32 100644
---
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/postgresql/PostgreSQLDataTypeTransformer.java
+++
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/catalog/jdbc/postgresql/PostgreSQLDataTypeTransformer.java
@@ -45,13 +45,43 @@ public class PostgreSQLDataTypeTransformer extends
GeneralDataTypeTransformer {
return io.trino.spi.type.VarcharType.createUnboundedVarcharType();
} else if (Name.TIMESTAMP == type.name()) {
Types.TimestampType timestampType = (Types.TimestampType) type;
- if (timestampType.hasTimeZone()) {
- return TimestampWithTimeZoneType.TIMESTAMP_TZ_MICROS;
- } else {
- return TimestampType.TIMESTAMP_MICROS;
+ boolean hasTimeZone = timestampType.hasTimeZone();
+ if (timestampType.hasPrecisionSet()) {
+ int precision = timestampType.precision();
+ if (precision >= TRINO_SECONDS_PRECISION && precision <=
TRINO_PICOS_PRECISION) {
+ // Exceeding precision will be reduced to the maximum allowed
precision of 6 (microseconds
+ // precision)
+ precision = Math.min(TRINO_MICROS_PRECISION, precision);
+ return hasTimeZone
+ ?
TimestampWithTimeZoneType.createTimestampWithTimeZoneType(precision)
+ : TimestampType.createTimestampType(precision);
+ } else {
+ throw new TrinoException(
+ GravitinoErrorCode.GRAVITINO_UNSUPPORTED_GRAVITINO_DATATYPE,
+ "Unsupported timestamp precision for PostgreSQL: " + precision);
+ }
}
+ // When precision is not set, the default precision is 3 (milliseconds
precision)
+ return hasTimeZone
+ ? TimestampWithTimeZoneType.TIMESTAMP_TZ_MILLIS
+ : TimestampType.TIMESTAMP_MILLIS;
} else if (Name.TIME == type.name()) {
- return TimeType.TIME_MICROS;
+ Types.TimeType timeType = (Types.TimeType) type;
+ if (timeType.hasPrecisionSet()) {
+ int precision = timeType.precision();
+ if (precision >= TRINO_SECONDS_PRECISION && precision <=
TRINO_PICOS_PRECISION) {
+ // Exceeding precision will be reduced to the maximum allowed
precision of 6 (microseconds
+ // precision)
+ precision = Math.min(TRINO_MICROS_PRECISION, precision);
+ return TimeType.createTimeType(precision);
+ } else {
+ throw new TrinoException(
+ GravitinoErrorCode.GRAVITINO_UNSUPPORTED_GRAVITINO_DATATYPE,
+ "Unsupported time precision for PostgreSQL: " + precision);
+ }
+ }
+ // When precision is not set, the default precision is 3 (milliseconds
precision)
+ return TimeType.TIME_MILLIS;
}
return super.getTrinoType(type);
diff --git
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/GeneralDataTypeTransformer.java
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/GeneralDataTypeTransformer.java
index 4c972dd917..90c5222512 100644
---
a/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/GeneralDataTypeTransformer.java
+++
b/trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/util/GeneralDataTypeTransformer.java
@@ -55,6 +55,14 @@ import
org.apache.gravitino.trino.connector.GravitinoErrorCode;
/** This class is used to transform datatype between Apache Gravitino and
Trino */
public class GeneralDataTypeTransformer {
+ // Trino supports time/timestamp precision from 0 to 12 (picoseconds
precision).
+ // @see
+ // https://trino.io/docs/current/language/types.html#date-and-time
+ protected static final int TRINO_SECONDS_PRECISION = 0;
+ protected static final int TRINO_MILLIS_PRECISION = 3;
+ protected static final int TRINO_MICROS_PRECISION = 6;
+ protected static final int TRINO_PICOS_PRECISION = 12;
+
/**
* Transforms a Gravitino datatype to a Trino datatype.
*
@@ -108,13 +116,38 @@ public class GeneralDataTypeTransformer {
case DATE:
return DATE;
case TIME:
+ Types.TimeType timeType = (Types.TimeType) type;
+ if (timeType.hasPrecisionSet()) {
+ int precision = timeType.precision();
+ if (precision >= TRINO_SECONDS_PRECISION && precision <=
TRINO_PICOS_PRECISION) {
+ return TimeType.createTimeType(precision);
+ } else {
+ throw new TrinoException(
+ GravitinoErrorCode.GRAVITINO_UNSUPPORTED_GRAVITINO_DATATYPE,
+ "Unsupported time precision for Trino: " + precision);
+ }
+ }
+ // default millis (precision 3) to match Trino default precision
return TimeType.TIME_MILLIS;
case TIMESTAMP:
- if (((Types.TimestampType) type).hasTimeZone()) {
- return TimestampWithTimeZoneType.TIMESTAMP_TZ_MILLIS;
- } else {
- return TimestampType.TIMESTAMP_MILLIS;
+ Types.TimestampType timestampType = (Types.TimestampType) type;
+ boolean hasTimeZone = timestampType.hasTimeZone();
+ if (timestampType.hasPrecisionSet()) {
+ int precision = timestampType.precision();
+ if (precision >= TRINO_SECONDS_PRECISION && precision <=
TRINO_PICOS_PRECISION) {
+ return hasTimeZone
+ ?
TimestampWithTimeZoneType.createTimestampWithTimeZoneType(precision)
+ : TimestampType.createTimestampType(precision);
+ } else {
+ throw new TrinoException(
+ GravitinoErrorCode.GRAVITINO_UNSUPPORTED_GRAVITINO_DATATYPE,
+ "Unsupported timestamp precision for Trino: " + precision);
+ }
}
+ // default millis (precision 3) to match Trino default precision
+ return hasTimeZone
+ ? TimestampWithTimeZoneType.TIMESTAMP_TZ_MILLIS
+ : TimestampType.TIMESTAMP_MILLIS;
case LIST:
return new ArrayType(getTrinoType(((Types.ListType)
type).elementType()));
case MAP:
@@ -191,11 +224,11 @@ public class GeneralDataTypeTransformer {
} else if (typeClass == io.trino.spi.type.DateType.class) {
return Types.DateType.get();
} else if (io.trino.spi.type.TimeType.class.isAssignableFrom(typeClass)) {
- return Types.TimeType.get();
+ return Types.TimeType.of(((TimeType) type).getPrecision());
} else if
(io.trino.spi.type.TimestampType.class.isAssignableFrom(typeClass)) {
- return Types.TimestampType.withoutTimeZone();
+ return Types.TimestampType.withoutTimeZone(((TimestampType)
type).getPrecision());
} else if
(io.trino.spi.type.TimestampWithTimeZoneType.class.isAssignableFrom(typeClass))
{
- return Types.TimestampType.withTimeZone();
+ return Types.TimestampType.withTimeZone(((TimestampWithTimeZoneType)
type).getPrecision());
} else if (typeClass == io.trino.spi.type.ArrayType.class) {
// Ignore nullability for the type, we could only get nullability from
column metadata
return Types.ListType.of(
diff --git
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/util/TestDataTypeTransformer.java
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/util/TestDataTypeTransformer.java
index b5548170a5..777713b98d 100644
---
a/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/util/TestDataTypeTransformer.java
+++
b/trino-connector/trino-connector/src/test/java/org/apache/gravitino/trino/connector/util/TestDataTypeTransformer.java
@@ -88,13 +88,13 @@ public class TestDataTypeTransformer {
Assertions.assertEquals(
dataTypeTransformer.getGravitinoType(DateType.DATE),
Types.DateType.get());
Assertions.assertEquals(
- dataTypeTransformer.getGravitinoType(TimeType.TIME_MILLIS),
Types.TimeType.get());
+ dataTypeTransformer.getGravitinoType(TimeType.TIME_MILLIS),
Types.TimeType.of(3));
Assertions.assertEquals(
dataTypeTransformer.getGravitinoType(TimestampType.TIMESTAMP_MILLIS),
- Types.TimestampType.withoutTimeZone());
+ Types.TimestampType.withoutTimeZone(3));
Assertions.assertEquals(
dataTypeTransformer.getGravitinoType(TimestampWithTimeZoneType.TIMESTAMP_TZ_MILLIS),
- Types.TimestampType.withTimeZone());
+ Types.TimestampType.withTimeZone(3));
Assertions.assertEquals(
dataTypeTransformer.getGravitinoType(new
ArrayType(IntegerType.INTEGER)),