@@ -163,7 +163,7 @@ private static String grok(List<Column> previousOutput) {
163163 result .append (randomIdentifier ());
164164 } else {
165165 String fieldName = randomRawName (previousOutput );
166- if (fieldName . isEmpty ()) { // it's a bug, managed later, skipping for now
166+ if (fieldName == null ) {
167167 fieldName = randomIdentifier ();
168168 }
169169 result .append (fieldName );
@@ -191,7 +191,7 @@ private static String dissect(List<Column> previousOutput) {
191191 result .append (randomIdentifier ());
192192 } else {
193193 String fieldName = randomRawName (previousOutput );
194- if (fieldName . isEmpty ()) { // it's a bug, managed later, skipping for now
194+ if (fieldName == null ) {
195195 fieldName = randomIdentifier ();
196196 }
197197 result .append (fieldName );
@@ -210,6 +210,9 @@ private static String keep(List<Column> previousOutput) {
210210 proj .add ("*" );
211211 } else {
212212 String name = randomName (previousOutput );
213+ if (name == null ) {
214+ continue ;
215+ }
213216 if (name .length () > 1 && name .startsWith ("`" ) == false && randomIntBetween (0 , 100 ) < 10 ) {
214217 if (randomBoolean ()) {
215218 name = name .substring (0 , randomIntBetween (1 , name .length () - 1 )) + "*" ;
@@ -220,31 +223,42 @@ private static String keep(List<Column> previousOutput) {
220223 proj .add (name );
221224 }
222225 }
226+ if (proj .isEmpty ()) {
227+ return "" ;
228+ }
223229 return " | keep " + proj .stream ().collect (Collectors .joining (", " ));
224230 }
225231
226232 private static String randomName (List <Column > previousOutput ) {
227233 String result = randomRawName (previousOutput );
228- if ((randomBoolean () && result .contains ("*" ) == false )) {
234+ if (result == null ) {
235+ return null ;
236+ }
237+ if (randomBoolean () && result .contains ("*" ) == false ) {
229238 result = "`" + result + "`" ;
230239 }
231240 return result ;
232241 }
233242
243+ /**
244+ * Returns a field name from a list of columns.
245+ * Could be null if none of the fields can be considered
246+ */
234247 private static String randomRawName (List <Column > previousOutput ) {
235- // we need to exclude <all-fields-projected>
236- // https://github.com/elastic/elasticsearch/issues/121741
237- String result = randomFrom (previousOutput .stream ().filter (x -> x .name ().equals ("<all-fields-projected>" ) == false ).toList ()).name ();
248+ var list = previousOutput .stream ().filter (EsqlQueryGenerator ::fieldCanBeUsed ).toList ();
249+ if (list .isEmpty ()) {
250+ return null ;
251+ }
252+ String result = randomFrom (list ).name ();
238253 return result ;
239254 }
240255
256+ /**
257+ * Returns a field that can be used for grouping.
258+ * Can return null
259+ */
241260 private static String randomGroupableName (List <Column > previousOutput ) {
242- // we need to exclude <all-fields-projected>
243- // https://github.com/elastic/elasticsearch/issues/121741
244- var candidates = previousOutput .stream ()
245- .filter (EsqlQueryGenerator ::groupable )
246- .filter (x -> x .name ().equals ("<all-fields-projected>" ) == false )
247- .toList ();
261+ var candidates = previousOutput .stream ().filter (EsqlQueryGenerator ::groupable ).filter (EsqlQueryGenerator ::fieldCanBeUsed ).toList ();
248262 if (candidates .isEmpty ()) {
249263 return null ;
250264 }
@@ -260,13 +274,12 @@ private static boolean groupable(Column col) {
260274 || col .type .equals ("version" );
261275 }
262276
277+ /**
278+ * returns a field that can be sorted.
279+ * Null if no fields are sortable.
280+ */
263281 private static String randomSortableName (List <Column > previousOutput ) {
264- // we need to exclude <all-fields-projected>
265- // https://github.com/elastic/elasticsearch/issues/121741
266- var candidates = previousOutput .stream ()
267- .filter (EsqlQueryGenerator ::sortable )
268- .filter (x -> x .name ().equals ("<all-fields-projected>" ) == false )
269- .toList ();
282+ var candidates = previousOutput .stream ().filter (EsqlQueryGenerator ::sortable ).filter (EsqlQueryGenerator ::fieldCanBeUsed ).toList ();
270283 if (candidates .isEmpty ()) {
271284 return null ;
272285 }
@@ -290,10 +303,18 @@ private static String rename(List<Column> previousOutput) {
290303 for (Column column : previousOutput ) {
291304 nameToType .put (column .name , column .type );
292305 }
293- List <String > names = new ArrayList <>(previousOutput .stream ().map (Column ::name ).collect (Collectors .toList ()));
306+ List <String > names = new ArrayList <>(
307+ previousOutput .stream ().filter (EsqlQueryGenerator ::fieldCanBeUsed ).map (Column ::name ).collect (Collectors .toList ())
308+ );
309+ if (names .isEmpty ()) {
310+ return "" ;
311+ }
294312 for (int i = 0 ; i < n ; i ++) {
313+ if (names .isEmpty ()) {
314+ break ;
315+ }
295316 var name = randomFrom (names );
296- if (name . equals ( "<all-fields-projected>" ) || nameToType .get (name ).endsWith ("_range" )) {
317+ if (nameToType .get (name ).endsWith ("_range" )) {
297318 // ranges are not fully supported yet
298319 continue ;
299320 }
@@ -306,9 +327,6 @@ private static String rename(List<Column> previousOutput) {
306327 } else {
307328 newName = names .get (randomIntBetween (0 , names .size () - 1 ));
308329 }
309- if (newName .equals ("<all-fields-projected>" )) { // it's a bug, managed as an error later
310- continue ;
311- }
312330 nameToType .put (newName , nameToType .get (name ));
313331 if (randomBoolean () && name .startsWith ("`" ) == false ) {
314332 name = "`" + name + "`" ;
@@ -332,6 +350,9 @@ private static String drop(List<Column> previousOutput) {
332350 Set <String > proj = new HashSet <>();
333351 for (int i = 0 ; i < n ; i ++) {
334352 String name = randomRawName (previousOutput );
353+ if (name == null ) {
354+ continue ;
355+ }
335356 if (name .length () > 1 && name .startsWith ("`" ) == false && randomIntBetween (0 , 100 ) < 10 ) {
336357 if (randomBoolean ()) {
337358 name = name .substring (0 , randomIntBetween (1 , name .length () - 1 )) + "*" ;
@@ -343,6 +364,9 @@ private static String drop(List<Column> previousOutput) {
343364 }
344365 proj .add (name );
345366 }
367+ if (proj .isEmpty ()) {
368+ return "" ;
369+ }
346370 return " | drop " + proj .stream ().collect (Collectors .joining (", " ));
347371 }
348372
@@ -363,7 +387,11 @@ private static String sort(List<Column> previousOutput) {
363387 }
364388
365389 private static String mvExpand (List <Column > previousOutput ) {
366- return " | mv_expand " + randomName (previousOutput );
390+ String toExpand = randomName (previousOutput );
391+ if (toExpand == null ) {
392+ return "" ; // no columns to expand
393+ }
394+ return " | mv_expand " + toExpand ;
367395 }
368396
369397 private static String eval (List <Column > previousOutput ) {
@@ -376,6 +404,9 @@ private static String eval(List<Column> previousOutput) {
376404 name = randomIdentifier ();
377405 } else {
378406 name = randomName (previousOutput );
407+ if (name == null ) {
408+ name = randomIdentifier ();
409+ }
379410 }
380411 String expression = expression (previousOutput );
381412 if (i > 0 ) {
@@ -390,7 +421,10 @@ private static String eval(List<Column> previousOutput) {
390421 }
391422
392423 private static String stats (List <Column > previousOutput ) {
393- List <Column > nonNull = previousOutput .stream ().filter (x -> x .type ().equals ("null" ) == false ).collect (Collectors .toList ());
424+ List <Column > nonNull = previousOutput .stream ()
425+ .filter (EsqlQueryGenerator ::fieldCanBeUsed )
426+ .filter (x -> x .type ().equals ("null" ) == false )
427+ .collect (Collectors .toList ());
394428 if (nonNull .isEmpty ()) {
395429 return "" ; // cannot do any stats, just skip
396430 }
@@ -402,6 +436,9 @@ private static String stats(List<Column> previousOutput) {
402436 name = randomIdentifier ();
403437 } else {
404438 name = randomName (previousOutput );
439+ if (name == null ) {
440+ name = randomIdentifier ();
441+ }
405442 }
406443 String expression = agg (nonNull );
407444 if (i > 0 ) {
@@ -433,6 +470,9 @@ private static String agg(List<Column> previousOutput) {
433470 }
434471 // all types
435472 name = randomName (previousOutput );
473+ if (name == null ) {
474+ return "count(*)" ;
475+ }
436476 return switch (randomIntBetween (0 , 2 )) {
437477 case 0 -> "count(*)" ;
438478 case 1 -> "count(" + name + ")" ;
@@ -529,4 +569,12 @@ private static String randomIdentifier() {
529569 return randomAlphaOfLength (randomIntBetween (8 , 12 ));
530570 }
531571
572+ private static boolean fieldCanBeUsed (Column field ) {
573+ return (
574+ // https://github.com/elastic/elasticsearch/issues/121741
575+ field .name ().equals ("<all-fields-projected>" )
576+ // this is a known pathological case, no need to test it for now
577+ || field .name ().equals ("<no-fields>" )) == false ;
578+ }
579+
532580}
0 commit comments