1616import com .fasterxml .jackson .annotation .JsonCreator ;
1717import com .fasterxml .jackson .annotation .JsonIgnore ;
1818import com .fasterxml .jackson .annotation .JsonProperty ;
19+ import com .google .common .collect .ImmutableList ;
20+ import com .google .common .collect .Iterables ;
1921import io .trino .spi .connector .ColumnHandle ;
2022import io .trino .spi .type .Type ;
21- import io .trino .spi .type .TypeManager ;
22- import org .apache .iceberg .types .Types ;
2323
24+ import java .util .List ;
2425import java .util .Objects ;
2526import java .util .Optional ;
2627
27- import static io .trino .plugin .iceberg .ColumnIdentity .createColumnIdentity ;
28- import static io .trino .plugin .iceberg .ColumnIdentity .primitiveColumnIdentity ;
29- import static io .trino .plugin .iceberg .TypeConverter .toTrinoType ;
3028import static java .util .Objects .requireNonNull ;
3129
3230public class IcebergColumnHandle
3331 implements ColumnHandle
3432{
35- private final ColumnIdentity columnIdentity ;
33+ private final ColumnIdentity baseColumnIdentity ;
34+ private final Type baseType ;
35+ // The list of field ids to indicate the projected part of the top-level column represented by baseColumnIdentity
36+ private final List <Integer > path ;
3637 private final Type type ;
3738 private final Optional <String > comment ;
39+ // Cache of ColumnIdentity#getId to ensure quick access, even with dereferences
40+ private final int id ;
3841
3942 @ JsonCreator
4043 public IcebergColumnHandle (
41- @ JsonProperty ("columnIdentity" ) ColumnIdentity columnIdentity ,
44+ @ JsonProperty ("baseColumnIdentity" ) ColumnIdentity baseColumnIdentity ,
45+ @ JsonProperty ("baseType" ) Type baseType ,
46+ @ JsonProperty ("path" ) List <Integer > path ,
4247 @ JsonProperty ("type" ) Type type ,
4348 @ JsonProperty ("comment" ) Optional <String > comment )
4449 {
45- this .columnIdentity = requireNonNull (columnIdentity , "columnIdentity is null" );
50+ this .baseColumnIdentity = requireNonNull (baseColumnIdentity , "baseColumnIdentity is null" );
51+ this .baseType = requireNonNull (baseType , "baseType is null" );
52+ this .path = ImmutableList .copyOf (requireNonNull (path , "path is null" ));
4653 this .type = requireNonNull (type , "type is null" );
4754 this .comment = requireNonNull (comment , "comment is null" );
55+ this .id = path .isEmpty () ? baseColumnIdentity .getId () : Iterables .getLast (path );
4856 }
4957
50- @ JsonProperty
58+ @ JsonIgnore
5159 public ColumnIdentity getColumnIdentity ()
5260 {
61+ ColumnIdentity columnIdentity = baseColumnIdentity ;
62+ for (int fieldId : path ) {
63+ columnIdentity = columnIdentity .getChildByFieldId (fieldId );
64+ }
5365 return columnIdentity ;
5466 }
5567
@@ -59,6 +71,24 @@ public Type getType()
5971 return type ;
6072 }
6173
74+ @ JsonProperty
75+ public ColumnIdentity getBaseColumnIdentity ()
76+ {
77+ return baseColumnIdentity ;
78+ }
79+
80+ @ JsonProperty
81+ public Type getBaseType ()
82+ {
83+ return baseType ;
84+ }
85+
86+ @ JsonIgnore
87+ public IcebergColumnHandle getBaseColumn ()
88+ {
89+ return new IcebergColumnHandle (getBaseColumnIdentity (), getBaseType (), ImmutableList .of (), getBaseType (), Optional .empty ());
90+ }
91+
6292 @ JsonProperty
6393 public Optional <String > getComment ()
6494 {
@@ -68,19 +98,50 @@ public Optional<String> getComment()
6898 @ JsonIgnore
6999 public int getId ()
70100 {
71- return columnIdentity . getId () ;
101+ return id ;
72102 }
73103
104+ /**
105+ * For nested columns, this is the unqualified name of the last field in the path
106+ */
74107 @ JsonIgnore
75108 public String getName ()
76109 {
77- return columnIdentity .getName ();
110+ return getColumnIdentity ().getName ();
111+ }
112+
113+ @ JsonProperty
114+ public List <Integer > getPath ()
115+ {
116+ return path ;
117+ }
118+
119+ /**
120+ * The dot separated path components used to address this column, including all dereferences and the column name.
121+ */
122+ @ JsonIgnore
123+ public String getQualifiedName ()
124+ {
125+ ImmutableList .Builder <String > pathNames = ImmutableList .builder ();
126+ ColumnIdentity columnIdentity = baseColumnIdentity ;
127+ pathNames .add (columnIdentity .getName ());
128+ for (int fieldId : path ) {
129+ columnIdentity = columnIdentity .getChildByFieldId (fieldId );
130+ pathNames .add (columnIdentity .getName ());
131+ }
132+ // Iceberg tables are guaranteed not to have ambiguous column names so joining them like this must uniquely identify a single column.
133+ return String .join ("." , pathNames .build ());
134+ }
135+
136+ public boolean isBaseColumn ()
137+ {
138+ return path .isEmpty ();
78139 }
79140
80141 @ Override
81142 public int hashCode ()
82143 {
83- return Objects .hash (columnIdentity , type , comment );
144+ return Objects .hash (baseColumnIdentity , baseType , path , type , comment );
84145 }
85146
86147 @ Override
@@ -93,7 +154,9 @@ public boolean equals(Object obj)
93154 return false ;
94155 }
95156 IcebergColumnHandle other = (IcebergColumnHandle ) obj ;
96- return Objects .equals (this .columnIdentity , other .columnIdentity ) &&
157+ return Objects .equals (this .baseColumnIdentity , other .baseColumnIdentity ) &&
158+ Objects .equals (this .baseType , other .baseType ) &&
159+ Objects .equals (this .path , other .path ) &&
97160 Objects .equals (this .type , other .type ) &&
98161 Objects .equals (this .comment , other .comment );
99162 }
@@ -103,17 +166,4 @@ public String toString()
103166 {
104167 return getId () + ":" + getName () + ":" + type .getDisplayName ();
105168 }
106-
107- public static IcebergColumnHandle primitiveIcebergColumnHandle (int id , String name , Type type , Optional <String > comment )
108- {
109- return new IcebergColumnHandle (primitiveColumnIdentity (id , name ), type , comment );
110- }
111-
112- public static IcebergColumnHandle create (Types .NestedField column , TypeManager typeManager )
113- {
114- return new IcebergColumnHandle (
115- createColumnIdentity (column ),
116- toTrinoType (column .type (), typeManager ),
117- Optional .ofNullable (column .doc ()));
118- }
119169}
0 commit comments