14
14
package io .trino .plugin .deltalake .transactionlog ;
15
15
16
16
import io .airlift .log .Logger ;
17
+ import io .airlift .slice .Slice ;
17
18
import io .trino .plugin .base .type .DecodedTimestamp ;
19
+ import io .trino .spi .block .BlockBuilder ;
20
+ import io .trino .spi .block .RowBlockBuilder ;
18
21
import io .trino .spi .type .DateType ;
19
22
import io .trino .spi .type .DecimalType ;
23
+ import io .trino .spi .type .Decimals ;
24
+ import io .trino .spi .type .Int128 ;
25
+ import io .trino .spi .type .RowType ;
26
+ import io .trino .spi .type .TimestampType ;
20
27
import io .trino .spi .type .TimestampWithTimeZoneType ;
21
28
import io .trino .spi .type .Type ;
22
29
import io .trino .spi .type .VarcharType ;
29
36
import org .apache .parquet .hadoop .metadata .ColumnChunkMetaData ;
30
37
import org .apache .parquet .schema .LogicalTypeAnnotation ;
31
38
39
+ import javax .annotation .Nullable ;
40
+
32
41
import java .math .BigDecimal ;
33
42
import java .math .BigInteger ;
34
43
import java .time .Instant ;
35
44
import java .time .LocalDate ;
36
45
import java .time .ZonedDateTime ;
37
46
import java .util .Collection ;
47
+ import java .util .HashMap ;
48
+ import java .util .List ;
38
49
import java .util .Map ;
39
50
import java .util .Optional ;
40
51
import java .util .function .BiFunction ;
44
55
import static io .trino .parquet .ParquetTimestampUtils .decodeInt96Timestamp ;
45
56
import static io .trino .spi .type .BigintType .BIGINT ;
46
57
import static io .trino .spi .type .BooleanType .BOOLEAN ;
58
+ import static io .trino .spi .type .DateTimeEncoding .unpackMillisUtc ;
59
+ import static io .trino .spi .type .Decimals .isShortDecimal ;
47
60
import static io .trino .spi .type .DoubleType .DOUBLE ;
48
61
import static io .trino .spi .type .IntegerType .INTEGER ;
49
62
import static io .trino .spi .type .RealType .REAL ;
50
63
import static io .trino .spi .type .SmallintType .SMALLINT ;
64
+ import static io .trino .spi .type .TimestampWithTimeZoneType .TIMESTAMP_TZ_MILLIS ;
65
+ import static io .trino .spi .type .Timestamps .MICROSECONDS_PER_MILLISECOND ;
51
66
import static io .trino .spi .type .TinyintType .TINYINT ;
67
+ import static io .trino .spi .type .TypeUtils .writeNativeValue ;
68
+ import static java .lang .Float .floatToRawIntBits ;
69
+ import static java .lang .Float .intBitsToFloat ;
70
+ import static java .lang .Math .toIntExact ;
52
71
import static java .nio .charset .StandardCharsets .UTF_8 ;
53
72
import static java .time .ZoneOffset .UTC ;
54
73
import static java .time .format .DateTimeFormatter .ISO_INSTANT ;
@@ -71,6 +90,119 @@ public static boolean hasInvalidStatistics(Collection<ColumnChunkMetaData> metad
71
90
(!metadata .getStatistics ().hasNonNullValue () && metadata .getStatistics ().getNumNulls () != metadata .getValueCount ()));
72
91
}
73
92
93
+ @ Nullable
94
+ public static Object toTrinoValue (Type type , @ Nullable Object value )
95
+ {
96
+ if (value == null ) {
97
+ return null ;
98
+ }
99
+
100
+ if (type == SMALLINT || type == TINYINT || type == INTEGER ) {
101
+ return (long ) (int ) value ;
102
+ }
103
+ if (type == BIGINT ) {
104
+ return (long ) (int ) value ;
105
+ }
106
+ if (type == REAL ) {
107
+ return (long ) floatToRawIntBits ((float ) (double ) value );
108
+ }
109
+ if (type == DOUBLE ) {
110
+ return value ;
111
+ }
112
+ if (type instanceof DecimalType ) {
113
+ BigDecimal decimal ;
114
+ checkArgument (value instanceof String || value instanceof Double , "Value must be instance of String or Double" );
115
+ if (value instanceof String ) {
116
+ decimal = new BigDecimal ((String ) value );
117
+ }
118
+ else {
119
+ decimal = BigDecimal .valueOf ((double ) value );
120
+ }
121
+
122
+ if (isShortDecimal (type )) {
123
+ return Decimals .encodeShortScaledValue (decimal , ((DecimalType ) type ).getScale ());
124
+ }
125
+ return Decimals .encodeScaledValue (decimal , ((DecimalType ) type ).getScale ());
126
+ }
127
+ if (type instanceof VarcharType ) {
128
+ return value ;
129
+ }
130
+ if (type .equals (DateType .DATE )) {
131
+ return LocalDate .parse ((String ) value ).toEpochDay ();
132
+ }
133
+ if (type instanceof TimestampType ) {
134
+ return Instant .parse ((String ) value ).toEpochMilli () * MICROSECONDS_PER_MILLISECOND ;
135
+ }
136
+ if (type instanceof RowType ) {
137
+ RowType rowType = (RowType ) type ;
138
+ Map <?, ?> values = (Map <?, ?>) value ;
139
+ List <Type > fieldTypes = rowType .getTypeParameters ();
140
+ BlockBuilder blockBuilder = new RowBlockBuilder (fieldTypes , null , 1 );
141
+ BlockBuilder singleRowBlockWriter = blockBuilder .beginBlockEntry ();
142
+ for (int i = 0 ; i < values .size (); ++i ) {
143
+ Type fieldType = fieldTypes .get (i );
144
+ Object fieldValue = toTrinoValue (fieldType , values .get (rowType .getFields ().get (i ).getName ().orElseThrow ()));
145
+ writeNativeValue (fieldType , singleRowBlockWriter , fieldValue );
146
+ }
147
+
148
+ blockBuilder .closeEntry ();
149
+ return blockBuilder .build ();
150
+ }
151
+
152
+ throw new UnsupportedOperationException ("Unsupported type: " + type );
153
+ }
154
+
155
+ public static Optional <Map <String , Object >> toJsonValues (Map <String , Type > columnTypeMapping , Optional <Map <String , Object >> values )
156
+ {
157
+ if (values .isEmpty ()) {
158
+ return values ;
159
+ }
160
+
161
+ Map <String , Object > jsonValues = new HashMap <>();
162
+ for (Map .Entry <String , Object > value : values .get ().entrySet ()) {
163
+ jsonValues .put (value .getKey (), toJsonValue (columnTypeMapping .get (value .getKey ()), value .getValue ()));
164
+ }
165
+ return Optional .of (jsonValues );
166
+ }
167
+
168
+ @ Nullable
169
+ private static Object toJsonValue (Type type , @ Nullable Object value )
170
+ {
171
+ if (value == null ) {
172
+ return null ;
173
+ }
174
+
175
+ if (type == SMALLINT || type == TINYINT || type == INTEGER || type == BIGINT ) {
176
+ return value ;
177
+ }
178
+ if (type == REAL ) {
179
+ return intBitsToFloat (toIntExact ((long ) value ));
180
+ }
181
+ if (type == DOUBLE ) {
182
+ return value ;
183
+ }
184
+ if (type instanceof DecimalType ) {
185
+ DecimalType decimalType = (DecimalType ) type ;
186
+ if (decimalType .isShort ()) {
187
+ return Decimals .toString ((long ) value , decimalType .getScale ());
188
+ }
189
+ return Decimals .toString ((Int128 ) value , decimalType .getScale ());
190
+ }
191
+
192
+ if (type instanceof VarcharType ) {
193
+ return ((Slice ) value ).toStringUtf8 ();
194
+ }
195
+ if (type == DateType .DATE ) {
196
+ return LocalDate .ofEpochDay ((long ) value ).format (ISO_LOCAL_DATE );
197
+ }
198
+ if (type == TIMESTAMP_TZ_MILLIS ) {
199
+ Instant ts = Instant .ofEpochMilli (unpackMillisUtc ((long ) value ));
200
+ return ISO_INSTANT .format (ZonedDateTime .ofInstant (ts , UTC ));
201
+ }
202
+
203
+ throw new UnsupportedOperationException ("Unsupported type: " + type );
204
+ }
205
+
74
206
public static Map <String , Object > jsonEncodeMin (Map <String , Optional <Statistics <?>>> stats , Map <String , Type > typeForColumn )
75
207
{
76
208
return jsonEncode (stats , typeForColumn , DeltaLakeParquetStatisticsUtils ::getMin );
0 commit comments