7676import org .elasticsearch .xpack .esql .plan .IndexPattern ;
7777import org .elasticsearch .xpack .esql .plan .logical .Aggregate ;
7878import org .elasticsearch .xpack .esql .plan .logical .Dedup ;
79- import org .elasticsearch .xpack .esql .plan .logical .Dissect ;
8079import org .elasticsearch .xpack .esql .plan .logical .Drop ;
8180import org .elasticsearch .xpack .esql .plan .logical .Enrich ;
8281import org .elasticsearch .xpack .esql .plan .logical .EsRelation ;
8382import org .elasticsearch .xpack .esql .plan .logical .Eval ;
8483import org .elasticsearch .xpack .esql .plan .logical .Fork ;
85- import org .elasticsearch .xpack .esql .plan .logical .Grok ;
8684import org .elasticsearch .xpack .esql .plan .logical .Insist ;
8785import org .elasticsearch .xpack .esql .plan .logical .Keep ;
8886import org .elasticsearch .xpack .esql .plan .logical .Limit ;
9189import org .elasticsearch .xpack .esql .plan .logical .MvExpand ;
9290import org .elasticsearch .xpack .esql .plan .logical .OrderBy ;
9391import org .elasticsearch .xpack .esql .plan .logical .Project ;
94- import org .elasticsearch .xpack .esql .plan .logical .RegexExtract ;
9592import org .elasticsearch .xpack .esql .plan .logical .Rename ;
9693import org .elasticsearch .xpack .esql .plan .logical .RrfScoreEval ;
9794import org .elasticsearch .xpack .esql .plan .logical .UnresolvedRelation ;
@@ -1065,7 +1062,10 @@ private LogicalPlan resolveEnrich(Enrich enrich, List<Attribute> childrenOutput)
10651062 final DataType dataType = resolved .dataType ();
10661063 String matchType = enrich .policy ().getType ();
10671064 DataType [] allowed = allowedEnrichTypes (matchType );
1068- if (Arrays .asList (allowed ).contains (dataType ) == false ) {
1065+ if (Arrays .asList (allowed ).contains (dataType ) == false && multiTypedField (resolved ) == null ) { // leave multi-typed
1066+ // fields to
1067+ // ImplicitCasting to
1068+ // deal with
10691069 String suffix = "only ["
10701070 + Arrays .stream (allowed ).map (DataType ::typeName ).collect (Collectors .joining (", " ))
10711071 + "] allowed for type ["
@@ -1269,10 +1269,10 @@ public LogicalPlan apply(LogicalPlan plan, AnalyzerContext context) {
12691269 if (p instanceof OrderBy
12701270 || p instanceof EsqlProject
12711271 || p instanceof Aggregate
1272- || p instanceof RegexExtract
12731272 || p instanceof MvExpand
12741273 || p instanceof Eval
1275- || p instanceof LookupJoin ) {
1274+ || p instanceof LookupJoin
1275+ || p instanceof Enrich ) {
12761276 return castInvalidMappedFieldInLogicalPlan (p , false );
12771277 }
12781278 return p ;
@@ -1317,10 +1317,10 @@ private static LogicalPlan castInvalidMappedFieldInLogicalPlan(LogicalPlan plan,
13171317 case EsqlProject project -> project .projections ();
13181318 case OrderBy ob -> ob .order ();
13191319 case Aggregate agg -> agg .groupings ();
1320- case RegexExtract re -> List .of (re .input ());
13211320 case MvExpand me -> List .of (me .target ());
1322- case Eval e -> e .fields ();
1321+ case Eval eval -> eval .fields ();
13231322 case LookupJoin lj -> lj .config ().leftFields ();
1323+ case Enrich enrich -> List .of (enrich .matchField ());
13241324 // The other types of plans are unexpected
13251325 default -> throw new EsqlIllegalArgumentException ("unexpected logical plan: " + plan );
13261326 };
@@ -1355,32 +1355,13 @@ private static LogicalPlan castInvalidMappedFieldInLogicalPlan(LogicalPlan plan,
13551355 }
13561356 return agg .with (evalForInvalidMappedField (agg .source (), agg .child (), aliases ), newProjections , newAggs );
13571357 }
1358- case Dissect d -> {
1359- return new Dissect (
1360- plan .source (),
1361- evalForInvalidMappedField (d .source (), d .child (), aliases ),
1362- newProjections .get (0 ),
1363- d .parser (),
1364- d .extractedFields ()
1365- );
1366- }
1367- case Grok g -> {
1368- return new Grok (
1369- plan .source (),
1370- evalForInvalidMappedField (g .source (), g .child (), aliases ),
1371- newProjections .get (0 ),
1372- g .parser (),
1373- g .extractedFields ()
1374- );
1375- }
13761358 case MvExpand mve -> {
13771359 NamedExpression newTarget = Expressions .attribute (newProjections .get (0 ));
13781360 return new MvExpand (
1379- plan .source (),
1361+ mve .source (),
13801362 evalForInvalidMappedField (mve .source (), mve .child (), aliases ),
13811363 newTarget ,
1382- new ReferenceAttribute (newTarget .source (), newTarget .name (), newTarget .dataType (), newTarget .nullable (),
1383- mve .expanded ().id (), false )
1364+ newTarget .toAttribute ()
13841365 );
13851366 }
13861367 case Eval ev -> {
@@ -1400,6 +1381,20 @@ private static LogicalPlan castInvalidMappedFieldInLogicalPlan(LogicalPlan plan,
14001381 newJoinConfig
14011382 );
14021383 }
1384+ case Enrich enrich -> {
1385+ NamedExpression newMatchField = Expressions .attribute (newProjections .get (0 ));
1386+ return new Enrich (
1387+ enrich .source (),
1388+ evalForInvalidMappedField (enrich .source (), enrich .child (), aliases ),
1389+ enrich .mode (),
1390+ enrich .policyName (),
1391+ // Let resolveEnrich check whether the data type is supported, e.g. Enrich does not support data_nanos
1392+ new UnresolvedAttribute (newMatchField .source (), newMatchField .name ()),
1393+ enrich .policy (),
1394+ enrich .concreteIndices (),
1395+ enrich .enrichFields ()
1396+ );
1397+ }
14031398 // The other types of plans are unexpected
14041399 default -> throw new EsqlIllegalArgumentException ("unexpected logical plan: " + plan );
14051400 }
@@ -1462,13 +1457,11 @@ private static Tuple<List<Alias>, List<Expression>> castInvalidMappedFields(
14621457 Expression e = Alias .unwrap (exp );
14631458 e = e instanceof Order o ? o .child () : e ;
14641459 String alias = exp instanceof Alias a ? a .name () : null ;
1465- if (e .resolved ()
1466- && e .dataType () == UNSUPPORTED
1467- && e instanceof FieldAttribute fa
1468- && fa .field () instanceof InvalidMappedField imf ) {
1460+ InvalidMappedField multiTypedField = multiTypedField (e );
1461+ if (multiTypedField != null ) {
14691462 // This is an invalid mapped field, find a common data type and cast to it.
14701463 DataType targetType = null ;
1471- for (DataType type : imf .types ()) {
1464+ for (DataType type : multiTypedField .types ()) {
14721465 if (targetType == null ) { // Initialize the target type to the first type.
14731466 targetType = type ;
14741467 } else {
@@ -1480,9 +1473,9 @@ private static Tuple<List<Alias>, List<Expression>> castInvalidMappedFields(
14801473 }
14811474 }
14821475 if (targetType != null && isRepresentable (targetType ) && (isMillisOrNanos (targetType ) || targetType .isNumeric ())) {
1483- alias = alias != null ? alias : fa . name ();
1484- Source source = fa .source ();
1485- Expression newChild = castInvalidMappedField (targetType , fa );
1476+ alias = alias != null ? alias : multiTypedField . getName ();
1477+ Source source = e .source ();
1478+ Expression newChild = castInvalidMappedField (targetType , e );
14861479 Alias newAlias = new Alias (source , alias , newChild );
14871480 newAliases .add (newAlias );
14881481 if (createNewChildPlan ) {
@@ -1525,7 +1518,7 @@ private static Eval evalForInvalidMappedField(Source source, LogicalPlan childPl
15251518 /**
15261519 * Do implicit casting for data, date_nanos and numeric types only
15271520 */
1528- private static Expression castInvalidMappedField (DataType targetType , FieldAttribute fa ) {
1521+ private static Expression castInvalidMappedField (DataType targetType , Expression fa ) {
15291522 Source source = fa .source ();
15301523 return switch (targetType ) {
15311524 case INTEGER -> new ToInteger (source , fa );
@@ -1956,4 +1949,15 @@ private static LogicalPlan planWithoutSyntheticAttributes(LogicalPlan plan) {
19561949 return newOutput .size () == output .size () ? plan : new Project (Source .EMPTY , plan , newOutput );
19571950 }
19581951 }
1952+
1953+ private static InvalidMappedField multiTypedField (Expression e ) {
1954+ Expression exp = Alias .unwrap (e );
1955+ if (exp .resolved ()
1956+ && exp .dataType () == UNSUPPORTED
1957+ && exp instanceof FieldAttribute fa
1958+ && fa .field () instanceof InvalidMappedField imf ) {
1959+ return imf ;
1960+ }
1961+ return null ;
1962+ }
19591963}
0 commit comments