Skip to content

Commit 48519ff

Browse files
guyco33hashhar
authored andcommitted
Support TIMESTAMPS with precisions higher than 3 in MySQL
1 parent f2b6d09 commit 48519ff

File tree

2 files changed

+163
-202
lines changed

2 files changed

+163
-202
lines changed

plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java

+29-26
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import io.trino.plugin.jdbc.JdbcSortItem;
2626
import io.trino.plugin.jdbc.JdbcTableHandle;
2727
import io.trino.plugin.jdbc.JdbcTypeHandle;
28-
import io.trino.plugin.jdbc.LongReadFunction;
2928
import io.trino.plugin.jdbc.PreparedQuery;
3029
import io.trino.plugin.jdbc.WriteMapping;
3130
import io.trino.plugin.jdbc.expression.AggregateFunctionRewriter;
@@ -54,6 +53,7 @@
5453
import io.trino.spi.type.DecimalType;
5554
import io.trino.spi.type.Decimals;
5655
import io.trino.spi.type.StandardTypes;
56+
import io.trino.spi.type.TimestampType;
5757
import io.trino.spi.type.Type;
5858
import io.trino.spi.type.TypeManager;
5959
import io.trino.spi.type.TypeSignature;
@@ -67,7 +67,6 @@
6767
import java.sql.ResultSet;
6868
import java.sql.SQLException;
6969
import java.sql.Types;
70-
import java.time.LocalDateTime;
7170
import java.util.Collection;
7271
import java.util.List;
7372
import java.util.Map;
@@ -101,11 +100,13 @@
101100
import static io.trino.plugin.jdbc.StandardColumnMappings.integerColumnMapping;
102101
import static io.trino.plugin.jdbc.StandardColumnMappings.integerWriteFunction;
103102
import static io.trino.plugin.jdbc.StandardColumnMappings.longDecimalWriteFunction;
103+
import static io.trino.plugin.jdbc.StandardColumnMappings.longTimestampWriteFunction;
104104
import static io.trino.plugin.jdbc.StandardColumnMappings.realColumnMapping;
105105
import static io.trino.plugin.jdbc.StandardColumnMappings.realWriteFunction;
106106
import static io.trino.plugin.jdbc.StandardColumnMappings.shortDecimalWriteFunction;
107107
import static io.trino.plugin.jdbc.StandardColumnMappings.smallintColumnMapping;
108108
import static io.trino.plugin.jdbc.StandardColumnMappings.smallintWriteFunction;
109+
import static io.trino.plugin.jdbc.StandardColumnMappings.timestampColumnMapping;
109110
import static io.trino.plugin.jdbc.StandardColumnMappings.timestampWriteFunction;
110111
import static io.trino.plugin.jdbc.StandardColumnMappings.tinyintColumnMapping;
111112
import static io.trino.plugin.jdbc.StandardColumnMappings.tinyintWriteFunction;
@@ -122,22 +123,25 @@
122123
import static io.trino.spi.type.RealType.REAL;
123124
import static io.trino.spi.type.SmallintType.SMALLINT;
124125
import static io.trino.spi.type.TimeWithTimeZoneType.TIME_WITH_TIME_ZONE;
125-
import static io.trino.spi.type.TimestampType.TIMESTAMP_MILLIS;
126+
import static io.trino.spi.type.TimestampType.createTimestampType;
126127
import static io.trino.spi.type.TimestampWithTimeZoneType.TIMESTAMP_TZ_MILLIS;
127-
import static io.trino.spi.type.Timestamps.MICROSECONDS_PER_MILLISECOND;
128-
import static io.trino.spi.type.Timestamps.MICROSECONDS_PER_SECOND;
129-
import static io.trino.spi.type.Timestamps.NANOSECONDS_PER_MILLISECOND;
130128
import static io.trino.spi.type.TinyintType.TINYINT;
131129
import static io.trino.spi.type.VarbinaryType.VARBINARY;
132130
import static java.lang.Math.max;
133131
import static java.lang.Math.min;
134132
import static java.lang.String.format;
135-
import static java.time.ZoneOffset.UTC;
136133
import static java.util.stream.Collectors.joining;
137134

138135
public class MySqlClient
139136
extends BaseJdbcClient
140137
{
138+
private static final int MAX_SUPPORTED_TIMESTAMP_PRECISION = 6;
139+
// MySQL driver returns width of timestamp types instead of precision.
140+
// 19 characters are used for zero-precision timestamps while others
141+
// require 19 + precision + 1 characters with the additional character
142+
// required for the decimal separator.
143+
private static final int ZERO_PRECISION_TIMESTAMP_COLUMN_SIZE = 19;
144+
141145
private final Type jsonType;
142146
private final AggregateFunctionRewriter aggregateFunctionRewriter;
143147

@@ -319,29 +323,22 @@ public Optional<ColumnMapping> toColumnMapping(ConnectorSession session, Connect
319323
return Optional.of(dateColumnMapping());
320324

321325
case Types.TIMESTAMP:
322-
// TODO support higher precisions (https://github.com/trinodb/trino/issues/6910)
323-
return Optional.of(ColumnMapping.longMapping(
324-
TIMESTAMP_MILLIS,
325-
timestampMillisReadFunction(),
326-
timestampWriteFunction(TIMESTAMP_MILLIS),
327-
DISABLE_PUSHDOWN));
326+
TimestampType timestampType = createTimestampType(getTimestampPrecision(typeHandle.getRequiredColumnSize()));
327+
return Optional.of(timestampColumnMapping(timestampType));
328328
}
329329

330330
// TODO add explicit mappings
331331
return legacyColumnMapping(session, connection, typeHandle);
332332
}
333333

334-
// TODO support higher precisions (https://github.com/trinodb/trino/issues/6910)
335-
private static LongReadFunction timestampMillisReadFunction()
336-
{
337-
return (resultSet, columnIndex) -> toTrinoTimestampMillis(resultSet.getObject(columnIndex, LocalDateTime.class));
338-
}
339-
340-
private static long toTrinoTimestampMillis(LocalDateTime localDateTime)
334+
private static int getTimestampPrecision(int timestampColumnSize)
341335
{
342-
return localDateTime.toEpochSecond(UTC) * MICROSECONDS_PER_SECOND
343-
// rounding to millis, TODO support higher precisions (https://github.com/trinodb/trino/issues/6910)
344-
+ Math.round(localDateTime.getNano() * 1.0 / NANOSECONDS_PER_MILLISECOND) * MICROSECONDS_PER_MILLISECOND;
336+
if (timestampColumnSize == ZERO_PRECISION_TIMESTAMP_COLUMN_SIZE) {
337+
return 0;
338+
}
339+
int timestampPrecision = timestampColumnSize - ZERO_PRECISION_TIMESTAMP_COLUMN_SIZE - 1;
340+
verify(1 <= timestampPrecision && timestampPrecision <= MAX_SUPPORTED_TIMESTAMP_PRECISION, "Unexpected timestamp precision %s calculated from timestamp column size %s", timestampPrecision, timestampColumnSize);
341+
return timestampPrecision;
345342
}
346343

347344
@Override
@@ -382,10 +379,16 @@ public WriteMapping toWriteMapping(ConnectorSession session, Type type)
382379
if (TIME_WITH_TIME_ZONE.equals(type) || TIMESTAMP_TZ_MILLIS.equals(type)) {
383380
throw new TrinoException(NOT_SUPPORTED, "Unsupported column type: " + type.getDisplayName());
384381
}
385-
if (TIMESTAMP_MILLIS.equals(type)) {
386-
// TODO use `timestampWriteFunction` (https://github.com/trinodb/trino/issues/6910)
387-
return WriteMapping.longMapping("datetime(3)", timestampWriteFunction(TIMESTAMP_MILLIS));
382+
383+
if (type instanceof TimestampType) {
384+
TimestampType timestampType = (TimestampType) type;
385+
if (timestampType.getPrecision() <= MAX_SUPPORTED_TIMESTAMP_PRECISION) {
386+
verify(timestampType.getPrecision() <= TimestampType.MAX_SHORT_PRECISION);
387+
return WriteMapping.longMapping(format("datetime(%s)", timestampType.getPrecision()), timestampWriteFunction(timestampType));
388+
}
389+
return WriteMapping.objectMapping(format("datetime(%s)", MAX_SUPPORTED_TIMESTAMP_PRECISION), longTimestampWriteFunction(timestampType));
388390
}
391+
389392
if (VARBINARY.equals(type)) {
390393
return WriteMapping.sliceMapping("mediumblob", varbinaryWriteFunction());
391394
}

0 commit comments

Comments
 (0)