4343import io .trino .hive .thrift .metastore .SerDeInfo ;
4444import io .trino .hive .thrift .metastore .StorageDescriptor ;
4545import io .trino .hive .thrift .metastore .StringColumnStatsData ;
46+ import io .trino .hive .thrift .metastore .Timestamp ;
47+ import io .trino .hive .thrift .metastore .TimestampColumnStatsData ;
4648import io .trino .metastore .AcidOperation ;
4749import io .trino .metastore .Column ;
4850import io .trino .metastore .Database ;
8385import java .math .BigInteger ;
8486import java .nio .ByteBuffer ;
8587import java .time .LocalDate ;
88+ import java .time .LocalDateTime ;
89+ import java .time .ZoneOffset ;
8690import java .util .ArrayDeque ;
8791import java .util .Arrays ;
8892import java .util .Collection ;
149153import static io .trino .spi .type .IntegerType .INTEGER ;
150154import static io .trino .spi .type .RealType .REAL ;
151155import static io .trino .spi .type .SmallintType .SMALLINT ;
156+ import static io .trino .spi .type .StandardTypes .TIMESTAMP ;
157+ import static io .trino .spi .type .Timestamps .MICROSECONDS_PER_MILLISECOND ;
158+ import static io .trino .spi .type .Timestamps .MICROSECONDS_PER_SECOND ;
152159import static io .trino .spi .type .TinyintType .TINYINT ;
153160import static io .trino .spi .type .VarbinaryType .VARBINARY ;
161+ import static java .lang .Math .ceilDiv ;
162+ import static java .lang .Math .floorDiv ;
154163import static java .lang .Math .toIntExact ;
155164import static java .lang .String .format ;
156165import static java .util .Locale .ENGLISH ;
@@ -522,6 +531,10 @@ public static HiveColumnStatistics fromMetastoreApiColumnStatistics(ColumnStatis
522531 LongColumnStatsData longStatsData = columnStatistics .getStatsData ().getLongStats ();
523532 OptionalLong min = longStatsData .isSetLowValue () ? OptionalLong .of (longStatsData .getLowValue ()) : OptionalLong .empty ();
524533 OptionalLong max = longStatsData .isSetHighValue () ? OptionalLong .of (longStatsData .getHighValue ()) : OptionalLong .empty ();
534+ if (min .isPresent () && max .isPresent () && columnStatistics .getColType ().equals (TIMESTAMP )) {
535+ min = OptionalLong .of (min .getAsLong () * MICROSECONDS_PER_SECOND );
536+ max = OptionalLong .of (max .getAsLong () * MICROSECONDS_PER_SECOND );
537+ }
525538 OptionalLong nullsCount = longStatsData .isSetNumNulls () ? fromMetastoreNullsCount (longStatsData .getNumNulls ()) : OptionalLong .empty ();
526539 OptionalLong distinctValuesWithNullCount = longStatsData .isSetNumDVs () ? OptionalLong .of (longStatsData .getNumDVs ()) : OptionalLong .empty ();
527540 return createIntegerColumnStatistics (min , max , nullsCount , distinctValuesWithNullCount );
@@ -586,6 +599,14 @@ public static HiveColumnStatistics fromMetastoreApiColumnStatistics(ColumnStatis
586599 averageColumnLength ,
587600 nullsCount );
588601 }
602+ if (columnStatistics .getStatsData ().isSetTimestampStats ()) {
603+ TimestampColumnStatsData timestampStatsData = columnStatistics .getStatsData ().getTimestampStats ();
604+ OptionalLong min = timestampStatsData .isSetLowValue () ? fromMetastoreTimestamp (timestampStatsData .getLowValue ()) : OptionalLong .empty ();
605+ OptionalLong max = timestampStatsData .isSetHighValue () ? fromMetastoreTimestamp (timestampStatsData .getHighValue ()) : OptionalLong .empty ();
606+ OptionalLong nullsCount = timestampStatsData .isSetNumNulls () ? fromMetastoreNullsCount (timestampStatsData .getNumNulls ()) : OptionalLong .empty ();
607+ OptionalLong distinctValuesWithNullCount = timestampStatsData .isSetNumDVs () ? OptionalLong .of (timestampStatsData .getNumDVs ()) : OptionalLong .empty ();
608+ return createIntegerColumnStatistics (min , max , nullsCount , distinctValuesWithNullCount );
609+ }
589610 throw new TrinoException (HIVE_INVALID_METADATA , "Invalid column statistics data: " + columnStatistics );
590611 }
591612
@@ -610,6 +631,14 @@ public static OptionalLong fromMetastoreNullsCount(long nullsCount)
610631 return OptionalLong .of (nullsCount );
611632 }
612633
634+ private static OptionalLong fromMetastoreTimestamp (Timestamp timestamp )
635+ {
636+ if (timestamp == null ) {
637+ return OptionalLong .empty ();
638+ }
639+ return OptionalLong .of (LocalDateTime .ofEpochSecond (timestamp .getSecondsSinceEpoch (), 0 , ZoneOffset .UTC ).toInstant (ZoneOffset .UTC ).toEpochMilli () * MICROSECONDS_PER_MILLISECOND );
640+ }
641+
613642 private static Optional <BigDecimal > fromMetastoreDecimal (@ Nullable Decimal decimal )
614643 {
615644 if (decimal == null ) {
@@ -769,8 +798,9 @@ public static ColumnStatisticsObj createMetastoreColumnStatistics(String columnN
769798 case SHORT :
770799 case INT :
771800 case LONG :
772- case TIMESTAMP :
773801 return createLongStatistics (columnName , columnType , statistics );
802+ case TIMESTAMP :
803+ return createTimestampStatistics (columnName , columnType , statistics );
774804 case FLOAT :
775805 case DOUBLE :
776806 return createDoubleStatistics (columnName , columnType , statistics );
@@ -820,6 +850,18 @@ private static ColumnStatisticsObj createLongStatistics(String columnName, HiveT
820850 return new ColumnStatisticsObj (columnName , columnType .toString (), longStats (data ));
821851 }
822852
853+ private static ColumnStatisticsObj createTimestampStatistics (String columnName , HiveType columnType , HiveColumnStatistics statistics )
854+ {
855+ LongColumnStatsData data = new LongColumnStatsData ();
856+ statistics .getIntegerStatistics ().ifPresent (timestampStatistics -> {
857+ timestampStatistics .getMin ().ifPresent (value -> data .setLowValue (floorDiv (value , MICROSECONDS_PER_SECOND )));
858+ timestampStatistics .getMax ().ifPresent (value -> data .setHighValue (ceilDiv (value , MICROSECONDS_PER_SECOND )));
859+ });
860+ statistics .getNullsCount ().ifPresent (data ::setNumNulls );
861+ statistics .getDistinctValuesWithNullCount ().ifPresent (data ::setNumDVs );
862+ return new ColumnStatisticsObj (columnName , columnType .toString (), longStats (data ));
863+ }
864+
823865 private static ColumnStatisticsObj createDoubleStatistics (String columnName , HiveType columnType , HiveColumnStatistics statistics )
824866 {
825867 DoubleColumnStatsData data = new DoubleColumnStatsData ();
@@ -894,8 +936,7 @@ public static Set<HiveColumnStatisticType> getSupportedColumnStatistics(Type typ
894936 return ImmutableSet .of (MIN_VALUE , MAX_VALUE , NUMBER_OF_DISTINCT_VALUES , NUMBER_OF_NON_NULL_VALUES );
895937 }
896938 if (type instanceof TimestampType || type instanceof TimestampWithTimeZoneType ) {
897- // TODO (https://github.com/trinodb/trino/issues/5859) Add support for timestamp MIN_VALUE, MAX_VALUE
898- return ImmutableSet .of (NUMBER_OF_DISTINCT_VALUES , NUMBER_OF_NON_NULL_VALUES );
939+ return ImmutableSet .of (MIN_VALUE , MAX_VALUE , NUMBER_OF_DISTINCT_VALUES , NUMBER_OF_NON_NULL_VALUES );
899940 }
900941 if (type instanceof VarcharType || type instanceof CharType ) {
901942 // TODO Collect MIN,MAX once it is used by the optimizer
0 commit comments