|
25 | 25 | import io.trino.plugin.jdbc.JdbcSortItem;
|
26 | 26 | import io.trino.plugin.jdbc.JdbcTableHandle;
|
27 | 27 | import io.trino.plugin.jdbc.JdbcTypeHandle;
|
28 |
| -import io.trino.plugin.jdbc.LongReadFunction; |
29 | 28 | import io.trino.plugin.jdbc.PreparedQuery;
|
30 | 29 | import io.trino.plugin.jdbc.WriteMapping;
|
31 | 30 | import io.trino.plugin.jdbc.expression.AggregateFunctionRewriter;
|
|
54 | 53 | import io.trino.spi.type.DecimalType;
|
55 | 54 | import io.trino.spi.type.Decimals;
|
56 | 55 | import io.trino.spi.type.StandardTypes;
|
| 56 | +import io.trino.spi.type.TimestampType; |
57 | 57 | import io.trino.spi.type.Type;
|
58 | 58 | import io.trino.spi.type.TypeManager;
|
59 | 59 | import io.trino.spi.type.TypeSignature;
|
|
67 | 67 | import java.sql.ResultSet;
|
68 | 68 | import java.sql.SQLException;
|
69 | 69 | import java.sql.Types;
|
70 |
| -import java.time.LocalDateTime; |
71 | 70 | import java.util.Collection;
|
72 | 71 | import java.util.List;
|
73 | 72 | import java.util.Map;
|
|
101 | 100 | import static io.trino.plugin.jdbc.StandardColumnMappings.integerColumnMapping;
|
102 | 101 | import static io.trino.plugin.jdbc.StandardColumnMappings.integerWriteFunction;
|
103 | 102 | import static io.trino.plugin.jdbc.StandardColumnMappings.longDecimalWriteFunction;
|
| 103 | +import static io.trino.plugin.jdbc.StandardColumnMappings.longTimestampWriteFunction; |
104 | 104 | import static io.trino.plugin.jdbc.StandardColumnMappings.realColumnMapping;
|
105 | 105 | import static io.trino.plugin.jdbc.StandardColumnMappings.realWriteFunction;
|
106 | 106 | import static io.trino.plugin.jdbc.StandardColumnMappings.shortDecimalWriteFunction;
|
107 | 107 | import static io.trino.plugin.jdbc.StandardColumnMappings.smallintColumnMapping;
|
108 | 108 | import static io.trino.plugin.jdbc.StandardColumnMappings.smallintWriteFunction;
|
| 109 | +import static io.trino.plugin.jdbc.StandardColumnMappings.timestampColumnMapping; |
109 | 110 | import static io.trino.plugin.jdbc.StandardColumnMappings.timestampWriteFunction;
|
110 | 111 | import static io.trino.plugin.jdbc.StandardColumnMappings.tinyintColumnMapping;
|
111 | 112 | import static io.trino.plugin.jdbc.StandardColumnMappings.tinyintWriteFunction;
|
|
122 | 123 | import static io.trino.spi.type.RealType.REAL;
|
123 | 124 | import static io.trino.spi.type.SmallintType.SMALLINT;
|
124 | 125 | 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; |
126 | 127 | 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; |
130 | 128 | import static io.trino.spi.type.TinyintType.TINYINT;
|
131 | 129 | import static io.trino.spi.type.VarbinaryType.VARBINARY;
|
132 | 130 | import static java.lang.Math.max;
|
133 | 131 | import static java.lang.Math.min;
|
134 | 132 | import static java.lang.String.format;
|
135 |
| -import static java.time.ZoneOffset.UTC; |
136 | 133 | import static java.util.stream.Collectors.joining;
|
137 | 134 |
|
138 | 135 | public class MySqlClient
|
139 | 136 | extends BaseJdbcClient
|
140 | 137 | {
|
| 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 | + |
141 | 145 | private final Type jsonType;
|
142 | 146 | private final AggregateFunctionRewriter aggregateFunctionRewriter;
|
143 | 147 |
|
@@ -319,29 +323,22 @@ public Optional<ColumnMapping> toColumnMapping(ConnectorSession session, Connect
|
319 | 323 | return Optional.of(dateColumnMapping());
|
320 | 324 |
|
321 | 325 | 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)); |
328 | 328 | }
|
329 | 329 |
|
330 | 330 | // TODO add explicit mappings
|
331 | 331 | return legacyColumnMapping(session, connection, typeHandle);
|
332 | 332 | }
|
333 | 333 |
|
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) |
341 | 335 | {
|
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; |
345 | 342 | }
|
346 | 343 |
|
347 | 344 | @Override
|
@@ -382,10 +379,16 @@ public WriteMapping toWriteMapping(ConnectorSession session, Type type)
|
382 | 379 | if (TIME_WITH_TIME_ZONE.equals(type) || TIMESTAMP_TZ_MILLIS.equals(type)) {
|
383 | 380 | throw new TrinoException(NOT_SUPPORTED, "Unsupported column type: " + type.getDisplayName());
|
384 | 381 | }
|
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)); |
388 | 390 | }
|
| 391 | + |
389 | 392 | if (VARBINARY.equals(type)) {
|
390 | 393 | return WriteMapping.sliceMapping("mediumblob", varbinaryWriteFunction());
|
391 | 394 | }
|
|
0 commit comments