1313 */
1414package io .trino .operator .scalar ;
1515
16+ import com .fasterxml .jackson .core .io .JsonStringEncoder ;
1617import com .google .common .collect .ImmutableList ;
1718import io .airlift .slice .Slice ;
1819import io .trino .annotation .UsedByGeneratedCode ;
1920import io .trino .metadata .SqlScalarFunction ;
2021import io .trino .spi .TrinoException ;
2122import io .trino .spi .block .Block ;
23+ import io .trino .spi .block .SqlMap ;
2224import io .trino .spi .block .SqlRow ;
2325import io .trino .spi .connector .ConnectorSession ;
2426import io .trino .spi .function .BoundSignature ;
2830import io .trino .spi .function .FunctionDependencyDeclaration .FunctionDependencyDeclarationBuilder ;
2931import io .trino .spi .function .FunctionMetadata ;
3032import io .trino .spi .function .Signature ;
33+ import io .trino .spi .type .ArrayType ;
3134import io .trino .spi .type .CharType ;
3235import io .trino .spi .type .DecimalType ;
3336import io .trino .spi .type .Int128 ;
37+ import io .trino .spi .type .MapType ;
3438import io .trino .spi .type .RowType ;
3539import io .trino .spi .type .TimeType ;
3640import io .trino .spi .type .TimestampType ;
3741import io .trino .spi .type .TimestampWithTimeZoneType ;
3842import io .trino .spi .type .Type ;
3943import io .trino .spi .type .TypeSignature ;
44+ import io .trino .spi .type .UuidType ;
45+ import io .trino .spi .type .VarbinaryType ;
4046import io .trino .spi .type .VarcharType ;
4147
4248import java .lang .invoke .MethodHandle ;
4349import java .math .BigDecimal ;
4450import java .time .LocalDate ;
4551import java .time .LocalTime ;
52+ import java .util .Base64 ;
4653import java .util .IllegalFormatException ;
4754import java .util .List ;
4855import java .util .function .BiFunction ;
@@ -124,7 +131,21 @@ private static void addDependencies(FunctionDependencyDeclarationBuilder builder
124131 type instanceof TimeType ||
125132 type instanceof DecimalType ||
126133 type instanceof VarcharType ||
127- type instanceof CharType ) {
134+ type instanceof CharType ||
135+ type instanceof VarbinaryType ) {
136+ return ;
137+ }
138+ if (type instanceof ArrayType arrayType ) {
139+ addDependencies (builder , arrayType .getElementType ());
140+ return ;
141+ }
142+ if (type instanceof MapType mapType ) {
143+ addDependencies (builder , mapType .getKeyType ());
144+ addDependencies (builder , mapType .getValueType ());
145+ return ;
146+ }
147+ if (type instanceof RowType rowType ) {
148+ rowType .getTypeParameters ().forEach (t -> addDependencies (builder , t ));
128149 return ;
129150 }
130151
@@ -236,6 +257,18 @@ private static BiFunction<Block, Integer, Object> valueConverter(FunctionDepende
236257 if (type instanceof CharType charType ) {
237258 return (block , position ) -> padSpaces (charType .getSlice (block , position ), charType ).toStringUtf8 ();
238259 }
260+ if (type instanceof RowType rowType ) {
261+ return (block , position ) -> rowToString (functionDependencies , rowType , (SqlRow ) rowType .getObject (block , position ));
262+ }
263+ if (type instanceof MapType mapType ) {
264+ return (block , position ) -> mapToString (functionDependencies , mapType , (SqlMap ) mapType .getObject (block , position ));
265+ }
266+ if (type instanceof ArrayType arrayType ) {
267+ return (block , position ) -> arrayToString (functionDependencies , arrayType , (Block ) arrayType .getObject (block , position ));
268+ }
269+ if (type instanceof VarbinaryType varbinaryType ) {
270+ return (block , position ) -> Base64 .getEncoder ().encodeToString (varbinaryType .getSlice (block , position ).getBytes ());
271+ }
239272
240273 BiFunction <Block , Integer , Object > function ;
241274 if (type .getJavaType () == long .class ) {
@@ -258,6 +291,63 @@ else if (type.getJavaType() == Slice.class) {
258291 return (block , position ) -> convertToString (handle , function .apply (block , position ));
259292 }
260293
294+ private static Object quotedValue (FunctionDependencies functionDependencies , Type type , Block block , int position )
295+ {
296+ Object value = FormatFunction .converter (functionDependencies , type ).apply (block , position );
297+ if (value != null && (
298+ type instanceof VarcharType ||
299+ type instanceof CharType ||
300+ type instanceof VarbinaryType ||
301+ type instanceof UuidType )) {
302+ return String .format ("\" %s\" " , new String (JsonStringEncoder .getInstance ().quoteAsString ((String ) value )));
303+ }
304+ return value ;
305+ }
306+
307+ private static String rowToString (FunctionDependencies functionDependencies , RowType rowType , SqlRow row )
308+ {
309+ List <RowType .Field > fields = rowType .getFields ();
310+ boolean hasAllFieldNames = fields .stream ().allMatch (field -> field .getName ().isPresent ());
311+ StringBuilder builder = new StringBuilder (hasAllFieldNames ? "{" : "[" );
312+ int rawIndex = row .getRawIndex ();
313+ for (int i = 0 ; i < fields .size (); i ++) {
314+ builder .append (i == 0 ? "" : ", " );
315+ if (hasAllFieldNames ) {
316+ String fieldName = fields .get (i ).getName ().get ();
317+ builder .append ('"' ).append (new String (JsonStringEncoder .getInstance ().quoteAsString (fieldName ))).append ("\" : " );
318+ }
319+ builder .append (quotedValue (functionDependencies , fields .get (i ).getType (), row .getRawFieldBlock (i ), rawIndex ));
320+ }
321+ return builder .append (hasAllFieldNames ? '}' : ']' ).toString ();
322+ }
323+
324+ private static String mapToString (FunctionDependencies functionDependencies , MapType mapType , SqlMap sqlMap )
325+ {
326+ StringBuilder builder = new StringBuilder ("{" );
327+ Block keys = sqlMap .getRawKeyBlock ();
328+ Block values = sqlMap .getRawValueBlock ();
329+ int rawOffset = sqlMap .getRawOffset ();
330+ for (int i = 0 ; i < sqlMap .getSize (); i ++) {
331+ builder
332+ .append (i == 0 ? "" : ", " )
333+ .append (quotedValue (functionDependencies , mapType .getKeyType (), keys , rawOffset + i ))
334+ .append (": " )
335+ .append (quotedValue (functionDependencies , mapType .getValueType (), values , rawOffset + i ));
336+ }
337+ return builder .append ('}' ).toString ();
338+ }
339+
340+ private static String arrayToString (FunctionDependencies functionDependencies , ArrayType arrayType , Block elementBlock )
341+ {
342+ StringBuilder builder = new StringBuilder ("[" );
343+ for (int i = 0 ; i < elementBlock .getPositionCount (); i ++) {
344+ builder
345+ .append (i == 0 ? "" : ", " )
346+ .append (quotedValue (functionDependencies , arrayType .getElementType (), elementBlock , i ));
347+ }
348+ return builder .append (']' ).toString ();
349+ }
350+
261351 private static LocalTime toLocalTime (long value )
262352 {
263353 long nanoOfDay = roundDiv (value , PICOSECONDS_PER_NANOSECOND );
0 commit comments