diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/CoercionUtils.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/CoercionUtils.java index c353c9d27af4..a0aa9435c00e 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/CoercionUtils.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/CoercionUtils.java @@ -18,6 +18,7 @@ import io.trino.plugin.hive.HiveType; import io.trino.plugin.hive.coercions.BooleanCoercer.BooleanToVarcharCoercer; import io.trino.plugin.hive.coercions.DateCoercer.VarcharToDateCoercer; +import io.trino.plugin.hive.coercions.TimestampCoercer.LongTimestampToDateCoercer; import io.trino.plugin.hive.coercions.TimestampCoercer.LongTimestampToVarcharCoercer; import io.trino.plugin.hive.coercions.TimestampCoercer.VarcharToLongTimestampCoercer; import io.trino.plugin.hive.coercions.TimestampCoercer.VarcharToShortTimestampCoercer; @@ -189,8 +190,14 @@ public static Type createTypeFromCoercer(TypeManager typeManager, HiveType fromH if (fromType == REAL && toType instanceof DecimalType toDecimalType) { return Optional.of(createRealToDecimalCoercer(toDecimalType)); } - if (fromType instanceof TimestampType && toType instanceof VarcharType varcharType) { - return Optional.of(new LongTimestampToVarcharCoercer(TIMESTAMP_NANOS, varcharType)); + if (fromType instanceof TimestampType) { + if (toType instanceof VarcharType varcharType) { + return Optional.of(new LongTimestampToVarcharCoercer(TIMESTAMP_NANOS, varcharType)); + } + if (toType instanceof DateType toDateType) { + return Optional.of(new LongTimestampToDateCoercer(TIMESTAMP_NANOS, toDateType)); + } + return Optional.empty(); } if (fromType == DOUBLE && toType instanceof VarcharType toVarcharType) { return Optional.of(new DoubleToVarcharCoercer(toVarcharType, coercionContext.treatNaNAsNull())); diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/TimestampCoercer.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/TimestampCoercer.java index 0b903a3561b4..477015889c82 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/TimestampCoercer.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/coercions/TimestampCoercer.java @@ -18,6 +18,7 @@ import io.trino.spi.TrinoException; import io.trino.spi.block.Block; import io.trino.spi.block.BlockBuilder; +import io.trino.spi.type.DateType; import io.trino.spi.type.LongTimestamp; import io.trino.spi.type.TimestampType; import io.trino.spi.type.VarcharType; @@ -94,6 +95,27 @@ protected void applyCoercedValue(BlockBuilder blockBuilder, Block block, int pos } } + public static class LongTimestampToDateCoercer + extends TypeCoercer + { + public LongTimestampToDateCoercer(TimestampType fromType, DateType toType) + { + super(fromType, toType); + } + + @Override + protected void applyCoercedValue(BlockBuilder blockBuilder, Block block, int position) + { + LongTimestamp timestamp = (LongTimestamp) fromType.getObject(block, position); + + long epochSecond = floorDiv(timestamp.getEpochMicros(), MICROSECONDS_PER_SECOND); + if (epochSecond < START_OF_MODERN_ERA_SECONDS) { + throw new TrinoException(HIVE_INVALID_TIMESTAMP_COERCION, "Coercion on historical dates is not supported"); + } + toType.writeLong(blockBuilder, floorDiv(epochSecond, SECONDS_PER_DAY)); + } + } + public static class VarcharToShortTimestampCoercer extends TypeCoercer { diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/orc/OrcTypeTranslator.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/orc/OrcTypeTranslator.java index ff2449ce535e..00f050fa97b4 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/orc/OrcTypeTranslator.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/orc/OrcTypeTranslator.java @@ -18,6 +18,7 @@ import io.trino.plugin.hive.coercions.DateCoercer.VarcharToDateCoercer; import io.trino.plugin.hive.coercions.DoubleToVarcharCoercer; import io.trino.plugin.hive.coercions.IntegerNumberToDoubleCoercer; +import io.trino.plugin.hive.coercions.TimestampCoercer.LongTimestampToDateCoercer; import io.trino.plugin.hive.coercions.TimestampCoercer.LongTimestampToVarcharCoercer; import io.trino.plugin.hive.coercions.TimestampCoercer.VarcharToLongTimestampCoercer; import io.trino.plugin.hive.coercions.TimestampCoercer.VarcharToShortTimestampCoercer; @@ -53,8 +54,14 @@ private OrcTypeTranslator() {} public static Optional> createCoercer(OrcTypeKind fromOrcType, Type toTrinoType) { - if (fromOrcType == TIMESTAMP && toTrinoType instanceof VarcharType varcharType) { - return Optional.of(new LongTimestampToVarcharCoercer(TIMESTAMP_NANOS, varcharType)); + if (fromOrcType == TIMESTAMP) { + if (toTrinoType instanceof VarcharType varcharType) { + return Optional.of(new LongTimestampToVarcharCoercer(TIMESTAMP_NANOS, varcharType)); + } + if (toTrinoType instanceof DateType toDateType) { + return Optional.of(new LongTimestampToDateCoercer(TIMESTAMP_NANOS, toDateType)); + } + return Optional.empty(); } if (isVarcharType(fromOrcType)) { if (toTrinoType instanceof TimestampType timestampType) { diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/util/HiveCoercionPolicy.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/util/HiveCoercionPolicy.java index 857d64eec157..d424fcda56ee 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/util/HiveCoercionPolicy.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/util/HiveCoercionPolicy.java @@ -83,6 +83,9 @@ private boolean canCoerce(HiveType fromHiveType, HiveType toHiveType, HiveTimest fromHiveType.equals(HIVE_DOUBLE) || fromType instanceof DecimalType; } + if (toHiveType.equals(HIVE_DATE)) { + return fromHiveType.equals(HIVE_TIMESTAMP); + } if (fromHiveType.equals(HIVE_BYTE)) { return toHiveType.equals(HIVE_SHORT) || toHiveType.equals(HIVE_INT) || toHiveType.equals(HIVE_LONG) || toHiveType.equals(HIVE_DOUBLE); } diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/coercions/TestTimestampCoercer.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/coercions/TestTimestampCoercer.java index 3971b657c7cd..86f3b12f5a86 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/coercions/TestTimestampCoercer.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/coercions/TestTimestampCoercer.java @@ -24,6 +24,7 @@ import io.trino.spi.type.VarcharType; import org.junit.jupiter.api.Test; +import java.time.LocalDate; import java.time.LocalDateTime; import static io.airlift.slice.Slices.utf8Slice; @@ -33,6 +34,7 @@ import static io.trino.plugin.hive.coercions.CoercionUtils.createCoercer; import static io.trino.spi.predicate.Utils.blockToNativeValue; import static io.trino.spi.predicate.Utils.nativeValueToBlock; +import static io.trino.spi.type.DateType.DATE; import static io.trino.spi.type.TimestampType.TIMESTAMP_MICROS; import static io.trino.spi.type.TimestampType.TIMESTAMP_PICOS; import static io.trino.spi.type.VarcharType.createUnboundedVarcharType; @@ -45,6 +47,41 @@ public class TestTimestampCoercer { + @Test + public void testTimestampToDate() + { + // before epoch + assertTimestampToDateCoercion("1900-01-01T00:00:00.000", "1900-01-01"); + assertTimestampToDateCoercion("1958-01-01T13:18:03.123", "1958-01-01"); + // after epoch + assertTimestampToDateCoercion("2019-03-18T10:01:17.987", "2019-03-18"); + assertTimestampToDateCoercion("2021-12-31T23:59:59.000", "2021-12-31"); + assertTimestampToDateCoercion("2021-12-31T23:59:59.999", "2021-12-31"); + assertTimestampToDateCoercion("2021-12-31T23:59:59.999999", "2021-12-31"); + assertTimestampToDateCoercion("2021-12-31T23:59:59.999999999", "2021-12-31"); + // time doubled in JVM zone + assertTimestampToDateCoercion("2018-10-28T01:33:17.456", "2018-10-28"); + // epoch + assertTimestampToDateCoercion("1970-01-01T00:00:00.000", "1970-01-01"); + // time gap in JVM zone + assertTimestampToDateCoercion("1970-01-01T00:13:42.000", "1970-01-01"); + assertTimestampToDateCoercion("2018-04-01T02:13:55.123", "2018-04-01"); + // time gap in Vilnius + assertTimestampToDateCoercion("2018-03-25T03:17:17.000", "2018-03-25"); + // time gap in Kathmandu + assertTimestampToDateCoercion("1986-01-01T00:13:07.000", "1986-01-01"); + // before epoch with second fraction + assertTimestampToDateCoercion("1969-12-31T23:59:59.123456", "1969-12-31"); + } + + @Test + public void testHistoricalLongTimestampToDate() + { + assertThatThrownBy(() -> assertTimestampToDateCoercion("1899-12-31T23:59:59.999999999", "1899-12-31")) + .isInstanceOf(TrinoException.class) + .hasMessageContaining("Coercion on historical dates is not supported"); + } + @Test public void testTimestampToVarchar() { @@ -277,4 +314,11 @@ public static void assertCoercions(Type fromType, Object valueToBeCoerced, Type assertThat(blockToNativeValue(toType, coercedValue)) .isEqualTo(expectedValue); } + + private static void assertTimestampToDateCoercion(String timestampAsString, String expectedDate) + { + LocalDateTime localDateTime = LocalDateTime.parse(timestampAsString); + SqlTimestamp timestamp = SqlTimestamp.fromSeconds(TIMESTAMP_PICOS.getPrecision(), localDateTime.toEpochSecond(UTC), localDateTime.get(NANO_OF_SECOND)); + assertCoercions(TIMESTAMP_PICOS, new LongTimestamp(timestamp.getEpochMicros(), timestamp.getPicosOfMicros()), DATE, LocalDate.parse(expectedDate).toEpochDay(), NANOSECONDS); + } } diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/BaseTestHiveCoercion.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/BaseTestHiveCoercion.java index c7ae6580e599..f02df83c37c1 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/BaseTestHiveCoercion.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/BaseTestHiveCoercion.java @@ -52,6 +52,7 @@ import static io.trino.tempto.assertions.QueryAssert.Row.row; import static io.trino.tempto.context.ThreadLocalTestContextHolder.testContext; import static io.trino.tempto.fulfillment.table.TableHandle.tableHandle; +import static io.trino.tests.product.utils.JdbcDriverUtils.resetSessionProperty; import static io.trino.tests.product.utils.JdbcDriverUtils.setSessionProperty; import static io.trino.tests.product.utils.QueryExecutors.onHive; import static io.trino.tests.product.utils.QueryExecutors.onTrino; @@ -148,6 +149,9 @@ protected void doTestHiveCoercion(HiveTableDefinition tableDefinition) "varchar_to_special_double", "char_to_bigger_char", "char_to_smaller_char", + "timestamp_millis_to_date", + "timestamp_micros_to_date", + "timestamp_nanos_to_date", "timestamp_to_string", "timestamp_to_bounded_varchar", "timestamp_to_smaller_varchar", @@ -178,6 +182,8 @@ protected void doTestHiveCoercion(HiveTableDefinition tableDefinition) protected void insertTableRows(String tableName, String floatToDoubleType) { + // Insert all the data with nanoseconds precision + setHiveTimestampPrecision(NANOSECONDS); onTrino().executeQuery(format( "INSERT INTO %1$s VALUES " + "(" + @@ -233,6 +239,9 @@ protected void insertTableRows(String tableName, String floatToDoubleType) " 'NaN'," + " 'abc', " + " 'abc', " + + " TIMESTAMP '2022-12-31 23:59:59.999', " + + " TIMESTAMP '2023-12-31 23:59:59.999999', " + + " TIMESTAMP '2024-12-31 23:59:59.999999999', " + " TIMESTAMP '2121-07-15 15:30:12.123', " + " TIMESTAMP '2121-07-15 15:30:12.123', " + " TIMESTAMP '2121-07-15 15:30:12.123', " + @@ -293,6 +302,9 @@ protected void insertTableRows(String tableName, String floatToDoubleType) " '\uD83D\uDCB0\uD83D\uDCB0\uD83D\uDCB0', " + " '\uD83D\uDCB0\uD83D\uDCB0\uD83D\uDCB0', " + " TIMESTAMP '1970-01-01 00:00:00.123', " + + " TIMESTAMP '1970-01-01 00:00:00.123456', " + + " TIMESTAMP '1970-01-01 00:00:00.123456789', " + + " TIMESTAMP '1970-01-01 00:00:00.123', " + " TIMESTAMP '1970-01-01 00:00:00.123', " + " TIMESTAMP '1970-01-01 00:00:00.123', " + " '1970', " + @@ -300,6 +312,7 @@ protected void insertTableRows(String tableName, String floatToDoubleType) " 1)", tableName, floatToDoubleType)); + resetHiveTimestampPrecision(); } protected Map> expectedValuesForEngineProvider(Engine engine, String tableName, String decimalToFloatVal, String floatToDecimalVal) @@ -512,6 +525,15 @@ else if (getHiveVersionMajor() == 3 && isFormat.test("orc")) { .put("char_to_smaller_char", ImmutableList.of( "ab", "\uD83D\uDCB0\uD83D\uDCB0")) + .put("timestamp_millis_to_date", ImmutableList.of( + java.sql.Date.valueOf("2022-12-31"), + java.sql.Date.valueOf("1970-01-01"))) + .put("timestamp_micros_to_date", ImmutableList.of( + java.sql.Date.valueOf("2023-12-31"), + java.sql.Date.valueOf("1970-01-01"))) + .put("timestamp_nanos_to_date", ImmutableList.of( + java.sql.Date.valueOf("2024-12-31"), + java.sql.Date.valueOf("1970-01-01"))) .put("timestamp_to_string", ImmutableList.of( "2121-07-15 15:30:12.123", "1970-01-01 00:00:00.123")) @@ -543,11 +565,12 @@ protected void doTestHiveCoercionWithDifferentTimestampPrecision(HiveTableDefini """ INSERT INTO %s SELECT - (CAST(ROW (timestamp_value, -1, timestamp_value, CAST(timestamp_value AS VARCHAR)) AS ROW(keep TIMESTAMP(9), si2i SMALLINT, timestamp2string TIMESTAMP(9), string2timestamp VARCHAR))), - ARRAY [CAST(ROW (timestamp_value, -1, timestamp_value, CAST(timestamp_value AS VARCHAR)) AS ROW (keep TIMESTAMP(9), si2i SMALLINT, timestamp2string TIMESTAMP(9), string2timestamp VARCHAR))], - MAP (ARRAY [2], ARRAY [CAST(ROW (timestamp_value, -1, timestamp_value, CAST(timestamp_value AS VARCHAR)) AS ROW (keep TIMESTAMP(9), si2i SMALLINT, timestamp2string TIMESTAMP(9), string2timestamp VARCHAR))]), + (CAST(ROW (timestamp_value, -1, timestamp_value, CAST(timestamp_value AS VARCHAR), timestamp_value) AS ROW(keep TIMESTAMP(9), si2i SMALLINT, timestamp2string TIMESTAMP(9), string2timestamp VARCHAR, timestamp2date TIMESTAMP(9)))), + ARRAY [CAST(ROW (timestamp_value, -1, timestamp_value, CAST(timestamp_value AS VARCHAR), timestamp_value) AS ROW (keep TIMESTAMP(9), si2i SMALLINT, timestamp2string TIMESTAMP(9), string2timestamp VARCHAR, timestamp2date TIMESTAMP(9)))], + MAP (ARRAY [2], ARRAY [CAST(ROW (timestamp_value, -1, timestamp_value, CAST(timestamp_value AS VARCHAR), timestamp_value) AS ROW (keep TIMESTAMP(9), si2i SMALLINT, timestamp2string TIMESTAMP(9), string2timestamp VARCHAR, timestamp2date TIMESTAMP(9)))]), timestamp_value, CAST(timestamp_value AS VARCHAR), + timestamp_value, 1 FROM (VALUES (TIMESTAMP '2121-07-15 15:30:12.123499'), @@ -558,21 +581,23 @@ protected void doTestHiveCoercionWithDifferentTimestampPrecision(HiveTableDefini (TIMESTAMP '2121-07-15 15:30:12.123500001')) AS t (timestamp_value) """.formatted(tableName)); - onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_row_to_row timestamp_row_to_row struct", tableName)); - onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_list_to_list timestamp_list_to_list array>", tableName)); - onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_map_to_map timestamp_map_to_map map>", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_row_to_row timestamp_row_to_row struct", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_list_to_list timestamp_list_to_list array>", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_map_to_map timestamp_map_to_map map>", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_to_string timestamp_to_string string", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN string_to_timestamp string_to_timestamp TIMESTAMP", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_to_date timestamp_to_date DATE", tableName)); for (HiveTimestampPrecision hiveTimestampPrecision : HiveTimestampPrecision.values()) { String timestampType = "timestamp(%d)".formatted(hiveTimestampPrecision.getPrecision()); setHiveTimestampPrecision(hiveTimestampPrecision); assertThat(onTrino().executeQuery("SHOW COLUMNS FROM " + tableName).project(1, 2)).containsExactlyInOrder( - row("timestamp_row_to_row", "row(keep %1$s, si2i integer, timestamp2string varchar, string2timestamp %1$s)".formatted(timestampType)), - row("timestamp_list_to_list", "array(row(keep %1$s, si2i integer, timestamp2string varchar, string2timestamp %1$s))".formatted(timestampType)), - row("timestamp_map_to_map", "map(integer, row(keep %1$s, si2i integer, timestamp2string varchar, string2timestamp %1$s))".formatted(timestampType)), + row("timestamp_row_to_row", "row(keep %1$s, si2i integer, timestamp2string varchar, string2timestamp %1$s, timestamp2date date)".formatted(timestampType)), + row("timestamp_list_to_list", "array(row(keep %1$s, si2i integer, timestamp2string varchar, string2timestamp %1$s, timestamp2date date))".formatted(timestampType)), + row("timestamp_map_to_map", "map(integer, row(keep %1$s, si2i integer, timestamp2string varchar, string2timestamp %1$s, timestamp2date date))".formatted(timestampType)), row("timestamp_to_string", "varchar"), row("string_to_timestamp", timestampType), + row("timestamp_to_date", "date"), row("id", "bigint")); List allColumns = ImmutableList.of( @@ -581,6 +606,7 @@ protected void doTestHiveCoercionWithDifferentTimestampPrecision(HiveTableDefini "timestamp_map_to_map", "timestamp_to_string", "string_to_timestamp", + "timestamp_to_date", "id"); // For Trino, remove unsupported columns @@ -611,14 +637,15 @@ protected Map> expectedRowsForEngineProvider(Engine engine, "2121-07-15 15:30:12.123499999", "2121-07-15 15:30:12.1235", "2121-07-15 15:30:12.123500001"); + if (engine == Engine.HIVE) { List baseData = ImmutableList.of( - "{\"keep\":\"2121-07-15 15:30:12.123499\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123499\",\"string2timestamp\":\"2121-07-15 15:30:12.123499\"}", - "{\"keep\":\"2121-07-15 15:30:12.1235\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.1235\",\"string2timestamp\":\"2121-07-15 15:30:12.1235\"}", - "{\"keep\":\"2121-07-15 15:30:12.123501\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123501\",\"string2timestamp\":\"2121-07-15 15:30:12.123501\"}", - "{\"keep\":\"2121-07-15 15:30:12.123499999\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123499999\",\"string2timestamp\":\"2121-07-15 15:30:12.123499999\"}", - "{\"keep\":\"2121-07-15 15:30:12.1235\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.1235\",\"string2timestamp\":\"2121-07-15 15:30:12.1235\"}", - "{\"keep\":\"2121-07-15 15:30:12.123500001\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123500001\",\"string2timestamp\":\"2121-07-15 15:30:12.123500001\"}"); + "{\"keep\":\"2121-07-15 15:30:12.123499\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123499\",\"string2timestamp\":\"2121-07-15 15:30:12.123499\",\"timestamp2date\":\"2121-07-15\"}", + "{\"keep\":\"2121-07-15 15:30:12.1235\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.1235\",\"string2timestamp\":\"2121-07-15 15:30:12.1235\",\"timestamp2date\":\"2121-07-15\"}", + "{\"keep\":\"2121-07-15 15:30:12.123501\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123501\",\"string2timestamp\":\"2121-07-15 15:30:12.123501\",\"timestamp2date\":\"2121-07-15\"}", + "{\"keep\":\"2121-07-15 15:30:12.123499999\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123499999\",\"string2timestamp\":\"2121-07-15 15:30:12.123499999\",\"timestamp2date\":\"2121-07-15\"}", + "{\"keep\":\"2121-07-15 15:30:12.1235\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.1235\",\"string2timestamp\":\"2121-07-15 15:30:12.1235\",\"timestamp2date\":\"2121-07-15\"}", + "{\"keep\":\"2121-07-15 15:30:12.123500001\",\"si2i\":-1,\"timestamp2string\":\"2121-07-15 15:30:12.123500001\",\"string2timestamp\":\"2121-07-15 15:30:12.123500001\",\"timestamp2date\":\"2121-07-15\"}"); return ImmutableMap.>builder() .put("timestamp_row_to_row", baseData) .put("timestamp_list_to_list", baseData.stream() @@ -633,6 +660,7 @@ protected Map> expectedRowsForEngineProvider(Engine engine, .map(String.class::cast) .map(Timestamp::valueOf) .collect(toImmutableList())) + .put("timestamp_to_date", nCopies(6, java.sql.Date.valueOf("2121-07-15"))) .put("id", nCopies(6, 1)) .buildOrThrow(); } @@ -669,6 +697,7 @@ protected Map> expectedRowsForEngineProvider(Engine engine, .addField("si2i", -1) .addField("timestamp2string", timestampCoerced) .addField("string2timestamp", timestamp) + .addField("timestamp2date", java.sql.Date.valueOf("2121-07-15")) .build()) .collect(toImmutableList()); @@ -682,6 +711,7 @@ protected Map> expectedRowsForEngineProvider(Engine engine, .collect(toImmutableList())) .put("timestamp_to_string", timestampAsString) .put("string_to_timestamp", timestampValue) + .put("timestamp_to_date", nCopies(6, java.sql.Date.valueOf("2121-07-15"))) .put("id", nCopies(6, 1)) .buildOrThrow(); } @@ -949,6 +979,9 @@ private void assertProperAlteredTableSchema(String tableName) row("varchar_to_special_double", "double"), row("char_to_bigger_char", "char(4)"), row("char_to_smaller_char", "char(2)"), + row("timestamp_millis_to_date", "date"), + row("timestamp_micros_to_date", "date"), + row("timestamp_nanos_to_date", "date"), row("timestamp_to_string", "varchar"), row("timestamp_to_bounded_varchar", "varchar(30)"), row("timestamp_to_smaller_varchar", "varchar(4)"), @@ -1031,6 +1064,10 @@ private void assertColumnTypes( .put("timestamp_to_smaller_varchar", VARCHAR) .put("smaller_varchar_to_timestamp", TIMESTAMP) .put("varchar_to_timestamp", TIMESTAMP) + .put("timestamp_to_date", DATE) + .put("timestamp_millis_to_date", DATE) + .put("timestamp_micros_to_date", DATE) + .put("timestamp_nanos_to_date", DATE) .put("timestamp_to_varchar", VARCHAR) .put("timestamp_row_to_row", engine == Engine.TRINO ? JAVA_OBJECT : STRUCT) // row .put("timestamp_list_to_list", ARRAY) // list @@ -1098,6 +1135,9 @@ private static void alterTableColumnTypes(String tableName) onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN varchar_to_special_double varchar_to_special_double double", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN char_to_bigger_char char_to_bigger_char char(4)", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN char_to_smaller_char char_to_smaller_char char(2)", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_millis_to_date timestamp_millis_to_date date", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_micros_to_date timestamp_micros_to_date date", tableName)); + onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_nanos_to_date timestamp_nanos_to_date date", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_to_string timestamp_to_string string", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_to_bounded_varchar timestamp_to_bounded_varchar varchar(30)", tableName)); onHive().executeQuery(format("ALTER TABLE %s CHANGE COLUMN timestamp_to_smaller_varchar timestamp_to_smaller_varchar varchar(4)", tableName)); @@ -1199,4 +1239,14 @@ private static void setHiveTimestampPrecision(HiveTimestampPrecision hiveTimesta throw new RuntimeException(e); } } + + private static void resetHiveTimestampPrecision() + { + try { + resetSessionProperty(onTrino().getConnection(), "hive.timestamp_precision"); + } + catch (SQLException e) { + throw new RuntimeException(e); + } + } } diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnPartitionedTable.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnPartitionedTable.java index 709d10125f72..8960585ad40a 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnPartitionedTable.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnPartitionedTable.java @@ -152,6 +152,9 @@ private static HiveTableDefinition.HiveTableDefinitionBuilder tableDefinitionBui " varchar_to_special_double VARCHAR(40)," + " char_to_bigger_char CHAR(3)," + " char_to_smaller_char CHAR(3)," + + " timestamp_millis_to_date TIMESTAMP," + + " timestamp_micros_to_date TIMESTAMP," + + " timestamp_nanos_to_date TIMESTAMP," + " timestamp_to_string TIMESTAMP," + " timestamp_to_bounded_varchar TIMESTAMP," + " timestamp_to_smaller_varchar TIMESTAMP," + @@ -169,11 +172,12 @@ private static HiveTableDefinition.HiveTableDefinitionBuilder tableDefinitionFor return HiveTableDefinition.builder(tableName) .setCreateTableDDLTemplate("" + "CREATE TABLE %NAME%(" + - " timestamp_row_to_row STRUCT, " + - " timestamp_list_to_list ARRAY>, " + - " timestamp_map_to_map MAP>," + + " timestamp_row_to_row STRUCT, " + + " timestamp_list_to_list ARRAY>, " + + " timestamp_map_to_map MAP>," + " timestamp_to_string TIMESTAMP," + - " string_to_timestamp STRING" + + " string_to_timestamp STRING," + + " timestamp_to_date TIMESTAMP" + ") " + "PARTITIONED BY (id BIGINT) " + rowFormat.map(s -> format("ROW FORMAT %s ", s)).orElse("") + diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnUnpartitionedTable.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnUnpartitionedTable.java index cca6f5b05fb8..f11ceb4a1520 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnUnpartitionedTable.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveCoercionOnUnpartitionedTable.java @@ -101,6 +101,9 @@ varchar_to_double_infinity VARCHAR(40), varchar_to_special_double VARCHAR(40), char_to_bigger_char CHAR(3), char_to_smaller_char CHAR(3), + timestamp_millis_to_date TIMESTAMP, + timestamp_micros_to_date TIMESTAMP, + timestamp_nanos_to_date TIMESTAMP, timestamp_to_string TIMESTAMP, timestamp_to_bounded_varchar TIMESTAMP, timestamp_to_smaller_varchar TIMESTAMP, @@ -116,11 +119,12 @@ private static HiveTableDefinition.HiveTableDefinitionBuilder tableDefinitionFor return HiveTableDefinition.builder(tableName) .setCreateTableDDLTemplate(""" CREATE TABLE %NAME%( - timestamp_row_to_row STRUCT, - timestamp_list_to_list ARRAY>, - timestamp_map_to_map MAP>, + timestamp_row_to_row STRUCT, + timestamp_list_to_list ARRAY>, + timestamp_map_to_map MAP>, timestamp_to_string TIMESTAMP, string_to_timestamp STRING, + timestamp_to_date TIMESTAMP, id BIGINT) STORED AS\s""" + fileFormat); }