66 */
77package org .elasticsearch .xpack .esql .core .expression ;
88
9- import org .elasticsearch .TransportVersions ;
109import org .elasticsearch .common .Strings ;
1110import org .elasticsearch .common .io .stream .NamedWriteableRegistry ;
1211import org .elasticsearch .common .io .stream .StreamInput ;
1312import org .elasticsearch .common .io .stream .StreamOutput ;
14- import org .elasticsearch .core .Nullable ;
1513import org .elasticsearch .xpack .esql .core .tree .NodeInfo ;
1614import org .elasticsearch .xpack .esql .core .tree .Source ;
1715import org .elasticsearch .xpack .esql .core .type .DataType ;
1816import org .elasticsearch .xpack .esql .core .type .EsField ;
1917import org .elasticsearch .xpack .esql .core .util .PlanStreamInput ;
2018import org .elasticsearch .xpack .esql .core .util .PlanStreamOutput ;
19+ import org .elasticsearch .xpack .esql .core .util .StringUtils ;
2120
2221import java .io .IOException ;
2322import java .util .Objects ;
2423
25- import static org .elasticsearch .xpack .esql .core .util .PlanStreamInput .readCachedStringWithVersionCheck ;
26- import static org .elasticsearch .xpack .esql .core .util .PlanStreamOutput .writeCachedStringWithVersionCheck ;
27-
2824/**
2925 * Attribute for an ES field.
3026 * To differentiate between the different type of fields this class offers:
@@ -41,31 +37,32 @@ public class FieldAttribute extends TypedAttribute {
4137 FieldAttribute ::readFrom
4238 );
4339
44- private final String parentName ;
40+ private final FieldAttribute parent ;
41+ private final String path ;
4542 private final EsField field ;
4643
4744 public FieldAttribute (Source source , String name , EsField field ) {
4845 this (source , null , name , field );
4946 }
5047
51- public FieldAttribute (Source source , @ Nullable String parentName , String name , EsField field ) {
52- this (source , parentName , name , field , Nullability .TRUE , null , false );
48+ public FieldAttribute (Source source , FieldAttribute parent , String name , EsField field ) {
49+ this (source , parent , name , field , Nullability .TRUE , null , false );
5350 }
5451
55- public FieldAttribute (Source source , @ Nullable String parentName , String name , EsField field , boolean synthetic ) {
56- this (source , parentName , name , field , Nullability .TRUE , null , synthetic );
52+ public FieldAttribute (Source source , FieldAttribute parent , String name , EsField field , boolean synthetic ) {
53+ this (source , parent , name , field , Nullability .TRUE , null , synthetic );
5754 }
5855
5956 public FieldAttribute (
6057 Source source ,
61- @ Nullable String parentName ,
58+ FieldAttribute parent ,
6259 String name ,
6360 EsField field ,
6461 Nullability nullability ,
65- @ Nullable NameId id ,
62+ NameId id ,
6663 boolean synthetic
6764 ) {
68- this (source , parentName , name , field .getDataType (), field , nullability , id , synthetic );
65+ this (source , parent , name , field .getDataType (), field , nullability , id , synthetic );
6966 }
7067
7168 /**
@@ -74,16 +71,17 @@ public FieldAttribute(
7471 */
7572 FieldAttribute (
7673 Source source ,
77- @ Nullable String parentName ,
74+ FieldAttribute parent ,
7875 String name ,
7976 DataType type ,
8077 EsField field ,
8178 Nullability nullability ,
82- @ Nullable NameId id ,
79+ NameId id ,
8380 boolean synthetic
8481 ) {
8582 super (source , name , type , nullability , id , synthetic );
86- this .parentName = parentName ;
83+ this .path = parent != null ? parent .name () : StringUtils .EMPTY ;
84+ this .parent = parent ;
8785 this .field = field ;
8886 }
8987
@@ -93,16 +91,16 @@ public FieldAttribute(
9391 */
9492 private FieldAttribute (
9593 Source source ,
96- @ Nullable String parentName ,
94+ FieldAttribute parent ,
9795 String name ,
9896 DataType type ,
9997 EsField field ,
100- @ Nullable String qualifier ,
98+ String qualifier ,
10199 Nullability nullability ,
102- @ Nullable NameId id ,
100+ NameId id ,
103101 boolean synthetic
104102 ) {
105- this (source , parentName , name , type , field , nullability , id , synthetic );
103+ this (source , parent , name , type , field , nullability , id , synthetic );
106104 }
107105
108106 private FieldAttribute (StreamInput in ) throws IOException {
@@ -116,8 +114,8 @@ private FieldAttribute(StreamInput in) throws IOException {
116114 */
117115 this (
118116 Source .readFrom ((StreamInput & PlanStreamInput ) in ),
119- readParentName ( in ),
120- readCachedStringWithVersionCheck ( in ),
117+ in . readOptionalWriteable ( FieldAttribute :: readFrom ),
118+ (( PlanStreamInput ) in ). readCachedString ( ),
121119 DataType .readFrom (in ),
122120 EsField .readFrom (in ),
123121 in .readOptionalString (),
@@ -131,8 +129,8 @@ private FieldAttribute(StreamInput in) throws IOException {
131129 public void writeTo (StreamOutput out ) throws IOException {
132130 if (((PlanStreamOutput ) out ).writeAttributeCacheHeader (this )) {
133131 Source .EMPTY .writeTo (out );
134- writeParentName ( out );
135- writeCachedStringWithVersionCheck ( out , name ());
132+ out . writeOptionalWriteable ( parent );
133+ (( PlanStreamOutput ) out ). writeCachedString ( name ());
136134 dataType ().writeTo (out );
137135 field .writeTo (out );
138136 // We used to write the qualifier here. We can still do if needed in the future.
@@ -147,49 +145,22 @@ public static FieldAttribute readFrom(StreamInput in) throws IOException {
147145 return ((PlanStreamInput ) in ).readAttributeWithCache (FieldAttribute ::new );
148146 }
149147
150- private void writeParentName (StreamOutput out ) throws IOException {
151- if (out .getTransportVersion ().onOrAfter (TransportVersions .ESQL_FIELD_ATTRIBUTE_PARENT_SIMPLIFIED )) {
152- ((PlanStreamOutput ) out ).writeOptionalCachedString (parentName );
153- } else {
154- // Previous versions only used the parent field attribute to retrieve the parent's name, so we can use just any
155- // fake FieldAttribute here as long as the name is correct.
156- FieldAttribute fakeParent = parentName () == null ? null : new FieldAttribute (Source .EMPTY , parentName (), field ());
157- out .writeOptionalWriteable (fakeParent );
158- }
159- }
160-
161- private static String readParentName (StreamInput in ) throws IOException {
162- if (in .getTransportVersion ().onOrAfter (TransportVersions .ESQL_FIELD_ATTRIBUTE_PARENT_SIMPLIFIED )) {
163- return ((PlanStreamInput ) in ).readOptionalCachedString ();
164- }
165-
166- FieldAttribute parent = in .readOptionalWriteable (FieldAttribute ::readFrom );
167- return parent == null ? null : parent .name ();
168- }
169-
170148 @ Override
171149 public String getWriteableName () {
172150 return ENTRY .name ;
173151 }
174152
175153 @ Override
176154 protected NodeInfo <FieldAttribute > info () {
177- return NodeInfo .create (
178- this ,
179- FieldAttribute ::new ,
180- parentName ,
181- name (),
182- dataType (),
183- field ,
184- (String ) null ,
185- nullable (),
186- id (),
187- synthetic ()
188- );
155+ return NodeInfo .create (this , FieldAttribute ::new , parent , name (), dataType (), field , (String ) null , nullable (), id (), synthetic ());
156+ }
157+
158+ public FieldAttribute parent () {
159+ return parent ;
189160 }
190161
191- public String parentName () {
192- return parentName ;
162+ public String path () {
163+ return path ;
193164 }
194165
195166 /**
@@ -203,7 +174,7 @@ public String fieldName() {
203174 if ((synthetic () || name ().startsWith (SYNTHETIC_ATTRIBUTE_NAME_PREFIX )) == false ) {
204175 return name ();
205176 }
206- return Strings .hasText (parentName ) ? parentName + "." + field .getName () : field .getName ();
177+ return Strings .hasText (path ) ? path + "." + field .getName () : field .getName ();
207178 }
208179
209180 public EsField .Exact getExactInfo () {
@@ -219,13 +190,13 @@ public FieldAttribute exactAttribute() {
219190 }
220191
221192 private FieldAttribute innerField (EsField type ) {
222- return new FieldAttribute (source (), name () , name () + "." + type .getName (), type , nullable (), id (), synthetic ());
193+ return new FieldAttribute (source (), this , name () + "." + type .getName (), type , nullable (), id (), synthetic ());
223194 }
224195
225196 @ Override
226197 protected Attribute clone (Source source , String name , DataType type , Nullability nullability , NameId id , boolean synthetic ) {
227198 // Ignore `type`, this must be the same as the field's type.
228- return new FieldAttribute (source , parentName , name , field , nullability , id , synthetic );
199+ return new FieldAttribute (source , parent , name , field , nullability , id , synthetic );
229200 }
230201
231202 @ Override
@@ -235,13 +206,13 @@ public Attribute withDataType(DataType type) {
235206
236207 @ Override
237208 public int hashCode () {
238- return Objects .hash (super .hashCode (), parentName , field );
209+ return Objects .hash (super .hashCode (), path , field );
239210 }
240211
241212 @ Override
242213 public boolean equals (Object obj ) {
243214 return super .equals (obj )
244- && Objects .equals (parentName , ((FieldAttribute ) obj ).parentName )
215+ && Objects .equals (path , ((FieldAttribute ) obj ).path )
245216 && Objects .equals (field , ((FieldAttribute ) obj ).field );
246217 }
247218
0 commit comments