From 9b7b56f871f6437c43aa23f1c0a6c02233e4f6dd Mon Sep 17 00:00:00 2001 From: Fang Xing <155562079+fang-xing-esql@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:14:19 -0400 Subject: [PATCH] [ESQL] Ensure date/date_nanos implicit casting rule behind snapshot (#130026) * put date date_nanos implicit casting rule behind snapshot --- docs/changelog/127797.yaml | 6 --- .../xpack/esql/analysis/Analyzer.java | 48 +++++++++++++------ 2 files changed, 34 insertions(+), 20 deletions(-) delete mode 100644 docs/changelog/127797.yaml diff --git a/docs/changelog/127797.yaml b/docs/changelog/127797.yaml deleted file mode 100644 index 8fca3da004130..0000000000000 --- a/docs/changelog/127797.yaml +++ /dev/null @@ -1,6 +0,0 @@ -pr: 127797 -summary: "Date nanos implicit casting in union types option #2" -area: ES|QL -type: enhancement -issues: - - 110009 diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java index e9f57b92ede28..1c27446903615 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java @@ -130,6 +130,7 @@ import static java.util.Collections.singletonList; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; 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.DATETIME; import static org.elasticsearch.xpack.esql.core.type.DataType.DATE_NANOS; @@ -168,7 +169,7 @@ public class Analyzer extends ParameterizedRuleExecutor( "Resolution", @@ -1692,23 +1693,42 @@ private static LogicalPlan planWithoutSyntheticAttributes(LogicalPlan plan) { * 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 { + + private final boolean isSnapshot; + + DateMillisToNanosInEsRelation(boolean isSnapshot) { + this.isSnapshot = isSnapshot; + } + @Override public LogicalPlan apply(LogicalPlan plan) { - return plan.transformUp(EsRelation.class, 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 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()); + if (isSnapshot) { + return plan.transformUp(EsRelation.class, relation -> { + if (relation.indexMode() == IndexMode.LOOKUP) { + return relation; } - return f; + return relation.transformExpressionsUp(FieldAttribute.class, f -> { + if (f.field() instanceof InvalidMappedField imf && imf.types().stream().allMatch(DataType::isDate)) { + HashMap 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; + } } }