|
@@ -56,6 +56,7 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Case;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Greatest;
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Greatest;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Least;
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Least;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
|
|
|
|
|
+import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ConvertFunction;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FoldablesConvertFunction;
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FoldablesConvertFunction;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDateNanos;
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDateNanos;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble;
|
|
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble;
|
|
@@ -70,6 +71,7 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In;
|
|
|
import org.elasticsearch.xpack.esql.index.EsIndex;
|
|
import org.elasticsearch.xpack.esql.index.EsIndex;
|
|
|
import org.elasticsearch.xpack.esql.index.IndexResolution;
|
|
import org.elasticsearch.xpack.esql.index.IndexResolution;
|
|
|
import org.elasticsearch.xpack.esql.inference.ResolvedInference;
|
|
import org.elasticsearch.xpack.esql.inference.ResolvedInference;
|
|
|
|
|
+import org.elasticsearch.xpack.esql.optimizer.rules.logical.SubstituteSurrogateExpressions;
|
|
|
import org.elasticsearch.xpack.esql.parser.ParsingException;
|
|
import org.elasticsearch.xpack.esql.parser.ParsingException;
|
|
|
import org.elasticsearch.xpack.esql.plan.IndexPattern;
|
|
import org.elasticsearch.xpack.esql.plan.IndexPattern;
|
|
|
import org.elasticsearch.xpack.esql.plan.logical.Aggregate;
|
|
import org.elasticsearch.xpack.esql.plan.logical.Aggregate;
|
|
@@ -1450,10 +1452,12 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
int alreadyAddedUnionFieldAttributes = unionFieldAttributes.size();
|
|
int alreadyAddedUnionFieldAttributes = unionFieldAttributes.size();
|
|
|
// See if the eval function has an unresolved MultiTypeEsField field
|
|
// See if the eval function has an unresolved MultiTypeEsField field
|
|
|
// Replace the entire convert function with a new FieldAttribute (containing type conversion knowledge)
|
|
// Replace the entire convert function with a new FieldAttribute (containing type conversion knowledge)
|
|
|
- plan = plan.transformExpressionsOnly(
|
|
|
|
|
- AbstractConvertFunction.class,
|
|
|
|
|
- convert -> resolveConvertFunction(convert, unionFieldAttributes)
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ plan = plan.transformExpressionsOnly(e -> {
|
|
|
|
|
+ if (e instanceof ConvertFunction convert) {
|
|
|
|
|
+ return resolveConvertFunction(convert, unionFieldAttributes);
|
|
|
|
|
+ }
|
|
|
|
|
+ return e;
|
|
|
|
|
+ });
|
|
|
// If no union fields were generated, return the plan as is
|
|
// If no union fields were generated, return the plan as is
|
|
|
if (unionFieldAttributes.size() == alreadyAddedUnionFieldAttributes) {
|
|
if (unionFieldAttributes.size() == alreadyAddedUnionFieldAttributes) {
|
|
|
return plan;
|
|
return plan;
|
|
@@ -1484,7 +1488,8 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
return plan;
|
|
return plan;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private Expression resolveConvertFunction(AbstractConvertFunction convert, List<FieldAttribute> unionFieldAttributes) {
|
|
|
|
|
|
|
+ private Expression resolveConvertFunction(ConvertFunction convert, List<FieldAttribute> unionFieldAttributes) {
|
|
|
|
|
+ Expression convertExpression = (Expression) convert;
|
|
|
if (convert.field() instanceof FieldAttribute fa && fa.field() instanceof InvalidMappedField imf) {
|
|
if (convert.field() instanceof FieldAttribute fa && fa.field() instanceof InvalidMappedField imf) {
|
|
|
HashMap<TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
|
|
HashMap<TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
|
|
|
Set<DataType> supportedTypes = convert.supportedTypes();
|
|
Set<DataType> supportedTypes = convert.supportedTypes();
|
|
@@ -1517,7 +1522,7 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
// example, an expression like multiTypeEsField(synthetic=false, date_nanos)::date_nanos::datetime is rewritten to
|
|
// example, an expression like multiTypeEsField(synthetic=false, date_nanos)::date_nanos::datetime is rewritten to
|
|
|
// multiTypeEsField(synthetic=true, date_nanos)::datetime, the implicit casting is overwritten by explicit casting and
|
|
// multiTypeEsField(synthetic=true, date_nanos)::datetime, the implicit casting is overwritten by explicit casting and
|
|
|
// the multiTypeEsField is not casted to datetime directly.
|
|
// the multiTypeEsField is not casted to datetime directly.
|
|
|
- if (convert.dataType() == mtf.getDataType()) {
|
|
|
|
|
|
|
+ if (((Expression) convert).dataType() == mtf.getDataType()) {
|
|
|
return createIfDoesNotAlreadyExist(fa, mtf, unionFieldAttributes);
|
|
return createIfDoesNotAlreadyExist(fa, mtf, unionFieldAttributes);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1531,21 +1536,23 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
String indexName = entry.getKey();
|
|
String indexName = entry.getKey();
|
|
|
AbstractConvertFunction originalConversionFunction = (AbstractConvertFunction) entry.getValue();
|
|
AbstractConvertFunction originalConversionFunction = (AbstractConvertFunction) entry.getValue();
|
|
|
Expression originalField = originalConversionFunction.field();
|
|
Expression originalField = originalConversionFunction.field();
|
|
|
- Expression newConvertFunction = convert.replaceChildren(Collections.singletonList(originalField));
|
|
|
|
|
|
|
+ Expression newConvertFunction = convertExpression.replaceChildren(Collections.singletonList(originalField));
|
|
|
indexToConversionExpressions.put(indexName, newConvertFunction);
|
|
indexToConversionExpressions.put(indexName, newConvertFunction);
|
|
|
}
|
|
}
|
|
|
MultiTypeEsField multiTypeEsField = new MultiTypeEsField(
|
|
MultiTypeEsField multiTypeEsField = new MultiTypeEsField(
|
|
|
fa.fieldName().string(),
|
|
fa.fieldName().string(),
|
|
|
- convert.dataType(),
|
|
|
|
|
|
|
+ convertExpression.dataType(),
|
|
|
false,
|
|
false,
|
|
|
indexToConversionExpressions
|
|
indexToConversionExpressions
|
|
|
);
|
|
);
|
|
|
return createIfDoesNotAlreadyExist(fa, multiTypeEsField, unionFieldAttributes);
|
|
return createIfDoesNotAlreadyExist(fa, multiTypeEsField, unionFieldAttributes);
|
|
|
}
|
|
}
|
|
|
} else if (convert.field() instanceof AbstractConvertFunction subConvert) {
|
|
} else if (convert.field() instanceof AbstractConvertFunction subConvert) {
|
|
|
- return convert.replaceChildren(Collections.singletonList(resolveConvertFunction(subConvert, unionFieldAttributes)));
|
|
|
|
|
|
|
+ return convertExpression.replaceChildren(
|
|
|
|
|
+ Collections.singletonList(resolveConvertFunction(subConvert, unionFieldAttributes))
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
- return convert;
|
|
|
|
|
|
|
+ return convertExpression;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private Expression createIfDoesNotAlreadyExist(
|
|
private Expression createIfDoesNotAlreadyExist(
|
|
@@ -1594,12 +1601,7 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private static Expression typeSpecificConvert(
|
|
|
|
|
- AbstractConvertFunction convert,
|
|
|
|
|
- Source source,
|
|
|
|
|
- DataType type,
|
|
|
|
|
- InvalidMappedField mtf
|
|
|
|
|
- ) {
|
|
|
|
|
|
|
+ private static Expression typeSpecificConvert(ConvertFunction convert, Source source, DataType type, InvalidMappedField mtf) {
|
|
|
EsField field = new EsField(mtf.getName(), type, mtf.getProperties(), mtf.isAggregatable());
|
|
EsField field = new EsField(mtf.getName(), type, mtf.getProperties(), mtf.isAggregatable());
|
|
|
FieldAttribute originalFieldAttr = (FieldAttribute) convert.field();
|
|
FieldAttribute originalFieldAttr = (FieldAttribute) convert.field();
|
|
|
FieldAttribute resolvedAttr = new FieldAttribute(
|
|
FieldAttribute resolvedAttr = new FieldAttribute(
|
|
@@ -1611,7 +1613,13 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
originalFieldAttr.id(),
|
|
originalFieldAttr.id(),
|
|
|
true
|
|
true
|
|
|
);
|
|
);
|
|
|
- return convert.replaceChildren(Collections.singletonList(resolvedAttr));
|
|
|
|
|
|
|
+ Expression e = ((Expression) convert).replaceChildren(Collections.singletonList(resolvedAttr));
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Resolve surrogates immediately because these type specific conversions are serialized
|
|
|
|
|
+ * and SurrogateExpressions are expected to be resolved on the coordinating node. At least,
|
|
|
|
|
+ * TO_IP is expected to be resolved there.
|
|
|
|
|
+ */
|
|
|
|
|
+ return SubstituteSurrogateExpressions.rule(e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1696,7 +1704,7 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
|
|
|
|
|
|
|
|
private static void typeResolutions(
|
|
private static void typeResolutions(
|
|
|
FieldAttribute fieldAttribute,
|
|
FieldAttribute fieldAttribute,
|
|
|
- AbstractConvertFunction convert,
|
|
|
|
|
|
|
+ ConvertFunction convert,
|
|
|
DataType type,
|
|
DataType type,
|
|
|
InvalidMappedField imf,
|
|
InvalidMappedField imf,
|
|
|
HashMap<ResolveUnionTypes.TypeResolutionKey, Expression> typeResolutions
|
|
HashMap<ResolveUnionTypes.TypeResolutionKey, Expression> typeResolutions
|