[ESQL] Ensure date/date_nanos implicit casting rule behind snapshot (#130026)

* put date date_nanos implicit casting rule behind snapshot
This commit is contained in:
Fang Xing 2025-07-02 13:14:19 -04:00 committed by GitHub
parent a7a79f7612
commit c43a51d842
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 24 deletions

View File

@ -1,6 +0,0 @@
pr: 127797
summary: "Date nanos implicit casting in union types option #2"
area: ES|QL
type: enhancement
issues:
- 110009

View File

@ -134,6 +134,7 @@ import java.util.stream.Collectors;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.GEO_MATCH_TYPE; import static org.elasticsearch.xpack.core.enrich.EnrichPolicy.GEO_MATCH_TYPE;
import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.Cap.IMPLICIT_CASTING_DATE_AND_DATE_NANOS;
import static org.elasticsearch.xpack.esql.core.type.DataType.BOOLEAN; import static org.elasticsearch.xpack.esql.core.type.DataType.BOOLEAN;
import static org.elasticsearch.xpack.esql.core.type.DataType.DATETIME; import static org.elasticsearch.xpack.esql.core.type.DataType.DATETIME;
import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS; import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS;
@ -175,7 +176,7 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
new ResolveInference(), new ResolveInference(),
new ResolveLookupTables(), new ResolveLookupTables(),
new ResolveFunctions(), new ResolveFunctions(),
new DateMillisToNanosInEsRelation() new DateMillisToNanosInEsRelation(IMPLICIT_CASTING_DATE_AND_DATE_NANOS.isEnabled())
), ),
new Batch<>( new Batch<>(
"Resolution", "Resolution",
@ -1819,10 +1820,6 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
private static Expression typeSpecificConvert(ConvertFunction 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());
return typeSpecificConvert(convert, source, field);
}
private static Expression typeSpecificConvert(ConvertFunction convert, Source source, EsField field) {
FieldAttribute originalFieldAttr = (FieldAttribute) convert.field(); FieldAttribute originalFieldAttr = (FieldAttribute) convert.field();
FieldAttribute resolvedAttr = new FieldAttribute( FieldAttribute resolvedAttr = new FieldAttribute(
source, source,
@ -1902,23 +1899,42 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
* Cast the union typed fields in EsRelation to date_nanos if they are mixed date and date_nanos types. * Cast the union typed fields in EsRelation to date_nanos if they are mixed date and date_nanos types.
*/ */
private static class DateMillisToNanosInEsRelation extends Rule<LogicalPlan, LogicalPlan> { private static class DateMillisToNanosInEsRelation extends Rule<LogicalPlan, LogicalPlan> {
private final boolean isSnapshot;
DateMillisToNanosInEsRelation(boolean isSnapshot) {
this.isSnapshot = isSnapshot;
}
@Override @Override
public LogicalPlan apply(LogicalPlan plan) { public LogicalPlan apply(LogicalPlan plan) {
return plan.transformUp(EsRelation.class, relation -> { if (isSnapshot) {
if (relation.indexMode() == IndexMode.LOOKUP) { return plan.transformUp(EsRelation.class, relation -> {
return relation; if (relation.indexMode() == IndexMode.LOOKUP) {
} return relation;
return relation.transformExpressionsUp(FieldAttribute.class, f -> {
if (f.field() instanceof InvalidMappedField imf && imf.types().stream().allMatch(DataType::isDate)) {
HashMap<ResolveUnionTypes.TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
var convert = new ToDateNanos(f.source(), f);
imf.types().forEach(type -> typeResolutions(f, convert, type, imf, typeResolutions));
var resolvedField = ResolveUnionTypes.resolvedMultiTypeEsField(f, typeResolutions);
return new FieldAttribute(f.source(), f.parentName(), f.name(), resolvedField, f.nullable(), f.id(), f.synthetic());
} }
return f; return relation.transformExpressionsUp(FieldAttribute.class, f -> {
if (f.field() instanceof InvalidMappedField imf && imf.types().stream().allMatch(DataType::isDate)) {
HashMap<ResolveUnionTypes.TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
var convert = new ToDateNanos(f.source(), f);
imf.types().forEach(type -> typeResolutions(f, convert, type, imf, typeResolutions));
var resolvedField = ResolveUnionTypes.resolvedMultiTypeEsField(f, typeResolutions);
return new FieldAttribute(
f.source(),
f.parentName(),
f.name(),
resolvedField,
f.nullable(),
f.id(),
f.synthetic()
);
}
return f;
});
}); });
}); } else {
return plan;
}
} }
} }