diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index 33f20df4eccc..29b8ddde5fb2 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -38,7 +38,7 @@ dependencies { exclude group: 'net.sf.jopt-simple', module: 'jopt-simple' } api(project(':modules:aggregations')) - api(project(':x-pack:plugin:ql')) + api(project(':x-pack:plugin:esql-core')) api(project(':x-pack:plugin:esql')) api(project(':x-pack:plugin:esql:compute')) implementation project(path: ':libs:elasticsearch-vec') diff --git a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/EvalBenchmark.java b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/EvalBenchmark.java index 6eeb58fe67bf..1fd2e296f007 100644 --- a/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/EvalBenchmark.java +++ b/benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/EvalBenchmark.java @@ -22,6 +22,12 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.Operator; import org.elasticsearch.core.TimeValue; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.evaluator.EvalMapper; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Abs; @@ -31,12 +37,6 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Equals; import org.elasticsearch.xpack.esql.planner.Layout; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RLikePattern; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; diff --git a/docs/reference/esql/functions/examples/to_integer.asciidoc b/docs/reference/esql/functions/examples/to_integer.asciidoc index 2fecba05cb89..ab90de6a90da 100644 --- a/docs/reference/esql/functions/examples/to_integer.asciidoc +++ b/docs/reference/esql/functions/examples/to_integer.asciidoc @@ -19,6 +19,6 @@ The header will provide information on the source of the failure: A following header will contain the failure reason and the offending value: -`"org.elasticsearch.xpack.ql.InvalidArgumentException: [501379200000] out of [integer] range"` +`"org.elasticsearch.xpack.esql.core.InvalidArgumentException: [501379200000] out of [integer] range"` diff --git a/x-pack/plugin/esql-core/README.md b/x-pack/plugin/esql-core/README.md new file mode 100644 index 000000000000..a1ab3a250710 --- /dev/null +++ b/x-pack/plugin/esql-core/README.md @@ -0,0 +1,14 @@ +# ES|QL core + +This project originated as a copy of the `ql` x-pack plugin. +It contains some fundamental classes used in `esql`, like `Node`, its subclasses `Expression`, `QueryPlan`, and the plan optimizer code. +Originally, `ql` shared classes between ES|QL, SQL and EQL, but ES|QL diverged far enough to justify a split. + +## Warning + +- **Consider the contents of this project untested.** + There may be some tests in `sql` and `eql` that may have indirectly covered the initial version of this (when it was copied from `ql`); + but neither do these tests apply to `esql`, nor do they even run against this. +- **Consider this project technical debt.** + The contents of this project need to be consolidated with the `esql` plugin. + In particular, there is a significant amount of code (or code paths) that are not used/executed at all in `esql`. diff --git a/x-pack/plugin/esql-core/build.gradle b/x-pack/plugin/esql-core/build.gradle new file mode 100644 index 000000000000..ed9f5066d10e --- /dev/null +++ b/x-pack/plugin/esql-core/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'elasticsearch.internal-es-plugin' +apply plugin: 'elasticsearch.internal-test-artifact' + +esplugin { + name 'x-pack-esql-core' + description 'Elasticsearch infrastructure plugin for ESQL' + classname 'org.elasticsearch.xpack.esql.core.plugin.EsqlCorePlugin' + extendedPlugins = ['x-pack-core'] +} + +base { + archivesName = 'x-pack-esql-core' +} + +dependencies { + api "org.antlr:antlr4-runtime:${versions.antlr4}" + api project(path: xpackModule('mapper-version')) + compileOnly project(path: xpackModule('core')) + testApi(project(xpackModule('esql-core:test-fixtures'))) { + exclude group: 'org.elasticsearch.plugin', module: 'esql-core' + } + testImplementation project(':test:framework') + testImplementation(testArtifact(project(xpackModule('core')))) +} diff --git a/x-pack/plugin/esql-core/licenses/antlr4-runtime-LICENSE.txt b/x-pack/plugin/esql-core/licenses/antlr4-runtime-LICENSE.txt new file mode 100644 index 000000000000..95d0a2554f68 --- /dev/null +++ b/x-pack/plugin/esql-core/licenses/antlr4-runtime-LICENSE.txt @@ -0,0 +1,26 @@ +[The "BSD license"] +Copyright (c) 2015 Terence Parr, Sam Harwell +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/x-pack/plugin/esql-core/licenses/antlr4-runtime-NOTICE.txt b/x-pack/plugin/esql-core/licenses/antlr4-runtime-NOTICE.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/InvalidArgumentException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/InvalidArgumentException.java new file mode 100644 index 000000000000..c051a9fa724f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/InvalidArgumentException.java @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core; + +/** + * Exception thrown when unable to continue processing client request, + * in cases such as invalid query parameter or failure to apply requested processing to given data. + * It's meant as a generic equivalent to QlIllegalArgumentException (that's a server exception). + * TODO: reason for [E|S|ES]QL specializations of QlIllegalArgumentException? + * TODO: the intended use of ql.ParsingException, vs its [E|S|ES]QL equivalents, subclassed from the respective XxxClientException? + * Same for PlanningException. + */ +public class InvalidArgumentException extends QlClientException { + + public InvalidArgumentException(String message, Object... args) { + super(message, args); + } + + public InvalidArgumentException(Throwable cause, String message, Object... args) { + super(cause, message, args); + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/ParsingException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/ParsingException.java new file mode 100644 index 000000000000..bce3f848c938 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/ParsingException.java @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; + +public class ParsingException extends QlClientException { + private final int line; + private final int charPositionInLine; + + public ParsingException(String message, Exception cause, int line, int charPositionInLine) { + super(message, cause); + this.line = line; + this.charPositionInLine = charPositionInLine; + } + + public ParsingException(String message, Object... args) { + this(Source.EMPTY, message, args); + } + + public ParsingException(Source source, String message, Object... args) { + super(message, args); + this.line = source.source().getLineNumber(); + this.charPositionInLine = source.source().getColumnNumber(); + } + + public ParsingException(Exception cause, Source source, String message, Object... args) { + super(cause, message, args); + this.line = source.source().getLineNumber(); + this.charPositionInLine = source.source().getColumnNumber(); + } + + public int getLineNumber() { + return line; + } + + public int getColumnNumber() { + return charPositionInLine + 1; + } + + public String getErrorMessage() { + return super.getMessage(); + } + + @Override + public String getMessage() { + return format("line {}:{}: {}", getLineNumber(), getColumnNumber(), getErrorMessage()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlClientException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlClientException.java new file mode 100644 index 000000000000..3babe8e8cfaa --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlClientException.java @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core; + +import org.elasticsearch.rest.RestStatus; + +/** + * Exception thrown by performing client (or user) code. + * Typically it means the given action or query is incorrect and needs fixing. + */ +public class QlClientException extends QlException { + + protected QlClientException(String message, Object... args) { + super(message, args); + } + + protected QlClientException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + protected QlClientException(String message, Throwable cause) { + super(message, cause); + } + + protected QlClientException(Throwable cause, String message, Object... args) { + super(cause, message, args); + } + + protected QlClientException(Throwable cause) { + super(cause); + } + + @Override + public RestStatus status() { + return RestStatus.BAD_REQUEST; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlException.java new file mode 100644 index 000000000000..dd88a6f55203 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlException.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core; + +import org.elasticsearch.ElasticsearchException; + +/** + * Base class for all QL exceptions. Useful as a catch-all. + */ +public abstract class QlException extends ElasticsearchException { + public QlException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public QlException(String message, Throwable cause) { + super(message, cause); + } + + public QlException(String message, Object... args) { + super(message, args); + } + + public QlException(Throwable cause, String message, Object... args) { + super(message, cause, args); + } + + public QlException(Throwable cause) { + super(cause); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlIllegalArgumentException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlIllegalArgumentException.java new file mode 100644 index 000000000000..73c8c8b0ed80 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlIllegalArgumentException.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core; + +public class QlIllegalArgumentException extends QlServerException { + public QlIllegalArgumentException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public QlIllegalArgumentException(String message, Throwable cause) { + super(message, cause); + } + + public QlIllegalArgumentException(String message, Object... args) { + super(message, args); + } + + public QlIllegalArgumentException(Throwable cause, String message, Object... args) { + super(cause, message, args); + } + + public QlIllegalArgumentException(String message) { + super(message); + } + + public QlIllegalArgumentException(Throwable cause) { + super(cause); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlServerException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlServerException.java new file mode 100644 index 000000000000..44d54cf5a8ce --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/QlServerException.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core; + +/** + * Exception triggered inside server-side code. + * Typically a validation error or worse, a bug. + */ +public abstract class QlServerException extends QlException { + + protected QlServerException(String message, Object... args) { + super(message, args); + } + + protected QlServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + protected QlServerException(String message, Throwable cause) { + super(message, cause); + } + + protected QlServerException(Throwable cause, String message, Object... args) { + super(cause, message, args); + } + + protected QlServerException(Throwable cause) { + super(cause); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/AnalyzerRules.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/AnalyzerRules.java new file mode 100644 index 000000000000..2bc150db6495 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/AnalyzerRules.java @@ -0,0 +1,259 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.analyzer; + +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogic; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRule; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; + +public final class AnalyzerRules { + + public static class AddMissingEqualsToBoolField extends AnalyzerRule { + + @Override + protected LogicalPlan rule(Filter filter) { + if (filter.resolved() == false) { + return filter; + } + // check the condition itself + Expression condition = replaceRawBoolFieldWithEquals(filter.condition()); + // otherwise look for binary logic + if (condition == filter.condition()) { + condition = condition.transformUp( + BinaryLogic.class, + b -> b.replaceChildren(asList(replaceRawBoolFieldWithEquals(b.left()), replaceRawBoolFieldWithEquals(b.right()))) + ); + } + + if (condition != filter.condition()) { + filter = filter.with(condition); + } + return filter; + } + + private static Expression replaceRawBoolFieldWithEquals(Expression e) { + if (e instanceof FieldAttribute && e.dataType() == BOOLEAN) { + e = new Equals(e.source(), e, Literal.of(e, Boolean.TRUE)); + } + return e; + } + + @Override + protected boolean skipResolved() { + return false; + } + } + + public abstract static class AnalyzerRule extends Rule { + + // transformUp (post-order) - that is first children and then the node + // but with a twist; only if the tree is not resolved or analyzed + @Override + public final LogicalPlan apply(LogicalPlan plan) { + return plan.transformUp(typeToken(), t -> t.analyzed() || skipResolved() && t.resolved() ? t : rule(t)); + } + + protected abstract LogicalPlan rule(SubPlan plan); + + protected boolean skipResolved() { + return true; + } + } + + public abstract static class ParameterizedAnalyzerRule extends ParameterizedRule< + SubPlan, + LogicalPlan, + P> { + + // transformUp (post-order) - that is first children and then the node + // but with a twist; only if the tree is not resolved or analyzed + public final LogicalPlan apply(LogicalPlan plan, P context) { + return plan.transformUp(typeToken(), t -> t.analyzed() || skipResolved() && t.resolved() ? t : rule(t, context)); + } + + protected abstract LogicalPlan rule(SubPlan plan, P context); + + protected boolean skipResolved() { + return true; + } + } + + public abstract static class BaseAnalyzerRule extends AnalyzerRule { + + @Override + protected LogicalPlan rule(LogicalPlan plan) { + if (plan.childrenResolved() == false) { + return plan; + } + return doRule(plan); + } + + protected abstract LogicalPlan doRule(LogicalPlan plan); + } + + public static Function resolveFunction(UnresolvedFunction uf, Configuration configuration, FunctionRegistry functionRegistry) { + Function f = null; + if (uf.analyzed()) { + f = uf; + } else if (uf.childrenResolved() == false) { + f = uf; + } else { + String functionName = functionRegistry.resolveAlias(uf.name()); + if (functionRegistry.functionExists(functionName) == false) { + f = uf.missing(functionName, functionRegistry.listFunctions()); + } else { + FunctionDefinition def = functionRegistry.resolveFunction(functionName); + f = uf.buildResolved(configuration, def); + } + } + return f; + } + + public static List maybeResolveAgainstList( + UnresolvedAttribute u, + Collection attrList, + java.util.function.Function fieldInspector + ) { + // first take into account the qualified version + final String qualifier = u.qualifier(); + final String name = u.name(); + final boolean qualified = u.qualifier() != null; + + Predicate predicate = a -> { + return qualified ? Objects.equals(qualifier, a.qualifiedName()) : + // if the field is unqualified + // first check the names directly + (Objects.equals(name, a.name())) + // but also if the qualifier might not be quoted and if there's any ambiguity with nested fields + || Objects.equals(name, a.qualifiedName()); + + }; + return maybeResolveAgainstList(predicate, () -> u, attrList, false, fieldInspector); + } + + public static List maybeResolveAgainstList( + Predicate matcher, + Supplier unresolved, + Collection attrList, + boolean isPattern, + java.util.function.Function fieldInspector + ) { + List matches = new ArrayList<>(); + + for (Attribute attribute : attrList) { + if (attribute.synthetic() == false) { + boolean match = matcher.test(attribute); + if (match) { + matches.add(attribute); + } + } + } + + if (matches.isEmpty()) { + return matches; + } + + UnresolvedAttribute ua = unresolved.get(); + // found exact match or multiple if pattern + if (matches.size() == 1 || isPattern) { + // NB: only add the location if the match is univocal; b/c otherwise adding the location will overwrite any preexisting one + matches.replaceAll(e -> fieldInspector.apply(e)); + return matches; + } + + // report ambiguity + List refs = matches.stream().sorted((a, b) -> { + int lineDiff = a.sourceLocation().getLineNumber() - b.sourceLocation().getLineNumber(); + int colDiff = a.sourceLocation().getColumnNumber() - b.sourceLocation().getColumnNumber(); + return lineDiff != 0 ? lineDiff : (colDiff != 0 ? colDiff : a.qualifiedName().compareTo(b.qualifiedName())); + }) + .map( + a -> "line " + + a.sourceLocation().toString().substring(1) + + " [" + + (a.qualifier() != null ? "\"" + a.qualifier() + "\".\"" + a.name() + "\"" : a.name()) + + "]" + ) + .toList(); + + return singletonList( + ua.withUnresolvedMessage( + "Reference [" + + ua.qualifiedName() + + "] is ambiguous (to disambiguate use quotes or qualifiers); " + + "matches any of " + + refs + ) + ); + } + + public static Attribute handleSpecialFields(UnresolvedAttribute u, Attribute named, boolean allowCompound) { + // if it's a object/compound type, keep it unresolved with a nice error message + if (named instanceof FieldAttribute fa) { + + // incompatible mappings + if (fa.field() instanceof InvalidMappedField imf) { + named = u.withUnresolvedMessage("Cannot use field [" + fa.name() + "] due to ambiguities being " + imf.errorMessage()); + } + // unsupported types + else if (DataTypes.isUnsupported(fa.dataType())) { + UnsupportedEsField unsupportedField = (UnsupportedEsField) fa.field(); + if (unsupportedField.hasInherited()) { + named = u.withUnresolvedMessage( + "Cannot use field [" + + fa.name() + + "] with unsupported type [" + + unsupportedField.getOriginalType() + + "] in hierarchy (field [" + + unsupportedField.getInherited() + + "])" + ); + } else { + named = u.withUnresolvedMessage( + "Cannot use field [" + fa.name() + "] with unsupported type [" + unsupportedField.getOriginalType() + "]" + ); + } + } + // compound fields + else if (allowCompound == false && DataTypes.isPrimitive(fa.dataType()) == false) { + named = u.withUnresolvedMessage( + "Cannot use field [" + fa.name() + "] type [" + fa.dataType().typeName() + "] only its subfields" + ); + } + } + // make sure to copy the resolved attribute with the proper location + return named.withLocation(u.source()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/PreAnalyzer.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/PreAnalyzer.java new file mode 100644 index 000000000000..bf40370b5fe4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/PreAnalyzer.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.analyzer; + +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnresolvedRelation; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Collections.emptyList; + +// Since the pre-analyzer only inspect (and does NOT transform) the tree +// it is not built as a rule executor. +// Further more it applies 'the rules' only once and needs to return some +// state back. +public class PreAnalyzer { + + public static class PreAnalysis { + public static final PreAnalysis EMPTY = new PreAnalysis(emptyList()); + + public final List indices; + + public PreAnalysis(List indices) { + this.indices = indices; + } + } + + public PreAnalysis preAnalyze(LogicalPlan plan) { + if (plan.analyzed()) { + return PreAnalysis.EMPTY; + } + + return doPreAnalyze(plan); + } + + private static PreAnalysis doPreAnalyze(LogicalPlan plan) { + List indices = new ArrayList<>(); + + plan.forEachUp(UnresolvedRelation.class, p -> indices.add(new TableInfo(p.table(), p.frozen()))); + + // mark plan as preAnalyzed (if it were marked, there would be no analysis) + plan.forEachUp(LogicalPlan::setPreAnalyzed); + + return new PreAnalysis(indices); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/TableInfo.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/TableInfo.java new file mode 100644 index 000000000000..8e1e7bec9400 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/TableInfo.java @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.analyzer; + +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; + +public class TableInfo { + + private final TableIdentifier id; + private final boolean isFrozen; + + public TableInfo(TableIdentifier id, boolean isFrozen) { + this.id = id; + this.isFrozen = isFrozen; + } + + public TableIdentifier id() { + return id; + } + + public boolean isFrozen() { + return isFrozen; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/VerifierChecks.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/VerifierChecks.java new file mode 100644 index 000000000000..44ac786ba32f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/analyzer/VerifierChecks.java @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.analyzer; + +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; + +import java.util.Set; + +import static org.elasticsearch.xpack.esql.core.common.Failure.fail; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; + +public final class VerifierChecks { + + public static void checkFilterConditionType(LogicalPlan p, Set localFailures) { + if (p instanceof Filter) { + Expression condition = ((Filter) p).condition(); + if (condition.dataType() != BOOLEAN) { + localFailures.add(fail(condition, "Condition expression needs to be boolean, found [{}]", condition.dataType())); + } + } + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/async/AsyncTaskManagementService.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/async/AsyncTaskManagementService.java new file mode 100644 index 000000000000..deb5cae1172f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/async/AsyncTaskManagementService.java @@ -0,0 +1,362 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.async; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.support.ListenerTimeouts; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.UUIDs; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.index.engine.DocumentMissingException; +import org.elasticsearch.index.engine.VersionConflictEngineException; +import org.elasticsearch.tasks.CancellableTask; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.tasks.TaskAwareRequest; +import org.elasticsearch.tasks.TaskId; +import org.elasticsearch.tasks.TaskManager; +import org.elasticsearch.threadpool.Scheduler; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.xpack.core.ClientHelper; +import org.elasticsearch.xpack.core.async.AsyncExecutionId; +import org.elasticsearch.xpack.core.async.AsyncTask; +import org.elasticsearch.xpack.core.async.AsyncTaskIndexService; +import org.elasticsearch.xpack.core.async.StoredAsyncResponse; +import org.elasticsearch.xpack.core.async.StoredAsyncTask; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import static org.elasticsearch.core.Strings.format; + +/** + * Service for managing EQL requests + */ +public class AsyncTaskManagementService< + Request extends TaskAwareRequest, + Response extends ActionResponse, + T extends StoredAsyncTask> { + + private static final Logger logger = LogManager.getLogger(AsyncTaskManagementService.class); + + private final TaskManager taskManager; + private final String action; + private final AsyncTaskIndexService> asyncTaskIndexService; + private final AsyncOperation operation; + private final ThreadPool threadPool; + private final ClusterService clusterService; + private final Class taskClass; + + public interface AsyncOperation< + Request extends TaskAwareRequest, + Response extends ActionResponse, + T extends CancellableTask & AsyncTask> { + + T createTask( + Request request, + long id, + String type, + String action, + TaskId parentTaskId, + Map headers, + Map originHeaders, + AsyncExecutionId asyncExecutionId + ); + + void execute(Request request, T task, ActionListener listener); + + Response initialResponse(T task); + + Response readResponse(StreamInput inputStream) throws IOException; + } + + /** + * Wrapper for EqlSearchRequest that creates an async version of EqlSearchTask + */ + private class AsyncRequestWrapper implements TaskAwareRequest { + private final Request request; + private final String doc; + private final String node; + + AsyncRequestWrapper(Request request, String node) { + this.request = request; + this.doc = UUIDs.randomBase64UUID(); + this.node = node; + } + + @Override + public void setParentTask(TaskId taskId) { + request.setParentTask(taskId); + } + + @Override + public TaskId getParentTask() { + return request.getParentTask(); + } + + @Override + public void setRequestId(long requestId) { + request.setRequestId(requestId); + } + + @Override + public long getRequestId() { + return request.getRequestId(); + } + + @Override + public Task createTask(long id, String type, String actionName, TaskId parentTaskId, Map headers) { + Map originHeaders = ClientHelper.getPersistableSafeSecurityHeaders( + threadPool.getThreadContext(), + clusterService.state() + ); + return operation.createTask( + request, + id, + type, + actionName, + parentTaskId, + headers, + originHeaders, + new AsyncExecutionId(doc, new TaskId(node, id)) + ); + } + + @Override + public String getDescription() { + return request.getDescription(); + } + } + + public AsyncTaskManagementService( + String index, + Client client, + String origin, + NamedWriteableRegistry registry, + TaskManager taskManager, + String action, + AsyncOperation operation, + Class taskClass, + ClusterService clusterService, + ThreadPool threadPool, + BigArrays bigArrays + ) { + this.taskManager = taskManager; + this.action = action; + this.operation = operation; + this.taskClass = taskClass; + this.asyncTaskIndexService = new AsyncTaskIndexService<>( + index, + clusterService, + threadPool.getThreadContext(), + client, + origin, + i -> new StoredAsyncResponse<>(operation::readResponse, i), + registry, + bigArrays + ); + this.clusterService = clusterService; + this.threadPool = threadPool; + } + + public void asyncExecute( + Request request, + TimeValue waitForCompletionTimeout, + TimeValue keepAlive, + boolean keepOnCompletion, + ActionListener listener + ) { + String nodeId = clusterService.localNode().getId(); + try (var ignored = threadPool.getThreadContext().newTraceContext()) { + @SuppressWarnings("unchecked") + T searchTask = (T) taskManager.register("transport", action + "[a]", new AsyncRequestWrapper(request, nodeId)); + boolean operationStarted = false; + try { + operation.execute( + request, + searchTask, + wrapStoringListener(searchTask, waitForCompletionTimeout, keepAlive, keepOnCompletion, listener) + ); + operationStarted = true; + } finally { + // If we didn't start operation for any reason, we need to clean up the task that we have created + if (operationStarted == false) { + taskManager.unregister(searchTask); + } + } + } + } + + private ActionListener wrapStoringListener( + T searchTask, + TimeValue waitForCompletionTimeout, + TimeValue keepAlive, + boolean keepOnCompletion, + ActionListener listener + ) { + AtomicReference> exclusiveListener = new AtomicReference<>(listener); + // This is will performed in case of timeout + Scheduler.ScheduledCancellable timeoutHandler = threadPool.schedule(() -> { + ActionListener acquiredListener = exclusiveListener.getAndSet(null); + if (acquiredListener != null) { + acquiredListener.onResponse(operation.initialResponse(searchTask)); + } + }, waitForCompletionTimeout, threadPool.executor(ThreadPool.Names.SEARCH)); + + // This will be performed at the end of normal execution + return ActionListener.wrap(response -> { + ActionListener acquiredListener = exclusiveListener.getAndSet(null); + if (acquiredListener != null) { + // We finished before timeout + timeoutHandler.cancel(); + if (keepOnCompletion) { + storeResults( + searchTask, + new StoredAsyncResponse<>(response, threadPool.absoluteTimeInMillis() + keepAlive.getMillis()), + ActionListener.running(() -> acquiredListener.onResponse(response)) + ); + } else { + taskManager.unregister(searchTask); + searchTask.onResponse(response); + acquiredListener.onResponse(response); + } + } else { + // We finished after timeout - saving results + storeResults( + searchTask, + new StoredAsyncResponse<>(response, threadPool.absoluteTimeInMillis() + keepAlive.getMillis()), + ActionListener.running(response::decRef) + ); + } + }, e -> { + ActionListener acquiredListener = exclusiveListener.getAndSet(null); + if (acquiredListener != null) { + // We finished before timeout + timeoutHandler.cancel(); + if (keepOnCompletion) { + storeResults( + searchTask, + new StoredAsyncResponse<>(e, threadPool.absoluteTimeInMillis() + keepAlive.getMillis()), + ActionListener.running(() -> acquiredListener.onFailure(e)) + ); + } else { + taskManager.unregister(searchTask); + searchTask.onFailure(e); + acquiredListener.onFailure(e); + } + } else { + // We finished after timeout - saving exception + storeResults(searchTask, new StoredAsyncResponse<>(e, threadPool.absoluteTimeInMillis() + keepAlive.getMillis())); + } + }); + } + + private void storeResults(T searchTask, StoredAsyncResponse storedResponse) { + storeResults(searchTask, storedResponse, null); + } + + private void storeResults(T searchTask, StoredAsyncResponse storedResponse, ActionListener finalListener) { + try { + asyncTaskIndexService.createResponseForEQL( + searchTask.getExecutionId().getDocId(), + searchTask.getOriginHeaders(), + threadPool.getThreadContext().getResponseHeaders(), // includes ESQL warnings + storedResponse, + ActionListener.wrap( + // We should only unregister after the result is saved + resp -> { + // TODO: generalize the logging, not just eql + logger.trace(() -> "stored eql search results for [" + searchTask.getExecutionId().getEncoded() + "]"); + taskManager.unregister(searchTask); + if (storedResponse.getException() != null) { + searchTask.onFailure(storedResponse.getException()); + } else { + searchTask.onResponse(storedResponse.getResponse()); + } + if (finalListener != null) { + finalListener.onResponse(null); + } + }, + exc -> { + taskManager.unregister(searchTask); + searchTask.onFailure(exc); + Throwable cause = ExceptionsHelper.unwrapCause(exc); + if (cause instanceof DocumentMissingException == false + && cause instanceof VersionConflictEngineException == false) { + logger.error( + // TODO: generalize the logging, not just eql + () -> format("failed to store eql search results for [%s]", searchTask.getExecutionId().getEncoded()), + exc + ); + } + if (finalListener != null) { + finalListener.onFailure(exc); + } + } + ) + ); + } catch (Exception exc) { + taskManager.unregister(searchTask); + searchTask.onFailure(exc); + logger.error(() -> "failed to store eql search results for [" + searchTask.getExecutionId().getEncoded() + "]", exc); + } + } + + /** + * Adds a self-unregistering listener to a task. It works as a normal listener except it retrieves a partial response and unregister + * itself from the task if timeout occurs. Returns false if the listener could not be added, if say for example the task completed. + * Otherwise, returns true. + */ + public static > boolean addCompletionListener( + ThreadPool threadPool, + Task task, + ActionListener> listener, + TimeValue timeout + ) { + if (timeout.getMillis() <= 0) { + getCurrentResult(task, listener); + return true; + } else { + return task.addCompletionListener( + () -> ListenerTimeouts.wrapWithTimeout( + threadPool, + timeout, + threadPool.executor(ThreadPool.Names.SEARCH), + ActionListener.wrap( + r -> listener.onResponse(new StoredAsyncResponse<>(r, task.getExpirationTimeMillis())), + e -> listener.onResponse(new StoredAsyncResponse<>(e, task.getExpirationTimeMillis())) + ), + wrapper -> { + // Timeout was triggered + task.removeCompletionListener(wrapper); + getCurrentResult(task, listener); + } + ) + ); + } + } + + private static > void getCurrentResult( + Task task, + ActionListener> listener + ) { + try { + listener.onResponse(new StoredAsyncResponse<>(task.getCurrentResult(), task.getExpirationTimeMillis())); + } catch (Exception ex) { + listener.onFailure(ex); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/async/QlStatusResponse.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/async/QlStatusResponse.java new file mode 100644 index 000000000000..8c28f08e8d88 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/async/QlStatusResponse.java @@ -0,0 +1,200 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.async; + +import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.async.StoredAsyncResponse; +import org.elasticsearch.xpack.core.search.action.SearchStatusResponse; + +import java.io.IOException; +import java.util.Objects; + +/** + * A response for *QL search status request + */ +public class QlStatusResponse extends ActionResponse implements SearchStatusResponse, ToXContentObject { + private final String id; + private final boolean isRunning; + private final boolean isPartial; + private final Long startTimeMillis; + private final long expirationTimeMillis; + private final RestStatus completionStatus; + + public interface AsyncStatus { + String id(); + + boolean isRunning(); + + boolean isPartial(); + } + + public QlStatusResponse( + String id, + boolean isRunning, + boolean isPartial, + Long startTimeMillis, + long expirationTimeMillis, + RestStatus completionStatus + ) { + this.id = id; + this.isRunning = isRunning; + this.isPartial = isPartial; + this.startTimeMillis = startTimeMillis; + this.expirationTimeMillis = expirationTimeMillis; + this.completionStatus = completionStatus; + } + + /** + * Get status from the stored Ql search response + * @param storedResponse - a response from a stored search + * @param expirationTimeMillis – expiration time in milliseconds + * @param id – encoded async search id + * @return a status response + */ + public static QlStatusResponse getStatusFromStoredSearch( + StoredAsyncResponse storedResponse, + long expirationTimeMillis, + String id + ) { + S searchResponse = storedResponse.getResponse(); + if (searchResponse != null) { + assert searchResponse.isRunning() == false : "Stored Ql search response must have a completed status!"; + return new QlStatusResponse( + searchResponse.id(), + false, + searchResponse.isPartial(), + null, // we don't store in the index the start time for completed response + expirationTimeMillis, + RestStatus.OK + ); + } else { + Exception exc = storedResponse.getException(); + assert exc != null : "Stored Ql response must either have a search response or an exception!"; + return new QlStatusResponse( + id, + false, + false, + null, // we don't store in the index the start time for completed response + expirationTimeMillis, + ExceptionsHelper.status(exc) + ); + } + } + + public QlStatusResponse(StreamInput in) throws IOException { + this.id = in.readString(); + this.isRunning = in.readBoolean(); + this.isPartial = in.readBoolean(); + this.startTimeMillis = in.readOptionalLong(); + this.expirationTimeMillis = in.readLong(); + this.completionStatus = (this.isRunning == false) ? RestStatus.readFrom(in) : null; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(id); + out.writeBoolean(isRunning); + out.writeBoolean(isPartial); + out.writeOptionalLong(startTimeMillis); + out.writeLong(expirationTimeMillis); + if (isRunning == false) { + RestStatus.writeTo(out, completionStatus); + } + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + { + builder.field("id", id); + builder.field("is_running", isRunning); + builder.field("is_partial", isPartial); + if (startTimeMillis != null) { // start time is available only for a running eql search + builder.timeField("start_time_in_millis", "start_time", startTimeMillis); + } + builder.timeField("expiration_time_in_millis", "expiration_time", expirationTimeMillis); + if (isRunning == false) { // completion status is available only for a completed eql search + builder.field("completion_status", completionStatus.getStatus()); + } + } + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + QlStatusResponse other = (QlStatusResponse) obj; + return id.equals(other.id) + && isRunning == other.isRunning + && isPartial == other.isPartial + && Objects.equals(startTimeMillis, other.startTimeMillis) + && expirationTimeMillis == other.expirationTimeMillis + && Objects.equals(completionStatus, other.completionStatus); + } + + @Override + public int hashCode() { + return Objects.hash(id, isRunning, isPartial, startTimeMillis, expirationTimeMillis, completionStatus); + } + + /** + * Returns the id of the eql search status request. + */ + public String getId() { + return id; + } + + /** + * Returns {@code true} if the eql search is still running in the cluster, + * or {@code false} if the search has been completed. + */ + public boolean isRunning() { + return isRunning; + } + + /** + * Returns {@code true} if the eql search results are partial. + * This could be either because eql search hasn't finished yet, + * or if it finished and some shards have failed or timed out. + */ + public boolean isPartial() { + return isPartial; + } + + /** + * Returns a timestamp when the eql search task started, in milliseconds since epoch. + * For a completed eql search returns {@code null}, as we don't store start time for completed searches. + */ + public Long getStartTime() { + return startTimeMillis; + } + + /** + * Returns a timestamp when the eql search will be expired, in milliseconds since epoch. + */ + @Override + public long getExpirationTime() { + return expirationTimeMillis; + } + + /** + * For a completed eql search returns the completion status. + * For a still running eql search returns {@code null}. + */ + public RestStatus getCompletionStatus() { + return completionStatus; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Resolvable.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Resolvable.java new file mode 100644 index 000000000000..0a2fbedd1684 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Resolvable.java @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.capabilities; + +public interface Resolvable { + + boolean resolved(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Resolvables.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Resolvables.java new file mode 100644 index 000000000000..deca9bea7452 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Resolvables.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.capabilities; + +public abstract class Resolvables { + + public static boolean resolved(Iterable resolvables) { + for (Resolvable resolvable : resolvables) { + if (resolvable.resolved() == false) { + return false; + } + } + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Unresolvable.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Unresolvable.java new file mode 100644 index 000000000000..11bfe4df35e3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/Unresolvable.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.capabilities; + +public interface Unresolvable extends Resolvable { + + String UNRESOLVED_PREFIX = "?"; + + @Override + default boolean resolved() { + return false; + } + + String unresolvedMessage(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/UnresolvedException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/UnresolvedException.java new file mode 100644 index 000000000000..a94283db0161 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/capabilities/UnresolvedException.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.capabilities; + +import org.elasticsearch.xpack.esql.core.QlServerException; + +/** + * Thrown when we accidentally attempt to resolve something on on an unresolved entity. Throwing this + * is always a bug. + */ +public class UnresolvedException extends QlServerException { + public UnresolvedException(String action, Object target) { + super("Invalid call to {} on an unresolved object {}", action, target); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/common/Failure.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/common/Failure.java new file mode 100644 index 000000000000..719ae7ffbd1c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/common/Failure.java @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.common; + +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; + +public class Failure { + + private final Node node; + private final String message; + + public Failure(Node node, String message) { + this.node = node; + this.message = message; + } + + public Node node() { + return node; + } + + public String message() { + return message; + } + + @Override + public int hashCode() { + return Objects.hash(node); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Failure other = (Failure) obj; + return Objects.equals(node, other.node); + } + + @Override + public String toString() { + return message; + } + + public static Failure fail(Node source, String message, Object... args) { + return new Failure(source, format(message, args)); + } + + public static String failMessage(Collection failures) { + return failures.stream().map(f -> { + Location l = f.node().source().source(); + return "line " + l.getLineNumber() + ":" + l.getColumnNumber() + ": " + f.message(); + }) + .collect( + Collectors.joining( + StringUtils.NEW_LINE, + format("Found {} problem{}\n", failures.size(), failures.size() > 1 ? "s" : StringUtils.EMPTY), + StringUtils.EMPTY + ) + ); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/common/Failures.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/common/Failures.java new file mode 100644 index 000000000000..c06fe94c9a33 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/common/Failures.java @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.common; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Objects; + +/** + * Glorified list for managing {@link Failure}s. + */ +public class Failures { + + private final Collection failures; + + public Failures() { + this.failures = new LinkedHashSet<>(); + } + + public Failures add(Failure failure) { + if (failure != null) { + failures.add(failure); + } + return this; + } + + public boolean hasFailures() { + return failures.size() > 0; + } + + public Collection failures() { + return failures; + } + + @Override + public int hashCode() { + return Objects.hash(failures); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Failures failures1 = (Failures) o; + return Objects.equals(failures, failures1.failures); + } + + @Override + public String toString() { + return failures.isEmpty() ? "[]" : Failure.failMessage(failures); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/AggRef.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/AggRef.java new file mode 100644 index 000000000000..54e44f55c96a --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/AggRef.java @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search; + +/** + * Reference to a ES aggregation (which can be either a GROUP BY or Metric agg). + */ +public abstract class AggRef implements FieldExtraction { + + @Override + public void collectFields(QlSourceBuilder sourceBuilder) { + // Aggregations do not need any special fields + } + + @Override + public boolean supportedByAggsOnlyQuery() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/FieldExtraction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/FieldExtraction.java new file mode 100644 index 000000000000..6751a8412153 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/FieldExtraction.java @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search; + +import org.elasticsearch.search.builder.SearchSourceBuilder; + +/** + * An interface for something that needs to extract field(s) from a result. + */ +public interface FieldExtraction { + + /** + * Add whatever is necessary to the {@link SearchSourceBuilder} + * in order to fetch the field. This can include tracking the score, + * {@code _source} fields, doc values fields, and script fields. + */ + void collectFields(QlSourceBuilder sourceBuilder); + + /** + * Is this aggregation supported in an "aggregation only" query + * ({@code true}) or should it force a scroll query ({@code false})? + */ + boolean supportedByAggsOnlyQuery(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/QlSourceBuilder.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/QlSourceBuilder.java new file mode 100644 index 000000000000..a8a019840002 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/QlSourceBuilder.java @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search; + +import org.elasticsearch.script.Script; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.fetch.subphase.FieldAndFormat; + +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +/** + * A {@code SqlSourceBuilder} is a builder object passed to objects implementing + * {@link FieldExtraction} that can "build" whatever needs to be extracted from + * the resulting ES document as a field. + */ +public class QlSourceBuilder { + // The LinkedHashMaps preserve the order of the fields in the response + private final Set fetchFields = new LinkedHashSet<>(); + private final Map scriptFields = new LinkedHashMap<>(); + + boolean trackScores = false; + + public QlSourceBuilder() {} + + /** + * Turns on returning the {@code _score} for documents. + */ + public void trackScores() { + this.trackScores = true; + } + + /** + * Retrieve the requested field using the "fields" API + */ + public void addFetchField(String field, String format) { + fetchFields.add(new FieldAndFormat(field, format)); + } + + /** + * Return the given field as a script field with the supplied script + */ + public void addScriptField(String name, Script script) { + scriptFields.put(name, script); + } + + /** + * Collect the necessary fields, modifying the {@code SearchSourceBuilder} + * to retrieve them from the document. + */ + public void build(SearchSourceBuilder sourceBuilder) { + sourceBuilder.trackScores(this.trackScores); + fetchFields.forEach(field -> sourceBuilder.fetchField(new FieldAndFormat(field.field, field.format, null))); + scriptFields.forEach(sourceBuilder::scriptField); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/AbstractFieldHitExtractor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/AbstractFieldHitExtractor.java new file mode 100644 index 000000000000..6a8bd61f89c0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/AbstractFieldHitExtractor.java @@ -0,0 +1,270 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.TransportVersions; +import org.elasticsearch.common.document.DocumentField; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.io.IOException; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Extractor for ES fields. Works for both 'normal' fields but also nested ones (which require hitName to be set). + * The latter is used as metadata in assembling the results in the tabular response. + */ +public abstract class AbstractFieldHitExtractor implements HitExtractor { + + private final String fieldName, hitName; + private final DataType dataType; + private final ZoneId zoneId; + + protected MultiValueSupport multiValueSupport; + + public enum MultiValueSupport { + NONE, + LENIENT, + FULL + } + + protected AbstractFieldHitExtractor(String name, DataType dataType, ZoneId zoneId) { + this(name, dataType, zoneId, null, MultiValueSupport.NONE); + } + + protected AbstractFieldHitExtractor(String name, DataType dataType, ZoneId zoneId, MultiValueSupport multiValueSupport) { + this(name, dataType, zoneId, null, multiValueSupport); + } + + protected AbstractFieldHitExtractor( + String name, + DataType dataType, + ZoneId zoneId, + String hitName, + MultiValueSupport multiValueSupport + ) { + this.fieldName = name; + this.dataType = dataType; + this.zoneId = zoneId; + this.multiValueSupport = multiValueSupport; + this.hitName = hitName; + + if (hitName != null) { + if (name.contains(hitName) == false) { + throw new QlIllegalArgumentException("Hitname [{}] specified but not part of the name [{}]", hitName, name); + } + } + } + + @SuppressWarnings("this-escape") + protected AbstractFieldHitExtractor(StreamInput in) throws IOException { + fieldName = in.readString(); + String typeName = in.readOptionalString(); + dataType = typeName != null ? loadTypeFromName(typeName) : null; + hitName = in.readOptionalString(); + if (in.getTransportVersion().before(TransportVersions.V_8_6_0)) { + this.multiValueSupport = in.readBoolean() ? MultiValueSupport.LENIENT : MultiValueSupport.NONE; + } else { + this.multiValueSupport = in.readEnum(MultiValueSupport.class); + } + zoneId = readZoneId(in); + } + + protected DataType loadTypeFromName(String typeName) { + return DataTypes.fromTypeName(typeName); + } + + protected abstract ZoneId readZoneId(StreamInput in) throws IOException; + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(fieldName); + out.writeOptionalString(dataType == null ? null : dataType.typeName()); + out.writeOptionalString(hitName); + if (out.getTransportVersion().before(TransportVersions.V_8_6_0)) { + out.writeBoolean(multiValueSupport != MultiValueSupport.NONE); + } else { + out.writeEnum(multiValueSupport); + } + + } + + @Override + public Object extract(SearchHit hit) { + Object value = null; + DocumentField field = null; + if (hitName != null) { + value = unwrapFieldsMultiValue(extractNestedField(hit)); + } else { + field = hit.field(fieldName); + if (field != null) { + value = unwrapFieldsMultiValue(field.getValues()); + } + } + return value; + } + + /* + * For a path of fields like root.nested1.nested2.leaf where nested1 and nested2 are nested field types, + * fieldName is root.nested1.nested2.leaf, while hitName is root.nested1.nested2 + * We first look for root.nested1.nested2 or root.nested1 or root in the SearchHit until we find something. + * If the DocumentField lives under "root.nested1" the remaining path to search for (in the DocumentField itself) is nested2. + * After this step is done, what remains to be done is just getting the leaf values. + */ + @SuppressWarnings("unchecked") + private Object extractNestedField(SearchHit hit) { + Object value; + DocumentField field; + String tempHitname = hitName; + List remainingPath = new ArrayList<>(); + // first, search for the "root" DocumentField under which the remaining path of nested document values is + while ((field = hit.field(tempHitname)) == null) { + int indexOfDot = tempHitname.lastIndexOf('.'); + if (indexOfDot < 0) {// there is no such field in the hit + return null; + } + remainingPath.add(0, tempHitname.substring(indexOfDot + 1)); + tempHitname = tempHitname.substring(0, indexOfDot); + } + // then dig into DocumentField's structure until we reach the field we are interested into + if (remainingPath.size() > 0) { + List values = field.getValues(); + Iterator pathIterator = remainingPath.iterator(); + while (pathIterator.hasNext()) { + String pathElement = pathIterator.next(); + Map> elements = (Map>) values.get(0); + values = elements.get(pathElement); + /* + * if this path is not found it means we hit another nested document (inner_root_1.inner_root_2.nested_field_2) + * something like this + * "root_field_1.root_field_2.nested_field_1" : [ + * { + * "inner_root_1.inner_root_2.nested_field_2" : [ + * { + * "leaf_field" : [ + * "abc2" + * ] + * So, start re-building the path until the right one is found, ie inner_root_1.inner_root_2...... + */ + while (values == null) { + pathElement += "." + pathIterator.next(); + values = elements.get(pathElement); + } + } + value = ((Map) values.get(0)).get(fieldName.substring(hitName.length() + 1)); + } else { + value = field.getValues(); + } + return value; + } + + protected Object unwrapFieldsMultiValue(Object values) { + if (values == null) { + return null; + } + if (values instanceof Map && hitName != null) { + // extract the sub-field from a nested field (dep.dep_name -> dep_name) + return unwrapFieldsMultiValue(((Map) values).get(fieldName.substring(hitName.length() + 1))); + } + if (values instanceof List list) { + if (list.isEmpty()) { + return null; + } else { + if (isPrimitive(list) == false) { + if (list.size() == 1 || multiValueSupport == MultiValueSupport.LENIENT) { + return unwrapFieldsMultiValue(list.get(0)); + } else if (multiValueSupport == MultiValueSupport.FULL) { + List unwrappedValues = new ArrayList<>(); + for (Object value : list) { + unwrappedValues.add(unwrapFieldsMultiValue(value)); + } + values = unwrappedValues; + } else { + // missing `field_multi_value_leniency` setting + throw new InvalidArgumentException("Arrays (returned by [{}]) are not supported", fieldName); + } + } + } + } + + Object unwrapped = unwrapCustomValue(values); + if (unwrapped != null && isListOfNulls(unwrapped) == false) { + return unwrapped; + } + + return values; + } + + private static boolean isListOfNulls(Object unwrapped) { + if (unwrapped instanceof List list) { + if (list.size() == 0) { + return false; + } + for (Object o : list) { + if (o != null) { + return false; + } + } + return true; + } + return false; + } + + protected abstract Object unwrapCustomValue(Object values); + + protected abstract boolean isPrimitive(List list); + + @Override + public String hitName() { + return hitName; + } + + public String fieldName() { + return fieldName; + } + + public ZoneId zoneId() { + return zoneId; + } + + public DataType dataType() { + return dataType; + } + + public MultiValueSupport multiValueSupport() { + return multiValueSupport; + } + + @Override + public String toString() { + return fieldName + "@" + hitName + "@" + zoneId; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + AbstractFieldHitExtractor other = (AbstractFieldHitExtractor) obj; + return fieldName.equals(other.fieldName) && hitName.equals(other.hitName) && multiValueSupport == other.multiValueSupport; + } + + @Override + public int hashCode() { + return Objects.hash(fieldName, hitName, multiValueSupport); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/BucketExtractor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/BucketExtractor.java new file mode 100644 index 000000000000..a25482d92ecc --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/BucketExtractor.java @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket; + +/** + * Extracts an aggregation value from a {@link Bucket}. + */ +public interface BucketExtractor extends NamedWriteable { + + Object extract(Bucket bucket); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/BucketExtractors.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/BucketExtractors.java new file mode 100644 index 000000000000..fa7443e190d3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/BucketExtractors.java @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; + +import java.util.ArrayList; +import java.util.List; + +public final class BucketExtractors { + + private BucketExtractors() {} + + /** + * All of the named writeables needed to deserialize the instances of + * {@linkplain BucketExtractor}s. + */ + public static List getNamedWriteables() { + List entries = new ArrayList<>(); + entries.add(new Entry(BucketExtractor.class, ComputingExtractor.NAME, ComputingExtractor::new)); + entries.add(new Entry(BucketExtractor.class, ConstantExtractor.NAME, ConstantExtractor::new)); + return entries; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ComputingExtractor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ComputingExtractor.java new file mode 100644 index 000000000000..1116a43022da --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ComputingExtractor.java @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.HitExtractorProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; +import java.util.Objects; + +/** + * Hit/BucketExtractor that delegates to a processor. The difference between this class + * and {@link HitExtractorProcessor} is that the latter is used inside a + * {@link Processor} tree as a leaf (and thus can effectively parse the + * {@link SearchHit} while this class is used when scrolling and passing down + * the results. + * + * In the future, the processor might be used across the board for all columns + * to reduce API complexity (and keep the {@link HitExtractor} only as an + * internal implementation detail). + */ +public class ComputingExtractor implements HitExtractor, BucketExtractor { + /** + * Stands for {@code comPuting}. We try to use short names for {@link HitExtractor}s + * to save a few bytes when when we send them back to the user. + */ + static final String NAME = "p"; + private final Processor processor; + private final String hitName; + + public ComputingExtractor(Processor processor) { + this(processor, null); + } + + public ComputingExtractor(Processor processor, String hitName) { + this.processor = processor; + this.hitName = hitName; + } + + // Visibility required for tests + public ComputingExtractor(StreamInput in) throws IOException { + processor = in.readNamedWriteable(Processor.class); + hitName = in.readOptionalString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteable(processor); + out.writeOptionalString(hitName); + } + + @Override + public String getWriteableName() { + return NAME; + } + + public Processor processor() { + return processor; + } + + public Object extract(Object input) { + return processor.process(input); + } + + @Override + public Object extract(Bucket bucket) { + return processor.process(bucket); + } + + @Override + public Object extract(SearchHit hit) { + return processor.process(hit); + } + + @Override + public String hitName() { + return hitName; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + ComputingExtractor other = (ComputingExtractor) obj; + return Objects.equals(processor, other.processor) && Objects.equals(hitName, other.hitName); + } + + @Override + public int hashCode() { + return Objects.hash(processor, hitName); + } + + @Override + public String toString() { + return processor.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ConstantExtractor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ConstantExtractor.java new file mode 100644 index 000000000000..bba311a085ed --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ConstantExtractor.java @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket; + +import java.io.IOException; +import java.util.Objects; + +/** + * Returns the a constant for every search hit against which it is run. + */ +public class ConstantExtractor implements HitExtractor, BucketExtractor { + /** + * Stands for {@code constant}. We try to use short names for {@link HitExtractor}s + * to save a few bytes when when we send them back to the user. + */ + static final String NAME = "c"; + private final Object constant; + + public ConstantExtractor(Object constant) { + this.constant = constant; + } + + ConstantExtractor(StreamInput in) throws IOException { + constant = in.readGenericValue(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeGenericValue(constant); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public Object extract(SearchHit hit) { + return constant; + } + + @Override + public Object extract(Bucket bucket) { + return constant; + } + + @Override + public String hitName() { + return null; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + ConstantExtractor other = (ConstantExtractor) obj; + return Objects.equals(constant, other.constant); + } + + @Override + public int hashCode() { + return Objects.hashCode(constant); + } + + @Override + public String toString() { + return "^" + constant; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/HitExtractor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/HitExtractor.java new file mode 100644 index 000000000000..38b72c5e8cd7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/HitExtractor.java @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.core.Nullable; +import org.elasticsearch.search.SearchHit; + +/** + * Extracts a column value from a {@link SearchHit}. + */ +public interface HitExtractor extends NamedWriteable { + /** + * Extract the value from a hit. + */ + Object extract(SearchHit hit); + + /** + * Name of the inner hit needed by this extractor if it needs one, {@code null} otherwise. + */ + @Nullable + String hitName(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/HitExtractors.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/HitExtractors.java new file mode 100644 index 000000000000..743856d41f8d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/HitExtractors.java @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; + +import java.util.ArrayList; +import java.util.List; + +public final class HitExtractors { + + private HitExtractors() {} + + /** + * All of the named writeables needed to deserialize the instances of + * {@linkplain HitExtractor}. + */ + public static List getNamedWriteables() { + List entries = new ArrayList<>(); + entries.add(new Entry(HitExtractor.class, ConstantExtractor.NAME, ConstantExtractor::new)); + entries.add(new Entry(HitExtractor.class, ComputingExtractor.NAME, ComputingExtractor::new)); + return entries; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/TotalHitsExtractor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/TotalHitsExtractor.java new file mode 100644 index 000000000000..52a911661902 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/TotalHitsExtractor.java @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.io.IOException; + +public class TotalHitsExtractor extends ConstantExtractor { + + public TotalHitsExtractor(Long constant) { + super(constant); + } + + TotalHitsExtractor(StreamInput in) throws IOException { + super(in); + } + + @Override + public Object extract(MultiBucketsAggregation.Bucket bucket) { + return validate(super.extract(bucket)); + } + + @Override + public Object extract(SearchHit hit) { + return validate(super.extract(hit)); + } + + private static Object validate(Object value) { + if (Number.class.isInstance(value) == false) { + throw new QlIllegalArgumentException( + "Inconsistent total hits count handling, expected a numeric value but found a {}: {}", + value == null ? null : value.getClass().getSimpleName(), + value + ); + } + if (((Number) value).longValue() < 0) { + throw new QlIllegalArgumentException( + "Inconsistent total hits count handling, expected a non-negative value but found {}", + value + ); + } + return value; + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Alias.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Alias.java new file mode 100644 index 000000000000..58203c8a0072 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Alias.java @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.List; + +import static java.util.Collections.singletonList; + +/** + * An {@code Alias} is a {@code NamedExpression} that gets renamed to something else through the Alias. + * + * For example, in the statement {@code 5 + 2 AS x}, {@code x} is an alias which is points to {@code ADD(5, 2)}. + * + * And in {@code SELECT col AS x} "col" is a named expression that gets renamed to "x" through an alias. + * + */ +public class Alias extends NamedExpression { + + private final Expression child; + private final String qualifier; + + /** + * Postpone attribute creation until it is actually created. + * Being immutable, create only one instance. + */ + private Attribute lazyAttribute; + + public Alias(Source source, String name, Expression child) { + this(source, name, null, child, null); + } + + public Alias(Source source, String name, String qualifier, Expression child) { + this(source, name, qualifier, child, null); + } + + public Alias(Source source, String name, String qualifier, Expression child, NameId id) { + this(source, name, qualifier, child, id, false); + } + + public Alias(Source source, String name, String qualifier, Expression child, NameId id, boolean synthetic) { + super(source, name, singletonList(child), id, synthetic); + this.child = child; + this.qualifier = qualifier; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Alias::new, name(), qualifier, child, id(), synthetic()); + } + + public Alias replaceChild(Expression child) { + return new Alias(source(), name(), qualifier, child, id(), synthetic()); + } + + @Override + public Alias replaceChildren(List newChildren) { + return new Alias(source(), name(), qualifier, newChildren.get(0), id(), synthetic()); + } + + public Expression child() { + return child; + } + + public String qualifier() { + return qualifier; + } + + public String qualifiedName() { + return qualifier == null ? name() : qualifier + "." + name(); + } + + @Override + public Nullability nullable() { + return child.nullable(); + } + + @Override + public DataType dataType() { + return child.dataType(); + } + + @Override + public Attribute toAttribute() { + if (lazyAttribute == null) { + lazyAttribute = resolved() + ? new ReferenceAttribute(source(), name(), dataType(), qualifier, nullable(), id(), synthetic()) + : new UnresolvedAttribute(source(), name(), qualifier); + } + return lazyAttribute; + } + + @Override + public String toString() { + return child + " AS " + name() + "#" + id(); + } + + @Override + public String nodeString() { + return child.nodeString() + " AS " + name(); + } + + /** + * If the given expression is an alias, return its child - otherwise return as is. + */ + public static Expression unwrap(Expression e) { + return e instanceof Alias as ? as.child() : e; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Attribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Attribute.java new file mode 100644 index 000000000000..0736ad3d1e29 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Attribute.java @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.core.Tuple; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.emptyList; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.splitQualifiedIndex; + +/** + * {@link Expression}s that can be materialized and describe properties of the derived table. + * In other words, an attribute represent a column in the results of a query. + * + * In the statement {@code SELECT ABS(foo), A, B+C FROM ...} the three named + * expressions {@code ABS(foo), A, B+C} get converted to attributes and the user can + * only see Attributes. + * + * In the statement {@code SELECT foo FROM TABLE WHERE foo > 10 + 1} only {@code foo} inside the SELECT + * is a named expression (an {@code Alias} will be created automatically for it). + * The rest are not as they are not part of the projection and thus are not part of the derived table. + */ +public abstract class Attribute extends NamedExpression { + + // empty - such as a top level attribute in SELECT cause + // present - table name or a table name alias + private final String qualifier; + // cluster name in the qualifier (if any) + private final String cluster; + + // can the attr be null - typically used in JOINs + private final Nullability nullability; + + public Attribute(Source source, String name, String qualifier, NameId id) { + this(source, name, qualifier, Nullability.TRUE, id); + } + + public Attribute(Source source, String name, String qualifier, Nullability nullability, NameId id) { + this(source, name, qualifier, nullability, id, false); + } + + public Attribute(Source source, String name, String qualifier, Nullability nullability, NameId id, boolean synthetic) { + super(source, name, emptyList(), id, synthetic); + if (qualifier != null) { + Tuple splitQualifier = splitQualifiedIndex(qualifier); + this.cluster = splitQualifier.v1(); + this.qualifier = splitQualifier.v2(); + } else { + this.cluster = null; + this.qualifier = null; + } + this.nullability = nullability; + } + + @Override + public final Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + public String qualifier() { + return qualifier; + } + + public String qualifiedName() { + return qualifier == null ? name() : qualifier + "." + name(); + } + + @Override + public Nullability nullable() { + return nullability; + } + + @Override + public AttributeSet references() { + return new AttributeSet(this); + } + + public Attribute withLocation(Source source) { + return Objects.equals(source(), source) ? this : clone(source, name(), dataType(), qualifier(), nullable(), id(), synthetic()); + } + + public Attribute withQualifier(String qualifier) { + return Objects.equals(qualifier(), qualifier) + ? this + : clone(source(), name(), dataType(), qualifier, nullable(), id(), synthetic()); + } + + public Attribute withName(String name) { + return Objects.equals(name(), name) ? this : clone(source(), name, dataType(), qualifier(), nullable(), id(), synthetic()); + } + + public Attribute withNullability(Nullability nullability) { + return Objects.equals(nullable(), nullability) + ? this + : clone(source(), name(), dataType(), qualifier(), nullability, id(), synthetic()); + } + + public Attribute withId(NameId id) { + return clone(source(), name(), dataType(), qualifier(), nullable(), id, synthetic()); + } + + public Attribute withDataType(DataType type) { + return Objects.equals(dataType(), type) ? this : clone(source(), name(), type, qualifier(), nullable(), id(), synthetic()); + } + + protected abstract Attribute clone( + Source source, + String name, + DataType type, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ); + + @Override + public Attribute toAttribute() { + return this; + } + + @Override + public int semanticHash() { + return id().hashCode(); + } + + @Override + public boolean semanticEquals(Expression other) { + return other instanceof Attribute ? id().equals(((Attribute) other).id()) : false; + } + + @Override + protected Expression canonicalize() { + return clone(Source.EMPTY, name(), dataType(), qualifier, nullability, id(), synthetic()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), qualifier, nullability); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + Attribute other = (Attribute) obj; + return Objects.equals(qualifier, other.qualifier) && Objects.equals(nullability, other.nullability); + } + + return false; + } + + @Override + public String toString() { + return qualifiedName() + "{" + label() + "}" + "#" + id(); + } + + @Override + public String nodeString() { + return toString(); + } + + protected abstract String label(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeMap.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeMap.java new file mode 100644 index 000000000000..64a7b36cf162 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeMap.java @@ -0,0 +1,406 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.common.util.set.Sets; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import static java.util.Collections.emptyMap; + +/** + * Dedicated map for checking {@link Attribute} equality. + * This is typically the case when comparing the initial declaration of an Attribute, such as {@link FieldAttribute} with + * references to it, namely {@link ReferenceAttribute}. + * Using plain object equality, the two references are difference due to their type however semantically, they are the same. + * Expressions support semantic equality through {@link Expression#semanticEquals(Expression)} - this map is dedicated solution + * for attributes as its common case picked up by the plan rules. + *

+ * The map implementation is mutable thus consumers need to be careful NOT to modify the content unless they have ownership. + * Worth noting the {@link #combine(AttributeMap)}, {@link #intersect(AttributeMap)} and {@link #subtract(AttributeMap)} methods which + * return copies, decoupled from the input maps. In other words the returned maps can be modified without affecting the input or vice-versa. + */ +public final class AttributeMap implements Map { + + static class AttributeWrapper { + + private final Attribute attr; + + AttributeWrapper(Attribute attr) { + this.attr = attr; + } + + @Override + public int hashCode() { + return attr.semanticHash(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof AttributeWrapper aw ? attr.semanticEquals(aw.attr) : false; + } + + @Override + public String toString() { + return attr.toString(); + } + } + + /** + * Set that does unwrapping of keys inside the keySet and iterator. + */ + private abstract static class UnwrappingSet extends AbstractSet { + private final Set set; + + UnwrappingSet(Set originalSet) { + set = originalSet; + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + final Iterator i = set.iterator(); + + @Override + public boolean hasNext() { + return i.hasNext(); + } + + @Override + public U next() { + return unwrap(i.next()); + } + + @Override + public void remove() { + i.remove(); + } + }; + } + + protected abstract U unwrap(W next); + + @Override + public Stream stream() { + return set.stream().map(this::unwrap); + } + + @Override + public Stream parallelStream() { + return set.parallelStream().map(this::unwrap); + } + + @Override + public int size() { + return set.size(); + } + + @Override + public boolean equals(Object o) { + return set.equals(o); + } + + @Override + public int hashCode() { + return set.hashCode(); + } + + @Override + public Object[] toArray() { + Object[] array = set.toArray(); + for (int i = 0; i < array.length; i++) { + array[i] = ((AttributeWrapper) array[i]).attr; + } + return array; + } + + @Override + @SuppressWarnings("unchecked") + public A[] toArray(A[] a) { + // collection is immutable so use that to our advantage + if (a.length < size()) { + a = (A[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size()); + } + int i = 0; + Object[] result = a; + for (U u : this) { + result[i++] = u; + } + // array larger than size, mark the ending element as null + if (a.length > size()) { + a[size()] = null; + } + return a; + } + + @Override + public String toString() { + return set.toString(); + } + } + + @SuppressWarnings("rawtypes") + private static final AttributeMap EMPTY = new AttributeMap<>(emptyMap()); + + @SuppressWarnings("unchecked") + public static AttributeMap emptyAttributeMap() { + return EMPTY; + } + + private final Map delegate; + + private AttributeMap(Map other) { + delegate = other; + } + + public AttributeMap() { + delegate = new LinkedHashMap<>(); + } + + public AttributeMap(Attribute key, E value) { + delegate = new LinkedHashMap<>(); + add(key, value); + } + + public AttributeMap combine(AttributeMap other) { + AttributeMap combine = new AttributeMap<>(); + combine.addAll(this); + combine.addAll(other); + + return combine; + } + + public AttributeMap subtract(AttributeMap other) { + AttributeMap diff = new AttributeMap<>(); + for (Entry entry : this.delegate.entrySet()) { + if (other.delegate.containsKey(entry.getKey()) == false) { + diff.delegate.put(entry.getKey(), entry.getValue()); + } + } + + return diff; + } + + public AttributeMap intersect(AttributeMap other) { + AttributeMap smaller = (other.size() > size() ? this : other); + AttributeMap larger = (smaller == this ? other : this); + + AttributeMap intersect = new AttributeMap<>(); + for (Entry entry : smaller.delegate.entrySet()) { + if (larger.delegate.containsKey(entry.getKey())) { + intersect.delegate.put(entry.getKey(), entry.getValue()); + } + } + + return intersect; + } + + public boolean subsetOf(AttributeMap other) { + if (this.size() > other.size()) { + return false; + } + for (AttributeWrapper aw : delegate.keySet()) { + if (other.delegate.containsKey(aw) == false) { + return false; + } + } + + return true; + } + + public void add(Attribute key, E value) { + put(key, value); + } + + public void addAll(AttributeMap other) { + putAll(other); + } + + public Set attributeNames() { + Set s = Sets.newLinkedHashSetWithExpectedSize(size()); + + for (AttributeWrapper aw : delegate.keySet()) { + s.add(aw.attr.name()); + } + return s; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return key instanceof NamedExpression ne ? delegate.containsKey(new AttributeWrapper(ne.toAttribute())) : false; + } + + @Override + public boolean containsValue(Object value) { + return delegate.containsValue(value); + } + + @Override + public E get(Object key) { + return key instanceof NamedExpression ne ? delegate.get(new AttributeWrapper(ne.toAttribute())) : null; + } + + @Override + public E getOrDefault(Object key, E defaultValue) { + return key instanceof NamedExpression ne + ? delegate.getOrDefault(new AttributeWrapper(ne.toAttribute()), defaultValue) + : defaultValue; + } + + public E resolve(Object key) { + return resolve(key, null); + } + + public E resolve(Object key, E defaultValue) { + E value = defaultValue; + E candidate = null; + int allowedLookups = 1000; + while ((candidate = get(key)) != null || containsKey(key)) { + // instead of circling around, return + if (candidate == key) { + return candidate; + } + if (--allowedLookups == 0) { + throw new QlIllegalArgumentException("Potential cycle detected"); + } + key = candidate; + value = candidate; + } + return value; + } + + @Override + public E put(Attribute key, E value) { + return delegate.put(new AttributeWrapper(key), value); + } + + @Override + public void putAll(Map m) { + for (Entry entry : m.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + @Override + public E remove(Object key) { + return key instanceof NamedExpression ne ? delegate.remove(new AttributeWrapper(ne.toAttribute())) : null; + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Set keySet() { + return new UnwrappingSet<>(delegate.keySet()) { + @Override + protected Attribute unwrap(AttributeWrapper next) { + return next.attr; + } + }; + } + + @Override + public Collection values() { + return delegate.values(); + } + + @Override + public Set> entrySet() { + return new UnwrappingSet<>(delegate.entrySet()) { + @Override + protected Entry unwrap(final Entry next) { + return new Entry<>() { + @Override + public Attribute getKey() { + return next.getKey().attr; + } + + @Override + public E getValue() { + return next.getValue(); + } + + @Override + public E setValue(E value) { + return next.setValue(value); + } + }; + } + }; + } + + @Override + public void forEach(BiConsumer action) { + delegate.forEach((k, v) -> action.accept(k.attr, v)); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AttributeMap am) { + obj = am.delegate; + } + return delegate.equals(obj); + } + + @Override + public String toString() { + return delegate.toString(); + } + + public static Builder builder() { + return new Builder<>(); + } + + public static Builder builder(AttributeMap map) { + return new Builder().putAll(map); + } + + public static class Builder { + private AttributeMap map = new AttributeMap<>(); + + private Builder() {} + + public Builder put(Attribute attr, E value) { + map.add(attr, value); + return this; + } + + public Builder putAll(AttributeMap m) { + map.addAll(m); + return this; + } + + public AttributeMap build() { + return map; + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java new file mode 100644 index 000000000000..e3eac6070391 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/AttributeSet.java @@ -0,0 +1,190 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Set variant of {@link AttributeMap} - please see that class Javadoc. + */ +public class AttributeSet implements Set { + + public static final AttributeSet EMPTY = new AttributeSet(AttributeMap.emptyAttributeMap()); + + // use the same name as in HashSet + private static final Object PRESENT = new Object(); + + private final AttributeMap delegate; + + public AttributeSet() { + delegate = new AttributeMap<>(); + } + + public AttributeSet(Attribute attr) { + delegate = new AttributeMap<>(attr, PRESENT); + } + + public AttributeSet(Collection attr) { + delegate = new AttributeMap<>(); + + for (Attribute a : attr) { + delegate.add(a, PRESENT); + } + } + + private AttributeSet(AttributeMap delegate) { + this.delegate = delegate; + } + + public AttributeSet combine(AttributeSet other) { + return new AttributeSet(delegate.combine(other.delegate)); + } + + public AttributeSet subtract(AttributeSet other) { + return new AttributeSet(delegate.subtract(other.delegate)); + } + + public AttributeSet intersect(AttributeSet other) { + return new AttributeSet(delegate.intersect(other.delegate)); + } + + public boolean subsetOf(AttributeSet other) { + return delegate.subsetOf(other.delegate); + } + + public Set names() { + return delegate.attributeNames(); + } + + @Override + public void forEach(Consumer action) { + delegate.forEach((k, v) -> action.accept(k)); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.containsKey(o); + } + + @Override + public boolean containsAll(Collection c) { + for (Object o : c) { + if (delegate.containsKey(o) == false) { + return false; + } + } + return true; + } + + @Override + public Iterator iterator() { + return delegate.keySet().iterator(); + } + + @Override + public Object[] toArray() { + return delegate.keySet().toArray(); + } + + @Override + public T[] toArray(T[] a) { + return delegate.keySet().toArray(a); + } + + @Override + public boolean add(Attribute e) { + return delegate.put(e, PRESENT) != null; + } + + @Override + public boolean remove(Object o) { + return delegate.remove(o) != null; + } + + public void addAll(AttributeSet other) { + delegate.addAll(other.delegate); + } + + @Override + public boolean addAll(Collection c) { + int size = delegate.size(); + for (var e : c) { + delegate.put(e, PRESENT); + } + return delegate.size() != size; + } + + @Override + public boolean retainAll(Collection c) { + return delegate.keySet().removeIf(e -> c.contains(e) == false); + } + + @Override + public boolean removeAll(Collection c) { + int size = delegate.size(); + for (var e : c) { + delegate.remove(e); + } + return delegate.size() != size; + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Spliterator spliterator() { + return delegate.keySet().spliterator(); + } + + @Override + public boolean removeIf(Predicate filter) { + return delegate.keySet().removeIf(filter); + } + + @Override + public Stream stream() { + return delegate.keySet().stream(); + } + + @Override + public Stream parallelStream() { + return delegate.keySet().parallelStream(); + } + + @Override + public boolean equals(Object o) { + return delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.keySet().toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/EmptyAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/EmptyAttribute.java new file mode 100644 index 000000000000..56e5c65b179f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/EmptyAttribute.java @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +/** + * Marker for optional attributes. Acting as a dummy placeholder to avoid using null + * in the tree (which is not allowed). + */ +public class EmptyAttribute extends Attribute { + + public EmptyAttribute(Source source) { + super(source, StringUtils.EMPTY, null, null); + } + + @Override + protected Attribute clone( + Source source, + String name, + DataType type, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + return this; + } + + @Override + protected String label() { + return "e"; + } + + @Override + public boolean resolved() { + return true; + } + + @Override + public DataType dataType() { + return DataTypes.NULL; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this); + } + + @Override + public int hashCode() { + return EmptyAttribute.class.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expression.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expression.java new file mode 100644 index 000000000000..00765a8c0528 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expression.java @@ -0,0 +1,199 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvable; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.List; +import java.util.function.Supplier; + +/** + * In a SQL statement, an Expression is whatever a user specifies inside an + * action, so for instance: + * + * {@code SELECT a, b, ABS(c) FROM i} + * + * a, b, ABS(c), and i are all Expressions, with ABS(c) being a Function + * (which is a type of expression) with a single child, c. + */ +public abstract class Expression extends Node implements Resolvable { + + public static class TypeResolution { + private final boolean failed; + private final String message; + + public static final TypeResolution TYPE_RESOLVED = new TypeResolution(false, StringUtils.EMPTY); + + public TypeResolution(String message) { + this(true, message); + } + + private TypeResolution(boolean unresolved, String message) { + this.failed = unresolved; + this.message = message; + } + + public boolean unresolved() { + return failed; + } + + public boolean resolved() { + return failed == false; + } + + public TypeResolution and(TypeResolution other) { + return failed ? this : other; + } + + public TypeResolution and(Supplier other) { + return failed ? this : other.get(); + } + + public String message() { + return message; + } + + @Override + public String toString() { + return resolved() ? "" : message; + } + } + + private TypeResolution lazyTypeResolution = null; + private Boolean lazyChildrenResolved = null; + private Expression lazyCanonical = null; + private AttributeSet lazyReferences = null; + + public Expression(Source source, List children) { + super(source, children); + } + + // whether the expression can be evaluated statically (folded) or not + public boolean foldable() { + return false; + } + + public Object fold() { + throw new QlIllegalArgumentException("Should not fold expression"); + } + + public abstract Nullability nullable(); + + // the references/inputs/leaves of the expression tree + public AttributeSet references() { + if (lazyReferences == null) { + lazyReferences = Expressions.references(children()); + } + return lazyReferences; + } + + public boolean childrenResolved() { + if (lazyChildrenResolved == null) { + lazyChildrenResolved = Boolean.valueOf(Resolvables.resolved(children())); + } + return lazyChildrenResolved; + } + + /** + * Does the tree rooted at this expression have valid types at all nodes? + *

+ * For example, {@code SIN(1.2)} has a valid type and should return + * {@link TypeResolution#TYPE_RESOLVED} to signal "this type is fine". + * Another example, {@code SIN("cat")} has an invalid type in the + * tree. The value passed to the {@code SIN} function is a string which + * doesn't make any sense. So this method should return a "failure" + * resolution which it can build by calling {@link TypeResolution#TypeResolution(String)}. + *

+ *

+ * Take {@code SIN(1.2) + COS(ATAN("cat"))}, this tree should also + * fail, specifically because {@code ATAN("cat")} is invalid. This should + * fail even though {@code +} is perfectly valid when run on the results + * of {@code SIN} and {@code COS}. And {@code COS} can operate on the results + * of any valid call to {@code ATAN}. For this method to return a "valid" + * result the whole tree rooted at this expression must + * be valid. + *

+ */ + public final TypeResolution typeResolved() { + if (lazyTypeResolution == null) { + lazyTypeResolution = resolveType(); + } + return lazyTypeResolution; + } + + /** + * The implementation of {@link #typeResolved}, which is just a caching wrapper + * around this method. See it's javadoc for what this method should return. + *

+ * Implementations will rarely interact with the {@link TypeResolution} + * class directly, instead usually calling the utility methods on {@link TypeResolutions}. + *

+ *

+ * Implementations should fail if {@link #childrenResolved()} returns {@code false}. + *

+ */ + protected TypeResolution resolveType() { + return TypeResolution.TYPE_RESOLVED; + } + + public final Expression canonical() { + if (lazyCanonical == null) { + lazyCanonical = canonicalize(); + } + return lazyCanonical; + } + + protected Expression canonicalize() { + if (children().isEmpty()) { + return this; + } + List canonicalChildren = Expressions.canonicalize(children()); + // check if replacement is really needed + if (children().equals(canonicalChildren)) { + return this; + } + return replaceChildrenSameSize(canonicalChildren); + } + + public boolean semanticEquals(Expression other) { + return canonical().equals(other.canonical()); + } + + public int semanticHash() { + return canonical().hashCode(); + } + + @Override + public boolean resolved() { + return childrenResolved() && typeResolved().resolved(); + } + + /** + * The {@link DataType} returned by executing the tree rooted at this + * expression. If {@link #typeResolved()} returns an error then the behavior + * of this method is undefined. It may return a valid + * type. Or it may throw an exception. Or it may return a totally nonsensical + * type. + */ + public abstract DataType dataType(); + + @Override + public String toString() { + return sourceText(); + } + + @Override + public String propertiesToString(boolean skipIfChild) { + return super.propertiesToString(false); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/ExpressionSet.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/ExpressionSet.java new file mode 100644 index 000000000000..befccc39cdb1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/ExpressionSet.java @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static java.util.Collections.emptyList; + +/** + * @param expression type + */ +public final class ExpressionSet implements Set { + + @SuppressWarnings("rawtypes") + public static final ExpressionSet EMPTY = new ExpressionSet<>(emptyList()); + + @SuppressWarnings("unchecked") + public static ExpressionSet emptySet() { + return (ExpressionSet) EMPTY; + } + + // canonical to actual/original association + private final Map map = new LinkedHashMap<>(); + + public ExpressionSet() { + super(); + } + + public ExpressionSet(Collection c) { + addAll(c); + } + + // Returns the equivalent expression (if already exists in the set) or null if none is found + public E get(Expression e) { + return map.get(e.canonical()); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o instanceof Expression) { + return map.containsKey(((Expression) o).canonical()); + } + return false; + } + + @Override + public boolean containsAll(Collection c) { + for (Object o : c) { + if (contains(o) == false) { + return false; + } + } + return true; + } + + @Override + public Iterator iterator() { + return map.values().iterator(); + } + + @Override + public boolean add(E e) { + return map.putIfAbsent(e.canonical(), e) == null; + } + + @Override + public boolean addAll(Collection c) { + boolean result = true; + for (E o : c) { + result &= add(o); + } + return result; + } + + @Override + public boolean retainAll(Collection c) { + boolean modified = false; + + Iterator keys = map.keySet().iterator(); + + while (keys.hasNext()) { + Expression key = keys.next(); + boolean found = false; + for (Object o : c) { + if (o instanceof Expression) { + o = ((Expression) o).canonical(); + } + if (key.equals(o)) { + found = true; + break; + } + } + if (found == false) { + keys.remove(); + } + } + return modified; + } + + @Override + public boolean remove(Object o) { + if (o instanceof Expression) { + return map.remove(((Expression) o).canonical()) != null; + } + return false; + } + + @Override + public boolean removeAll(Collection c) { + boolean modified = false; + for (Object o : c) { + modified |= remove(o); + } + return modified; + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Object[] toArray() { + return map.values().toArray(); + } + + @Override + public T[] toArray(T[] a) { + return map.values().toArray(a); + } + + @Override + public String toString() { + return map.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expressions.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expressions.java new file mode 100644 index 000000000000..7c14c425e5e1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expressions.java @@ -0,0 +1,241 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.core.Tuple; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.AttributeInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.ConstantInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +import static java.util.Collections.emptyList; + +public final class Expressions { + + private Expressions() {} + + public static NamedExpression wrapAsNamed(Expression exp) { + return exp instanceof NamedExpression ne ? ne : new Alias(exp.source(), exp.sourceText(), exp); + } + + public static List asAttributes(List named) { + if (named.isEmpty()) { + return emptyList(); + } + List list = new ArrayList<>(named.size()); + for (NamedExpression exp : named) { + list.add(exp.toAttribute()); + } + return list; + } + + public static AttributeMap asAttributeMap(List named) { + if (named.isEmpty()) { + return AttributeMap.emptyAttributeMap(); + } + + AttributeMap map = new AttributeMap<>(); + for (NamedExpression exp : named) { + map.add(exp.toAttribute(), exp); + } + return map; + } + + public static boolean anyMatch(List exps, Predicate predicate) { + for (Expression exp : exps) { + if (exp.anyMatch(predicate)) { + return true; + } + } + return false; + } + + public static boolean match(List exps, Predicate predicate) { + for (Expression exp : exps) { + if (predicate.test(exp)) { + return true; + } + } + return false; + } + + /** + * Return the logical AND of a list of {@code Nullability} + *
+     *  UNKNOWN AND TRUE/FALSE/UNKNOWN = UNKNOWN
+     *  FALSE AND FALSE = FALSE
+     *  TRUE AND FALSE/TRUE = TRUE
+     * 
+ */ + public static Nullability nullable(List exps) { + Nullability value = Nullability.FALSE; + for (Expression exp : exps) { + switch (exp.nullable()) { + case UNKNOWN: + return Nullability.UNKNOWN; + case TRUE: + value = Nullability.TRUE; + break; + default: + // not nullable + break; + } + } + return value; + } + + public static List canonicalize(List exps) { + List canonical = new ArrayList<>(exps.size()); + for (Expression exp : exps) { + canonical.add(exp.canonical()); + } + return canonical; + } + + public static boolean foldable(List exps) { + for (Expression exp : exps) { + if (exp.foldable() == false) { + return false; + } + } + return true; + } + + public static List fold(List exps) { + List folded = new ArrayList<>(exps.size()); + for (Expression exp : exps) { + folded.add(exp.fold()); + } + + return folded; + } + + public static AttributeSet references(List exps) { + if (exps.isEmpty()) { + return AttributeSet.EMPTY; + } + + AttributeSet set = new AttributeSet(); + for (Expression exp : exps) { + set.addAll(exp.references()); + } + return set; + } + + public static String name(Expression e) { + return e instanceof NamedExpression ne ? ne.name() : e.sourceText(); + } + + public static boolean isNull(Expression e) { + return e.dataType() == DataTypes.NULL || (e.foldable() && e.fold() == null); + } + + public static List names(Collection e) { + List names = new ArrayList<>(e.size()); + for (Expression ex : e) { + names.add(name(ex)); + } + + return names; + } + + public static Attribute attribute(Expression e) { + if (e instanceof NamedExpression ne) { + return ne.toAttribute(); + } + return null; + } + + public static boolean isPresent(NamedExpression e) { + return e instanceof EmptyAttribute == false; + } + + public static boolean equalsAsAttribute(Expression left, Expression right) { + if (left.semanticEquals(right) == false) { + Attribute l = attribute(left); + return (l != null && l.semanticEquals(attribute(right))); + } + return true; + } + + public static List> aliases(List named) { + // an alias of same name and data type can be reused (by mistake): need to use a list to collect all refs (and later report them) + List> aliases = new ArrayList<>(); + for (NamedExpression ne : named) { + if (ne instanceof Alias as) { + aliases.add(new Tuple<>(ne.toAttribute(), as.child())); + } + } + return aliases; + } + + public static boolean hasReferenceAttribute(Collection output) { + for (Attribute attribute : output) { + if (attribute instanceof ReferenceAttribute) { + return true; + } + } + return false; + } + + public static List onlyPrimitiveFieldAttributes(Collection attributes) { + List filtered = new ArrayList<>(); + // add only primitives + // but filter out multi fields (allow only the top-level value) + Set seenMultiFields = new LinkedHashSet<>(); + + for (Attribute a : attributes) { + if (DataTypes.isUnsupported(a.dataType()) == false && DataTypes.isPrimitive(a.dataType())) { + if (a instanceof FieldAttribute fa) { + // skip nested fields and seen multi-fields + if (fa.isNested() == false && seenMultiFields.contains(fa.parent()) == false) { + filtered.add(a); + seenMultiFields.add(a); + } + } else { + filtered.add(a); + } + } + } + + return filtered; + } + + public static Pipe pipe(Expression e) { + if (e.foldable()) { + return new ConstantInput(e.source(), e, e.fold()); + } + if (e instanceof NamedExpression ne) { + return new AttributeInput(e.source(), e, ne.toAttribute()); + } + if (e instanceof Function f) { + return f.asPipe(); + } + throw new QlIllegalArgumentException("Cannot create pipe for {}", e); + } + + public static List pipe(List expressions) { + List pipes = new ArrayList<>(expressions.size()); + for (Expression e : expressions) { + pipes.add(pipe(e)); + } + return pipes; + } + + public static String id(Expression e) { + return Integer.toHexString(e.hashCode()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java new file mode 100644 index 000000000000..fc63ab5d8e7f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/FieldAttribute.java @@ -0,0 +1,156 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.Objects; + +/** + * Attribute for an ES field. + * To differentiate between the different type of fields this class offers: + * - name - the fully qualified name (foo.bar.tar) + * - path - the path pointing to the field name (foo.bar) + * - parent - the immediate parent of the field; useful for figuring out the type of field (nested vs object) + * - nestedParent - if nested, what's the parent (which might not be the immediate one) + */ +public class FieldAttribute extends TypedAttribute { + + private final FieldAttribute parent; + private final FieldAttribute nestedParent; + private final String path; + private final EsField field; + + public FieldAttribute(Source source, String name, EsField field) { + this(source, null, name, field); + } + + public FieldAttribute(Source source, FieldAttribute parent, String name, EsField field) { + this(source, parent, name, field, null, Nullability.TRUE, null, false); + } + + public FieldAttribute( + Source source, + FieldAttribute parent, + String name, + EsField field, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + this(source, parent, name, field.getDataType(), field, qualifier, nullability, id, synthetic); + } + + public FieldAttribute( + Source source, + FieldAttribute parent, + String name, + DataType type, + EsField field, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + super(source, name, type, qualifier, nullability, id, synthetic); + this.path = parent != null ? parent.name() : StringUtils.EMPTY; + this.parent = parent; + this.field = field; + + // figure out the last nested parent + FieldAttribute nestedPar = null; + if (parent != null) { + nestedPar = parent.nestedParent; + if (parent.dataType() == DataTypes.NESTED) { + nestedPar = parent; + } + } + this.nestedParent = nestedPar; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, FieldAttribute::new, parent, name(), dataType(), field, qualifier(), nullable(), id(), synthetic()); + } + + public FieldAttribute parent() { + return parent; + } + + public String path() { + return path; + } + + public String qualifiedPath() { + // return only the qualifier is there's no path + return qualifier() != null ? qualifier() + (Strings.hasText(path) ? "." + path : StringUtils.EMPTY) : path; + } + + public boolean isNested() { + return nestedParent != null; + } + + public FieldAttribute nestedParent() { + return nestedParent; + } + + public EsField.Exact getExactInfo() { + return field.getExactInfo(); + } + + public FieldAttribute exactAttribute() { + EsField exactField = field.getExactField(); + if (exactField.equals(field) == false) { + return innerField(exactField); + } + return this; + } + + private FieldAttribute innerField(EsField type) { + return new FieldAttribute(source(), this, name() + "." + type.getName(), type, qualifier(), nullable(), id(), synthetic()); + } + + @Override + protected Attribute clone( + Source source, + String name, + DataType type, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + FieldAttribute qualifiedParent = parent != null ? (FieldAttribute) parent.withQualifier(qualifier) : null; + return new FieldAttribute(source, qualifiedParent, name, field, qualifier, nullability, id, synthetic); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), path); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) && Objects.equals(path, ((FieldAttribute) obj).path); + } + + @Override + protected String label() { + return "f"; + } + + public EsField field() { + return field; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Foldables.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Foldables.java new file mode 100644 index 000000000000..601758bca591 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Foldables.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +public abstract class Foldables { + + public static Object valueOf(Expression e) { + if (e.foldable()) { + return e.fold(); + } + throw new QlIllegalArgumentException("Cannot determine value for {}", e); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/LeafExpression.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/LeafExpression.java new file mode 100644 index 000000000000..d18c549b2500 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/LeafExpression.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; + +import static java.util.Collections.emptyList; + +public abstract class LeafExpression extends Expression { + + protected LeafExpression(Source source) { + super(source, emptyList()); + } + + @Override + public final Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + public AttributeSet references() { + return AttributeSet.EMPTY; + } + + @Override + protected Expression canonicalize() { + return this; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java new file mode 100644 index 000000000000..ea37629df608 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Literal.java @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.Objects; + +/** + * SQL Literal or constant. + */ +public class Literal extends LeafExpression { + + public static final Literal TRUE = new Literal(Source.EMPTY, Boolean.TRUE, DataTypes.BOOLEAN); + public static final Literal FALSE = new Literal(Source.EMPTY, Boolean.FALSE, DataTypes.BOOLEAN); + public static final Literal NULL = new Literal(Source.EMPTY, null, DataTypes.NULL); + + private final Object value; + private final DataType dataType; + + public Literal(Source source, Object value, DataType dataType) { + super(source); + this.dataType = dataType; + this.value = value; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Literal::new, value, dataType); + } + + public Object value() { + return value; + } + + @Override + public boolean foldable() { + return true; + } + + @Override + public Nullability nullable() { + return value == null ? Nullability.TRUE : Nullability.FALSE; + } + + @Override + public DataType dataType() { + return dataType; + } + + @Override + public boolean resolved() { + return true; + } + + @Override + public Object fold() { + return value; + } + + @Override + public int hashCode() { + return Objects.hash(dataType, value); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Literal other = (Literal) obj; + return Objects.equals(value, other.value) && Objects.equals(dataType, other.dataType); + } + + @Override + public String toString() { + return String.valueOf(value); + } + + @Override + public String nodeString() { + return toString() + "[" + dataType + "]"; + } + + /** + * Utility method for creating a literal out of a foldable expression. + * Throws an exception if the expression is not foldable. + */ + public static Literal of(Expression foldable) { + if (foldable.foldable() == false) { + throw new QlIllegalArgumentException("Foldable expression required for Literal creation; received unfoldable " + foldable); + } + + if (foldable instanceof Literal) { + return (Literal) foldable; + } + + return new Literal(foldable.source(), foldable.fold(), foldable.dataType()); + } + + public static Literal of(Expression source, Object value) { + return new Literal(source.source(), value, source.dataType()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java new file mode 100644 index 000000000000..17d4287325c8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/MetadataAttribute.java @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.core.Tuple; +import org.elasticsearch.index.mapper.IdFieldMapper; +import org.elasticsearch.index.mapper.SourceFieldMapper; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.Map; + +import static org.elasticsearch.core.Tuple.tuple; + +public class MetadataAttribute extends TypedAttribute { + + private static final Map> ATTRIBUTES_MAP = Map.of( + "_version", + tuple(DataTypes.LONG, false), // _version field is not searchable + "_index", + tuple(DataTypes.KEYWORD, true), + IdFieldMapper.NAME, + tuple(DataTypes.KEYWORD, false), // actually searchable, but fielddata access on the _id field is disallowed by default + SourceFieldMapper.NAME, + tuple(DataTypes.SOURCE, false) + ); + + private final boolean searchable; + + public MetadataAttribute( + Source source, + String name, + DataType dataType, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic, + boolean searchable + ) { + super(source, name, dataType, qualifier, nullability, id, synthetic); + this.searchable = searchable; + } + + public MetadataAttribute(Source source, String name, DataType dataType, boolean searchable) { + this(source, name, dataType, null, Nullability.TRUE, null, false, searchable); + } + + @Override + protected MetadataAttribute clone( + Source source, + String name, + DataType type, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + return new MetadataAttribute(source, name, type, qualifier, nullability, id, synthetic, searchable); + } + + @Override + protected String label() { + return "m"; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, MetadataAttribute::new, name(), dataType(), qualifier(), nullable(), id(), synthetic(), searchable); + } + + public boolean searchable() { + return searchable; + } + + private MetadataAttribute withSource(Source source) { + return new MetadataAttribute(source, name(), dataType(), qualifier(), nullable(), id(), synthetic(), searchable()); + } + + public static MetadataAttribute create(Source source, String name) { + var t = ATTRIBUTES_MAP.get(name); + return t != null ? new MetadataAttribute(source, name, t.v1(), t.v2()) : null; + } + + public static DataType dataType(String name) { + var t = ATTRIBUTES_MAP.get(name); + return t != null ? t.v1() : null; + } + + public static boolean isSupported(String name) { + return ATTRIBUTES_MAP.containsKey(name); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/NameId.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/NameId.java new file mode 100644 index 000000000000..d643c6fedcb7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/NameId.java @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Unique identifier for a named expression. + *

+ * We use an {@link AtomicLong} to guarantee that they are unique + * and that create reproducible values when run in subsequent + * tests. They don't produce reproducible values in production, but + * you rarely debug with them in production and commonly do so in + * tests. + */ +public class NameId { + private static final AtomicLong COUNTER = new AtomicLong(); + private final long id; + + public NameId() { + this.id = COUNTER.incrementAndGet(); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != getClass()) { + return false; + } + NameId other = (NameId) obj; + return id == other.id; + } + + @Override + public String toString() { + return Long.toString(id); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/NamedExpression.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/NamedExpression.java new file mode 100644 index 000000000000..4a3666c8b8aa --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/NamedExpression.java @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +/** + * An expression that has a name. Named expressions can be used as a result + * (by converting to an attribute). + */ +public abstract class NamedExpression extends Expression { + + private final String name; + private final NameId id; + private final boolean synthetic; + + public NamedExpression(Source source, String name, List children, NameId id) { + this(source, name, children, id, false); + } + + public NamedExpression(Source source, String name, List children, NameId id, boolean synthetic) { + super(source, children); + this.name = name; + this.id = id == null ? new NameId() : id; + this.synthetic = synthetic; + } + + public String name() { + return name; + } + + public NameId id() { + return id; + } + + public boolean synthetic() { + return synthetic; + } + + public abstract Attribute toAttribute(); + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), name, synthetic); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + NamedExpression other = (NamedExpression) obj; + return Objects.equals(synthetic, other.synthetic) + /* + * It is important that the line below be `name` + * and not `name()` because subclasses might override + * `name()` in ways that are not compatible with + * equality. Specifically the `Unresolved` subclasses. + */ + && Objects.equals(name, other.name) + && Objects.equals(children(), other.children()); + } + + @Override + public String toString() { + return super.toString() + "#" + id(); + } + + @Override + public String nodeString() { + return name(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Nullability.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Nullability.java new file mode 100644 index 000000000000..b08024a70777 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Nullability.java @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +public enum Nullability { + TRUE, // Whether the expression can become null + FALSE, // The expression can never become null + UNKNOWN // Cannot determine if the expression supports possible null folding +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Order.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Order.java new file mode 100644 index 000000000000..a7377aab369b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Order.java @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isExact; + +public class Order extends Expression { + + public enum OrderDirection { + ASC, + DESC + } + + public enum NullsPosition { + FIRST, + LAST, + /** + * Nulls position has not been specified by the user and an appropriate default will be used. + * + * The default values are chosen such that it stays compatible with previous behavior. Unfortunately, this results in + * inconsistencies across different types of queries (see https://github.com/elastic/elasticsearch/issues/77068). + */ + ANY; + } + + private final Expression child; + private final OrderDirection direction; + private final NullsPosition nulls; + + public Order(Source source, Expression child, OrderDirection direction, NullsPosition nulls) { + super(source, singletonList(child)); + this.child = child; + this.direction = direction; + this.nulls = nulls == null ? NullsPosition.ANY : nulls; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Order::new, child, direction, nulls); + } + + @Override + public Nullability nullable() { + return Nullability.FALSE; + } + + @Override + protected TypeResolution resolveType() { + return isExact(child, "ORDER BY cannot be applied to field of data type [{}]: {}"); + } + + @Override + public DataType dataType() { + return child.dataType(); + } + + @Override + public Order replaceChildren(List newChildren) { + return new Order(source(), newChildren.get(0), direction, nulls); + } + + public Expression child() { + return child; + } + + public OrderDirection direction() { + return direction; + } + + public NullsPosition nullsPosition() { + return nulls; + } + + @Override + public int hashCode() { + return Objects.hash(child, direction, nulls); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Order other = (Order) obj; + return Objects.equals(direction, other.direction) && Objects.equals(nulls, other.nulls) && Objects.equals(child, other.child); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/ReferenceAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/ReferenceAttribute.java new file mode 100644 index 000000000000..d9311dfa27ed --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/ReferenceAttribute.java @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +/** + * Attribute based on a reference to an expression. + */ +public class ReferenceAttribute extends TypedAttribute { + + public ReferenceAttribute(Source source, String name, DataType dataType) { + this(source, name, dataType, null, Nullability.FALSE, null, false); + } + + public ReferenceAttribute( + Source source, + String name, + DataType dataType, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + super(source, name, dataType, qualifier, nullability, id, synthetic); + } + + @Override + protected Attribute clone( + Source source, + String name, + DataType dataType, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + return new ReferenceAttribute(source, name, dataType, qualifier, nullability, id, synthetic); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, ReferenceAttribute::new, name(), dataType(), qualifier(), nullable(), id(), synthetic()); + } + + @Override + protected String label() { + return "r"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypeResolutions.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypeResolutions.java new file mode 100644 index 000000000000..a0b61022c145 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypeResolutions.java @@ -0,0 +1,184 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.expression.Expression.TypeResolution; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; + +import java.util.Locale; +import java.util.StringJoiner; +import java.util.function.Predicate; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.expression.Expressions.name; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; + +public final class TypeResolutions { + + public enum ParamOrdinal { + DEFAULT, + FIRST, + SECOND, + THIRD, + FOURTH, + FIFTH; + + public static ParamOrdinal fromIndex(int index) { + return switch (index) { + case 0 -> FIRST; + case 1 -> SECOND; + case 2 -> THIRD; + case 3 -> FOURTH; + case 4 -> FIFTH; + default -> DEFAULT; + }; + } + } + + private TypeResolutions() {} + + public static TypeResolution isBoolean(Expression e, String operationName, ParamOrdinal paramOrd) { + return isType(e, dt -> dt == BOOLEAN, operationName, paramOrd, "boolean"); + } + + public static TypeResolution isInteger(Expression e, String operationName, ParamOrdinal paramOrd) { + return isType(e, DataType::isInteger, operationName, paramOrd, "integer"); + } + + public static TypeResolution isNumeric(Expression e, String operationName, ParamOrdinal paramOrd) { + return isType(e, DataType::isNumeric, operationName, paramOrd, "numeric"); + } + + public static TypeResolution isString(Expression e, String operationName, ParamOrdinal paramOrd) { + return isType(e, DataTypes::isString, operationName, paramOrd, "string"); + } + + public static TypeResolution isIP(Expression e, String operationName, ParamOrdinal paramOrd) { + return isType(e, dt -> dt == IP, operationName, paramOrd, "ip"); + } + + public static TypeResolution isDate(Expression e, String operationName, ParamOrdinal paramOrd) { + return isType(e, dt -> dt == DATETIME, operationName, paramOrd, "datetime"); + } + + public static TypeResolution isExact(Expression e, String message) { + if (e instanceof FieldAttribute fa) { + EsField.Exact exact = fa.getExactInfo(); + if (exact.hasExact() == false) { + return new TypeResolution(format(null, message, e.dataType().typeName(), exact.errorMsg())); + } + } + return TypeResolution.TYPE_RESOLVED; + } + + public static TypeResolution isExact(Expression e, String operationName, ParamOrdinal paramOrd) { + if (e instanceof FieldAttribute fa) { + EsField.Exact exact = fa.getExactInfo(); + if (exact.hasExact() == false) { + return new TypeResolution( + format( + null, + "[{}] cannot operate on {}field of data type [{}]: {}", + operationName, + paramOrd == null || paramOrd == DEFAULT ? "" : paramOrd.name().toLowerCase(Locale.ROOT) + " argument ", + e.dataType().typeName(), + exact.errorMsg() + ) + ); + } + } + return TypeResolution.TYPE_RESOLVED; + } + + public static TypeResolution isStringAndExact(Expression e, String operationName, ParamOrdinal paramOrd) { + TypeResolution resolution = isString(e, operationName, paramOrd); + if (resolution.unresolved()) { + return resolution; + } + + return isExact(e, operationName, paramOrd); + } + + public static TypeResolution isIPAndExact(Expression e, String operationName, ParamOrdinal paramOrd) { + TypeResolution resolution = isIP(e, operationName, paramOrd); + if (resolution.unresolved()) { + return resolution; + } + + return isExact(e, operationName, paramOrd); + } + + public static TypeResolution isFoldable(Expression e, String operationName, ParamOrdinal paramOrd) { + if (e.foldable() == false) { + return new TypeResolution( + format( + null, + "{}argument of [{}] must be a constant, received [{}]", + paramOrd == null || paramOrd == DEFAULT ? "" : paramOrd.name().toLowerCase(Locale.ROOT) + " ", + operationName, + Expressions.name(e) + ) + ); + } + return TypeResolution.TYPE_RESOLVED; + } + + public static TypeResolution isNotFoldable(Expression e, String operationName, ParamOrdinal paramOrd) { + if (e.foldable()) { + return new TypeResolution( + format( + null, + "{}argument of [{}] must be a table column, found constant [{}]", + paramOrd == null || paramOrd == DEFAULT ? "" : paramOrd.name().toLowerCase(Locale.ROOT) + " ", + operationName, + Expressions.name(e) + ) + ); + } + return TypeResolution.TYPE_RESOLVED; + } + + public static TypeResolution isType( + Expression e, + Predicate predicate, + String operationName, + ParamOrdinal paramOrd, + String... acceptedTypes + ) { + return predicate.test(e.dataType()) || e.dataType() == NULL + ? TypeResolution.TYPE_RESOLVED + : new TypeResolution( + format( + null, + "{}argument of [{}] must be [{}], found value [{}] type [{}]", + paramOrd == null || paramOrd == DEFAULT ? "" : paramOrd.name().toLowerCase(Locale.ROOT) + " ", + operationName, + acceptedTypesForErrorMsg(acceptedTypes), + name(e), + e.dataType().typeName() + ) + ); + } + + private static String acceptedTypesForErrorMsg(String... acceptedTypes) { + StringJoiner sj = new StringJoiner(", "); + for (int i = 0; i < acceptedTypes.length - 1; i++) { + sj.add(acceptedTypes[i]); + } + if (acceptedTypes.length > 1) { + return sj.toString() + " or " + acceptedTypes[acceptedTypes.length - 1]; + } else { + return acceptedTypes[0]; + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypedAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypedAttribute.java new file mode 100644 index 000000000000..bf319856f9a9 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/TypedAttribute.java @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.Objects; + +public abstract class TypedAttribute extends Attribute { + + private final DataType dataType; + + protected TypedAttribute( + Source source, + String name, + DataType dataType, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + super(source, name, qualifier, nullability, id, synthetic); + this.dataType = dataType; + } + + @Override + public DataType dataType() { + return dataType; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), dataType); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) && Objects.equals(dataType, ((TypedAttribute) obj).dataType); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnaryExpression.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnaryExpression.java new file mode 100644 index 000000000000..5f9aac434481 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnaryExpression.java @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; + +public abstract class UnaryExpression extends Expression { + + private final Expression child; + + protected UnaryExpression(Source source, Expression child) { + super(source, singletonList(child)); + this.child = child; + } + + @Override + public final UnaryExpression replaceChildren(List newChildren) { + return replaceChild(newChildren.get(0)); + } + + protected abstract UnaryExpression replaceChild(Expression newChild); + + public Expression child() { + return child; + } + + @Override + public boolean foldable() { + return child.foldable(); + } + + @Override + public Nullability nullable() { + return child.nullable(); + } + + @Override + public boolean resolved() { + return child.resolved(); + } + + @Override + public DataType dataType() { + return child.dataType(); + } + + @Override + public int hashCode() { + return Objects.hash(child); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UnaryExpression other = (UnaryExpression) obj; + return Objects.equals(child, other.child); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAlias.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAlias.java new file mode 100644 index 000000000000..a4b0d06f54b8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAlias.java @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; + +public class UnresolvedAlias extends UnresolvedNamedExpression { + + private final Expression child; + + public UnresolvedAlias(Source source, Expression child) { + super(source, singletonList(child)); + this.child = child; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnresolvedAlias::new, child); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new UnresolvedAlias(source(), newChildren.get(0)); + } + + public Expression child() { + return child; + } + + @Override + public String unresolvedMessage() { + return "Unknown alias [" + name() + "]"; + } + + @Override + public Nullability nullable() { + throw new UnresolvedException("nullable", this); + } + + @Override + public int hashCode() { + return Objects.hash(child); + } + + @Override + public boolean equals(Object obj) { + /* + * Intentionally not calling the superclass + * equals because it uses id which we always + * mutate when we make a clone. + */ + if (obj == null || obj.getClass() != getClass()) { + return false; + } + return Objects.equals(child, ((UnresolvedAlias) obj).child); + } + + @Override + public String toString() { + return child + " AS ?"; + } + + @Override + public String nodeString() { + return toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAttribute.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAttribute.java new file mode 100644 index 000000000000..923a72d31116 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAttribute.java @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable; +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; + +// unfortunately we can't use UnresolvedNamedExpression +public class UnresolvedAttribute extends Attribute implements Unresolvable { + + private final String unresolvedMsg; + private final boolean customMessage; + private final Object resolutionMetadata; + + public UnresolvedAttribute(Source source, String name) { + this(source, name, null); + } + + public UnresolvedAttribute(Source source, String name, String qualifier) { + this(source, name, qualifier, null); + } + + public UnresolvedAttribute(Source source, String name, String qualifier, String unresolvedMessage) { + this(source, name, qualifier, null, unresolvedMessage, null); + } + + @SuppressWarnings("this-escape") + public UnresolvedAttribute( + Source source, + String name, + String qualifier, + NameId id, + String unresolvedMessage, + Object resolutionMetadata + ) { + super(source, name, qualifier, id); + this.customMessage = unresolvedMessage != null; + this.unresolvedMsg = unresolvedMessage == null ? errorMessage(qualifiedName(), null) : unresolvedMessage; + this.resolutionMetadata = resolutionMetadata; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnresolvedAttribute::new, name(), qualifier(), id(), unresolvedMsg, resolutionMetadata); + } + + public Object resolutionMetadata() { + return resolutionMetadata; + } + + public boolean customMessage() { + return customMessage; + } + + @Override + public boolean resolved() { + return false; + } + + @Override + protected Attribute clone( + Source source, + String name, + DataType dataType, + String qualifier, + Nullability nullability, + NameId id, + boolean synthetic + ) { + return this; + } + + public UnresolvedAttribute withUnresolvedMessage(String unresolvedMessage) { + return new UnresolvedAttribute(source(), name(), qualifier(), id(), unresolvedMessage, resolutionMetadata()); + } + + @Override + public DataType dataType() { + throw new UnresolvedException("dataType", this); + } + + @Override + public String toString() { + return UNRESOLVED_PREFIX + qualifiedName(); + } + + @Override + protected String label() { + return UNRESOLVED_PREFIX; + } + + @Override + public String nodeString() { + return toString(); + } + + @Override + public String unresolvedMessage() { + return unresolvedMsg; + } + + public static String errorMessage(String name, List potentialMatches) { + String msg = "Unknown column [" + name + "]"; + if (CollectionUtils.isEmpty(potentialMatches) == false) { + msg += ", did you mean " + + (potentialMatches.size() == 1 ? "[" + potentialMatches.get(0) + "]" : "any of " + potentialMatches.toString()) + + "?"; + } + return msg; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), resolutionMetadata, unresolvedMsg); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + UnresolvedAttribute ua = (UnresolvedAttribute) obj; + return Objects.equals(resolutionMetadata, ua.resolutionMetadata) && Objects.equals(unresolvedMsg, ua.unresolvedMsg); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedNamedExpression.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedNamedExpression.java new file mode 100644 index 000000000000..0f6544327e16 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedNamedExpression.java @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable; +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.List; + +public abstract class UnresolvedNamedExpression extends NamedExpression implements Unresolvable { + + public UnresolvedNamedExpression(Source source, List children) { + super(source, "", children, new NameId()); + } + + @Override + public boolean resolved() { + return false; + } + + @Override + public String name() { + throw new UnresolvedException("name", this); + } + + @Override + public NameId id() { + throw new UnresolvedException("id", this); + } + + @Override + public DataType dataType() { + throw new UnresolvedException("data type", this); + } + + @Override + public Attribute toAttribute() { + throw new UnresolvedException("attribute", this); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedStar.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedStar.java new file mode 100644 index 000000000000..198016c710ce --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedStar.java @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.emptyList; + +public class UnresolvedStar extends UnresolvedNamedExpression { + + // typically used for nested fields or inner/dotted fields + private final UnresolvedAttribute qualifier; + + public UnresolvedStar(Source source, UnresolvedAttribute qualifier) { + super(source, emptyList()); + this.qualifier = qualifier; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnresolvedStar::new, qualifier); + } + + @Override + public Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + @Override + public Nullability nullable() { + throw new UnresolvedException("nullable", this); + } + + public UnresolvedAttribute qualifier() { + return qualifier; + } + + @Override + public int hashCode() { + return Objects.hash(qualifier); + } + + @Override + public boolean equals(Object obj) { + /* + * Intentionally not calling the superclass + * equals because it uses id which we always + * mutate when we make a clone. So we need + * to ignore it in equals for the transform + * tests to pass. + */ + if (obj == null || obj.getClass() != getClass()) { + return false; + } + + UnresolvedStar other = (UnresolvedStar) obj; + return Objects.equals(qualifier, other.qualifier); + } + + private String message() { + return (qualifier() != null ? qualifier().qualifiedName() + "." : "") + "*"; + } + + @Override + public String unresolvedMessage() { + return "Cannot determine columns for [" + message() + "]"; + } + + @Override + public String nodeString() { + return toString(); + } + + @Override + public String toString() { + return UNRESOLVED_PREFIX + message(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/DefaultFunctionTypeRegistry.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/DefaultFunctionTypeRegistry.java new file mode 100644 index 000000000000..699d3742f265 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/DefaultFunctionTypeRegistry.java @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; + +public class DefaultFunctionTypeRegistry implements FunctionTypeRegistry { + + public static final DefaultFunctionTypeRegistry INSTANCE = new DefaultFunctionTypeRegistry(); + + private enum Types { + AGGREGATE(AggregateFunction.class), + SCALAR(ScalarFunction.class); + + private Class baseClass; + + Types(Class base) { + this.baseClass = base; + } + } + + @Override + public String type(Class clazz) { + for (Types type : Types.values()) { + if (type.baseClass.isAssignableFrom(clazz)) { + return type.name(); + } + } + return "UNKNOWN"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/Function.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/Function.java new file mode 100644 index 000000000000..fd875f780667 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/Function.java @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.ConstantInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Any SQL expression with parentheses, like {@code MAX()}, or {@code ABS()}. A + * function is always a {@code NamedExpression}. + */ +public abstract class Function extends Expression { + + private final String functionName = getClass().getSimpleName().toUpperCase(Locale.ROOT); + + private Pipe lazyPipe = null; + + // TODO: Functions supporting distinct should add a dedicated constructor Location, List, boolean + protected Function(Source source, List children) { + super(source, children); + } + + public final List arguments() { + return children(); + } + + public String functionName() { + return functionName; + } + + @Override + public Nullability nullable() { + return Expressions.nullable(children()); + } + + @Override + public int hashCode() { + return Objects.hash(getClass(), children()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Function other = (Function) obj; + return Objects.equals(children(), other.children()); + } + + public Pipe asPipe() { + if (lazyPipe == null) { + lazyPipe = foldable() ? new ConstantInput(source(), this, fold()) : makePipe(); + } + return lazyPipe; + } + + protected Pipe makePipe() { + throw new UnsupportedOperationException(); + } + + @Override + public String nodeString() { + StringJoiner sj = new StringJoiner(",", functionName() + "(", ")"); + for (Expression ex : arguments()) { + sj.add(ex.nodeString()); + } + return sj.toString(); + } + + public abstract ScriptTemplate asScript(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionDefinition.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionDefinition.java new file mode 100644 index 000000000000..09f68c5c9b4a --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionDefinition.java @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.session.Configuration; + +import java.util.List; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; + +public class FunctionDefinition { + /** + * Converts an {@link UnresolvedFunction} into the a proper {@link Function}. + *

+ * Provides the basic signature (unresolved function + runtime configuration object) while + * allowing extensions through the vararg extras which subclasses should expand for their + * own purposes. + */ + @FunctionalInterface + public interface Builder { + Function build(UnresolvedFunction uf, Configuration configuration, Object... extras); + } + + private final String name; + private final List aliases; + private final Class clazz; + private final Builder builder; + + public FunctionDefinition(String name, List aliases, Class clazz, Builder builder) { + this.name = name; + this.aliases = aliases; + this.clazz = clazz; + this.builder = builder; + } + + public String name() { + return name; + } + + public List aliases() { + return aliases; + } + + public Class clazz() { + return clazz; + } + + protected Builder builder() { + return builder; + } + + @Override + public String toString() { + return format(null, "{}({})", name, aliases.isEmpty() ? "" : aliases.size() == 1 ? aliases.get(0) : aliases); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionRegistry.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionRegistry.java new file mode 100644 index 000000000000..48da08b91522 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionRegistry.java @@ -0,0 +1,463 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.Check; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.BiFunction; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; +import static java.util.stream.Collectors.toList; + +public class FunctionRegistry { + + // Translation table for error messaging in the following function + private static final String[] NUM_NAMES = { "zero", "one", "two", "three", "four", "five", }; + + // list of functions grouped by type of functions (aggregate, statistics, math etc) and ordered alphabetically inside each group + // a single function will have one entry for itself with its name associated to its instance and, also, one entry for each alias + // it has with the alias name associated to the FunctionDefinition instance + private final Map defs = new LinkedHashMap<>(); + private final Map aliases = new HashMap<>(); + + public FunctionRegistry() {} + + /** + * Register the given function definitions with this registry. + */ + @SuppressWarnings("this-escape") + public FunctionRegistry(FunctionDefinition... functions) { + register(functions); + } + + @SuppressWarnings("this-escape") + public FunctionRegistry(FunctionDefinition[]... groupFunctions) { + register(groupFunctions); + } + + protected void register(FunctionDefinition[]... groupFunctions) { + for (FunctionDefinition[] group : groupFunctions) { + register(group); + } + } + + protected void register(FunctionDefinition... functions) { + // temporary map to hold [function_name/alias_name : function instance] + Map batchMap = new HashMap<>(); + for (FunctionDefinition f : functions) { + batchMap.put(f.name(), f); + for (String alias : f.aliases()) { + Object old = batchMap.put(alias, f); + if (old != null || defs.containsKey(alias)) { + throw new QlIllegalArgumentException( + "alias [" + + alias + + "] is used by " + + "[" + + (old != null ? old : defs.get(alias).name()) + + "] and [" + + f.name() + + "]" + ); + } + aliases.put(alias, f.name()); + } + } + // sort the temporary map by key name and add it to the global map of functions + defs.putAll( + batchMap.entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .collect( + Collectors.< + Entry, + String, + FunctionDefinition, + LinkedHashMap>toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (oldValue, newValue) -> oldValue, + LinkedHashMap::new + ) + ) + ); + } + + public FunctionDefinition resolveFunction(String functionName) { + FunctionDefinition def = defs.get(functionName); + if (def == null) { + throw new QlIllegalArgumentException("Cannot find function {}; this should have been caught during analysis", functionName); + } + return def; + } + + protected String normalize(String name) { + return name.toUpperCase(Locale.ROOT); + } + + public String resolveAlias(String alias) { + String normalized = normalize(alias); + return aliases.getOrDefault(normalized, normalized); + } + + public boolean functionExists(String functionName) { + return defs.containsKey(functionName); + } + + public Collection listFunctions() { + // It is worth double checking if we need this copy. These are immutable anyway. + return defs.values(); + } + + public Collection listFunctions(String pattern) { + // It is worth double checking if we need this copy. These are immutable anyway. + Pattern p = Strings.hasText(pattern) ? Pattern.compile(normalize(pattern)) : null; + return defs.entrySet() + .stream() + .filter(e -> p == null || p.matcher(e.getKey()).matches()) + .map(e -> cloneDefinition(e.getKey(), e.getValue())) + .collect(toList()); + } + + protected FunctionDefinition cloneDefinition(String name, FunctionDefinition definition) { + return new FunctionDefinition(name, emptyList(), definition.clazz(), definition.builder()); + } + + protected interface FunctionBuilder { + Function build(Source source, List children, Configuration cfg); + } + + /** + * Main method to register a function. + * + * @param names Must always have at least one entry which is the method's primary name + */ + @SuppressWarnings("overloads") + protected static FunctionDefinition def(Class function, FunctionBuilder builder, String... names) { + Check.isTrue(names.length > 0, "At least one name must be provided for the function"); + String primaryName = names[0]; + List aliases = Arrays.asList(names).subList(1, names.length); + FunctionDefinition.Builder realBuilder = (uf, cfg, extras) -> { + if (CollectionUtils.isEmpty(extras) == false) { + throw new ParsingException( + uf.source(), + "Unused parameters {} detected when building [{}]", + Arrays.toString(extras), + primaryName + ); + } + try { + return builder.build(uf.source(), uf.children(), cfg); + } catch (QlIllegalArgumentException e) { + throw new ParsingException(e, uf.source(), "error building [{}]: {}", primaryName, e.getMessage()); + } + }; + return new FunctionDefinition(primaryName, unmodifiableList(aliases), function, realBuilder); + } + + /** + * Build a {@linkplain FunctionDefinition} for a no-argument function. + */ + protected static FunctionDefinition def( + Class function, + java.util.function.Function ctorRef, + String... names + ) { + FunctionBuilder builder = (source, children, cfg) -> { + if (false == children.isEmpty()) { + throw new QlIllegalArgumentException("expects no arguments"); + } + return ctorRef.apply(source); + }; + return def(function, builder, names); + } + + /** + * Build a {@linkplain FunctionDefinition} for a unary function. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + public static FunctionDefinition def( + Class function, + BiFunction ctorRef, + String... names + ) { + FunctionBuilder builder = (source, children, cfg) -> { + if (children.size() != 1) { + throw new QlIllegalArgumentException("expects exactly one argument"); + } + return ctorRef.apply(source, children.get(0)); + }; + return def(function, builder, names); + } + + /** + * Build a {@linkplain FunctionDefinition} for multi-arg/n-ary function. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected FunctionDefinition def(Class function, NaryBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { return ctorRef.build(source, children); }; + return def(function, builder, names); + } + + protected interface NaryBuilder { + T build(Source source, List children); + } + + /** + * Build a {@linkplain FunctionDefinition} for a binary function. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, BinaryBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { + boolean isBinaryOptionalParamFunction = OptionalArgument.class.isAssignableFrom(function); + if (isBinaryOptionalParamFunction && (children.size() > 2 || children.size() < 1)) { + throw new QlIllegalArgumentException("expects one or two arguments"); + } else if (isBinaryOptionalParamFunction == false && children.size() != 2) { + throw new QlIllegalArgumentException("expects exactly two arguments"); + } + + return ctorRef.build(source, children.get(0), children.size() == 2 ? children.get(1) : null); + }; + return def(function, builder, names); + } + + protected interface BinaryBuilder { + T build(Source source, Expression left, Expression right); + } + + /** + * Build a {@linkplain FunctionDefinition} for a ternary function. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, TernaryBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { + boolean hasMinimumTwo = OptionalArgument.class.isAssignableFrom(function); + if (hasMinimumTwo && (children.size() > 3 || children.size() < 2)) { + throw new QlIllegalArgumentException("expects two or three arguments"); + } else if (hasMinimumTwo == false && children.size() != 3) { + throw new QlIllegalArgumentException("expects exactly three arguments"); + } + return ctorRef.build(source, children.get(0), children.get(1), children.size() == 3 ? children.get(2) : null); + }; + return def(function, builder, names); + } + + protected interface TernaryBuilder { + T build(Source source, Expression one, Expression two, Expression three); + } + + /** + * Build a {@linkplain FunctionDefinition} for a quaternary function. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, QuaternaryBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { + if (OptionalArgument.class.isAssignableFrom(function)) { + if (children.size() > 4 || children.size() < 3) { + throw new QlIllegalArgumentException("expects three or four arguments"); + } + } else if (TwoOptionalArguments.class.isAssignableFrom(function)) { + if (children.size() > 4 || children.size() < 2) { + throw new QlIllegalArgumentException("expects minimum two, maximum four arguments"); + } + } else if (children.size() != 4) { + throw new QlIllegalArgumentException("expects exactly four arguments"); + } + return ctorRef.build( + source, + children.get(0), + children.get(1), + children.size() > 2 ? children.get(2) : null, + children.size() > 3 ? children.get(3) : null + ); + }; + return def(function, builder, names); + } + + protected interface QuaternaryBuilder { + T build(Source source, Expression one, Expression two, Expression three, Expression four); + } + + /** + * Build a {@linkplain FunctionDefinition} for a quinary function. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def( + Class function, + QuinaryBuilder ctorRef, + int numOptionalParams, + String... names + ) { + FunctionBuilder builder = (source, children, cfg) -> { + final int NUM_TOTAL_PARAMS = 5; + boolean hasOptionalParams = OptionalArgument.class.isAssignableFrom(function); + if (hasOptionalParams && (children.size() > NUM_TOTAL_PARAMS || children.size() < NUM_TOTAL_PARAMS - numOptionalParams)) { + throw new QlIllegalArgumentException( + "expects between " + + NUM_NAMES[NUM_TOTAL_PARAMS - numOptionalParams] + + " and " + + NUM_NAMES[NUM_TOTAL_PARAMS] + + " arguments" + ); + } else if (hasOptionalParams == false && children.size() != NUM_TOTAL_PARAMS) { + throw new QlIllegalArgumentException("expects exactly " + NUM_NAMES[NUM_TOTAL_PARAMS] + " arguments"); + } + return ctorRef.build( + source, + children.size() > 0 ? children.get(0) : null, + children.size() > 1 ? children.get(1) : null, + children.size() > 2 ? children.get(2) : null, + children.size() > 3 ? children.get(3) : null, + children.size() > 4 ? children.get(4) : null + ); + }; + return def(function, builder, names); + } + + protected interface QuinaryBuilder { + T build(Source source, Expression one, Expression two, Expression three, Expression four, Expression five); + } + + /** + * Build a {@linkplain FunctionDefinition} for functions with a mandatory argument followed by a varidic list. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def(Class function, UnaryVariadicBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { + boolean hasMinimumOne = OptionalArgument.class.isAssignableFrom(function); + if (hasMinimumOne && children.size() < 1) { + throw new QlIllegalArgumentException("expects at least one argument"); + } else if (hasMinimumOne == false && children.size() < 2) { + throw new QlIllegalArgumentException("expects at least two arguments"); + } + return ctorRef.build(source, children.get(0), children.subList(1, children.size())); + }; + return def(function, builder, names); + } + + protected interface UnaryVariadicBuilder { + T build(Source source, Expression exp, List variadic); + } + + /** + * Build a {@linkplain FunctionDefinition} for a no-argument function that is configuration aware. + */ + @SuppressWarnings("overloads") + protected static FunctionDefinition def(Class function, ConfigurationAwareBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { + if (false == children.isEmpty()) { + throw new QlIllegalArgumentException("expects no arguments"); + } + return ctorRef.build(source, cfg); + }; + return def(function, builder, names); + } + + protected interface ConfigurationAwareBuilder { + T build(Source source, Configuration configuration); + } + + /** + * Build a {@linkplain FunctionDefinition} for a one-argument function that is configuration aware. + */ + @SuppressWarnings("overloads") + protected static FunctionDefinition def( + Class function, + UnaryConfigurationAwareBuilder ctorRef, + String... names + ) { + FunctionBuilder builder = (source, children, cfg) -> { + if (children.size() > 1) { + throw new QlIllegalArgumentException("expects exactly one argument"); + } + Expression ex = children.size() == 1 ? children.get(0) : null; + return ctorRef.build(source, ex, cfg); + }; + return def(function, builder, names); + } + + protected interface UnaryConfigurationAwareBuilder { + T build(Source source, Expression exp, Configuration configuration); + } + + /** + * Build a {@linkplain FunctionDefinition} for a binary function that is configuration aware. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected static FunctionDefinition def( + Class function, + BinaryConfigurationAwareBuilder ctorRef, + String... names + ) { + FunctionBuilder builder = (source, children, cfg) -> { + boolean isBinaryOptionalParamFunction = OptionalArgument.class.isAssignableFrom(function); + if (isBinaryOptionalParamFunction && (children.size() > 2 || children.size() < 1)) { + throw new QlIllegalArgumentException("expects one or two arguments"); + } else if (isBinaryOptionalParamFunction == false && children.size() != 2) { + throw new QlIllegalArgumentException("expects exactly two arguments"); + } + return ctorRef.build(source, children.get(0), children.size() == 2 ? children.get(1) : null, cfg); + }; + return def(function, builder, names); + } + + protected interface BinaryConfigurationAwareBuilder { + T build(Source source, Expression left, Expression right, Configuration configuration); + } + + /** + * Build a {@linkplain FunctionDefinition} for a ternary function that is configuration aware. + */ + @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do + protected FunctionDefinition def(Class function, TernaryConfigurationAwareBuilder ctorRef, String... names) { + FunctionBuilder builder = (source, children, cfg) -> { + boolean hasMinimumTwo = OptionalArgument.class.isAssignableFrom(function); + if (hasMinimumTwo && (children.size() > 3 || children.size() < 2)) { + throw new QlIllegalArgumentException("expects two or three arguments"); + } else if (hasMinimumTwo == false && children.size() != 3) { + throw new QlIllegalArgumentException("expects exactly three arguments"); + } + return ctorRef.build(source, children.get(0), children.get(1), children.size() == 3 ? children.get(2) : null, cfg); + }; + return def(function, builder, names); + } + + protected interface TernaryConfigurationAwareBuilder { + T build(Source source, Expression one, Expression two, Expression three, Configuration configuration); + } + + // + // Utility method for extra argument extraction. + // + protected static Boolean asBool(Object[] extras) { + if (CollectionUtils.isEmpty(extras)) { + return null; + } + if (extras.length != 1 || (extras[0] instanceof Boolean) == false) { + throw new QlIllegalArgumentException("Invalid number and types of arguments given to function definition"); + } + return (Boolean) extras[0]; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionResolutionStrategy.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionResolutionStrategy.java new file mode 100644 index 000000000000..a23112267dcf --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionResolutionStrategy.java @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.session.Configuration; + +/** + * Strategy indicating the type of resolution to apply for resolving the actual function definition in a pluggable way. + */ +public interface FunctionResolutionStrategy { + + /** + * Default behavior of standard function calls like {@code ABS(col)}. + */ + FunctionResolutionStrategy DEFAULT = new FunctionResolutionStrategy() { + }; + + /** + * Build the real function from this one and resolution metadata. + */ + default Function buildResolved(UnresolvedFunction uf, Configuration cfg, FunctionDefinition def) { + return def.builder().build(uf, cfg); + } + + /** + * The kind of strategy being applied. Used when + * building the error message sent back to the user when + * they specify a function that doesn't exist. + */ + default String kind() { + return "function"; + } + + /** + * Is {@code def} a valid alternative for function invocations + * of this kind. Used to filter the list of "did you mean" + * options sent back to the user when they specify a missing + * function. + */ + default boolean isValidAlternative(FunctionDefinition def) { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionTypeRegistry.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionTypeRegistry.java new file mode 100644 index 000000000000..8ba40d5b167f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionTypeRegistry.java @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function; + +public interface FunctionTypeRegistry { + + String type(Class clazz); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/Functions.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/Functions.java new file mode 100644 index 000000000000..18907b6904a2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/Functions.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.grouping.GroupingFunction; + +public abstract class Functions { + + public static boolean isAggregate(Expression e) { + return e instanceof AggregateFunction; + } + + public static boolean isGrouping(Expression e) { + return e instanceof GroupingFunction; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/OptionalArgument.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/OptionalArgument.java new file mode 100644 index 000000000000..90d1d0633733 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/OptionalArgument.java @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function; + +/** + * Marker interface indicating that a function accepts one optional argument (typically the last one). + * This is used by the {@link FunctionRegistry} to perform validation of function declaration. + */ +public interface OptionalArgument { + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/TwoOptionalArguments.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/TwoOptionalArguments.java new file mode 100644 index 000000000000..78684f034f44 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/TwoOptionalArguments.java @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function; + +/** + * Marker interface indicating that a function accepts two optional arguments (the last two). + * This is used by the {@link FunctionRegistry} to perform validation of function declaration. + */ +public interface TwoOptionalArguments { + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/UnresolvedFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/UnresolvedFunction.java new file mode 100644 index 000000000000..f0785bcc063c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/UnresolvedFunction.java @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable; +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class UnresolvedFunction extends Function implements Unresolvable { + + private final String name; + private final String unresolvedMsg; + private final FunctionResolutionStrategy resolution; + + /** + * Flag to indicate analysis has been applied and there's no point in + * doing it again this is an optimization to prevent searching for a + * better unresolved message over and over again. + */ + private final boolean analyzed; + + public UnresolvedFunction(Source source, String name, FunctionResolutionStrategy resolutionStrategy, List children) { + this(source, name, resolutionStrategy, children, false, null); + } + + /** + * Constructor used for specifying a more descriptive message (typically + * 'did you mean') instead of the default one. + * + * @see #withMessage(String) + */ + UnresolvedFunction( + Source source, + String name, + FunctionResolutionStrategy resolutionStrategy, + List children, + boolean analyzed, + String unresolvedMessage + ) { + super(source, children); + this.name = name; + this.resolution = resolutionStrategy; + this.analyzed = analyzed; + this.unresolvedMsg = unresolvedMessage == null ? "Unknown " + resolutionStrategy.kind() + " [" + name + "]" : unresolvedMessage; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnresolvedFunction::new, name, resolution, children(), analyzed, unresolvedMsg); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new UnresolvedFunction(source(), name, resolution, newChildren, analyzed, unresolvedMsg); + } + + public UnresolvedFunction withMessage(String message) { + return new UnresolvedFunction(source(), name(), resolution, children(), true, message); + } + + /** + * Build a function to replace this one after resolving the function. + */ + public Function buildResolved(Configuration configuration, FunctionDefinition def) { + return resolution.buildResolved(this, configuration, def); + } + + /** + * Build a marker {@link UnresolvedFunction} with an error message + * about the function being missing. + */ + public UnresolvedFunction missing(String normalizedName, Iterable alternatives) { + // try to find alternatives + Set names = new LinkedHashSet<>(); + for (FunctionDefinition def : alternatives) { + if (resolution.isValidAlternative(def)) { + names.add(def.name()); + names.addAll(def.aliases()); + } + } + + List matches = StringUtils.findSimilar(normalizedName, names); + if (matches.isEmpty()) { + return this; + } + String matchesMessage = matches.size() == 1 ? "[" + matches.get(0) + "]" : "any of " + matches; + return withMessage("Unknown " + resolution.kind() + " [" + name + "], did you mean " + matchesMessage + "?"); + } + + @Override + public boolean resolved() { + return false; + } + + public String name() { + return name; + } + + public FunctionResolutionStrategy resolutionStrategy() { + return resolution; + } + + public boolean analyzed() { + return analyzed; + } + + @Override + public DataType dataType() { + throw new UnresolvedException("dataType", this); + } + + @Override + public Nullability nullable() { + throw new UnresolvedException("nullable", this); + } + + @Override + public ScriptTemplate asScript() { + throw new UnresolvedException("script", this); + } + + @Override + public String unresolvedMessage() { + return unresolvedMsg; + } + + @Override + public String toString() { + return UNRESOLVED_PREFIX + name + children(); + } + + @Override + public String nodeString() { + return toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + UnresolvedFunction other = (UnresolvedFunction) obj; + return name.equals(other.name) + && resolution.equals(other.resolution) + && children().equals(other.children()) + && analyzed == other.analyzed + && Objects.equals(unresolvedMsg, other.unresolvedMsg); + } + + @Override + public int hashCode() { + return Objects.hash(name, resolution, children(), analyzed, unresolvedMsg); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/AggregateFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/AggregateFunction.java new file mode 100644 index 000000000000..ac2a9b50bc1b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/AggregateFunction.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.aggregate; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.AggNameInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; + +/** + * A type of {@code Function} that takes multiple values and extracts a single value out of them. For example, {@code AVG()}. + */ +public abstract class AggregateFunction extends Function { + + private final Expression field; + private final List parameters; + + protected AggregateFunction(Source source, Expression field) { + this(source, field, emptyList()); + } + + protected AggregateFunction(Source source, Expression field, List parameters) { + super(source, CollectionUtils.combine(singletonList(field), parameters)); + this.field = field; + this.parameters = parameters; + } + + public Expression field() { + return field; + } + + public List parameters() { + return parameters; + } + + @Override + protected TypeResolution resolveType() { + return TypeResolutions.isExact(field, sourceText(), DEFAULT); + } + + @Override + protected Pipe makePipe() { + // unresolved AggNameInput (should always get replaced by the folder) + return new AggNameInput(source(), this, sourceText()); + } + + @Override + public ScriptTemplate asScript() { + throw new QlIllegalArgumentException("Aggregate functions cannot be scripted"); + } + + @Override + public int hashCode() { + // NB: the hashcode is currently used for key generation so + // to avoid clashes between aggs with the same arguments, add the class name as variation + return Objects.hash(getClass(), children()); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + AggregateFunction other = (AggregateFunction) obj; + return Objects.equals(other.field(), field()) && Objects.equals(other.parameters(), parameters()); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/CompoundAggregate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/CompoundAggregate.java new file mode 100644 index 000000000000..26c975868a9c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/CompoundAggregate.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.aggregate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; + +import java.util.List; + +/** + * Marker type for compound aggregates, that is an aggregate that provides multiple values (like Stats or Matrix) + */ +public interface CompoundAggregate { + + Expression field(); + + List parameters(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/Count.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/Count.java new file mode 100644 index 000000000000..230d12985654 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/Count.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.aggregate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.List; +import java.util.Objects; + +/** + * Count the number of documents matched ({@code COUNT}) + * OR count the number of distinct values + * for a field that matched ({@code COUNT(DISTINCT}. + */ +public class Count extends AggregateFunction { + + private final boolean distinct; + + public Count(Source source, Expression field, boolean distinct) { + super(source, field); + this.distinct = distinct; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Count::new, field(), distinct); + } + + @Override + public Count replaceChildren(List newChildren) { + return new Count(source(), newChildren.get(0), distinct); + } + + public boolean distinct() { + return distinct; + } + + @Override + public DataType dataType() { + return DataTypes.LONG; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), distinct()); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + Count other = (Count) obj; + return Objects.equals(other.distinct(), distinct()); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/EnclosedAgg.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/EnclosedAgg.java new file mode 100644 index 000000000000..c1fc4379f58d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/EnclosedAgg.java @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.aggregate; + +// Agg 'enclosed' by another agg. Used for agg that return multiple embedded aggs (like MatrixStats) +public interface EnclosedAgg { + + String innerName(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/InnerAggregate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/InnerAggregate.java new file mode 100644 index 000000000000..6ba283e6653a --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/InnerAggregate.java @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.aggregate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.Check; + +import java.util.List; +import java.util.Objects; + +public class InnerAggregate extends AggregateFunction { + + private final AggregateFunction inner; + private final CompoundAggregate outer; + private final String innerName; + // used when the result needs to be extracted from a map (like in MatrixAggs or Percentiles) + private final Expression innerKey; + + public InnerAggregate(AggregateFunction inner, CompoundAggregate outer) { + this(inner.source(), inner, outer, null); + } + + public InnerAggregate(Source source, AggregateFunction inner, CompoundAggregate outer, Expression innerKey) { + super(source, outer.field(), outer.parameters()); + this.inner = inner; + this.outer = outer; + Check.isTrue(inner instanceof EnclosedAgg, "Inner function is not marked as Enclosed"); + Check.isTrue(outer instanceof Expression, "CompoundAggregate is not an Expression"); + this.innerName = ((EnclosedAgg) inner).innerName(); + this.innerKey = innerKey; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, InnerAggregate::new, inner, outer, innerKey); + } + + @Override + public Expression replaceChildren(List newChildren) { + /* I can't figure out how rewriting this one's children ever worked because its + * are all twisted up in `outer`. Refusing to rewrite it doesn't break anything + * that I can see right now so lets just go with it and hope for the best. + * Maybe someone will make this make sense one day! */ + throw new UnsupportedOperationException("can't be rewritten"); + } + + public AggregateFunction inner() { + return inner; + } + + public CompoundAggregate outer() { + return outer; + } + + public String innerName() { + return innerName; + } + + public Expression innerKey() { + return innerKey; + } + + @Override + public DataType dataType() { + return inner.dataType(); + } + + @Override + public String functionName() { + return inner.functionName(); + } + + @Override + public int hashCode() { + return Objects.hash(inner, outer, innerKey); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + InnerAggregate other = (InnerAggregate) obj; + return Objects.equals(inner, other.inner) && Objects.equals(outer, other.outer) && Objects.equals(innerKey, other.innerKey); + } + return false; + } + + @Override + public String toString() { + return nodeName() + "[" + outer + ">" + inner.nodeName() + "]"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/SpatialAggregateFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/SpatialAggregateFunction.java new file mode 100644 index 000000000000..f800d86815c8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/aggregate/SpatialAggregateFunction.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.aggregate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +/** + * All spatial aggregate functions extend this class to enable the planning of reading from doc values for higher performance. + * The AggregateMapper class will generate multiple aggregation functions for each combination, allowing the planner to + * select the best one. + */ +public abstract class SpatialAggregateFunction extends AggregateFunction { + protected final boolean useDocValues; + + protected SpatialAggregateFunction(Source source, Expression field, boolean useDocValues) { + super(source, field); + this.useDocValues = useDocValues; + } + + public abstract SpatialAggregateFunction withDocValues(); + + @Override + public int hashCode() { + // NB: the hashcode is currently used for key generation so + // to avoid clashes between aggs with the same arguments, add the class name as variation + return Objects.hash(getClass(), children(), useDocValues); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + SpatialAggregateFunction other = (SpatialAggregateFunction) obj; + return Objects.equals(other.field(), field()) + && Objects.equals(other.parameters(), parameters()) + && Objects.equals(other.useDocValues, useDocValues); + } + return false; + } + + public boolean useDocValues() { + return useDocValues; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/grouping/GroupingFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/grouping/GroupingFunction.java new file mode 100644 index 000000000000..6f8cdf2cfb27 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/grouping/GroupingFunction.java @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.grouping; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.AggNameInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +/** + * A type of {@code Function} that creates groups or buckets. + */ +public abstract class GroupingFunction extends Function { + + private final Expression field; + private final List parameters; + + protected GroupingFunction(Source source, Expression field) { + this(source, field, emptyList()); + } + + protected GroupingFunction(Source source, Expression field, List parameters) { + super(source, CollectionUtils.combine(singletonList(field), parameters)); + this.field = field; + this.parameters = parameters; + } + + public Expression field() { + return field; + } + + public List parameters() { + return parameters; + } + + @Override + protected Pipe makePipe() { + // unresolved AggNameInput (should always get replaced by the folder) + return new AggNameInput(source(), this, sourceText()); + } + + @Override + public ScriptTemplate asScript() { + throw new QlIllegalArgumentException("Grouping functions cannot be scripted"); + } + + @Override + public boolean equals(Object obj) { + if (false == super.equals(obj)) { + return false; + } + GroupingFunction other = (GroupingFunction) obj; + return Objects.equals(other.field(), field()) && Objects.equals(other.parameters(), parameters()); + } + + @Override + public int hashCode() { + return Objects.hash(field(), parameters()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/BaseSurrogateFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/BaseSurrogateFunction.java new file mode 100644 index 000000000000..71b4db5a15f3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/BaseSurrogateFunction.java @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; + +public abstract class BaseSurrogateFunction extends ScalarFunction implements SurrogateFunction { + + private ScalarFunction lazySubstitute; + + public BaseSurrogateFunction(Source source) { + super(source); + } + + public BaseSurrogateFunction(Source source, List fields) { + super(source, fields); + } + + @Override + public ScalarFunction substitute() { + if (lazySubstitute == null) { + lazySubstitute = makeSubstitute(); + } + return lazySubstitute; + } + + protected abstract ScalarFunction makeSubstitute(); + + @Override + public boolean foldable() { + return substitute().foldable(); + } + + @Override + public Object fold() { + return substitute().fold(); + } + + @Override + protected Pipe makePipe() { + return substitute().asPipe(); + } + + @Override + public ScriptTemplate asScript() { + return substitute().asScript(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/BinaryScalarFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/BinaryScalarFunction.java new file mode 100644 index 000000000000..c08e5277dfe5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/BinaryScalarFunction.java @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public abstract class BinaryScalarFunction extends ScalarFunction { + + private final Expression left, right; + + protected BinaryScalarFunction(Source source, Expression left, Expression right) { + super(source, Arrays.asList(left, right)); + this.left = left; + this.right = right; + } + + @Override + public final BinaryScalarFunction replaceChildren(List newChildren) { + Expression newLeft = newChildren.get(0); + Expression newRight = newChildren.get(1); + + return left.equals(newLeft) && right.equals(newRight) ? this : replaceChildren(newLeft, newRight); + } + + protected abstract BinaryScalarFunction replaceChildren(Expression newLeft, Expression newRight); + + public Expression left() { + return left; + } + + public Expression right() { + return right; + } + + @Override + public boolean foldable() { + return left.foldable() && right.foldable(); + } + + @Override + public ScriptTemplate asScript() { + ScriptTemplate leftScript = asScript(left()); + ScriptTemplate rightScript = asScript(right()); + + return asScriptFrom(leftScript, rightScript); + } + + protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) { + return Scripts.binaryMethod(Scripts.classPackageAsPrefix(getClass()), scriptMethodName(), leftScript, rightScript, dataType()); + } + + protected String scriptMethodName() { + return getClass().getSimpleName().toLowerCase(Locale.ROOT); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/ConfigurationFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/ConfigurationFunction.java new file mode 100644 index 000000000000..fe2e527b5741 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/ConfigurationFunction.java @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; + +public abstract class ConfigurationFunction extends ScalarFunction { + + private final Configuration configuration; + + protected ConfigurationFunction(Source source, List fields, Configuration configuration) { + super(source, fields); + this.configuration = configuration; + } + + public Configuration configuration() { + return configuration; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/IntervalScripting.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/IntervalScripting.java new file mode 100644 index 000000000000..121696f1df4f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/IntervalScripting.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +// FIXME: accessor interface until making script generation pluggable +public interface IntervalScripting { + + String script(); + + String value(); + + String typeName(); + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/ScalarFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/ScalarFunction.java new file mode 100644 index 000000000000..671fe0437a47 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/ScalarFunction.java @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.grouping.GroupingFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Params; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.DateUtils; + +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts.PARAM; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; + +/** + * A {@code ScalarFunction} is a {@code Function} that takes values from some + * operation and converts each to another value. An example would be + * {@code ABS()}, which takes one value at a time, applies a function to the + * value (abs) and returns a new value. + */ +public abstract class ScalarFunction extends Function { + + protected ScalarFunction(Source source) { + super(source, emptyList()); + } + + protected ScalarFunction(Source source, List fields) { + super(source, fields); + } + + // + // Script generation + // + public ScriptTemplate asScript(Expression exp) { + if (exp.foldable()) { + return scriptWithFoldable(exp); + } + + if (exp instanceof FieldAttribute) { + return scriptWithField((FieldAttribute) exp); + } + + if (exp instanceof ScalarFunction) { + return scriptWithScalar((ScalarFunction) exp); + } + + if (exp instanceof AggregateFunction) { + return scriptWithAggregate((AggregateFunction) exp); + } + + if (exp instanceof GroupingFunction) { + return scriptWithGrouping((GroupingFunction) exp); + } + throw new QlIllegalArgumentException("Cannot evaluate script for expression {}", exp); + } + + protected ScriptTemplate scriptWithFoldable(Expression foldable) { + Object fold = foldable.fold(); + + // FIXME: this needs to be refactored + // + // Custom type handling + // + + // wrap intervals with dedicated methods for serialization + if (fold instanceof ZonedDateTime zdt) { + return new ScriptTemplate( + processScript("{sql}.asDateTime({})"), + paramsBuilder().variable(DateUtils.toString(zdt)).build(), + dataType() + ); + } + + if (fold instanceof IntervalScripting is) { + return new ScriptTemplate( + processScript(is.script()), + paramsBuilder().variable(is.value()).variable(is.typeName()).build(), + dataType() + ); + } + + if (fold instanceof OffsetTime ot) { + return new ScriptTemplate(processScript("{sql}.asTime({})"), paramsBuilder().variable(ot.toString()).build(), dataType()); + } + + if (fold != null && fold.getClass().getSimpleName().equals("GeoShape")) { + return new ScriptTemplate(processScript("{sql}.stWktToSql({})"), paramsBuilder().variable(fold.toString()).build(), dataType()); + } + + return new ScriptTemplate(processScript("{}"), paramsBuilder().variable(fold).build(), dataType()); + } + + protected ScriptTemplate scriptWithScalar(ScalarFunction scalar) { + ScriptTemplate nested = scalar.asScript(); + return new ScriptTemplate(processScript(nested.template()), paramsBuilder().script(nested.params()).build(), dataType()); + } + + protected ScriptTemplate scriptWithAggregate(AggregateFunction aggregate) { + String template = PARAM; + ParamsBuilder paramsBuilder = paramsBuilder().agg(aggregate); + + DataType nullSafeCastDataType = null; + DataType dataType = aggregate.dataType(); + if (dataType.name().equals("DATE") || dataType == DATETIME || + // Aggregations on date_nanos are returned as string + aggregate.field().dataType() == DATETIME) { + + template = "{sql}.asDateTime({})"; + } else if (dataType.isInteger()) { + // MAX, MIN need to retain field's data type, so that possible operations on integral types (like division) work + // correctly -> perform a cast in the aggs filtering script, the bucket selector for HAVING. + // SQL function classes not available in QL: filter by name + String fn = aggregate.functionName(); + if ("MAX".equals(fn) || "MIN".equals(fn)) { + nullSafeCastDataType = dataType; + } else if ("SUM".equals(fn)) { + // SUM(integral_type) requires returning a LONG value + nullSafeCastDataType = LONG; + } + } + if (nullSafeCastDataType != null) { + template = "{ql}.nullSafeCastNumeric({},{})"; + paramsBuilder.variable(nullSafeCastDataType.name()); + } + return new ScriptTemplate(processScript(template), paramsBuilder.build(), dataType()); + } + + // This method isn't actually used at the moment, since there is no grouping function (ie HISTOGRAM) + // that currently results in a script being generated + protected ScriptTemplate scriptWithGrouping(GroupingFunction grouping) { + String template = PARAM; + return new ScriptTemplate(processScript(template), paramsBuilder().grouping(grouping).build(), dataType()); + } + + protected ScriptTemplate scriptWithField(FieldAttribute field) { + Params params = paramsBuilder().variable(field.exactAttribute().name()).build(); + // unsigned_long fields get returned in scripts as plain longs, so a conversion is required + return field.dataType() != UNSIGNED_LONG + ? new ScriptTemplate(processScript(Scripts.DOC_VALUE), params, dataType()) + : new ScriptTemplate( + processScript(format("{ql}.", "nullSafeCastToUnsignedLong({})", Scripts.DOC_VALUE)), + params, + UNSIGNED_LONG + ); + } + + protected String processScript(String script) { + return formatTemplate(script); + } + + protected String formatTemplate(String template) { + return Scripts.formatTemplate(template); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/SurrogateFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/SurrogateFunction.java new file mode 100644 index 000000000000..231554419661 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/SurrogateFunction.java @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +public interface SurrogateFunction { + + ScalarFunction substitute(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/UnaryScalarFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/UnaryScalarFunction.java new file mode 100644 index 000000000000..0be9887f85fc --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/UnaryScalarFunction.java @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; + +import static java.util.Collections.singletonList; + +public abstract class UnaryScalarFunction extends ScalarFunction { + + private final Expression field; + + protected UnaryScalarFunction(Source source) { + super(source); + this.field = null; + } + + protected UnaryScalarFunction(Source source, Expression field) { + super(source, singletonList(field)); + this.field = field; + } + + @Override + public final UnaryScalarFunction replaceChildren(List newChildren) { + return replaceChild(newChildren.get(0)); + } + + protected abstract UnaryScalarFunction replaceChild(Expression newChild); + + public Expression field() { + return field; + } + + @Override + public final Pipe makePipe() { + return new UnaryPipe(source(), this, Expressions.pipe(field()), makeProcessor()); + } + + protected abstract Processor makeProcessor(); + + @Override + public boolean foldable() { + return field.foldable(); + } + + @Override + public Object fold() { + return makeProcessor().process(field().fold()); + } + + @Override + public ScriptTemplate asScript() { + return asScript(field); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/BinaryComparisonCaseInsensitiveFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/BinaryComparisonCaseInsensitiveFunction.java new file mode 100644 index 000000000000..bf2e8dd1cf1f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/BinaryComparisonCaseInsensitiveFunction.java @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.Locale; +import java.util.Objects; + +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isStringAndExact; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; + +public abstract class BinaryComparisonCaseInsensitiveFunction extends CaseInsensitiveScalarFunction { + + private final Expression left, right; + + protected BinaryComparisonCaseInsensitiveFunction(Source source, Expression left, Expression right, boolean caseInsensitive) { + super(source, asList(left, right), caseInsensitive); + this.left = left; + this.right = right; + } + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + TypeResolution sourceResolution = isStringAndExact(left, sourceText(), FIRST); + if (sourceResolution.unresolved()) { + return sourceResolution; + } + + return isStringAndExact(right, sourceText(), SECOND); + } + + public Expression left() { + return left; + } + + public Expression right() { + return right; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public boolean foldable() { + return left.foldable() && right.foldable(); + } + + @Override + public ScriptTemplate asScript() { + ScriptTemplate leftScript = asScript(left); + ScriptTemplate rightScript = asScript(right); + + return asScriptFrom(leftScript, rightScript); + } + + protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) { + return new ScriptTemplate( + format( + Locale.ROOT, + formatTemplate("%s.%s(%s,%s,%s)"), + Scripts.classPackageAsPrefix(getClass()), + scriptMethodName(), + leftScript.template(), + rightScript.template(), + "{}" + ), + paramsBuilder().script(leftScript.params()).script(rightScript.params()).variable(isCaseInsensitive()).build(), + dataType() + ); + } + + protected String scriptMethodName() { + String simpleName = getClass().getSimpleName(); + return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1); + } + + @Override + public int hashCode() { + return Objects.hash(left, right, isCaseInsensitive()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + BinaryComparisonCaseInsensitiveFunction other = (BinaryComparisonCaseInsensitiveFunction) obj; + return Objects.equals(left, other.left) + && Objects.equals(right, other.right) + && Objects.equals(isCaseInsensitive(), other.isCaseInsensitive()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/CaseInsensitiveScalarFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/CaseInsensitiveScalarFunction.java new file mode 100644 index 000000000000..ffe6057ef78f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/CaseInsensitiveScalarFunction.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; + +public abstract class CaseInsensitiveScalarFunction extends ScalarFunction { + + private final boolean caseInsensitive; + + protected CaseInsensitiveScalarFunction(Source source, List fields, boolean caseInsensitive) { + super(source, fields); + this.caseInsensitive = caseInsensitive; + } + + public boolean isCaseInsensitive() { + return caseInsensitive; + } + + @Override + public ScriptTemplate scriptWithField(FieldAttribute field) { + return new ScriptTemplate( + processScript(Scripts.DOC_VALUE), + paramsBuilder().variable(field.exactAttribute().name()).build(), + dataType() + ); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), isCaseInsensitive()); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && Objects.equals(((CaseInsensitiveScalarFunction) other).caseInsensitive, caseInsensitive); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWith.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWith.java new file mode 100644 index 000000000000..8423a91ca8cf --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWith.java @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.Arrays; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isStringAndExact; +import static org.elasticsearch.xpack.esql.core.expression.function.scalar.string.StartsWithFunctionProcessor.doProcess; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; + +/** + * Function that checks if first parameter starts with the second parameter. Both parameters should be strings + * and the function returns a boolean value. + */ +public abstract class StartsWith extends CaseInsensitiveScalarFunction { + + private final Expression input; + private final Expression pattern; + + public StartsWith(Source source, Expression input, Expression pattern, boolean caseInsensitive) { + super(source, Arrays.asList(input, pattern), caseInsensitive); + this.input = input; + this.pattern = pattern; + } + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + TypeResolution fieldResolution = isStringAndExact(input, sourceText(), FIRST); + if (fieldResolution.unresolved()) { + return fieldResolution; + } + + return isStringAndExact(pattern, sourceText(), SECOND); + } + + public Expression input() { + return input; + } + + public Expression pattern() { + return pattern; + } + + @Override + public Pipe makePipe() { + return new StartsWithFunctionPipe(source(), this, Expressions.pipe(input), Expressions.pipe(pattern), isCaseInsensitive()); + } + + @Override + public boolean foldable() { + return input.foldable() && pattern.foldable(); + } + + @Override + public Object fold() { + return doProcess(input.fold(), pattern.fold(), isCaseInsensitive()); + } + + @Override + public ScriptTemplate asScript() { + ScriptTemplate fieldScript = asScript(input); + ScriptTemplate patternScript = asScript(pattern); + + return asScriptFrom(fieldScript, patternScript); + } + + protected ScriptTemplate asScriptFrom(ScriptTemplate fieldScript, ScriptTemplate patternScript) { + ParamsBuilder params = paramsBuilder(); + + String template = formatTemplate("{ql}.startsWith(" + fieldScript.template() + ", " + patternScript.template() + ", {})"); + params.script(fieldScript.params()).script(patternScript.params()).variable(isCaseInsensitive()); + + return new ScriptTemplate(template, params.build(), dataType()); + } + + @Override + public ScriptTemplate scriptWithField(FieldAttribute field) { + return new ScriptTemplate( + processScript(Scripts.DOC_VALUE), + paramsBuilder().variable(field.exactAttribute().name()).build(), + dataType() + ); + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionPipe.java new file mode 100644 index 000000000000..849c7d987200 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionPipe.java @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class StartsWithFunctionPipe extends Pipe { + + private final Pipe input; + private final Pipe pattern; + private final boolean isCaseSensitive; + + public StartsWithFunctionPipe(Source source, Expression expression, Pipe input, Pipe pattern, boolean isCaseSensitive) { + super(source, expression, Arrays.asList(input, pattern)); + this.input = input; + this.pattern = pattern; + this.isCaseSensitive = isCaseSensitive; + } + + @Override + public final Pipe replaceChildren(List newChildren) { + return replaceChildren(newChildren.get(0), newChildren.get(1)); + } + + @Override + public final Pipe resolveAttributes(AttributeResolver resolver) { + Pipe newField = input.resolveAttributes(resolver); + Pipe newPattern = pattern.resolveAttributes(resolver); + if (newField == input && newPattern == pattern) { + return this; + } + return replaceChildren(newField, newPattern); + } + + @Override + public boolean supportedByAggsOnlyQuery() { + return input.supportedByAggsOnlyQuery() && pattern.supportedByAggsOnlyQuery(); + } + + @Override + public boolean resolved() { + return input.resolved() && pattern.resolved(); + } + + protected Pipe replaceChildren(Pipe newField, Pipe newPattern) { + return new StartsWithFunctionPipe(source(), expression(), newField, newPattern, isCaseSensitive); + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + input.collectFields(sourceBuilder); + pattern.collectFields(sourceBuilder); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, StartsWithFunctionPipe::new, expression(), input, pattern, isCaseSensitive); + } + + @Override + public StartsWithFunctionProcessor asProcessor() { + return new StartsWithFunctionProcessor(input.asProcessor(), pattern.asProcessor(), isCaseSensitive); + } + + public Pipe input() { + return input; + } + + public Pipe pattern() { + return pattern; + } + + public boolean isCaseSensitive() { + return isCaseSensitive; + } + + @Override + public int hashCode() { + return Objects.hash(input, pattern, isCaseSensitive); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + StartsWithFunctionPipe other = (StartsWithFunctionPipe) obj; + return Objects.equals(input, other.input) + && Objects.equals(pattern, other.pattern) + && Objects.equals(isCaseSensitive, other.isCaseSensitive); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionProcessor.java new file mode 100644 index 000000000000..8172971fc39f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionProcessor.java @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; +import java.util.Locale; +import java.util.Objects; + +public class StartsWithFunctionProcessor implements Processor { + + public static final String NAME = "sstw"; + + private final Processor source; + private final Processor pattern; + private final boolean caseInsensitive; + + public StartsWithFunctionProcessor(Processor source, Processor pattern, boolean caseInsensitive) { + this.source = source; + this.pattern = pattern; + this.caseInsensitive = caseInsensitive; + } + + public StartsWithFunctionProcessor(StreamInput in) throws IOException { + source = in.readNamedWriteable(Processor.class); + pattern = in.readNamedWriteable(Processor.class); + caseInsensitive = in.readBoolean(); + } + + @Override + public final void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteable(source); + out.writeNamedWriteable(pattern); + out.writeBoolean(caseInsensitive); + } + + @Override + public Object process(Object input) { + return doProcess(source.process(input), pattern.process(input), isCaseInsensitive()); + } + + public static Object doProcess(Object source, Object pattern, boolean caseInsensitive) { + if (source == null) { + return null; + } + if (source instanceof String == false && source instanceof Character == false) { + throw new QlIllegalArgumentException("A string/char is required; received [{}]", source); + } + if (pattern == null) { + return null; + } + if (pattern instanceof String == false && pattern instanceof Character == false) { + throw new QlIllegalArgumentException("A string/char is required; received [{}]", pattern); + } + + if (caseInsensitive == false) { + return source.toString().startsWith(pattern.toString()); + } else { + return source.toString().toLowerCase(Locale.ROOT).startsWith(pattern.toString().toLowerCase(Locale.ROOT)); + } + } + + protected Processor source() { + return source; + } + + protected Processor pattern() { + return pattern; + } + + protected boolean isCaseInsensitive() { + return caseInsensitive; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + StartsWithFunctionProcessor other = (StartsWithFunctionProcessor) obj; + return Objects.equals(source(), other.source()) + && Objects.equals(pattern(), other.pattern()) + && Objects.equals(isCaseInsensitive(), other.isCaseInsensitive()); + } + + @Override + public int hashCode() { + return Objects.hash(source(), pattern(), isCaseInsensitive()); + } + + @Override + public String getWriteableName() { + return NAME; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/whitelist/InternalQlScriptUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/whitelist/InternalQlScriptUtils.java new file mode 100644 index 000000000000..8895a2dc5473 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/whitelist/InternalQlScriptUtils.java @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar.whitelist; + +import org.elasticsearch.index.fielddata.ScriptDocValues; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.string.StartsWithFunctionProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.NotProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor.UnaryArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.InProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexProcessor.RegexOperation; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.List; +import java.util.Map; + +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.convert; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.toUnsignedLong; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.fromTypeName; + +public class InternalQlScriptUtils { + + // + // Utilities + // + + // safe missing mapping/value extractor + public static Object docValue(Map> doc, String fieldName) { + if (doc.containsKey(fieldName)) { + ScriptDocValues docValues = doc.get(fieldName); + if (docValues.isEmpty() == false) { + return docValues.get(0); + } + } + return null; + } + + public static boolean nullSafeFilter(Boolean filter) { + return filter == null ? false : filter.booleanValue(); + } + + public static double nullSafeSortNumeric(Number sort) { + return sort == null ? 0.0d : sort.doubleValue(); + } + + public static String nullSafeSortString(Object sort) { + return sort == null ? StringUtils.EMPTY : sort.toString(); + } + + public static Number nullSafeCastNumeric(Number number, String typeName) { + return number == null || Double.isNaN(number.doubleValue()) ? null : (Number) convert(number, fromTypeName(typeName)); + } + + public static Number nullSafeCastToUnsignedLong(Number number) { + return number == null || Double.isNaN(number.doubleValue()) ? null : toUnsignedLong(number); + } + + // + // Operators + // + + // + // Logical + // + public static Boolean eq(Object left, Object right) { + return BinaryComparisonOperation.EQ.apply(left, right); + } + + public static Boolean nulleq(Object left, Object right) { + return BinaryComparisonOperation.NULLEQ.apply(left, right); + } + + public static Boolean neq(Object left, Object right) { + return BinaryComparisonOperation.NEQ.apply(left, right); + } + + public static Boolean lt(Object left, Object right) { + return BinaryComparisonOperation.LT.apply(left, right); + } + + public static Boolean lte(Object left, Object right) { + return BinaryComparisonOperation.LTE.apply(left, right); + } + + public static Boolean gt(Object left, Object right) { + return BinaryComparisonOperation.GT.apply(left, right); + } + + public static Boolean gte(Object left, Object right) { + return BinaryComparisonOperation.GTE.apply(left, right); + } + + public static Boolean in(Object value, List values) { + return InProcessor.apply(value, values); + } + + public static Boolean and(Boolean left, Boolean right) { + return BinaryLogicOperation.AND.apply(left, right); + } + + public static Boolean or(Boolean left, Boolean right) { + return BinaryLogicOperation.OR.apply(left, right); + } + + public static Boolean not(Boolean expression) { + return NotProcessor.apply(expression); + } + + public static Boolean isNull(Object expression) { + return CheckNullOperation.IS_NULL.test(expression); + } + + public static Boolean isNotNull(Object expression) { + return CheckNullOperation.IS_NOT_NULL.test(expression); + } + + // + // Regex + // + public static Boolean regex(String value, String pattern) { + return regex(value, pattern, Boolean.FALSE); + } + + public static Boolean regex(String value, String pattern, Boolean caseInsensitive) { + // TODO: this needs to be improved to avoid creating the pattern on every call + return RegexOperation.match(value, pattern, caseInsensitive); + } + + // + // Math + // + public static Number add(Number left, Number right) { + return (Number) DefaultBinaryArithmeticOperation.ADD.apply(left, right); + } + + public static Number div(Number left, Number right) { + return (Number) DefaultBinaryArithmeticOperation.DIV.apply(left, right); + } + + public static Number mod(Number left, Number right) { + return (Number) DefaultBinaryArithmeticOperation.MOD.apply(left, right); + } + + public static Number mul(Number left, Number right) { + return (Number) DefaultBinaryArithmeticOperation.MUL.apply(left, right); + } + + public static Number neg(Number value) { + return UnaryArithmeticOperation.NEGATE.apply(value); + } + + public static Number sub(Number left, Number right) { + return (Number) DefaultBinaryArithmeticOperation.SUB.apply(left, right); + } + + // + // String + // + public static Boolean startsWith(String s, String pattern, Boolean caseInsensitive) { + return (Boolean) StartsWithFunctionProcessor.doProcess(s, pattern, caseInsensitive); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggExtractorInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggExtractorInput.java new file mode 100644 index 000000000000..851bb0cd2053 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggExtractorInput.java @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.execution.search.extractor.BucketExtractor; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.BucketExtractorProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ChainingProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class AggExtractorInput extends LeafInput { + + private final Processor chained; + + public AggExtractorInput(Source source, Expression expression, Processor processor, BucketExtractor context) { + super(source, expression, context); + this.chained = processor; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, AggExtractorInput::new, expression(), chained, context()); + } + + @Override + public Processor asProcessor() { + Processor proc = new BucketExtractorProcessor(context()); + return chained != null ? new ChainingProcessor(proc, chained) : proc; + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return true; + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return this; + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + // Nothing to collect + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggNameInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggNameInput.java new file mode 100644 index 000000000000..ee8cc02ea2d0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggNameInput.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class AggNameInput extends CommonNonExecutableInput { + public AggNameInput(Source source, Expression expression, String context) { + super(source, expression, context); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, AggNameInput::new, expression(), context()); + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return true; + } + + @Override + public final boolean resolved() { + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggPathInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggPathInput.java new file mode 100644 index 000000000000..226bc818a791 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AggPathInput.java @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.AggRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class AggPathInput extends CommonNonExecutableInput { + + // used in case the agg itself is not returned in a suitable format (like date aggs) + private final Processor action; + + public AggPathInput(Expression expression, AggRef context) { + this(Source.EMPTY, expression, context, null); + } + + /** + * + * Constructs a new AggPathInput instance. + * The action is used for handling corner-case results such as date histogram which returns + * a full date object for year which requires additional extraction. + */ + public AggPathInput(Source source, Expression expression, AggRef context, Processor action) { + super(source, expression, context); + this.action = action; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, AggPathInput::new, expression(), context(), action); + } + + public Processor action() { + return action; + } + + @Override + public boolean resolved() { + return true; + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return true; + } + + @Override + public int hashCode() { + return Objects.hash(context(), action); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + AggPathInput other = (AggPathInput) obj; + return Objects.equals(context(), other.context()) && Objects.equals(action, other.action); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AttributeInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AttributeInput.java new file mode 100644 index 000000000000..5f25dfaea927 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AttributeInput.java @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * An input that must first be rewritten against the rest of the query + * before it can be further processed. + */ +public class AttributeInput extends NonExecutableInput { + public AttributeInput(Source source, Expression expression, Attribute context) { + super(source, expression, context); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, AttributeInput::new, expression(), context()); + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return true; + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return new ReferenceInput(source(), expression(), resolver.resolve(context())); + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + // Nothing to extract + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/BinaryPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/BinaryPipe.java new file mode 100644 index 000000000000..a1f8a2b8e644 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/BinaryPipe.java @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public abstract class BinaryPipe extends Pipe { + + private final Pipe left, right; + + public BinaryPipe(Source source, Expression expression, Pipe left, Pipe right) { + super(source, expression, Arrays.asList(left, right)); + this.left = left; + this.right = right; + } + + @Override + public final Pipe replaceChildren(List newChildren) { + return replaceChildren(newChildren.get(0), newChildren.get(1)); + } + + public Pipe left() { + return left; + } + + public Pipe right() { + return right; + } + + @Override + public boolean supportedByAggsOnlyQuery() { + return left.supportedByAggsOnlyQuery() || right.supportedByAggsOnlyQuery(); + } + + @Override + public final Pipe resolveAttributes(AttributeResolver resolver) { + Pipe newLeft = left.resolveAttributes(resolver); + Pipe newRight = right.resolveAttributes(resolver); + if (newLeft == left && newRight == right) { + return this; + } + return replaceChildren(newLeft, newRight); + } + + /** + * Build a copy of this object with new left and right children. Used by + * {@link #resolveAttributes(AttributeResolver)}. + */ + protected abstract BinaryPipe replaceChildren(Pipe left, Pipe right); + + @Override + public boolean resolved() { + return left().resolved() && right().resolved(); + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + left.collectFields(sourceBuilder); + right.collectFields(sourceBuilder); + } + + @Override + public int hashCode() { + return Objects.hash(left(), right()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + BinaryPipe other = (BinaryPipe) obj; + return Objects.equals(left(), other.left()) && Objects.equals(right(), other.right()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/CommonNonExecutableInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/CommonNonExecutableInput.java new file mode 100644 index 000000000000..c6f96f7062db --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/CommonNonExecutableInput.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * Implementation common to most subclasses of + * {@link NonExecutableInput} but not shared by all. + */ +abstract class CommonNonExecutableInput extends NonExecutableInput { + CommonNonExecutableInput(Source source, Expression expression, T context) { + super(source, expression, context); + } + + @Override + public final Processor asProcessor() { + throw new QlIllegalArgumentException("Unresolved input - needs resolving first"); + } + + @Override + public final Pipe resolveAttributes(AttributeResolver resolver) { + return this; + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + // Nothing to extract + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/ConstantInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/ConstantInput.java new file mode 100644 index 000000000000..560db5d43cad --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/ConstantInput.java @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class ConstantInput extends LeafInput { + + public ConstantInput(Source source, Expression expression, Object context) { + super(source, expression, context); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, ConstantInput::new, expression(), context()); + } + + @Override + public Processor asProcessor() { + return new ConstantProcessor(context()); + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return false; + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return this; + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + // Nothing to collect + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/HitExtractorInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/HitExtractorInput.java new file mode 100644 index 000000000000..b51d164d5c5d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/HitExtractorInput.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.execution.search.extractor.HitExtractor; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.HitExtractorProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class HitExtractorInput extends LeafInput { + + public HitExtractorInput(Source source, Expression expression, HitExtractor context) { + super(source, expression, context); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, HitExtractorInput::new, expression(), context()); + } + + @Override + public Processor asProcessor() { + return new HitExtractorProcessor(context()); + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return true; + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return this; + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + // No fields to collect + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/LeafInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/LeafInput.java new file mode 100644 index 000000000000..cf6c99a74c39 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/LeafInput.java @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.emptyList; + +public abstract class LeafInput extends Pipe { + + private T context; + + public LeafInput(Source source, Expression expression, T context) { + super(source, expression, emptyList()); + this.context = context; + } + + @Override + public final Pipe replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + public T context() { + return context; + } + + @Override + public boolean resolved() { + return true; + } + + @Override + public int hashCode() { + return Objects.hash(expression(), context); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + LeafInput other = (LeafInput) obj; + return Objects.equals(context(), other.context()) && Objects.equals(expression(), other.expression()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/MultiPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/MultiPipe.java new file mode 100644 index 000000000000..c75437c6cbe8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/MultiPipe.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.ArrayList; +import java.util.List; + +public abstract class MultiPipe extends Pipe { + + protected MultiPipe(Source source, Expression expression, List children) { + super(source, expression, children); + } + + @Override + public Processor asProcessor() { + List procs = new ArrayList<>(); + for (Pipe pipe : children()) { + procs.add(pipe.asProcessor()); + } + + return asProcessor(procs); + } + + public abstract Processor asProcessor(List procs); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/NonExecutableInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/NonExecutableInput.java new file mode 100644 index 000000000000..74b522c8a617 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/NonExecutableInput.java @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public abstract class NonExecutableInput extends LeafInput { + NonExecutableInput(Source source, Expression expression, T context) { + super(source, expression, context); + } + + @Override + public boolean resolved() { + return false; + } + + @Override + public Processor asProcessor() { + throw new QlIllegalArgumentException("Unresolved input - needs resolving first"); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/Pipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/Pipe.java new file mode 100644 index 000000000000..4883d0abd028 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/Pipe.java @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.capabilities.Resolvable; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.execution.search.FieldExtraction; +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.ArrayList; +import java.util.List; + +/** + * Processing pipe for an expression (tree). Used for local execution of expressions + * on the invoking node. + * For example, the {@code Pipe} of: + * + * ABS(MAX(foo)) + CAST(bar) + * + * Is an {@code Add} operator with left {@code ABS} over an aggregate (MAX), and + * right being a {@code CAST} function. + */ +public abstract class Pipe extends Node implements FieldExtraction, Resolvable { + + private final Expression expression; + + public Pipe(Source source, Expression expression, List children) { + super(source, children); + this.expression = expression; + } + + public Expression expression() { + return expression; + } + + @Override + public boolean resolved() { + return Resolvables.resolved(children()); + } + + @Override + public void collectFields(QlSourceBuilder sourceBuilder) { + children().forEach(c -> c.collectFields(sourceBuilder)); + } + + @Override + public boolean supportedByAggsOnlyQuery() { + return children().stream().anyMatch(Pipe::supportedByAggsOnlyQuery); + } + + public abstract Processor asProcessor(); + + /** + * Resolve {@link Attribute}s which are unprocessable into + * {@link Pipe}s that are. + * + * @return {@code this} if the resolution doesn't change the + * definition, a new {@link Pipe} otherwise + */ + public Pipe resolveAttributes(AttributeResolver resolver) { + List newPipes = new ArrayList<>(children().size()); + for (Pipe p : children()) { + newPipes.add(p.resolveAttributes(resolver)); + } + + return children().equals(newPipes) ? this : replaceChildrenSameSize(newPipes); + } + + public interface AttributeResolver { + FieldExtraction resolve(Attribute attribute); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/ReferenceInput.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/ReferenceInput.java new file mode 100644 index 000000000000..09db67c9bceb --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/ReferenceInput.java @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.FieldExtraction; +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class ReferenceInput extends NonExecutableInput { + public ReferenceInput(Source source, Expression expression, FieldExtraction context) { + super(source, expression, context); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, ReferenceInput::new, expression(), context()); + } + + @Override + public final boolean supportedByAggsOnlyQuery() { + return false; + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return this; + } + + @Override + public final void collectFields(QlSourceBuilder sourceBuilder) { + context().collectFields(sourceBuilder); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/UnaryPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/UnaryPipe.java new file mode 100644 index 000000000000..75257e7b3a4c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/UnaryPipe.java @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ChainingProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; + +public final class UnaryPipe extends Pipe { + + private final Pipe child; + private final Processor action; + + public UnaryPipe(Source source, Expression expression, Pipe child, Processor action) { + super(source, expression, singletonList(child)); + this.child = child; + this.action = action; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnaryPipe::new, expression(), child, action); + } + + @Override + public Pipe replaceChildren(List newChildren) { + return new UnaryPipe(source(), expression(), newChildren.get(0), action); + } + + public Pipe child() { + return child; + } + + public Processor action() { + return action; + } + + @Override + public boolean resolved() { + return child.resolved(); + } + + @Override + public Processor asProcessor() { + return new ChainingProcessor(child.asProcessor(), action); + } + + @Override + public boolean supportedByAggsOnlyQuery() { + return child.supportedByAggsOnlyQuery(); + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + Pipe newChild = child.resolveAttributes(resolver); + if (newChild == child) { + return this; + } + return new UnaryPipe(source(), expression(), newChild, action); + } + + @Override + public void collectFields(QlSourceBuilder sourceBuilder) { + child.collectFields(sourceBuilder); + } + + @Override + public int hashCode() { + return Objects.hash(expression(), child, action); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UnaryPipe other = (UnaryPipe) obj; + return Objects.equals(action, other.action) + && Objects.equals(child, other.child) + && Objects.equals(expression(), other.expression()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/BinaryProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/BinaryProcessor.java new file mode 100644 index 000000000000..13c4498e5498 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/BinaryProcessor.java @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; + +public abstract class BinaryProcessor implements Processor { + + private final Processor left, right; + + public BinaryProcessor(Processor left, Processor right) { + this.left = left; + this.right = right; + } + + protected BinaryProcessor(StreamInput in) throws IOException { + left = in.readNamedWriteable(Processor.class); + right = in.readNamedWriteable(Processor.class); + } + + @Override + public final void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteable(left); + out.writeNamedWriteable(right); + doWrite(out); + } + + protected abstract void doWrite(StreamOutput out) throws IOException; + + @Override + public Object process(Object input) { + Object l = left.process(input); + if (l == null) { + return null; + } + checkParameter(l); + + Object r = right.process(input); + if (r == null) { + return null; + } + checkParameter(r); + + return doProcess(l, r); + } + + /** + * Checks the parameter (typically for its type) if the value is not null. + */ + protected void checkParameter(Object param) { + // no-op + } + + protected Processor left() { + return left; + } + + protected Processor right() { + return right; + } + + protected abstract Object doProcess(Object left, Object right); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/BucketExtractorProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/BucketExtractorProcessor.java new file mode 100644 index 000000000000..afd4efc0e88e --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/BucketExtractorProcessor.java @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.execution.search.extractor.BucketExtractor; + +import java.io.IOException; +import java.util.Objects; + +/** + * Processor wrapping an {@link BucketExtractor}, essentially being a source/leaf of a + * Processor tree. + */ +public class BucketExtractorProcessor implements Processor { + + public static final String NAME = "a"; + + private final BucketExtractor extractor; + + public BucketExtractorProcessor(BucketExtractor extractor) { + this.extractor = extractor; + } + + public BucketExtractorProcessor(StreamInput in) throws IOException { + extractor = in.readNamedWriteable(BucketExtractor.class); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteable(extractor); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public Object process(Object input) { + if ((input instanceof Bucket) == false) { + throw new QlIllegalArgumentException("Expected an agg bucket but received {}", input); + } + return extractor.extract((Bucket) input); + } + + @Override + public int hashCode() { + return Objects.hash(extractor); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + BucketExtractorProcessor other = (BucketExtractorProcessor) obj; + return Objects.equals(extractor, other.extractor); + } + + @Override + public String toString() { + return extractor.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ChainingProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ChainingProcessor.java new file mode 100644 index 000000000000..60e60bc26436 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ChainingProcessor.java @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; +import java.util.Objects; + +/** + * A {@linkplain Processor} that composes the results of two + * {@linkplain Processor}s. + */ +public class ChainingProcessor extends UnaryProcessor { + public static final String NAME = "."; + + private final Processor processor; + + public ChainingProcessor(Processor first, Processor second) { + super(first); + this.processor = second; + } + + public ChainingProcessor(StreamInput in) throws IOException { + super(in); + processor = in.readNamedWriteable(Processor.class); + } + + @Override + protected void doWrite(StreamOutput out) throws IOException { + out.writeNamedWriteable(processor); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + protected Object doProcess(Object input) { + return processor.process(input); + } + + Processor first() { + return child(); + } + + Processor second() { + return processor; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), processor); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) && Objects.equals(processor, ((ChainingProcessor) obj).processor); + } + + @Override + public String toString() { + return processor + "(" + super.toString() + ")"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantNamedWriteable.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantNamedWriteable.java new file mode 100644 index 000000000000..97733ed4d705 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantNamedWriteable.java @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.NamedWriteable; + +/** + * Marker interface used by QL for pluggable constant serialization. + */ +public interface ConstantNamedWriteable extends NamedWriteable { + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantProcessor.java new file mode 100644 index 000000000000..ad426b641ed0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantProcessor.java @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.versionfield.Version; + +import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Objects; + +public class ConstantProcessor implements Processor { + + public static String NAME = "c"; + + private Object constant; + private final Type type; + + enum Type { + NAMED_WRITABLE, + ZONEDDATETIME, + GENERIC, + VERSION // Version is in x-pack, so StreamInput/Output cannot manage it as a generic type + } + + public ConstantProcessor(Object value) { + this.constant = value; + if (value instanceof NamedWriteable) { + type = Type.NAMED_WRITABLE; + } else if (value instanceof ZonedDateTime) { + type = Type.ZONEDDATETIME; + } else if (value instanceof Version) { + type = Type.VERSION; + } else { + type = Type.GENERIC; + } + } + + public ConstantProcessor(StreamInput in) throws IOException { + type = in.readEnum(Type.class); + switch (type) { + case NAMED_WRITABLE -> constant = in.readNamedWriteable(ConstantNamedWriteable.class); + case ZONEDDATETIME -> { + ZonedDateTime zdt; + ZoneId zoneId = in.readZoneId(); + zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(in.readLong()), zoneId); + constant = zdt.withNano(in.readInt()); + } + case VERSION -> constant = new Version(in.readString()); + case GENERIC -> constant = in.readGenericValue(); + } + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeEnum(type); + switch (type) { + case NAMED_WRITABLE -> out.writeNamedWriteable((NamedWriteable) constant); + case ZONEDDATETIME -> { + ZonedDateTime zdt = (ZonedDateTime) constant; + out.writeZoneId(zdt.getZone()); + out.writeLong(zdt.toInstant().toEpochMilli()); + out.writeInt(zdt.getNano()); + } + case VERSION -> out.writeString(constant.toString()); + case GENERIC -> out.writeGenericValue(constant); + } + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public Object process(Object input) { + return constant; + } + + @Override + public int hashCode() { + return Objects.hashCode(constant); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + ConstantProcessor other = (ConstantProcessor) obj; + return Objects.equals(constant, other.constant); + } + + @Override + public String toString() { + return "^" + constant; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/FunctionalBinaryProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/FunctionalBinaryProcessor.java new file mode 100644 index 000000000000..3713102b893f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/FunctionalBinaryProcessor.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; + +import java.io.IOException; +import java.util.Objects; +import java.util.function.BiFunction; + +/** + * Base class for definition binary processors based on functions (for applying). + */ +public abstract class FunctionalBinaryProcessor> extends BinaryProcessor { + + private final F function; + + protected FunctionalBinaryProcessor(Processor left, Processor right, F function) { + super(left, right); + this.function = function; + } + + protected FunctionalBinaryProcessor(StreamInput in, Reader reader) throws IOException { + super(in); + this.function = reader.read(in); + } + + public F function() { + return function; + } + + @SuppressWarnings("unchecked") + @Override + protected Object doProcess(Object left, Object right) { + return function.apply((T) left, (U) right); + } + + @Override + public int hashCode() { + return Objects.hash(left(), right(), function()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + FunctionalBinaryProcessor other = (FunctionalBinaryProcessor) obj; + return Objects.equals(function(), other.function()) + && Objects.equals(left(), other.left()) + && Objects.equals(right(), other.right()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/FunctionalEnumBinaryProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/FunctionalEnumBinaryProcessor.java new file mode 100644 index 000000000000..352cea13535c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/FunctionalEnumBinaryProcessor.java @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; +import java.util.function.BiFunction; + +/** + * Base class for definition binary processors based on functions (for applying) defined as enums (for serialization purposes). + */ +public abstract class FunctionalEnumBinaryProcessor & BiFunction> extends FunctionalBinaryProcessor< + T, + U, + R, + F> { + + protected FunctionalEnumBinaryProcessor(Processor left, Processor right, F function) { + super(left, right, function); + } + + protected FunctionalEnumBinaryProcessor(StreamInput in, Reader reader) throws IOException { + super(in, reader); + } + + @Override + protected void doWrite(StreamOutput out) throws IOException { + out.writeEnum(function()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/HitExtractorProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/HitExtractorProcessor.java new file mode 100644 index 000000000000..1662a8192acf --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/HitExtractorProcessor.java @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.execution.search.extractor.HitExtractor; + +import java.io.IOException; +import java.util.Objects; + +/** + * Processor wrapping a {@link HitExtractor}, essentially being a source/leaf of a + * Processor tree. + */ +public class HitExtractorProcessor implements Processor { + + public static final String NAME = "h"; + + private final HitExtractor extractor; + + public HitExtractorProcessor(HitExtractor extractor) { + this.extractor = extractor; + } + + public HitExtractorProcessor(StreamInput in) throws IOException { + extractor = in.readNamedWriteable(HitExtractor.class); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteable(extractor); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public Object process(Object input) { + if ((input instanceof SearchHit) == false) { + throw new QlIllegalArgumentException("Expected a SearchHit but received {}", input); + } + return extractor.extract((SearchHit) input); + } + + @Override + public int hashCode() { + return Objects.hash(extractor); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + HitExtractorProcessor other = (HitExtractorProcessor) obj; + return Objects.equals(extractor, other.extractor); + } + + @Override + public String toString() { + return extractor.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/Processor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/Processor.java new file mode 100644 index 000000000000..bafdf3b05f40 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/Processor.java @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.NamedWriteable; + +/** + * A {@code Processor} evaluates locally an expression. For instance, ABS(foo). + * Aggregate functions are handled by ES but scalars are not. + * + * This is an opaque class, the computed/compiled result gets saved on the client during scrolling. + */ +public interface Processor extends NamedWriteable { + + Object process(Object input); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/UnaryProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/UnaryProcessor.java new file mode 100644 index 000000000000..4ddf851ce3c2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/UnaryProcessor.java @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; +import java.util.Objects; + +public abstract class UnaryProcessor implements Processor { + + private final Processor child; + + public UnaryProcessor(Processor child) { + this.child = child; + } + + protected UnaryProcessor(StreamInput in) throws IOException { + child = in.readNamedWriteable(Processor.class); + } + + @Override + public final void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteable(child); + doWrite(out); + } + + protected abstract void doWrite(StreamOutput out) throws IOException; + + @Override + public final Object process(Object input) { + return doProcess(child.process(input)); + } + + public Processor child() { + return child; + } + + protected abstract Object doProcess(Object input); + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UnaryProcessor other = (UnaryProcessor) obj; + return Objects.equals(child, other.child); + } + + @Override + public int hashCode() { + return Objects.hashCode(child); + } + + @Override + public String toString() { + return Objects.toString(child); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Agg.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Agg.java new file mode 100644 index 000000000000..9f7c50789924 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Agg.java @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.Count; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.InnerAggregate; + +class Agg extends Param { + + private static final String COUNT_PATH = "_count"; + + Agg(AggregateFunction aggRef) { + super(aggRef); + } + + String aggName() { + return Expressions.id(value()); + } + + public String aggProperty() { + AggregateFunction agg = value(); + + if (agg instanceof InnerAggregate inner) { + return Expressions.id((Expression) inner.outer()) + "." + inner.innerName(); + } + // Count needs special handling since in most cases it is not a dedicated aggregation + else if (agg instanceof Count c) { + // for literals get the last count + if (c.field().foldable()) { + return COUNT_PATH; + } + // when dealing with fields, check whether there's a single-metric (distinct -> cardinality) + // or a bucket (non-distinct - filter agg) + else { + if (c.distinct()) { + return Expressions.id(c); + } else { + return Expressions.id(c) + "." + COUNT_PATH; + } + } + } + return null; + } + + @Override + public String prefix() { + return "a"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Grouping.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Grouping.java new file mode 100644 index 000000000000..c5b67708f985 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Grouping.java @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.xpack.esql.core.expression.function.grouping.GroupingFunction; + +class Grouping extends Param { + + Grouping(GroupingFunction groupRef) { + super(groupRef); + } + + String groupName() { + return Integer.toHexString(value().hashCode()); + } + + @Override + public String prefix() { + return "g"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Param.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Param.java new file mode 100644 index 000000000000..1f3a8e7c38c1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Param.java @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import java.util.Objects; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; + +abstract class Param { + private final T value; + + Param(T value) { + this.value = value; + } + + abstract String prefix(); + + T value() { + return value; + } + + @Override + public String toString() { + return format(null, "{{}={}}", prefix(), value); + } + + @Override + public int hashCode() { + if (this.value == null) { + return Objects.hashCode(null); + } + return this.value.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ((obj instanceof Param) == false) { + return false; + } + if (this.value == null) { + return ((Param) obj).value == null; + } + return this.value.equals(((Param) obj).value); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Params.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Params.java new file mode 100644 index 000000000000..b633a767ffbd --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Params.java @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.common.util.Maps; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Collections.emptyList; + +/** + * Parameters for a script + * + * This class mainly exists to handle the different aggregation cases. + * While aggs can appear in scripts like regular parameters, they are not passed + * as parameters but rather as bucket_path. + * However in some cases (like count), it's not the agg path that is relevant but rather + * its property (_count). + * As the agg name still needs to be remembered to properly associate the script with. + * + * Hence why this class supports aggRef (which always returns the agg names) and aggPaths + * (which returns the agg property if it exists or the agg name/reference). + * + * Also the parameter names support late binding/evaluation since the agg reference (like function id) + * can be changed during the optimization phase (for example min agg -> stats.min). + */ +public class Params { + + public static final Params EMPTY = new Params(emptyList()); + + private final List> params; + + Params(List> params) { + // flatten params + this.params = flatten(params); + } + + // return vars and aggs in the declared order for binding them to the script + List asCodeNames() { + if (params.isEmpty()) { + return emptyList(); + } + + List names = new ArrayList<>(params.size()); + int aggs = 0, vars = 0; + + for (Param p : params) { + names.add(p.prefix() + (p instanceof Agg ? aggs++ : vars++)); + } + + return names; + } + + // return only the vars (as parameter for a script) + // agg refs are returned separately to be provided as bucket_paths + Map asParams() { + Map map = Maps.newLinkedHashMapWithExpectedSize(params.size()); + + int count = 0; + + for (Param p : params) { + if (p instanceof Var) { + map.put(p.prefix() + count++, p.value()); + } + } + + return map; + } + + // return agg refs in a format suitable for bucket_paths + Map asAggPaths() { + Map map = new LinkedHashMap<>(); + + int aggs = 0; + + for (Param p : params) { + if (p instanceof Agg a) { + String s = a.aggProperty() != null ? a.aggProperty() : a.aggName(); + map.put(p.prefix() + aggs++, s); + } + if (p instanceof Grouping g) { + map.put(p.prefix() + aggs++, g.groupName()); + } + } + + return map; + } + + private static List> flatten(List> params) { + List> flatten = emptyList(); + + if (params.isEmpty() == false) { + flatten = new ArrayList<>(); + for (Param p : params) { + if (p instanceof Script) { + flatten.addAll(flatten(((Script) p).value().params)); + } else if (p instanceof Agg) { + flatten.add(p); + } else if (p instanceof Grouping) { + flatten.add(p); + } else if (p instanceof Var) { + flatten.add(p); + } else { + throw new QlIllegalArgumentException("Unsupported field {}", p); + } + } + } + return flatten; + } + + @Override + public String toString() { + return params.toString(); + } + + @Override + public int hashCode() { + return this.params.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if ((obj instanceof Params) == false) { + return false; + } + return this.params.equals(((Params) obj).params); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ParamsBuilder.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ParamsBuilder.java new file mode 100644 index 000000000000..16002f048809 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ParamsBuilder.java @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.grouping.GroupingFunction; + +import java.util.ArrayList; +import java.util.List; + +public class ParamsBuilder { + + private final List> params = new ArrayList<>(); + + public static ParamsBuilder paramsBuilder() { + return new ParamsBuilder(); + } + + public ParamsBuilder variable(Object value) { + params.add(new Var(value)); + return this; + } + + public ParamsBuilder agg(AggregateFunction agg) { + params.add(new Agg(agg)); + return this; + } + + public ParamsBuilder grouping(GroupingFunction grouping) { + params.add(new Grouping(grouping)); + return this; + } + + public ParamsBuilder script(Params ps) { + params.add(new Script(ps)); + return this; + } + + public Params build() { + return new Params(new ArrayList<>(params)); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Script.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Script.java new file mode 100644 index 000000000000..bd9195d34463 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Script.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +class Script extends Param { + + Script(Params value) { + super(value); + } + + @Override + public String prefix() { + return "s"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ScriptTemplate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ScriptTemplate.java new file mode 100644 index 000000000000..6ac8861c9bc9 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ScriptTemplate.java @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.script.Script; +import org.elasticsearch.script.ScriptType; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +import static java.lang.String.format; + +public class ScriptTemplate { + + public static final ScriptTemplate EMPTY = new ScriptTemplate(StringUtils.EMPTY); + + private final String template; + private final Params params; + // used for sorting based on scripts + private final DataType outputType; + + public ScriptTemplate(String template) { + this(template, Params.EMPTY, DataTypes.KEYWORD); + } + + public ScriptTemplate(String template, Params params, DataType outputType) { + this.template = template; + this.params = params; + this.outputType = outputType; + } + + public String template() { + return template; + } + + public Params params() { + return params; + } + + public Map aggPaths() { + return params.asAggPaths(); + } + + public DataType outputType() { + return outputType; + } + + public Script toPainless() { + return new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, bindTemplate(), params.asParams()); + } + + private String bindTemplate() { + List binding = params.asCodeNames(); + return binding.isEmpty() ? template : format(Locale.ROOT, template, binding.toArray()); + } + + @Override + public int hashCode() { + return Objects.hash(template, params, outputType); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + ScriptTemplate other = (ScriptTemplate) obj; + return Objects.equals(template, other.template) + && Objects.equals(params, other.params) + && Objects.equals(outputType, other.outputType); + } + + @Override + public String toString() { + return bindTemplate(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Scripts.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Scripts.java new file mode 100644 index 000000000000..739b32efbde2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Scripts.java @@ -0,0 +1,239 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.Check; + +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static java.util.Collections.unmodifiableMap; +import static java.util.stream.Collectors.toMap; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; + +public final class Scripts { + + public static final String DOC_VALUE = "doc[{}].value"; + public static final String QL_SCRIPTS = "{ql}"; + public static final String EQL_SCRIPTS = "{eql}"; + public static final String SQL_SCRIPTS = "{sql}"; + public static final String PARAM = "{}"; + static final String DOC_VALUE_PARAMS_REGEX = + "InternalQlScriptUtils\\.docValue\\(doc,(params\\.%s)\\)|(params\\.%s)|InternalQlScriptUtils\\.not\\("; + public static final String INTERNAL_QL_SCRIPT_UTILS = "InternalQlScriptUtils"; + public static final String INTERNAL_EQL_SCRIPT_UTILS = "InternalEqlScriptUtils"; + public static final String INTERNAL_SQL_SCRIPT_UTILS = "InternalSqlScriptUtils"; + + private static final int PKG_LENGTH = "org.elasticsearch.xpack.".length(); + + private Scripts() {} + + static final Map FORMATTING_PATTERNS = unmodifiableMap( + Stream.of( + new SimpleEntry<>(DOC_VALUE, QL_SCRIPTS + ".docValue(doc,{})"), + new SimpleEntry<>(QL_SCRIPTS, INTERNAL_QL_SCRIPT_UTILS), + new SimpleEntry<>(EQL_SCRIPTS, INTERNAL_EQL_SCRIPT_UTILS), + new SimpleEntry<>(SQL_SCRIPTS, INTERNAL_SQL_SCRIPT_UTILS), + new SimpleEntry<>(PARAM, "params.%s") + ).collect(toMap(e -> Pattern.compile(e.getKey(), Pattern.LITERAL), Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new)) + ); + static final Pattern qlDocValuePattern = Pattern.compile(DOC_VALUE_PARAMS_REGEX); + + /** + * Expands common tokens inside the script: + * + *
+     * {sql} -> InternalSqlScriptUtils
+     * doc[{}].value -> InternalSqlScriptUtils.docValue(doc, {})
+     * {}    -> params.%s
+     * 
+ */ + public static String formatTemplate(String template) { + for (Entry entry : FORMATTING_PATTERNS.entrySet()) { + template = entry.getKey().matcher(template).replaceAll(entry.getValue()); + } + return template; + } + + public static ScriptTemplate nullSafeFilter(ScriptTemplate script) { + return new ScriptTemplate( + formatTemplate(format(Locale.ROOT, "{ql}.nullSafeFilter(%s)", script.template())), + script.params(), + DataTypes.BOOLEAN + ); + } + + public static ScriptTemplate nullSafeSort(ScriptTemplate script) { + String methodName = script.outputType().isNumeric() ? "nullSafeSortNumeric" : "nullSafeSortString"; + return new ScriptTemplate( + formatTemplate(format(Locale.ROOT, "{ql}.%s(%s)", methodName, script.template())), + script.params(), + script.outputType() + ); + } + + public static ScriptTemplate and(ScriptTemplate left, ScriptTemplate right) { + return binaryMethod("{ql}", "and", left, right, DataTypes.BOOLEAN); + } + + public static ScriptTemplate or(ScriptTemplate left, ScriptTemplate right) { + return binaryMethod("{ql}", "or", left, right, DataTypes.BOOLEAN); + } + + public static ScriptTemplate binaryMethod( + String prefix, + String methodName, + ScriptTemplate leftScript, + ScriptTemplate rightScript, + DataType dataType + ) { + return new ScriptTemplate( + format( + Locale.ROOT, + formatTemplate("%s.%s(%s,%s)"), + formatTemplate(prefix), + methodName, + leftScript.template(), + rightScript.template() + ), + paramsBuilder().script(leftScript.params()).script(rightScript.params()).build(), + dataType + ); + } + + public static String classPackageAsPrefix(Class function) { + String prefix = function.getPackageName().substring(PKG_LENGTH); + int index = prefix.indexOf('.'); + Check.isTrue(index > 0, "invalid package {}", prefix); + return "{" + prefix.substring(0, index) + "}"; + } + + /** + * This method replaces any .docValue(doc,params.%s) call with a "Xn" variable. + * Each variable is then used in a {@code java.util.function.Predicate} to iterate over the doc_values in a Painless script. + * Multiple .docValue(doc,params.%s) calls for the same field will use multiple .docValue calls, meaning + * a different value of the field will be used for each usage in the script. + * + * For example, a query of the form fieldA - fieldB > 0 that gets translated into the following Painless script + * {@code InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.gt(InternalQlScriptUtils.sub( + * InternalQlScriptUtils.docValue(doc,params.v0),InternalQlScriptUtils.docValue(doc,params.v1)),params.v2))} + * will become, after this method rewrite + * {@code InternalEqlScriptUtils.multiValueDocValues(doc,params.v0,X1 -> InternalEqlScriptUtils.multiValueDocValues(doc,params.v1, + * X2 -> InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.gt(InternalQlScriptUtils.sub(X1,X2),params.v2))))} + */ + public static ScriptTemplate multiValueDocValuesRewrite(ScriptTemplate script) { + return docValuesRewrite(script, false); + } + + private static ScriptTemplate docValuesRewrite(ScriptTemplate script, boolean useSameValueInScript) { + int index = 0; // counts how many params there are to be able to get their value from script's params + Map params = script.params().asParams(); + List fieldVars = new ArrayList<>(); + List otherVars = new ArrayList<>(); + StringBuilder newTemplate = new StringBuilder(); + int negated = 0; + + String[] tokens = splitWithMatches(script.template(), qlDocValuePattern); + for (String token : tokens) { + // A docValue call will be replaced with "X" followed by a counter + // The scripts that come into this method can contain multiple docValue calls for the same field + // This method will use only one variable for one docValue call + if ("InternalQlScriptUtils.docValue(doc,params.%s)".equals(token)) { + Object fieldName = params.get("v" + index); + + if (useSameValueInScript) { + // if the field is already in our list, don't add it one more time + if (fieldVars.contains(fieldName) == false) { + fieldVars.add(fieldName); + } + newTemplate.append("X" + fieldVars.indexOf(fieldName)); + } else { + fieldVars.add(fieldName); + newTemplate.append("X" + (fieldVars.size() - 1)); + } + // increase the params position + index++; + } else if ("InternalQlScriptUtils.not(".equals(token)) { + negated++; + } else if ("params.%s".equals(token)) { + newTemplate.append(token); + // gather the other type of params (which are not docValues calls) so that at the end we rebuild the list of params + otherVars.add(params.get("v" + index)); + index++; + } else { + newTemplate.append(token); + } + for (int i = 0; i < negated - 1; i++) { + // remove this many closing parantheses as "InternalQlScriptUtils.not(" matches found, minus one + newTemplate.deleteCharAt(newTemplate.length() - 1); + } + } + + // iterate over the fields in reverse order and add a multiValueDocValues call for each + for (int i = fieldVars.size() - 1; i >= 0; i--) { + newTemplate.insert(0, "InternalEqlScriptUtils.multiValueDocValues(doc,params.%s,X" + i + " -> "); + newTemplate.append(")"); + } + if (negated > 0) { + newTemplate.insert(0, "InternalQlScriptUtils.not("); + } + + ParamsBuilder newParams = paramsBuilder(); + // field variables are first + fieldVars.forEach(v -> newParams.variable(v)); + // the rest of variables come after + otherVars.forEach(v -> newParams.variable(v)); + + return new ScriptTemplate(newTemplate.toString(), newParams.build(), DataTypes.BOOLEAN); + } + + /* + * Split a string given a regular expression into tokens. The list of tokens includes both the + * segments that matched the regex and also the segments that didn't. + * "fooxbarxbaz" split using the "x" regex will build an array like ["foo","x","bar","x","baz"] + */ + static String[] splitWithMatches(String input, Pattern pattern) { + int index = 0; + ArrayList matchList = new ArrayList<>(); + Matcher m = pattern.matcher(input); + + while (m.find()) { + if (index != m.start()) { + matchList.add(input.subSequence(index, m.start()).toString()); // add the segment before the match + } + if (m.start() != m.end()) { + matchList.add(input.subSequence(m.start(), m.end()).toString()); // add the match itself + } + index = m.end(); + } + + // if no match was found, return this + if (index == 0) { + return new String[] { input }; + } + + // add remaining segment and avoid an empty element in matches list + if (index < input.length()) { + matchList.add(input.subSequence(index, input.length()).toString()); + } + + // construct result + return matchList.toArray(new String[matchList.size()]); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Var.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Var.java new file mode 100644 index 000000000000..8bfd723798a2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/gen/script/Var.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +class Var extends Param { + + Var(Object value) { + super(value); + } + + @Override + public String prefix() { + return "v"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/BinaryOperator.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/BinaryOperator.java new file mode 100644 index 000000000000..f874669d6b78 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/BinaryOperator.java @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; + +/** + * Operator is a specialized binary predicate where both sides have the compatible types + * (it's up to the analyzer to do any conversion if needed). + */ +public abstract class BinaryOperator> extends BinaryPredicate { + + protected BinaryOperator(Source source, Expression left, Expression right, F function) { + super(source, left, right, function); + } + + protected abstract TypeResolution resolveInputType(Expression e, ParamOrdinal paramOrdinal); + + public abstract BinaryOperator swapLeftAndRight(); + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + TypeResolution resolution = resolveInputType(left(), FIRST); + if (resolution.unresolved()) { + return resolution; + } + return resolveInputType(right(), SECOND); + } + + protected boolean isCommutative() { + return false; + } + + @Override + protected Expression canonicalize() { + // fast check + if (isCommutative() == false) { + Expression exp = left().semanticHash() > right().semanticHash() ? swapLeftAndRight() : this; + // swap is not guaranteed to return a different expression, in which case simply delegate to super to avoid a cycle + return exp != this ? exp.canonical() : super.canonicalize(); + } + // break down all connected commutative operators + // in order to sort all their children at once + // then reassemble/reduce back the expression + List commutativeChildren = new ArrayList<>(2); + collectCommutative(commutativeChildren, this); + // sort + commutativeChildren.sort((l, r) -> Integer.compare(l.semanticHash(), r.semanticHash())); + + // reduce all children using the current operator - this method creates a balanced tree + while (commutativeChildren.size() > 1) { + // combine (in place) expressions in pairs + // NB: this loop modifies the list (just like an array) + for (int i = 0; i < commutativeChildren.size() - 1; i++) { + // reduce two children into one and moves to the next pair + Expression current = commutativeChildren.get(i); + Expression next = commutativeChildren.remove(i + 1); + // do the update in place to minimize the amount of array modifications + commutativeChildren.set(i, replaceChildren(current, next)); + + } + } + Iterator iterator = commutativeChildren.iterator(); + Expression last = iterator.next(); + while (iterator.hasNext()) { + last = replaceChildren(last, iterator.next()); + } + return last; + } + + protected void collectCommutative(List commutative, Expression expression) { + // keep digging for same binary operator + if (getClass() == expression.getClass()) { + BinaryOperator bi = (BinaryOperator) expression; + collectCommutative(commutative, bi.left()); + collectCommutative(commutative, bi.right()); + } else { + // not same operation - no ordering possible + commutative.add(expression.canonical()); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/BinaryPredicate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/BinaryPredicate.java new file mode 100644 index 000000000000..f059aa31e7ac --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/BinaryPredicate.java @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.BinaryScalarFunction; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +/** + * Binary operator. Operators act as _special_ functions in that they have a symbol + * instead of a name and do not use parentheses. + * Further more they are not registered as the rest of the functions as are implicit + * to the language. + */ +public abstract class BinaryPredicate> extends BinaryScalarFunction { + + private final F function; + + protected BinaryPredicate(Source source, Expression left, Expression right, F function) { + super(source, left, right); + this.function = function; + } + + @SuppressWarnings("unchecked") + @Override + public R fold() { + return function().apply((T) left().fold(), (U) right().fold()); + } + + @Override + protected String scriptMethodName() { + return function.scriptMethodName(); + } + + @Override + public int hashCode() { + return Objects.hash(left(), right(), function.symbol()); + } + + @Override + public boolean equals(Object obj) { + // NB: the id and name are being ignored for binary expressions as most of them + // are operators + + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + BinaryPredicate other = (BinaryPredicate) obj; + + return Objects.equals(symbol(), other.symbol()) && Objects.equals(left(), other.left()) && Objects.equals(right(), other.right()); + } + + public String symbol() { + return function.symbol(); + } + + public F function() { + return function; + } + + @Override + public String nodeString() { + return left().nodeString() + " " + symbol() + " " + right().nodeString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Negatable.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Negatable.java new file mode 100644 index 000000000000..0310f9f70d27 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Negatable.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; + +public interface Negatable { + + T negate(); + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/PredicateBiFunction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/PredicateBiFunction.java new file mode 100644 index 000000000000..5eac1c6fb5a5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/PredicateBiFunction.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import java.util.Locale; +import java.util.function.BiFunction; + +public interface PredicateBiFunction extends BiFunction { + + String name(); + + String symbol(); + + @Override + default R apply(T t, U u) { + if (t == null || u == null) { + return null; + } + + return doApply(t, u); + } + + R doApply(T t, U u); + + default String scriptMethodName() { + return name().toLowerCase(Locale.ROOT); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Predicates.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Predicates.java new file mode 100644 index 000000000000..28bbf956fd71 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Predicates.java @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +public abstract class Predicates { + + public static List splitAnd(Expression exp) { + if (exp instanceof And and) { + List list = new ArrayList<>(); + list.addAll(splitAnd(and.left())); + list.addAll(splitAnd(and.right())); + return list; + } + return singletonList(exp); + } + + public static List splitOr(Expression exp) { + if (exp instanceof Or or) { + List list = new ArrayList<>(); + list.addAll(splitOr(or.left())); + list.addAll(splitOr(or.right())); + return list; + } + return singletonList(exp); + } + + public static Expression combineOr(List exps) { + return combine(exps, (l, r) -> new Or(l.source(), l, r)); + } + + public static Expression combineAnd(List exps) { + return combine(exps, (l, r) -> new And(l.source(), l, r)); + } + + /** + * Build a binary 'pyramid' from the given list: + *
+     *       AND
+     *      /   \
+     *   AND     AND
+     *  /   \   /   \
+     * A     B C     D
+     * 
+ * + * using the given combiner. + * + * While a bit longer, this method creates a balanced tree as oppose to a plain + * recursive approach which creates an unbalanced one (either to the left or right). + */ + private static Expression combine(List exps, BiFunction combiner) { + if (exps.isEmpty()) { + return null; + } + + // clone the list (to modify it) + List result = new ArrayList<>(exps); + + while (result.size() > 1) { + // combine (in place) expressions in pairs + // NB: this loop modifies the list (just like an array) + for (int i = 0; i < result.size() - 1; i++) { + // keep the current element to update it in place + Expression l = result.get(i); + // remove the next element due to combining + Expression r = result.remove(i + 1); + result.set(i, combiner.apply(l, r)); + } + } + + return result.get(0); + } + + public static List inCommon(List l, List r) { + List common = new ArrayList<>(Math.min(l.size(), r.size())); + for (Expression lExp : l) { + for (Expression rExp : r) { + if (lExp.semanticEquals(rExp)) { + common.add(lExp); + } + } + } + return common.isEmpty() ? emptyList() : common; + } + + public static List subtract(List from, List list) { + List diff = new ArrayList<>(Math.min(from.size(), list.size())); + for (Expression f : from) { + boolean found = false; + for (Expression l : list) { + if (f.semanticEquals(l)) { + found = true; + break; + } + } + if (found == false) { + diff.add(f); + } + } + return diff.isEmpty() ? emptyList() : diff; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Range.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Range.java new file mode 100644 index 000000000000..482a7f94de22 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/Range.java @@ -0,0 +1,215 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Params; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicPipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonPipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DateUtils; + +import java.time.DateTimeException; +import java.time.ZoneId; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; + +// BETWEEN or range - is a mix of gt(e) AND lt(e) +public class Range extends ScalarFunction { + + private final Expression value, lower, upper; + private final boolean includeLower, includeUpper; + private final ZoneId zoneId; + + public Range(Source src, Expression value, Expression lower, boolean inclLower, Expression upper, boolean inclUpper, ZoneId zoneId) { + super(src, asList(value, lower, upper)); + + this.value = value; + this.lower = lower; + this.upper = upper; + this.includeLower = inclLower; + this.includeUpper = inclUpper; + this.zoneId = zoneId; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Range::new, value, lower, includeLower, upper, includeUpper, zoneId); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new Range(source(), newChildren.get(0), newChildren.get(1), includeLower, newChildren.get(2), includeUpper, zoneId); + } + + public Expression value() { + return value; + } + + public Expression lower() { + return lower; + } + + public Expression upper() { + return upper; + } + + public boolean includeLower() { + return includeLower; + } + + public boolean includeUpper() { + return includeUpper; + } + + public ZoneId zoneId() { + return zoneId; + } + + @Override + public boolean foldable() { + if (lower.foldable() && upper.foldable()) { + return areBoundariesInvalid() || value.foldable(); + } + + return false; + } + + @Override + public Object fold() { + if (areBoundariesInvalid()) { + return Boolean.FALSE; + } + + Object val = value.fold(); + Integer lowerCompare = BinaryComparison.compare(lower.fold(), val); + Integer upperCompare = BinaryComparison.compare(val, upper().fold()); + boolean lowerComparsion = lowerCompare == null ? false : (includeLower ? lowerCompare <= 0 : lowerCompare < 0); + boolean upperComparsion = upperCompare == null ? false : (includeUpper ? upperCompare <= 0 : upperCompare < 0); + return lowerComparsion && upperComparsion; + } + + /** + * Check whether the boundaries are invalid ( upper < lower) or not. + * If they are, the value does not have to be evaluated. + */ + protected boolean areBoundariesInvalid() { + Object lowerValue = lower.fold(); + Object upperValue = upper.fold(); + if (DataTypes.isDateTime(value.dataType()) || DataTypes.isDateTime(lower.dataType()) || DataTypes.isDateTime(upper.dataType())) { + try { + if (upperValue instanceof String upperString) { + upperValue = DateUtils.asDateTime(upperString); + } + if (lowerValue instanceof String lowerString) { + lowerValue = DateUtils.asDateTime(lowerString); + } + } catch (DateTimeException e) { + // one of the patterns is not a normal date, it could be a date math expression + // that has to be evaluated at lower level. + return false; + } + // for all the other cases, normal BinaryComparison logic is sufficient + } + + Integer compare = BinaryComparison.compare(lowerValue, upperValue); + // upper < lower OR upper == lower and the range doesn't contain any equals + return compare != null && (compare > 0 || (compare == 0 && (includeLower == false || includeUpper == false))); + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public ScriptTemplate asScript() { + ScriptTemplate valueScript = asScript(value); + ScriptTemplate lowerScript = asScript(lower); + ScriptTemplate upperScript = asScript(upper); + + String template = formatTemplate( + format( + Locale.ROOT, + "{ql}.and({ql}.%s(%s, %s), {ql}.%s(%s, %s))", + includeLower() ? "gte" : "gt", + valueScript.template(), + lowerScript.template(), + includeUpper() ? "lte" : "lt", + valueScript.template(), + upperScript.template() + ) + ); + + Params params = paramsBuilder().script(valueScript.params()) + .script(lowerScript.params()) + .script(valueScript.params()) + .script(upperScript.params()) + .build(); + + return new ScriptTemplate(template, params, DataTypes.BOOLEAN); + } + + @Override + protected Pipe makePipe() { + BinaryComparisonPipe lowerPipe = new BinaryComparisonPipe( + source(), + this, + Expressions.pipe(value()), + Expressions.pipe(lower()), + includeLower() ? BinaryComparisonOperation.GTE : BinaryComparisonOperation.GT + ); + BinaryComparisonPipe upperPipe = new BinaryComparisonPipe( + source(), + this, + Expressions.pipe(value()), + Expressions.pipe(upper()), + includeUpper() ? BinaryComparisonOperation.LTE : BinaryComparisonOperation.LT + ); + BinaryLogicPipe and = new BinaryLogicPipe(source(), this, lowerPipe, upperPipe, BinaryLogicOperation.AND); + return and; + } + + @Override + public int hashCode() { + return Objects.hash(includeLower, includeUpper, value, lower, upper, zoneId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Range other = (Range) obj; + return Objects.equals(includeLower, other.includeLower) + && Objects.equals(includeUpper, other.includeUpper) + && Objects.equals(value, other.value) + && Objects.equals(lower, other.lower) + && Objects.equals(upper, other.upper) + && Objects.equals(zoneId, other.zoneId); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextPredicate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextPredicate.java new file mode 100644 index 000000000000..06b70b4afa27 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextPredicate.java @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.fulltext; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public abstract class FullTextPredicate extends Expression { + + public enum Operator { + AND, + OR; + + public org.elasticsearch.index.query.Operator toEs() { + return org.elasticsearch.index.query.Operator.fromString(name()); + } + } + + private final String query; + private final String options; + private final Map optionMap; + // common properties + private final String analyzer; + + FullTextPredicate(Source source, String query, String options, List children) { + super(source, children); + this.query = query; + this.options = options; + // inferred + this.optionMap = FullTextUtils.parseSettings(options, source); + this.analyzer = optionMap.get("analyzer"); + } + + public String query() { + return query; + } + + public String options() { + return options; + } + + public Map optionMap() { + return optionMap; + } + + public String analyzer() { + return analyzer; + } + + @Override + public Nullability nullable() { + return Nullability.FALSE; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public int hashCode() { + return Objects.hash(query, options); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + FullTextPredicate other = (FullTextPredicate) obj; + return Objects.equals(query, other.query) && Objects.equals(options, other.options); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextUtils.java new file mode 100644 index 000000000000..6ba2650314d0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.fulltext; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.util.Maps; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.FullTextPredicate.Operator; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import static java.util.Collections.emptyMap; + +abstract class FullTextUtils { + + private static final String DELIMITER = ";"; + + static Map parseSettings(String options, Source source) { + if (Strings.hasText(options) == false) { + return emptyMap(); + } + String[] list = Strings.delimitedListToStringArray(options, DELIMITER); + Map op = Maps.newLinkedHashMapWithExpectedSize(list.length); + + for (String entry : list) { + String[] split = splitInTwo(entry, "="); + if (split == null) { + throw new ParsingException(source, "Cannot parse entry {} in options {}", entry, options); + } + + String previous = op.put(split[0], split[1]); + if (previous != null) { + throw new ParsingException(source, "Duplicate option {} detected in options {}", entry, options); + } + + } + return op; + } + + static Map parseFields(Map options, Source source) { + return parseFields(options.get("fields"), source); + } + + static Map parseFields(String fieldString, Source source) { + if (Strings.hasText(fieldString) == false) { + return emptyMap(); + } + Set fieldNames = Strings.commaDelimitedListToSet(fieldString); + + Float defaultBoost = Float.valueOf(1.0f); + Map fields = new LinkedHashMap<>(); + + for (String fieldName : fieldNames) { + if (fieldName.contains("^")) { + String[] split = splitInTwo(fieldName, "^"); + if (split == null) { + fields.put(fieldName, defaultBoost); + } else { + try { + fields.put(split[0], Float.parseFloat(split[1])); + } catch (NumberFormatException nfe) { + throw new ParsingException(source, "Cannot parse boosting for {}", fieldName); + } + } + } else { + fields.put(fieldName, defaultBoost); + } + } + + return fields; + } + + private static String[] splitInTwo(String string, String delimiter) { + String[] split = Strings.split(string, delimiter); + if (split == null || split.length != 2) { + return null; + } + return split; + } + + static FullTextPredicate.Operator operator(Map options, String key) { + String value = options.get(key); + return value != null ? Operator.valueOf(value.toUpperCase(Locale.ROOT)) : null; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/MatchQueryPredicate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/MatchQueryPredicate.java new file mode 100644 index 000000000000..fc5bd6320e44 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/MatchQueryPredicate.java @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.fulltext; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; + +public class MatchQueryPredicate extends FullTextPredicate { + + private final Expression field; + + public MatchQueryPredicate(Source source, Expression field, String query, String options) { + super(source, query, options, singletonList(field)); + this.field = field; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, MatchQueryPredicate::new, field, query(), options()); + } + + @Override + public MatchQueryPredicate replaceChildren(List newChildren) { + return new MatchQueryPredicate(source(), newChildren.get(0), query(), options()); + } + + public Expression field() { + return field; + } + + @Override + public int hashCode() { + return Objects.hash(field, super.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + MatchQueryPredicate other = (MatchQueryPredicate) obj; + return Objects.equals(field, other.field); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/MultiMatchQueryPredicate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/MultiMatchQueryPredicate.java new file mode 100644 index 000000000000..9e9d55ab4759 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/MultiMatchQueryPredicate.java @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.fulltext; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.Collections.emptyList; + +public class MultiMatchQueryPredicate extends FullTextPredicate { + + private final String fieldString; + private final Map fields; + + public MultiMatchQueryPredicate(Source source, String fieldString, String query, String options) { + super(source, query, options, emptyList()); + this.fieldString = fieldString; + // inferred + this.fields = FullTextUtils.parseFields(fieldString, source); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, MultiMatchQueryPredicate::new, fieldString, query(), options()); + } + + @Override + public Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + public String fieldString() { + return fieldString; + } + + public Map fields() { + return fields; + } + + @Override + public int hashCode() { + return Objects.hash(fieldString, super.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + MultiMatchQueryPredicate other = (MultiMatchQueryPredicate) obj; + return Objects.equals(fieldString, other.fieldString); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/StringQueryPredicate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/StringQueryPredicate.java new file mode 100644 index 000000000000..17b673cb0da4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/StringQueryPredicate.java @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.fulltext; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Map; + +import static java.util.Collections.emptyList; + +public final class StringQueryPredicate extends FullTextPredicate { + + private final Map fields; + + public StringQueryPredicate(Source source, String query, String options) { + super(source, query, options, emptyList()); + + // inferred + this.fields = FullTextUtils.parseFields(optionMap(), source); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, StringQueryPredicate::new, query(), options()); + } + + @Override + public Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + public Map fields() { + return fields; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/And.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/And.java new file mode 100644 index 000000000000..81418aa78ce5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/And.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class And extends BinaryLogic implements Negatable { + + public And(Source source, Expression left, Expression right) { + super(source, left, right, BinaryLogicOperation.AND); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, And::new, left(), right()); + } + + @Override + protected And replaceChildren(Expression newLeft, Expression newRight) { + return new And(source(), newLeft, newRight); + } + + @Override + public And swapLeftAndRight() { + return new And(source(), right(), left()); + } + + @Override + public Or negate() { + return new Or(source(), Not.negate(left()), Not.negate(right())); + } + + @Override + protected Expression canonicalize() { + // NB: this add a circular dependency between Predicates / Logical package + return Predicates.combineAnd(Predicates.splitAnd(super.canonicalize())); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogic.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogic.java new file mode 100644 index 000000000000..960933fabaf7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogic.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isBoolean; + +public abstract class BinaryLogic extends BinaryOperator { + + protected BinaryLogic(Source source, Expression left, Expression right, BinaryLogicOperation operation) { + super(source, left, right, operation); + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + protected TypeResolution resolveInputType(Expression e, ParamOrdinal paramOrdinal) { + return isBoolean(e, sourceText(), paramOrdinal); + } + + @Override + protected Pipe makePipe() { + return new BinaryLogicPipe(source(), this, Expressions.pipe(left()), Expressions.pipe(right()), function()); + } + + @Override + public Nullability nullable() { + // Cannot fold null due to 3vl, constant folding will do any possible folding. + return Nullability.UNKNOWN; + } + + @Override + protected boolean isCommutative() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicPipe.java new file mode 100644 index 000000000000..ec4a3a7684ca --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicPipe.java @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.BinaryPipe; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class BinaryLogicPipe extends BinaryPipe { + + private final BinaryLogicOperation operation; + + public BinaryLogicPipe(Source source, Expression expression, Pipe left, Pipe right, BinaryLogicOperation operation) { + super(source, expression, left, right); + this.operation = operation; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, BinaryLogicPipe::new, expression(), left(), right(), operation); + } + + @Override + protected BinaryPipe replaceChildren(Pipe left, Pipe right) { + return new BinaryLogicPipe(source(), expression(), left, right, operation); + } + + @Override + public BinaryLogicProcessor asProcessor() { + return new BinaryLogicProcessor(left().asProcessor(), right().asProcessor(), operation); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operation); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + BinaryLogicPipe other = (BinaryLogicPipe) obj; + return Objects.equals(operation, other.operation); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicProcessor.java new file mode 100644 index 000000000000..14d6b819e87f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicProcessor.java @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.FunctionalEnumBinaryProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.predicate.PredicateBiFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; + +import java.io.IOException; +import java.util.function.BiFunction; + +public class BinaryLogicProcessor extends FunctionalEnumBinaryProcessor { + + public enum BinaryLogicOperation implements PredicateBiFunction { + + AND((l, r) -> { + if (Boolean.FALSE.equals(l) || Boolean.FALSE.equals(r)) { + return Boolean.FALSE; + } + if (l == null || r == null) { + return null; + } + return Boolean.logicalAnd(l.booleanValue(), r.booleanValue()); + }, "AND"), + OR((l, r) -> { + if (Boolean.TRUE.equals(l) || Boolean.TRUE.equals(r)) { + return Boolean.TRUE; + } + if (l == null || r == null) { + return null; + } + return Boolean.logicalOr(l.booleanValue(), r.booleanValue()); + }, "OR"); + + private final BiFunction process; + private final String symbol; + + BinaryLogicOperation(BiFunction process, String symbol) { + this.process = process; + this.symbol = symbol; + } + + @Override + public String symbol() { + return symbol; + } + + @Override + public Boolean apply(Boolean left, Boolean right) { + return process.apply(left, right); + } + + @Override + public final Boolean doApply(Boolean left, Boolean right) { + return null; + } + + @Override + public String toString() { + return symbol; + } + } + + public static final String NAME = "lb"; + + public BinaryLogicProcessor(Processor left, Processor right, BinaryLogicOperation operation) { + super(left, right, operation); + } + + public BinaryLogicProcessor(StreamInput in) throws IOException { + super(in, i -> i.readEnum(BinaryLogicOperation.class)); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + protected void checkParameter(Object param) { + if (param != null && (param instanceof Boolean) == false) { + throw new QlIllegalArgumentException("A boolean is required; received {}", param); + } + } + + @Override + public Object process(Object input) { + Object l = left().process(input); + checkParameter(l); + Object r = right().process(input); + checkParameter(r); + + return doProcess(l, r); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/Not.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/Not.java new file mode 100644 index 000000000000..439d9bf52ac3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/Not.java @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isBoolean; + +public class Not extends UnaryScalarFunction implements Negatable { + + public Not(Source source, Expression child) { + super(source, child); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Not::new, field()); + } + + @Override + protected Not replaceChild(Expression newChild) { + return new Not(source(), newChild); + } + + @Override + protected TypeResolution resolveType() { + if (DataTypes.BOOLEAN == field().dataType()) { + return TypeResolution.TYPE_RESOLVED; + } + return isBoolean(field(), sourceText(), DEFAULT); + } + + @Override + public Object fold() { + return NotProcessor.INSTANCE.process(field().fold()); + } + + @Override + protected Processor makeProcessor() { + return NotProcessor.INSTANCE; + } + + @Override + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.QL_SCRIPTS + ".not(" + script + ")"); + } + + @Override + protected Expression canonicalize() { + if (field() instanceof Negatable) { + return ((Negatable) field()).negate().canonical(); + } + return super.canonicalize(); + } + + @Override + public Expression negate() { + return field(); + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + static Expression negate(Expression exp) { + return exp instanceof Negatable ? ((Negatable) exp).negate() : new Not(exp.source(), exp); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/NotProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/NotProcessor.java new file mode 100644 index 000000000000..5f633c902dff --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/NotProcessor.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; + +public class NotProcessor implements Processor { + + public static final NotProcessor INSTANCE = new NotProcessor(); + + public static final String NAME = "ln"; + + private NotProcessor() {} + + public NotProcessor(StreamInput in) throws IOException {} + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException {} + + @Override + public Object process(Object input) { + return apply(input); + } + + public static Boolean apply(Object input) { + if (input == null) { + return null; + } + + if ((input instanceof Boolean) == false) { + throw new QlIllegalArgumentException("A boolean is required; received {}", input); + } + + return ((Boolean) input).booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + @Override + public int hashCode() { + return NotProcessor.class.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + return obj == null || getClass() != obj.getClass(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/Or.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/Or.java new file mode 100644 index 000000000000..16781426d232 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/Or.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class Or extends BinaryLogic implements Negatable { + + public Or(Source source, Expression left, Expression right) { + super(source, left, right, BinaryLogicOperation.OR); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Or::new, left(), right()); + } + + @Override + protected Or replaceChildren(Expression newLeft, Expression newRight) { + return new Or(source(), newLeft, newRight); + } + + @Override + public Or swapLeftAndRight() { + return new Or(source(), right(), left()); + } + + @Override + public And negate() { + return new And(source(), Not.negate(left()), Not.negate(right())); + } + + @Override + protected Expression canonicalize() { + // NB: this add a circular dependency between Predicates / Logical package + return Predicates.combineOr(Predicates.splitOr(super.canonicalize())); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/CheckNullProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/CheckNullProcessor.java new file mode 100644 index 000000000000..10503fcd0017 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/CheckNullProcessor.java @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.nulls; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; +import java.util.Objects; +import java.util.function.Predicate; + +public class CheckNullProcessor implements Processor { + + public enum CheckNullOperation implements Predicate { + + IS_NULL(Objects::isNull, "IS NULL"), + IS_NOT_NULL(Objects::nonNull, "IS NOT NULL"); + + private final Predicate process; + private final String symbol; + + CheckNullOperation(Predicate process, String symbol) { + this.process = process; + this.symbol = symbol; + } + + public String symbol() { + return symbol; + } + + @Override + public String toString() { + return symbol; + } + + @Override + public boolean test(Object o) { + return process.test(o); + } + } + + public static final String NAME = "nckn"; + + private final CheckNullOperation operation; + + CheckNullProcessor(CheckNullOperation operation) { + this.operation = operation; + } + + public CheckNullProcessor(StreamInput in) throws IOException { + this(in.readEnum(CheckNullOperation.class)); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeEnum(operation); + } + + @Override + public Object process(Object input) { + return operation.test(input); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CheckNullProcessor that = (CheckNullProcessor) o; + return operation == that.operation; + } + + @Override + public int hashCode() { + return Objects.hash(operation); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/IsNotNull.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/IsNotNull.java new file mode 100644 index 000000000000..ae409bff5e58 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/IsNotNull.java @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.nulls; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +public class IsNotNull extends UnaryScalarFunction implements Negatable { + + public IsNotNull(Source source, Expression field) { + super(source, field); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, IsNotNull::new, field()); + } + + @Override + protected IsNotNull replaceChild(Expression newChild) { + return new IsNotNull(source(), newChild); + } + + @Override + public Object fold() { + return field().fold() != null && DataTypes.isNull(field().dataType()) == false; + } + + @Override + protected Processor makeProcessor() { + return new CheckNullProcessor(CheckNullOperation.IS_NOT_NULL); + } + + @Override + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.QL_SCRIPTS + ".isNotNull(" + script + ")"); + } + + @Override + public Nullability nullable() { + return Nullability.FALSE; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public UnaryScalarFunction negate() { + return new IsNull(source(), field()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/IsNull.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/IsNull.java new file mode 100644 index 000000000000..29b6d2a5be90 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/IsNull.java @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.nulls; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +public class IsNull extends UnaryScalarFunction implements Negatable { + + public IsNull(Source source, Expression field) { + super(source, field); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, IsNull::new, field()); + } + + @Override + protected IsNull replaceChild(Expression newChild) { + return new IsNull(source(), newChild); + } + + @Override + public Object fold() { + return field().fold() == null || DataTypes.isNull(field().dataType()); + } + + @Override + protected Processor makeProcessor() { + return new CheckNullProcessor(CheckNullOperation.IS_NULL); + } + + @Override + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.QL_SCRIPTS + ".isNull(" + script + ")"); + } + + @Override + public Nullability nullable() { + return Nullability.FALSE; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public UnaryScalarFunction negate() { + return new IsNotNull(source(), field()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Add.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Add.java new file mode 100644 index 000000000000..5b16b478f651 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Add.java @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * Addition function ({@code a + b}). + */ +public class Add extends DateTimeArithmeticOperation implements BinaryComparisonInversible { + public Add(Source source, Expression left, Expression right) { + super(source, left, right, DefaultBinaryArithmeticOperation.ADD); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Add::new, left(), right()); + } + + @Override + protected Add replaceChildren(Expression left, Expression right) { + return new Add(source(), left, right); + } + + @Override + public Add swapLeftAndRight() { + return new Add(source(), right(), left()); + } + + @Override + public ArithmeticOperationFactory binaryComparisonInverse() { + return Sub::new; + } + + @Override + protected boolean isCommutative() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/ArithmeticOperation.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/ArithmeticOperation.java new file mode 100644 index 000000000000..5e2e256a410d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/ArithmeticOperation.java @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; + +public abstract class ArithmeticOperation extends BinaryOperator { + + private DataType dataType; + + protected ArithmeticOperation(Source source, Expression left, Expression right, BinaryArithmeticOperation operation) { + super(source, left, right, operation); + } + + @Override + protected TypeResolution resolveInputType(Expression e, ParamOrdinal paramOrdinal) { + return isNumeric(e, sourceText(), paramOrdinal); + } + + @Override + public ArithmeticOperation swapLeftAndRight() { + return this; + } + + @Override + public DataType dataType() { + if (dataType == null) { + dataType = DataTypeConverter.commonType(left().dataType(), right().dataType()); + } + return dataType; + } + + @Override + protected Pipe makePipe() { + return new BinaryArithmeticPipe(source(), this, Expressions.pipe(left()), Expressions.pipe(right()), function()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Arithmetics.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Arithmetics.java new file mode 100644 index 000000000000..4776fd57dbfa --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Arithmetics.java @@ -0,0 +1,186 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.math.BigInteger; +import java.util.function.BiFunction; + +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asUnsignedLong; + +/** + * Arithmetic operation using the type widening rules of the JLS 5.6.2 namely + * widen to double or float or long or int in this order. + */ +public final class Arithmetics { + + private Arithmetics() {} + + public interface NumericArithmetic extends BiFunction { + default Object wrap(Object l, Object r) { + if ((l instanceof Number) == false) { + throw new QlIllegalArgumentException("A number is required; received {}", l); + } + + if ((r instanceof Number) == false) { + throw new QlIllegalArgumentException("A number is required; received {}", r); + } + + return apply((Number) l, (Number) r); + } + } + + public static Number add(Number l, Number r) { + if (l == null || r == null) { + return null; + } + + if (l instanceof Double || r instanceof Double) { + return Double.valueOf(l.doubleValue() + r.doubleValue()); + } + if (l instanceof Float || r instanceof Float) { + return Float.valueOf(l.floatValue() + r.floatValue()); + } + if (l instanceof BigInteger || r instanceof BigInteger) { + BigInteger bi = asBigInteger(l).add(asBigInteger(r)); + return asUnsignedLong(bi); + } + if (l instanceof Long || r instanceof Long) { + return Long.valueOf(Math.addExact(l.longValue(), r.longValue())); + } + + return Integer.valueOf(Math.addExact(l.intValue(), r.intValue())); + } + + public static Number sub(Number l, Number r) { + if (l == null || r == null) { + return null; + } + + if (l instanceof Double || r instanceof Double) { + return Double.valueOf(l.doubleValue() - r.doubleValue()); + } + if (l instanceof Float || r instanceof Float) { + return Float.valueOf(l.floatValue() - r.floatValue()); + } + if (l instanceof BigInteger || r instanceof BigInteger) { + BigInteger bi = asBigInteger(l).subtract(asBigInteger(r)); + return asUnsignedLong(bi); + } + if (l instanceof Long || r instanceof Long) { + return Long.valueOf(Math.subtractExact(l.longValue(), r.longValue())); + } + + return Integer.valueOf(Math.subtractExact(l.intValue(), r.intValue())); + } + + public static Number mul(Number l, Number r) { + if (l == null || r == null) { + return null; + } + + if (l instanceof Double || r instanceof Double) { + return Double.valueOf(l.doubleValue() * r.doubleValue()); + } + if (l instanceof Float || r instanceof Float) { + return Float.valueOf(l.floatValue() * r.floatValue()); + } + if (l instanceof BigInteger || r instanceof BigInteger) { + BigInteger bi = asBigInteger(l).multiply(asBigInteger(r)); + // Note: in case of unsigned_long overflow (or underflow, with negative fixed point numbers), the exception is thrown. + // This is unlike the way some other traditional RDBMS that support unsigned types work, which simply promote the result to a + // floating point type, but in line with how our implementation treats other fixed point type operations (i.e. Math#xxExact()). + return asUnsignedLong(bi); + } + if (l instanceof Long || r instanceof Long) { + return Long.valueOf(Math.multiplyExact(l.longValue(), r.longValue())); + } + + return Integer.valueOf(Math.multiplyExact(l.intValue(), r.intValue())); + } + + public static Number div(Number l, Number r) { + if (l == null || r == null) { + return null; + } + + if (l instanceof Double || r instanceof Double) { + return l.doubleValue() / r.doubleValue(); + } + if (l instanceof Float || r instanceof Float) { + return l.floatValue() / r.floatValue(); + } + if (l instanceof BigInteger || r instanceof BigInteger) { + BigInteger bi = asBigInteger(l).divide(asBigInteger(r)); + return asUnsignedLong(bi); + } + if (l instanceof Long || r instanceof Long) { + return l.longValue() / r.longValue(); + } + + return l.intValue() / r.intValue(); + } + + public static Number mod(Number l, Number r) { + if (l == null || r == null) { + return null; + } + + if (l instanceof Double || r instanceof Double) { + return Double.valueOf(l.doubleValue() % r.doubleValue()); + } + if (l instanceof Float || r instanceof Float) { + return Float.valueOf(l.floatValue() % r.floatValue()); + } + if (l instanceof BigInteger || r instanceof BigInteger) { + BigInteger bi = asBigInteger(l).remainder(asBigInteger(r)); + return asUnsignedLong(bi); + } + if (l instanceof Long || r instanceof Long) { + return Long.valueOf(l.longValue() % r.longValue()); + } + + return l.intValue() % r.intValue(); + } + + static Number negate(Number n) { + if (n == null) { + return null; + } + + if (n instanceof Double) { + double d = n.doubleValue(); + if (d == Double.MIN_VALUE) { + throw new ArithmeticException("double overflow"); + } + return Double.valueOf(-n.doubleValue()); + } + if (n instanceof Float) { + float f = n.floatValue(); + if (f == Float.MIN_VALUE) { + throw new ArithmeticException("float overflow"); + } + return Float.valueOf(-n.floatValue()); + } + if (n instanceof BigInteger) { + if (((BigInteger) n).signum() != 0) { + throw new ArithmeticException("unsigned_long overflow"); // in the scope of the unsigned_long type + } + return n; + } + if (n instanceof Long) { + return Long.valueOf(Math.negateExact(n.longValue())); + } + + return Integer.valueOf(Math.negateExact(n.intValue())); + } + + public static BigInteger asBigInteger(Number n) { + return n instanceof BigInteger ? (BigInteger) n : BigInteger.valueOf(n.longValue()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticOperation.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticOperation.java new file mode 100644 index 000000000000..5d42a61bbde7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticOperation.java @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.xpack.esql.core.expression.predicate.PredicateBiFunction; + +public interface BinaryArithmeticOperation extends PredicateBiFunction, NamedWriteable { + + @Override + String symbol(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticPipe.java new file mode 100644 index 000000000000..f6b75798ce90 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticPipe.java @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.BinaryPipe; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class BinaryArithmeticPipe extends BinaryPipe { + + private final BinaryArithmeticOperation operation; + + public BinaryArithmeticPipe(Source source, Expression expression, Pipe left, Pipe right, BinaryArithmeticOperation operation) { + super(source, expression, left, right); + this.operation = operation; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, BinaryArithmeticPipe::new, expression(), left(), right(), operation); + } + + @Override + protected BinaryPipe replaceChildren(Pipe left, Pipe right) { + return new BinaryArithmeticPipe(source(), expression(), left, right, operation); + } + + @Override + public Processor asProcessor() { + return new BinaryArithmeticProcessor(left().asProcessor(), right().asProcessor(), operation); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operation); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + BinaryArithmeticPipe other = (BinaryArithmeticPipe) obj; + return Objects.equals(operation, other.operation); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticProcessor.java new file mode 100644 index 000000000000..73e3ed560d6f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticProcessor.java @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.FunctionalBinaryProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; + +public final class BinaryArithmeticProcessor extends FunctionalBinaryProcessor { + + public static final String NAME = "abn"; + + public BinaryArithmeticProcessor(Processor left, Processor right, BinaryArithmeticOperation operation) { + super(left, right, operation); + } + + public BinaryArithmeticProcessor(StreamInput in) throws IOException { + super(in, i -> i.readNamedWriteable(BinaryArithmeticOperation.class)); + } + + @Override + protected void doWrite(StreamOutput out) throws IOException { + out.writeNamedWriteable(function()); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + protected Object doProcess(Object left, Object right) { + BinaryArithmeticOperation f = function(); + + if (left == null || right == null) { + return null; + } + + return f.apply(left, right); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryComparisonInversible.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryComparisonInversible.java new file mode 100644 index 000000000000..358ad59ec635 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryComparisonInversible.java @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/* + * Factory interface for arithmetic operations that have an inverse in reference to a binary comparison. + * For instance the division is multiplication's inverse, substitution addition's, log exponentiation's a.s.o. + * Not all operations - like modulo - are invertible. + */ +public interface BinaryComparisonInversible { + + interface ArithmeticOperationFactory { + ArithmeticOperation create(Source source, Expression left, Expression right); + } + + ArithmeticOperationFactory binaryComparisonInverse(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java new file mode 100644 index 000000000000..9e08cea749a3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +abstract class DateTimeArithmeticOperation extends ArithmeticOperation { + + DateTimeArithmeticOperation(Source source, Expression left, Expression right, BinaryArithmeticOperation operation) { + super(source, left, right, operation); + } + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + // arithmetic operation can work on numbers in QL + + DataType l = left().dataType(); + DataType r = right().dataType(); + + // 1. both are numbers + if (l.isNumeric() && r.isNumeric()) { + return TypeResolution.TYPE_RESOLVED; + } + + // fall-back to default checks + return super.resolveType(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/DefaultBinaryArithmeticOperation.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/DefaultBinaryArithmeticOperation.java new file mode 100644 index 000000000000..230ebef88e43 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/DefaultBinaryArithmeticOperation.java @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Arithmetics.NumericArithmetic; + +import java.io.IOException; +import java.util.function.BiFunction; + +public enum DefaultBinaryArithmeticOperation implements BinaryArithmeticOperation { + + ADD(Arithmetics::add, "+"), + SUB(Arithmetics::sub, "-"), + MUL(Arithmetics::mul, "*"), + DIV(Arithmetics::div, "/"), + MOD(Arithmetics::mod, "%"); + + public static final String NAME = "abn-def"; + + private final BiFunction process; + private final String symbol; + + DefaultBinaryArithmeticOperation(BiFunction process, String symbol) { + this.process = process; + this.symbol = symbol; + } + + DefaultBinaryArithmeticOperation(NumericArithmetic process, String symbol) { + this(process::wrap, symbol); + } + + @Override + public String symbol() { + return symbol; + } + + @Override + public final Object doApply(Object left, Object right) { + return process.apply(left, right); + } + + @Override + public String toString() { + return symbol; + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeEnum(this); + } + + public static DefaultBinaryArithmeticOperation read(StreamInput in) throws IOException { + return in.readEnum(DefaultBinaryArithmeticOperation.class); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Div.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Div.java new file mode 100644 index 000000000000..5f4c66047957 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Div.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; + +/** + * Division function ({@code a / b}). + */ +public class Div extends ArithmeticOperation implements BinaryComparisonInversible { + + private DataType dataType; + + public Div(Source source, Expression left, Expression right) { + this(source, left, right, null); + } + + public Div(Source source, Expression left, Expression right, DataType dataType) { + super(source, left, right, DefaultBinaryArithmeticOperation.DIV); + this.dataType = dataType; + } + + @Override + protected NodeInfo
info() { + return NodeInfo.create(this, Div::new, left(), right(), dataType); + } + + @Override + protected Div replaceChildren(Expression newLeft, Expression newRight) { + return new Div(source(), newLeft, newRight, dataType); + } + + @Override + public DataType dataType() { + if (dataType == null) { + dataType = DataTypeConverter.commonType(left().dataType(), right().dataType()); + } + return dataType; + } + + @Override + public ArithmeticOperationFactory binaryComparisonInverse() { + return Mul::new; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Mod.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Mod.java new file mode 100644 index 000000000000..dea7d4e02e0b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Mod.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * Modulo + * function ({@code a % b}). + * + * Note this operator is also registered as a function (needed for ODBC/SQL) purposes. + */ +public class Mod extends ArithmeticOperation { + + public Mod(Source source, Expression left, Expression right) { + super(source, left, right, DefaultBinaryArithmeticOperation.MOD); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Mod::new, left(), right()); + } + + @Override + protected Mod replaceChildren(Expression newLeft, Expression newRight) { + return new Mod(source(), newLeft, newRight); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Mul.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Mul.java new file mode 100644 index 000000000000..46cc72766d53 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Mul.java @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; + +/** + * Multiplication function ({@code a * b}). + */ +public class Mul extends ArithmeticOperation implements BinaryComparisonInversible { + + public Mul(Source source, Expression left, Expression right) { + super(source, left, right, DefaultBinaryArithmeticOperation.MUL); + } + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + DataType l = left().dataType(); + DataType r = right().dataType(); + + // 1. both are numbers + if (DataTypes.isNullOrNumeric(l) && DataTypes.isNullOrNumeric(r)) { + return TypeResolution.TYPE_RESOLVED; + } + + return new TypeResolution(format(null, "[{}] has arguments with incompatible types [{}] and [{}]", symbol(), l, r)); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Mul::new, left(), right()); + } + + @Override + protected Mul replaceChildren(Expression newLeft, Expression newRight) { + return new Mul(source(), newLeft, newRight); + } + + @Override + public Mul swapLeftAndRight() { + return new Mul(source(), right(), left()); + } + + @Override + public ArithmeticOperationFactory binaryComparisonInverse() { + return Div::new; + } + + @Override + protected boolean isCommutative() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Neg.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Neg.java new file mode 100644 index 000000000000..d9ccf558ccb5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Neg.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor.UnaryArithmeticOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; + +/** + * Negation function (@{code -x}). + */ +public class Neg extends UnaryScalarFunction { + + public Neg(Source source, Expression field) { + super(source, field); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Neg::new, field()); + } + + @Override + protected Neg replaceChild(Expression newChild) { + return new Neg(source(), newChild); + } + + @Override + protected TypeResolution resolveType() { + return isNumeric(field(), sourceText(), DEFAULT); + } + + @Override + public Object fold() { + return Arithmetics.negate((Number) field().fold()); + } + + @Override + public DataType dataType() { + return field().dataType(); + } + + @Override + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.QL_SCRIPTS + ".neg(" + script + ")"); + } + + @Override + protected Processor makeProcessor() { + return new UnaryArithmeticProcessor(UnaryArithmeticOperation.NEGATE); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Sub.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Sub.java new file mode 100644 index 000000000000..8a345986e5fb --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/Sub.java @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * Subtraction function ({@code a - b}). + */ +public class Sub extends DateTimeArithmeticOperation implements BinaryComparisonInversible { + + public Sub(Source source, Expression left, Expression right) { + super(source, left, right, DefaultBinaryArithmeticOperation.SUB); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Sub::new, left(), right()); + } + + @Override + protected Sub replaceChildren(Expression newLeft, Expression newRight) { + return new Sub(source(), newLeft, newRight); + } + + @Override + public ArithmeticOperationFactory binaryComparisonInverse() { + return Add::new; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/UnaryArithmeticProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/UnaryArithmeticProcessor.java new file mode 100644 index 000000000000..835d1a736648 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/UnaryArithmeticProcessor.java @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; +import java.util.function.Function; + +public class UnaryArithmeticProcessor implements Processor { + + public enum UnaryArithmeticOperation { + + NEGATE(Arithmetics::negate); + + private final Function process; + + UnaryArithmeticOperation(Function process) { + this.process = process; + } + + public final Number apply(Number number) { + return process.apply(number); + } + + public String symbol() { + return "-"; + } + } + + public static final String NAME = "au"; + + private final UnaryArithmeticOperation operation; + + public UnaryArithmeticProcessor(UnaryArithmeticOperation operation) { + this.operation = operation; + } + + public UnaryArithmeticProcessor(StreamInput in) throws IOException { + operation = in.readEnum(UnaryArithmeticOperation.class); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeEnum(operation); + } + + @Override + public Object process(Object input) { + if (input == null) { + return null; + } + + if (input instanceof Number number) { + return operation.apply(number); + } + throw new QlIllegalArgumentException("A number is required; received {}", input); + } + + @Override + public String toString() { + return operation.symbol() + super.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparison.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparison.java new file mode 100644 index 000000000000..f6e7ae4cb0fa --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparison.java @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.time.ZoneId; + +// marker class to indicate operations that rely on values +public abstract class BinaryComparison extends BinaryOperator { + + private final ZoneId zoneId; + + protected BinaryComparison(Source source, Expression left, Expression right, BinaryComparisonOperation operation, ZoneId zoneId) { + super(source, left, right, operation); + this.zoneId = zoneId; + } + + public ZoneId zoneId() { + return zoneId; + } + + @Override + protected TypeResolution resolveInputType(Expression e, ParamOrdinal paramOrdinal) { + return TypeResolutions.isExact(e, sourceText(), paramOrdinal); + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + protected Pipe makePipe() { + return new BinaryComparisonPipe(source(), this, Expressions.pipe(left()), Expressions.pipe(right()), function()); + } + + public static Integer compare(Object left, Object right) { + return Comparisons.compare(left, right); + } + + /** + * Reverses the direction of this comparison on the comparison axis. + * Some operations like Greater/LessThan/OrEqual will behave as if the operands of a numerical comparison get multiplied with a + * negative number. Others like Not/Equal can be immutable to this operation. + */ + public abstract BinaryComparison reverse(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonPipe.java new file mode 100644 index 000000000000..0cf0fc5ce544 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonPipe.java @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.BinaryPipe; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class BinaryComparisonPipe extends BinaryPipe { + + private final BinaryComparisonOperation operation; + + public BinaryComparisonPipe(Source source, Expression expression, Pipe left, Pipe right, BinaryComparisonOperation operation) { + super(source, expression, left, right); + this.operation = operation; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, BinaryComparisonPipe::new, expression(), left(), right(), operation); + } + + @Override + protected BinaryPipe replaceChildren(Pipe left, Pipe right) { + return new BinaryComparisonPipe(source(), expression(), left, right, operation); + } + + @Override + public BinaryComparisonProcessor asProcessor() { + return new BinaryComparisonProcessor(left().asProcessor(), right().asProcessor(), operation); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), operation); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + BinaryComparisonPipe other = (BinaryComparisonPipe) obj; + return Objects.equals(operation, other.operation); + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonProcessor.java new file mode 100644 index 000000000000..6434f2d9b6ac --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonProcessor.java @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.FunctionalEnumBinaryProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.predicate.PredicateBiFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; + +import java.io.IOException; +import java.util.function.BiFunction; + +public class BinaryComparisonProcessor extends FunctionalEnumBinaryProcessor { + + public enum BinaryComparisonOperation implements PredicateBiFunction { + + EQ(Comparisons::eq, "=="), + NULLEQ(Comparisons::nulleq, "<=>"), + NEQ(Comparisons::neq, "!="), + GT(Comparisons::gt, ">"), + GTE(Comparisons::gte, ">="), + LT(Comparisons::lt, "<"), + LTE(Comparisons::lte, "<="); + + private final BiFunction process; + private final String symbol; + + BinaryComparisonOperation(BiFunction process, String symbol) { + this.process = process; + this.symbol = symbol; + } + + @Override + public String symbol() { + return symbol; + } + + @Override + public Boolean apply(Object left, Object right) { + if (this != NULLEQ && (left == null || right == null)) { + return null; + } + return doApply(left, right); + } + + @Override + public final Boolean doApply(Object left, Object right) { + return process.apply(left, right); + } + + @Override + public String toString() { + return symbol; + } + } + + public static final String NAME = "cb"; + + public BinaryComparisonProcessor(Processor left, Processor right, BinaryComparisonOperation operation) { + super(left, right, operation); + } + + public BinaryComparisonProcessor(StreamInput in) throws IOException { + super(in, i -> i.readEnum(BinaryComparisonOperation.class)); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public Object process(Object input) { + if (function() == BinaryComparisonOperation.NULLEQ) { + return doProcess(left().process(input), right().process(input)); + } + return super.process(input); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/Comparisons.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/Comparisons.java new file mode 100644 index 000000000000..e08570fa4640 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/Comparisons.java @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.versionfield.Version; + +import java.math.BigInteger; +import java.util.Set; + +import static org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Arithmetics.asBigInteger; + +/** + * Comparison utilities. + */ +public final class Comparisons { + + private Comparisons() {} + + public static Boolean eq(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() == 0; + } + + public static boolean nulleq(Object l, Object r) { + if (l == null && r == null) { + return true; + } + Integer i = compare(l, r); + return i == null ? false : i.intValue() == 0; + } + + static Boolean neq(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() != 0; + } + + public static Boolean lt(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() < 0; + } + + static Boolean lte(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() <= 0; + } + + public static Boolean gt(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() > 0; + } + + static Boolean gte(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() >= 0; + } + + static Boolean in(Object l, Set r) { + return r.contains(l); + } + + /** + * Compares two expression arguments (typically Numbers), if possible. + * Otherwise returns null (the arguments are not comparable or at least + * one of them is null). + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + static Integer compare(Object l, Object r) { + if (l == null || r == null) { + return null; + } + // typical number comparison + if (l instanceof Number lN && r instanceof Number rN) { + return compare(lN, rN); + } + + // automatic conversion for versions + if (l instanceof Version lV && r instanceof String rStr) { + return lV.compareTo(new Version(rStr)); + } + if (l instanceof String lStr && r instanceof Version rV) { + return new Version(lStr).compareTo(rV); + } + + if (l instanceof Comparable lC && r instanceof Comparable) { + try { + return Integer.valueOf(lC.compareTo(r)); + } catch (ClassCastException cce) { + // when types are not compatible, cce is thrown + // fall back to null + return null; + } + } + + return null; + } + + private static Integer compare(Number l, Number r) { + if (l instanceof Double || r instanceof Double) { + return Double.compare(l.doubleValue(), r.doubleValue()); + } + if (l instanceof Float || r instanceof Float) { + return Float.compare(l.floatValue(), r.floatValue()); + } + if (l instanceof BigInteger || r instanceof BigInteger) { + return asBigInteger(l).compareTo(asBigInteger(r)); + } + if (l instanceof Long || r instanceof Long) { + return Long.compare(l.longValue(), r.longValue()); + } + + return Integer.valueOf(Integer.compare(l.intValue(), r.intValue())); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/Equals.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/Equals.java new file mode 100644 index 000000000000..ba4816e3b68f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/Equals.java @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +public class Equals extends BinaryComparison implements Negatable { + + public Equals(Source source, Expression left, Expression right) { + super(source, left, right, BinaryComparisonOperation.EQ, null); + } + + public Equals(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.EQ, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Equals::new, left(), right(), zoneId()); + } + + @Override + protected Equals replaceChildren(Expression newLeft, Expression newRight) { + return new Equals(source(), newLeft, newRight, zoneId()); + } + + @Override + public Equals swapLeftAndRight() { + return new Equals(source(), right(), left(), zoneId()); + } + + @Override + public BinaryComparison negate() { + return new NotEquals(source(), left(), right(), zoneId()); + } + + @Override + public BinaryComparison reverse() { + return this; + } + + @Override + protected boolean isCommutative() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/GreaterThan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/GreaterThan.java new file mode 100644 index 000000000000..4e3880defdd7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/GreaterThan.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +public class GreaterThan extends BinaryComparison implements Negatable { + + public GreaterThan(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.GT, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, GreaterThan::new, left(), right(), zoneId()); + } + + @Override + protected GreaterThan replaceChildren(Expression newLeft, Expression newRight) { + return new GreaterThan(source(), newLeft, newRight, zoneId()); + } + + @Override + public LessThan swapLeftAndRight() { + return new LessThan(source(), right(), left(), zoneId()); + } + + @Override + public LessThanOrEqual negate() { + return new LessThanOrEqual(source(), left(), right(), zoneId()); + } + + @Override + public BinaryComparison reverse() { + return new LessThan(source(), left(), right(), zoneId()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/GreaterThanOrEqual.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/GreaterThanOrEqual.java new file mode 100644 index 000000000000..2132a028c4d7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/GreaterThanOrEqual.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +public class GreaterThanOrEqual extends BinaryComparison implements Negatable { + + public GreaterThanOrEqual(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.GTE, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, GreaterThanOrEqual::new, left(), right(), zoneId()); + } + + @Override + protected GreaterThanOrEqual replaceChildren(Expression newLeft, Expression newRight) { + return new GreaterThanOrEqual(source(), newLeft, newRight, zoneId()); + } + + @Override + public LessThanOrEqual swapLeftAndRight() { + return new LessThanOrEqual(source(), right(), left(), zoneId()); + } + + @Override + public LessThan negate() { + return new LessThan(source(), left(), right(), zoneId()); + } + + @Override + public BinaryComparison reverse() { + return new LessThanOrEqual(source(), left(), right(), zoneId()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/In.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/In.java new file mode 100644 index 000000000000..f2bc52c842f8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/In.java @@ -0,0 +1,197 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Foldables; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; + +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.ordinal; + +public class In extends ScalarFunction { + + private final Expression value; + private final List list; + private final ZoneId zoneId; + + public In(Source source, Expression value, List list) { + this(source, value, list, null); + } + + public In(Source source, Expression value, List list, ZoneId zoneId) { + super(source, CollectionUtils.combine(list, value)); + this.value = value; + this.list = new ArrayList<>(new LinkedHashSet<>(list)); + this.zoneId = zoneId; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, In::new, value(), list(), zoneId()); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new In(source(), newChildren.get(newChildren.size() - 1), newChildren.subList(0, newChildren.size() - 1), zoneId()); + } + + public ZoneId zoneId() { + return zoneId; + } + + public Expression value() { + return value; + } + + public List list() { + return list; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public Nullability nullable() { + return Nullability.UNKNOWN; + } + + @Override + public boolean foldable() { + return Expressions.foldable(children()) || (Expressions.foldable(list) && list().stream().allMatch(Expressions::isNull)); + } + + @Override + public Boolean fold() { + // Optimization for early return and Query folding to LocalExec + if (Expressions.isNull(value) || list.size() == 1 && Expressions.isNull(list.get(0))) { + return null; + } + return InProcessor.apply(value.fold(), foldAndConvertListOfValues(list, value.dataType())); + } + + @Override + protected Expression canonicalize() { + // order values for commutative operators + List canonicalValues = Expressions.canonicalize(list); + Collections.sort(canonicalValues, (l, r) -> Integer.compare(l.hashCode(), r.hashCode())); + return new In(source(), value, canonicalValues, zoneId); + } + + @Override + public ScriptTemplate asScript() { + ScriptTemplate leftScript = asScript(value); + + // fold & remove duplicates + List values = new ArrayList<>(new LinkedHashSet<>(foldAndConvertListOfValues(list, value.dataType()))); + + return new ScriptTemplate( + formatTemplate(format("{ql}.", "in({}, {})", leftScript.template())), + paramsBuilder().script(leftScript.params()).variable(values).build(), + dataType() + ); + } + + protected List foldAndConvertListOfValues(List expressions, DataType dataType) { + List values = new ArrayList<>(expressions.size()); + for (Expression e : expressions) { + values.add(DataTypeConverter.convert(Foldables.valueOf(e), dataType)); + } + return values; + } + + protected boolean areCompatible(DataType left, DataType right) { + return DataTypes.areCompatible(left, right); + } + + @Override + protected Pipe makePipe() { + return new InPipe(source(), this, children().stream().map(Expressions::pipe).collect(Collectors.toList())); + } + + @Override + protected TypeResolution resolveType() { + TypeResolution resolution = TypeResolutions.isExact(value, functionName(), DEFAULT); + if (resolution.unresolved()) { + return resolution; + } + + for (Expression ex : list) { + if (ex.foldable() == false) { + return new TypeResolution( + format( + null, + "Comparisons against fields are not (currently) supported; offender [{}] in [{}]", + Expressions.name(ex), + sourceText() + ) + ); + } + } + + DataType dt = value.dataType(); + for (int i = 0; i < list.size(); i++) { + Expression listValue = list.get(i); + if (areCompatible(dt, listValue.dataType()) == false) { + return new TypeResolution( + format( + null, + "{} argument of [{}] must be [{}], found value [{}] type [{}]", + ordinal(i + 1), + sourceText(), + dt.typeName(), + Expressions.name(listValue), + listValue.dataType().typeName() + ) + ); + } + } + + return super.resolveType(); + } + + @Override + public int hashCode() { + return Objects.hash(value, list); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + In other = (In) obj; + return Objects.equals(value, other.value) && Objects.equals(list, other.list); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InPipe.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InPipe.java new file mode 100644 index 000000000000..e667a04f83ca --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InPipe.java @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.MultiPipe; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +public class InPipe extends MultiPipe { + + public InPipe(Source source, Expression expression, List pipes) { + super(source, expression, pipes); + } + + @Override + public final Pipe replaceChildren(List newChildren) { + return new InPipe(source(), expression(), newChildren); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, InPipe::new, expression(), children()); + } + + @Override + public int hashCode() { + return Objects.hash(children()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + InPipe other = (InPipe) obj; + return Objects.equals(children(), other.children()); + } + + @Override + public InProcessor asProcessor(List processors) { + return new InProcessor(processors); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InProcessor.java new file mode 100644 index 000000000000..61d33ab631bf --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InProcessor.java @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class InProcessor implements Processor { + + public static final String NAME = "in"; + + private final List processsors; + + InProcessor(List processors) { + this.processsors = processors; + } + + public InProcessor(StreamInput in) throws IOException { + processsors = in.readNamedWriteableCollectionAsList(Processor.class); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public final void writeTo(StreamOutput out) throws IOException { + out.writeNamedWriteableCollection(processsors); + } + + @Override + public Object process(Object input) { + Object leftValue = processsors.get(processsors.size() - 1).process(input); + return apply(leftValue, process(processsors.subList(0, processsors.size() - 1), leftValue)); + } + + private static List process(List processors, Object input) { + List values = new ArrayList<>(processors.size()); + for (Processor p : processors) { + values.add(p.process(input)); + } + return values; + } + + public static Boolean apply(Object input, List values) { + Boolean result = Boolean.FALSE; + for (Object v : values) { + Boolean compResult = Comparisons.eq(input, v); + if (compResult == null) { + result = null; + } else if (compResult == Boolean.TRUE) { + return Boolean.TRUE; + } + } + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InProcessor that = (InProcessor) o; + return Objects.equals(processsors, that.processsors); + } + + @Override + public int hashCode() { + return Objects.hash(processsors); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/LessThan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/LessThan.java new file mode 100644 index 000000000000..c7985548918f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/LessThan.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +public class LessThan extends BinaryComparison implements Negatable { + + public LessThan(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.LT, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, LessThan::new, left(), right(), zoneId()); + } + + @Override + protected LessThan replaceChildren(Expression newLeft, Expression newRight) { + return new LessThan(source(), newLeft, newRight, zoneId()); + } + + @Override + public GreaterThan swapLeftAndRight() { + return new GreaterThan(source(), right(), left(), zoneId()); + } + + @Override + public GreaterThanOrEqual negate() { + return new GreaterThanOrEqual(source(), left(), right(), zoneId()); + } + + @Override + public BinaryComparison reverse() { + return new GreaterThan(source(), left(), right(), zoneId()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/LessThanOrEqual.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/LessThanOrEqual.java new file mode 100644 index 000000000000..ff87d02cd654 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/LessThanOrEqual.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +public class LessThanOrEqual extends BinaryComparison implements Negatable { + + public LessThanOrEqual(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.LTE, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, LessThanOrEqual::new, left(), right(), zoneId()); + } + + @Override + protected LessThanOrEqual replaceChildren(Expression newLeft, Expression newRight) { + return new LessThanOrEqual(source(), newLeft, newRight, zoneId()); + } + + @Override + public GreaterThanOrEqual swapLeftAndRight() { + return new GreaterThanOrEqual(source(), right(), left(), zoneId()); + } + + @Override + public GreaterThan negate() { + return new GreaterThan(source(), left(), right(), zoneId()); + } + + @Override + public BinaryComparison reverse() { + return new GreaterThanOrEqual(source(), left(), right(), zoneId()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/NotEquals.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/NotEquals.java new file mode 100644 index 000000000000..936e684ab37c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/NotEquals.java @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +public class NotEquals extends BinaryComparison implements Negatable { + + public NotEquals(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.NEQ, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, NotEquals::new, left(), right(), zoneId()); + } + + @Override + protected NotEquals replaceChildren(Expression newLeft, Expression newRight) { + return new NotEquals(source(), newLeft, newRight, zoneId()); + } + + @Override + public NotEquals swapLeftAndRight() { + return new NotEquals(source(), right(), left(), zoneId()); + } + + @Override + public BinaryComparison negate() { + return new Equals(source(), left(), right(), zoneId()); + } + + @Override + public BinaryComparison reverse() { + return this; + } + + @Override + protected boolean isCommutative() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/NullEquals.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/NullEquals.java new file mode 100644 index 000000000000..0b135d380f62 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/NullEquals.java @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; + +/** + * Implements the MySQL {@code <=>} operator + */ +public class NullEquals extends BinaryComparison { + + public NullEquals(Source source, Expression left, Expression right, ZoneId zoneId) { + super(source, left, right, BinaryComparisonOperation.NULLEQ, zoneId); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, NullEquals::new, left(), right(), zoneId()); + } + + @Override + protected NullEquals replaceChildren(Expression newLeft, Expression newRight) { + return new NullEquals(source(), newLeft, newRight, zoneId()); + } + + @Override + public NullEquals swapLeftAndRight() { + return new NullEquals(source(), right(), left(), zoneId()); + } + + @Override + public Nullability nullable() { + return Nullability.FALSE; + } + + @Override + public BinaryComparison reverse() { + return this; + } + + @Override + protected boolean isCommutative() { + return true; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/math/Maths.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/math/Maths.java new file mode 100644 index 000000000000..78f16030054b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/math/Maths.java @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.math; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; + +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToInt; + +public final class Maths { + + public static Number round(Number n, long precision) throws ArithmeticException { + if (n instanceof Long || n instanceof Integer || n instanceof Short || n instanceof Byte) { + return convertToIntegerType(round(n.longValue(), precision), n.getClass()); + } + double nDouble = n.doubleValue(); + if (Double.isNaN(nDouble)) { + return n instanceof Float ? 0.0f : 0.0d; + } + + double tenAtScale = tenPower(precision); + if (tenAtScale == 0.0 || nDouble == 0.0) { + return n instanceof Float ? 0.0f : 0.0d; + } + + double middleResult = nDouble * tenAtScale; + int sign = middleResult >= 0 ? 1 : -1; + + if (Double.POSITIVE_INFINITY == middleResult || Double.NEGATIVE_INFINITY == middleResult) { + return n; + } + if (Long.MIN_VALUE + 1 < middleResult && middleResult < Long.MAX_VALUE) { + // the result can still be rounded using Math.round(), that is limited to long values + Double result = Math.round(Math.abs(middleResult)) / tenAtScale * sign; + return n instanceof Float ? result.floatValue() : result; + } + + // otherwise fall back to BigDecimal, that is ~40x slower, but works fine + MathContext prec = MathContext.DECIMAL128; + Double result = new BigDecimal(Math.abs(middleResult), prec).round(new MathContext(0)) + .divide(new BigDecimal(tenAtScale), prec) + .doubleValue() * sign; + return n instanceof Float ? result.floatValue() : result; + } + + public static BigInteger round(BigInteger n, long precision) throws ArithmeticException { + if (n.signum() == 0 || precision > 0) { + return n; + } + + int digitsToRound = safeToInt(-precision); // TODO: why is precision a long? + BigInteger tenAtScaleMinusOne = BigInteger.TEN.pow(digitsToRound - 1); + BigInteger tenAtScale = tenAtScaleMinusOne.multiply(BigInteger.TEN); + BigInteger middleResult = n.divide(tenAtScale); // TODO: "intermediateResult"? + BigInteger remainder = n.mod(tenAtScale); + BigInteger having = tenAtScaleMinusOne.multiply(BigInteger.valueOf(5)); + if (remainder.compareTo(having) >= 0) { + middleResult = middleResult.add(BigInteger.ONE); + } else if (remainder.compareTo(having.negate()) <= 0) { + middleResult = middleResult.subtract(BigInteger.ONE); + } + + return middleResult.multiply(tenAtScale); + } + + public static Long round(long n, long precision) throws ArithmeticException { + if (n == 0L || precision >= 0) { + return n; + } + + long digitsToRound = -precision; + int digits = (int) (Math.log10(Math.abs((double) n)) + 1); + if (digits <= digitsToRound) { + return 0L; + } + + long tenAtScaleMinusOne = (long) tenPower(digitsToRound - 1); + long tenAtScale = tenAtScaleMinusOne * 10; + long middleResult = n / tenAtScale; + long remainder = n % tenAtScale; // TODO: vs.: n - middleResult * tenAtScale + long halving = 5 * tenAtScaleMinusOne; + if (remainder >= halving) { + middleResult++; + } else if (remainder <= -halving) { + middleResult--; + } + + long result = middleResult * tenAtScale; + if (Long.signum(result) == Long.signum(n)) { + return result; + } else { + throw new ArithmeticException("long overflow"); + } + } + + public static Number truncate(Number n, Number precision) { + long longPrecision = precision.longValue(); + if (n instanceof Long || n instanceof Integer || n instanceof Short || n instanceof Byte) { + long nLong = n.longValue(); + if (nLong == 0L || longPrecision >= 0) { + return n; + } + + long digitsToTruncate = -longPrecision; + int digits = (int) (Math.log10(Math.abs(n.doubleValue())) + 1); + if (digits <= digitsToTruncate) { + return convertToIntegerType(0L, n.getClass()); + } + + long tenAtScale = (long) tenPower(digitsToTruncate); + return convertToIntegerType((nLong / tenAtScale) * tenAtScale, n.getClass()); + } + double tenAtScale = Math.pow(10d, longPrecision); + double g = n.doubleValue() * tenAtScale; + Double result = (((n.doubleValue() < 0) ? Math.ceil(g) : Math.floor(g)) / tenAtScale); + return n instanceof Float ? result.floatValue() : result; + } + + // optimise very common cases for round and truncate + private static double tenPower(long n) { + if (n == 0L) { + return 1d; + } else if (n == 1L) { + return 10d; + } else if (n == 2L) { + return 100d; + } else if (n == 3L) { + return 1000d; + } else if (n == 4L) { + return 10000d; + } else if (n == 5L) { + return 100000d; + } + return Math.pow(10, n); + } + + /** + * does not take number precision and overflow into consideration! + * Use only in cases when these aspects are guaranteed by previous logic (eg. ROUND, TRUNCATE) + * @param number the number to convert + * @param type the destination type + * @return the same number converted to the right type + * @throws ArithmeticException in case of integer overflow. + * See {@link org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Arithmetics} + */ + private static Number convertToIntegerType(Long number, Class type) throws ArithmeticException { + if (type == Integer.class) { + if (number > Integer.MAX_VALUE || number < Integer.MIN_VALUE) { + throw new ArithmeticException("integer overflow"); + } + return number.intValue(); + } else if (type == Short.class) { + return number.shortValue(); + } else if (type == Byte.class) { + return number.byteValue(); + } + return number; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/AbstractStringPattern.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/AbstractStringPattern.java new file mode 100644 index 000000000000..8d681977b5b4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/AbstractStringPattern.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.apache.lucene.util.IntsRef; +import org.apache.lucene.util.UnicodeUtil; +import org.apache.lucene.util.automaton.Automaton; +import org.apache.lucene.util.automaton.Operations; + +public abstract class AbstractStringPattern implements StringPattern { + + private Automaton automaton; + + public abstract Automaton createAutomaton(); + + private Automaton automaton() { + if (automaton == null) { + automaton = createAutomaton(); + } + return automaton; + } + + @Override + public boolean matchesAll() { + return Operations.isTotal(automaton()); + } + + @Override + public String exactMatch() { + IntsRef singleton = Operations.getSingleton(automaton()); + return singleton != null ? UnicodeUtil.newString(singleton.ints, singleton.offset, singleton.length) : null; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/Like.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/Like.java new file mode 100644 index 000000000000..84ed88da0fe4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/Like.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class Like extends RegexMatch { + + public Like(Source source, Expression left, LikePattern pattern) { + this(source, left, pattern, false); + } + + public Like(Source source, Expression left, LikePattern pattern, boolean caseInsensitive) { + super(source, left, pattern, caseInsensitive); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Like::new, field(), pattern(), caseInsensitive()); + } + + @Override + protected Like replaceChild(Expression newLeft) { + return new Like(source(), newLeft, pattern(), caseInsensitive()); + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/LikePattern.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/LikePattern.java new file mode 100644 index 000000000000..52ce2636e914 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/LikePattern.java @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.apache.lucene.index.Term; +import org.apache.lucene.search.WildcardQuery; +import org.apache.lucene.util.automaton.Automaton; +import org.apache.lucene.util.automaton.MinimizationOperations; +import org.apache.lucene.util.automaton.Operations; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.Objects; + +/** + * A SQL 'like' pattern. + * Similar to basic regex, supporting '_' instead of '?' and '%' instead of '*'. + *

+ * Allows escaping based on a regular char. + * + * To prevent conflicts with ES, the string and char must be validated to not contain '*'. + */ +public class LikePattern extends AbstractStringPattern { + + private final String pattern; + private final char escape; + + private final String regex; + private final String wildcard; + private final String indexNameWildcard; + + public LikePattern(String pattern, char escape) { + this.pattern = pattern; + this.escape = escape; + // early initialization to force string validation + this.regex = StringUtils.likeToJavaPattern(pattern, escape); + this.wildcard = StringUtils.likeToLuceneWildcard(pattern, escape); + this.indexNameWildcard = StringUtils.likeToIndexWildcard(pattern, escape); + } + + public String pattern() { + return pattern; + } + + public char escape() { + return escape; + } + + @Override + public Automaton createAutomaton() { + Automaton automaton = WildcardQuery.toAutomaton(new Term(null, wildcard)); + return MinimizationOperations.minimize(automaton, Operations.DEFAULT_DETERMINIZE_WORK_LIMIT); + } + + @Override + public String asJavaRegex() { + return regex; + } + + /** + * Returns the pattern in (Lucene) wildcard format. + */ + public String asLuceneWildcard() { + return wildcard; + } + + /** + * Returns the pattern in (IndexNameExpressionResolver) wildcard format. + */ + public String asIndexNameWildcard() { + return indexNameWildcard; + } + + @Override + public int hashCode() { + return Objects.hash(pattern, escape); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + LikePattern other = (LikePattern) obj; + return Objects.equals(pattern, other.pattern) && escape == other.escape; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLike.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLike.java new file mode 100644 index 000000000000..8020491c5021 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLike.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class RLike extends RegexMatch { + + public RLike(Source source, Expression value, RLikePattern pattern) { + super(source, value, pattern, false); + } + + public RLike(Source source, Expression field, RLikePattern rLikePattern, boolean caseInsensitive) { + super(source, field, rLikePattern, caseInsensitive); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, RLike::new, field(), pattern(), caseInsensitive()); + } + + @Override + protected RLike replaceChild(Expression newChild) { + return new RLike(source(), newChild, pattern(), caseInsensitive()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLikePattern.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLikePattern.java new file mode 100644 index 000000000000..4257285ba8bd --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RLikePattern.java @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.apache.lucene.util.automaton.Automaton; +import org.apache.lucene.util.automaton.RegExp; + +import java.util.Objects; + +public class RLikePattern extends AbstractStringPattern { + + private final String regexpPattern; + + public RLikePattern(String regexpPattern) { + this.regexpPattern = regexpPattern; + } + + @Override + public Automaton createAutomaton() { + return new RegExp(regexpPattern).toAutomaton(); + } + + @Override + public String asJavaRegex() { + return regexpPattern; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RLikePattern that = (RLikePattern) o; + return Objects.equals(regexpPattern, that.regexpPattern); + } + + @Override + public int hashCode() { + return Objects.hash(regexpPattern); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexMatch.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexMatch.java new file mode 100644 index 000000000000..8f905581f0f2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexMatch.java @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.Objects; + +import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isStringAndExact; +import static org.elasticsearch.xpack.esql.core.expression.gen.script.ParamsBuilder.paramsBuilder; + +public abstract class RegexMatch extends UnaryScalarFunction { + + private final T pattern; + private final boolean caseInsensitive; + + protected RegexMatch(Source source, Expression value, T pattern, boolean caseInsensitive) { + super(source, value); + this.pattern = pattern; + this.caseInsensitive = caseInsensitive; + } + + public T pattern() { + return pattern; + } + + public boolean caseInsensitive() { + return caseInsensitive; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + public Nullability nullable() { + if (pattern() == null) { + return Nullability.TRUE; + } + return field().nullable(); + } + + @Override + protected TypeResolution resolveType() { + return isStringAndExact(field(), sourceText(), DEFAULT); + } + + @Override + public boolean foldable() { + // right() is not directly foldable in any context but Like can fold it. + return field().foldable(); + } + + @Override + public Boolean fold() { + Object val = field().fold(); + if (val instanceof BytesRef br) { + val = br.utf8ToString(); + } + return RegexProcessor.RegexOperation.match(val, pattern().asJavaRegex()); + } + + @Override + protected Processor makeProcessor() { + return new RegexProcessor(pattern().asJavaRegex()); + } + + @Override + public ScriptTemplate asScript() { + ScriptTemplate fieldAsScript = asScript(field()); + // keep backwards compatibility with previous 7.x versions + if (caseInsensitive == false) { + return new ScriptTemplate( + formatTemplate(format("{ql}.", "regex({},{})", fieldAsScript.template())), + paramsBuilder().script(fieldAsScript.params()).variable(pattern.asJavaRegex()).build(), + dataType() + ); + } + return new ScriptTemplate( + formatTemplate(format("{ql}.", "regex({},{},{})", fieldAsScript.template())), + paramsBuilder().script(fieldAsScript.params()).variable(pattern.asJavaRegex()).variable(caseInsensitive).build(), + dataType() + ); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + RegexMatch other = (RegexMatch) obj; + return caseInsensitive == other.caseInsensitive && Objects.equals(pattern, other.pattern); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), pattern(), caseInsensitive); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexProcessor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexProcessor.java new file mode 100644 index 000000000000..41b0ab406bf8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/RegexProcessor.java @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; + +import java.io.IOException; +import java.util.Objects; +import java.util.regex.Pattern; + +public class RegexProcessor implements Processor { + + public static class RegexOperation { + + public static Boolean match(Object value, Pattern pattern) { + if (pattern == null) { + return Boolean.TRUE; + } + + if (value == null) { + return null; + } + + return pattern.matcher(value.toString()).matches(); + } + + public static Boolean match(Object value, String pattern) { + return match(value, pattern, Boolean.FALSE); + } + + public static Boolean match(Object value, String pattern, Boolean caseInsensitive) { + if (pattern == null) { + return Boolean.TRUE; + } + + if (value == null) { + return null; + } + + int flags = 0; + if (Boolean.TRUE.equals(caseInsensitive)) { + flags |= Pattern.CASE_INSENSITIVE; + } + return Pattern.compile(pattern, flags).matcher(value.toString()).matches(); + } + } + + public static final String NAME = "rgx"; + + private Pattern pattern; + + public RegexProcessor(String pattern) { + this.pattern = pattern != null ? Pattern.compile(pattern) : null; + } + + @Override + public String getWriteableName() { + return NAME; + } + + public RegexProcessor(StreamInput in) throws IOException { + this(in.readOptionalString()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeOptionalString(pattern != null ? pattern.toString() : null); + } + + @Override + public Object process(Object input) { + return RegexOperation.match(input, pattern); + } + + @Override + public int hashCode() { + return Objects.hash(pattern); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + RegexProcessor other = (RegexProcessor) obj; + return Objects.equals(pattern, other.pattern); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/StringPattern.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/StringPattern.java new file mode 100644 index 000000000000..cb2bdd55937b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/StringPattern.java @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +public interface StringPattern { + /** + * Returns the pattern in (Java) regex format. + */ + String asJavaRegex(); + + /** + * Hint method on whether this pattern matches everything or not. + */ + default boolean matchesAll() { + return false; + } + + /** + * Returns the match if this pattern is exact, that is has no wildcard + * or other patterns inside. + * If the pattern is not exact, null is returned. + */ + String exactMatch(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardLike.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardLike.java new file mode 100644 index 000000000000..8834c1a0211b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardLike.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +public class WildcardLike extends RegexMatch { + + public WildcardLike(Source source, Expression left, WildcardPattern pattern) { + this(source, left, pattern, false); + } + + public WildcardLike(Source source, Expression left, WildcardPattern pattern, boolean caseInsensitive) { + super(source, left, pattern, caseInsensitive); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, WildcardLike::new, field(), pattern(), caseInsensitive()); + } + + @Override + protected WildcardLike replaceChild(Expression newLeft) { + return new WildcardLike(source(), newLeft, pattern(), caseInsensitive()); + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardPattern.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardPattern.java new file mode 100644 index 000000000000..7cedbc474213 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/WildcardPattern.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.apache.lucene.index.Term; +import org.apache.lucene.search.WildcardQuery; +import org.apache.lucene.util.automaton.Automaton; +import org.apache.lucene.util.automaton.MinimizationOperations; +import org.apache.lucene.util.automaton.Operations; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.Objects; + +/** + * Similar to basic regex, supporting '?' wildcard for single character (same as regex ".") + * and '*' wildcard for multiple characters (same as regex ".*") + *

+ * Allows escaping based on a regular char + * + */ +public class WildcardPattern extends AbstractStringPattern { + + private final String wildcard; + private final String regex; + + public WildcardPattern(String pattern) { + this.wildcard = pattern; + // early initialization to force string validation + this.regex = StringUtils.wildcardToJavaPattern(pattern, '\\'); + } + + public String pattern() { + return wildcard; + } + + @Override + public Automaton createAutomaton() { + Automaton automaton = WildcardQuery.toAutomaton(new Term(null, wildcard)); + return MinimizationOperations.minimize(automaton, Operations.DEFAULT_DETERMINIZE_WORK_LIMIT); + } + + @Override + public String asJavaRegex() { + return regex; + } + + /** + * Returns the pattern in (Lucene) wildcard format. + */ + public String asLuceneWildcard() { + return wildcard; + } + + /** + * Returns the pattern in (IndexNameExpressionResolver) wildcard format. + */ + public String asIndexNameWildcard() { + return wildcard; + } + + @Override + public int hashCode() { + return Objects.hash(wildcard); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + WildcardPattern other = (WildcardPattern) obj; + return Objects.equals(wildcard, other.wildcard); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/processor/Processors.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/processor/Processors.java new file mode 100644 index 000000000000..f72fdb7e43fb --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/processor/Processors.java @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.processor; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.BucketExtractorProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ChainingProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.HitExtractorProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.NotProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexProcessor; +import org.elasticsearch.xpack.esql.core.type.Converter; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter.DefaultConverter; + +import java.util.ArrayList; +import java.util.List; + +public final class Processors { + + private Processors() {} + + /** + * All of the named writeables needed to deserialize the instances of + * {@linkplain Processors}. + */ + public static List getNamedWriteables() { + List entries = new ArrayList<>(); + + // base + entries.add(new Entry(Converter.class, DefaultConverter.NAME, DefaultConverter::read)); + + entries.add(new Entry(Processor.class, ConstantProcessor.NAME, ConstantProcessor::new)); + entries.add(new Entry(Processor.class, HitExtractorProcessor.NAME, HitExtractorProcessor::new)); + entries.add(new Entry(Processor.class, BucketExtractorProcessor.NAME, BucketExtractorProcessor::new)); + entries.add(new Entry(Processor.class, ChainingProcessor.NAME, ChainingProcessor::new)); + + // logical + entries.add(new Entry(Processor.class, BinaryLogicProcessor.NAME, BinaryLogicProcessor::new)); + entries.add(new Entry(Processor.class, NotProcessor.NAME, NotProcessor::new)); + + // arithmetic + // binary arithmetics are pluggable + entries.add( + new Entry(BinaryArithmeticOperation.class, DefaultBinaryArithmeticOperation.NAME, DefaultBinaryArithmeticOperation::read) + ); + entries.add(new Entry(Processor.class, BinaryArithmeticProcessor.NAME, BinaryArithmeticProcessor::new)); + entries.add(new Entry(Processor.class, UnaryArithmeticProcessor.NAME, UnaryArithmeticProcessor::new)); + // comparators + entries.add(new Entry(Processor.class, BinaryComparisonProcessor.NAME, BinaryComparisonProcessor::new)); + // regex + entries.add(new Entry(Processor.class, RegexProcessor.NAME, RegexProcessor::new)); + + return entries; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/EsIndex.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/EsIndex.java new file mode 100644 index 000000000000..3e6be6a1345d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/EsIndex.java @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.xpack.esql.core.type.EsField; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +public class EsIndex { + + private final String name; + private final Map mapping; + private final Set concreteIndices; + + public EsIndex(String name, Map mapping) { + this(name, mapping, Set.of()); + } + + public EsIndex(String name, Map mapping, Set concreteIndices) { + assert name != null; + assert mapping != null; + this.name = name; + this.mapping = mapping; + this.concreteIndices = concreteIndices; + } + + public String name() { + return name; + } + + public Map mapping() { + return mapping; + } + + public Set concreteIndices() { + return concreteIndices; + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + return Objects.hash(name, mapping, concreteIndices); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EsIndex other = (EsIndex) obj; + return Objects.equals(name, other.name) + && Objects.equals(mapping, other.mapping) + && Objects.equals(concreteIndices, other.concreteIndices); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexCompatibility.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexCompatibility.java new file mode 100644 index 000000000000..e0ee08968025 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexCompatibility.java @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.Version; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; + +import java.util.Map; + +import static org.elasticsearch.xpack.esql.core.index.VersionCompatibilityChecks.isTypeSupportedInVersion; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isPrimitive; +import static org.elasticsearch.xpack.esql.core.type.Types.propagateUnsupportedType; + +public final class IndexCompatibility { + + public static Map compatible(Map mapping, Version version) { + for (Map.Entry entry : mapping.entrySet()) { + EsField esField = entry.getValue(); + DataType dataType = esField.getDataType(); + if (isPrimitive(dataType) == false) { + compatible(esField.getProperties(), version); + } else if (isTypeSupportedInVersion(dataType, version) == false) { + EsField field = new UnsupportedEsField(entry.getKey(), dataType.name(), null, esField.getProperties()); + entry.setValue(field); + propagateUnsupportedType(entry.getKey(), dataType.name(), esField.getProperties()); + } + } + return mapping; + } + + public static EsIndex compatible(EsIndex esIndex, Version version) { + compatible(esIndex.mapping(), version); + return esIndex; + } + + public static IndexResolution compatible(IndexResolution indexResolution, Version version) { + if (indexResolution.isValid()) { + compatible(indexResolution.get(), version); + } + return indexResolution; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexResolution.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexResolution.java new file mode 100644 index 000000000000..2e42f7d998f4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexResolution.java @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.core.Nullable; + +import java.util.Objects; + +public final class IndexResolution { + public static IndexResolution valid(EsIndex index) { + Objects.requireNonNull(index, "index must not be null if it was found"); + return new IndexResolution(index, null); + } + + public static IndexResolution invalid(String invalid) { + Objects.requireNonNull(invalid, "invalid must not be null to signal that the index is invalid"); + return new IndexResolution(null, invalid); + } + + public static IndexResolution notFound(String name) { + Objects.requireNonNull(name, "name must not be null"); + return invalid("Unknown index [" + name + "]"); + } + + private final EsIndex index; + @Nullable + private final String invalid; + + private IndexResolution(EsIndex index, @Nullable String invalid) { + this.index = index; + this.invalid = invalid; + } + + public boolean matches(String indexName) { + return isValid() && this.index.name().equals(indexName); + } + + /** + * Get the {@linkplain EsIndex} + * @throws MappingException if the index is invalid for use with ql + */ + public EsIndex get() { + if (invalid != null) { + throw new MappingException(invalid); + } + return index; + } + + /** + * Is the index valid for use with ql? Returns {@code false} if the + * index wasn't found. + */ + public boolean isValid() { + return invalid == null; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + IndexResolution other = (IndexResolution) obj; + return Objects.equals(index, other.index) && Objects.equals(invalid, other.invalid); + } + + @Override + public int hashCode() { + return Objects.hash(index, invalid); + } + + @Override + public String toString() { + return invalid != null ? invalid : index.name(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexResolver.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexResolver.java new file mode 100644 index 000000000000..21222b5d36a5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/IndexResolver.java @@ -0,0 +1,1046 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.ElasticsearchSecurityException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest.Feature; +import org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction; +import org.elasticsearch.action.fieldcaps.FieldCapabilities; +import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest; +import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.metadata.AliasMetadata; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.util.Maps; +import org.elasticsearch.core.Tuple; +import org.elasticsearch.index.IndexNotFoundException; +import org.elasticsearch.index.mapper.TimeSeriesParams; +import org.elasticsearch.transport.NoSuchRemoteClusterException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeRegistry; +import org.elasticsearch.xpack.esql.core.type.DateEsField; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.type.KeywordEsField; +import org.elasticsearch.xpack.esql.core.type.TextEsField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.util.Holder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.regex.Pattern; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.elasticsearch.action.ActionListener.wrap; +import static org.elasticsearch.common.Strings.hasText; +import static org.elasticsearch.common.regex.Regex.simpleMatch; +import static org.elasticsearch.transport.RemoteClusterAware.buildRemoteIndexName; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.OBJECT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSUPPORTED; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.qualifyAndJoinIndices; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.splitQualifiedIndex; + +public class IndexResolver { + + public enum IndexType { + STANDARD_INDEX(SQL_TABLE, "INDEX"), + ALIAS(SQL_VIEW, "ALIAS"), + FROZEN_INDEX(SQL_TABLE, "FROZEN INDEX"), + // value for user types unrecognized + UNKNOWN("UNKNOWN", "UNKNOWN"); + + public static final EnumSet VALID_INCLUDE_FROZEN = EnumSet.of(STANDARD_INDEX, ALIAS, FROZEN_INDEX); + public static final EnumSet VALID_REGULAR = EnumSet.of(STANDARD_INDEX, ALIAS); + + private final String toSql; + private final String toNative; + + IndexType(String sql, String toNative) { + this.toSql = sql; + this.toNative = toNative; + } + + public String toSql() { + return toSql; + } + + public String toNative() { + return toNative; + } + } + + public record IndexInfo(String cluster, String name, IndexType type) { + + @Override + public String toString() { + return buildRemoteIndexName(cluster, name); + } + + } + + public static final String SQL_TABLE = "TABLE"; + public static final String SQL_VIEW = "VIEW"; + + private static final IndicesOptions INDICES_ONLY_OPTIONS = IndicesOptions.builder() + .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS) + .wildcardOptions( + IndicesOptions.WildcardOptions.builder() + .matchOpen(true) + .matchClosed(false) + .includeHidden(false) + .allowEmptyExpressions(true) + .resolveAliases(false) + ) + .gatekeeperOptions( + IndicesOptions.GatekeeperOptions.builder().ignoreThrottled(true).allowClosedIndices(true).allowAliasToMultipleIndices(true) + ) + .build(); + private static final IndicesOptions FROZEN_INDICES_OPTIONS = IndicesOptions.builder() + .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS) + .wildcardOptions( + IndicesOptions.WildcardOptions.builder() + .matchOpen(true) + .matchClosed(false) + .includeHidden(false) + .allowEmptyExpressions(true) + .resolveAliases(false) + ) + .gatekeeperOptions( + IndicesOptions.GatekeeperOptions.builder().ignoreThrottled(false).allowClosedIndices(true).allowAliasToMultipleIndices(true) + ) + .build(); + + public static final IndicesOptions FIELD_CAPS_INDICES_OPTIONS = IndicesOptions.builder() + .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS) + .wildcardOptions( + IndicesOptions.WildcardOptions.builder() + .matchOpen(true) + .matchClosed(false) + .includeHidden(false) + .allowEmptyExpressions(true) + .resolveAliases(true) + ) + .gatekeeperOptions( + IndicesOptions.GatekeeperOptions.builder().ignoreThrottled(true).allowClosedIndices(true).allowAliasToMultipleIndices(true) + ) + .build(); + public static final IndicesOptions FIELD_CAPS_FROZEN_INDICES_OPTIONS = IndicesOptions.builder() + .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS) + .wildcardOptions( + IndicesOptions.WildcardOptions.builder() + .matchOpen(true) + .matchClosed(false) + .includeHidden(false) + .allowEmptyExpressions(true) + .resolveAliases(true) + ) + .gatekeeperOptions( + IndicesOptions.GatekeeperOptions.builder().ignoreThrottled(false).allowClosedIndices(true).allowAliasToMultipleIndices(true) + ) + .build(); + + public static final Set ALL_FIELDS = Set.of("*"); + public static final Set INDEX_METADATA_FIELD = Set.of("_index"); + public static final String UNMAPPED = "unmapped"; + + private final Client client; + private final String clusterName; + private final DataTypeRegistry typeRegistry; + + private final Supplier> remoteClusters; + + public IndexResolver(Client client, String clusterName, DataTypeRegistry typeRegistry, Supplier> remoteClusters) { + this.client = client; + this.clusterName = clusterName; + this.typeRegistry = typeRegistry; + this.remoteClusters = remoteClusters; + } + + public String clusterName() { + return clusterName; + } + + public Set remoteClusters() { + return remoteClusters.get(); + } + + /** + * Resolves only the names, differentiating between indices and aliases. + * This method is required since the other methods rely on mapping which is tied to an index (not an alias). + */ + public void resolveNames( + String clusterWildcard, + String indexWildcard, + String javaRegex, + EnumSet types, + ActionListener> listener + ) { + + // first get aliases (if specified) + boolean retrieveAliases = CollectionUtils.isEmpty(types) || types.contains(IndexType.ALIAS); + boolean retrieveIndices = CollectionUtils.isEmpty(types) || types.contains(IndexType.STANDARD_INDEX); + boolean retrieveFrozenIndices = CollectionUtils.isEmpty(types) || types.contains(IndexType.FROZEN_INDEX); + + String[] indexWildcards = Strings.commaDelimitedListToStringArray(indexWildcard); + Set indexInfos = new HashSet<>(); + if (retrieveAliases && clusterIsLocal(clusterWildcard)) { + ResolveIndexAction.Request resolveRequest = new ResolveIndexAction.Request(indexWildcards, IndicesOptions.lenientExpandOpen()); + client.admin().indices().resolveIndex(resolveRequest, wrap(response -> { + for (ResolveIndexAction.ResolvedAlias alias : response.getAliases()) { + indexInfos.add(new IndexInfo(clusterName, alias.getName(), IndexType.ALIAS)); + } + for (ResolveIndexAction.ResolvedDataStream dataStream : response.getDataStreams()) { + indexInfos.add(new IndexInfo(clusterName, dataStream.getName(), IndexType.ALIAS)); + } + resolveIndices(clusterWildcard, indexWildcards, javaRegex, retrieveIndices, retrieveFrozenIndices, indexInfos, listener); + }, ex -> { + // with security, two exception can be thrown: + // INFE - if no alias matches + // security exception is the user cannot access aliases + + // in both cases, that is allowed and we continue with the indices request + if (ex instanceof IndexNotFoundException || ex instanceof ElasticsearchSecurityException) { + resolveIndices( + clusterWildcard, + indexWildcards, + javaRegex, + retrieveIndices, + retrieveFrozenIndices, + indexInfos, + listener + ); + } else { + listener.onFailure(ex); + } + })); + } else { + resolveIndices(clusterWildcard, indexWildcards, javaRegex, retrieveIndices, retrieveFrozenIndices, indexInfos, listener); + } + } + + private void resolveIndices( + String clusterWildcard, + String[] indexWildcards, + String javaRegex, + boolean retrieveIndices, + boolean retrieveFrozenIndices, + Set indexInfos, + ActionListener> listener + ) { + if (retrieveIndices || retrieveFrozenIndices) { + if (clusterIsLocal(clusterWildcard)) { // resolve local indices + GetIndexRequest indexRequest = new GetIndexRequest().local(true) + .indices(indexWildcards) + .features(Feature.SETTINGS) + .includeDefaults(false) + .indicesOptions(INDICES_ONLY_OPTIONS); + + // if frozen indices are requested, make sure to update the request accordingly + if (retrieveFrozenIndices) { + indexRequest.indicesOptions(FROZEN_INDICES_OPTIONS); + } + + client.admin().indices().getIndex(indexRequest, listener.delegateFailureAndWrap((delegate, indices) -> { + if (indices != null) { + for (String indexName : indices.getIndices()) { + boolean isFrozen = retrieveFrozenIndices + && indices.getSettings().get(indexName).getAsBoolean("index.frozen", false); + indexInfos.add( + new IndexInfo(clusterName, indexName, isFrozen ? IndexType.FROZEN_INDEX : IndexType.STANDARD_INDEX) + ); + } + } + resolveRemoteIndices(clusterWildcard, indexWildcards, javaRegex, retrieveFrozenIndices, indexInfos, delegate); + })); + } else { + resolveRemoteIndices(clusterWildcard, indexWildcards, javaRegex, retrieveFrozenIndices, indexInfos, listener); + } + } else { + filterResults(javaRegex, indexInfos, listener); + } + } + + private void resolveRemoteIndices( + String clusterWildcard, + String[] indexWildcards, + String javaRegex, + boolean retrieveFrozenIndices, + Set indexInfos, + ActionListener> listener + ) { + if (hasText(clusterWildcard)) { + IndicesOptions indicesOptions = retrieveFrozenIndices ? FIELD_CAPS_FROZEN_INDICES_OPTIONS : FIELD_CAPS_INDICES_OPTIONS; + FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest( + qualifyAndJoinIndices(clusterWildcard, indexWildcards), + ALL_FIELDS, + indicesOptions, + emptyMap() + ); + client.fieldCaps(fieldRequest, wrap(response -> { + String[] indices = response.getIndices(); + if (indices != null) { + for (String indexName : indices) { + // TODO: perform two requests w/ & w/o frozen option to retrieve (by diff) the throttling status? + Tuple splitRef = splitQualifiedIndex(indexName); + // Field caps on "remote:foo" should always return either empty or remote indices. But in case cluster's + // detail is missing, it's going to be a local index. TODO: why would this happen? + String cluster = splitRef.v1() == null ? clusterName : splitRef.v1(); + indexInfos.add(new IndexInfo(cluster, splitRef.v2(), IndexType.STANDARD_INDEX)); + } + } + filterResults(javaRegex, indexInfos, listener); + }, ex -> { + // see comment in resolveNames() + if (ex instanceof NoSuchRemoteClusterException || ex instanceof ElasticsearchSecurityException) { + filterResults(javaRegex, indexInfos, listener); + } else { + listener.onFailure(ex); + } + })); + } else { + filterResults(javaRegex, indexInfos, listener); + } + } + + private static void filterResults(String javaRegex, Set indexInfos, ActionListener> listener) { + + // since the index name does not support ?, filter the results manually + Pattern pattern = javaRegex != null ? Pattern.compile(javaRegex) : null; + + Set result = new TreeSet<>(Comparator.comparing(IndexInfo::cluster).thenComparing(IndexInfo::name)); + for (IndexInfo indexInfo : indexInfos) { + if (pattern == null || pattern.matcher(indexInfo.name()).matches()) { + result.add(indexInfo); + } + } + listener.onResponse(result); + } + + private boolean clusterIsLocal(String clusterWildcard) { + return clusterWildcard == null || simpleMatch(clusterWildcard, clusterName); + } + + /** + * Resolves a pattern to one (potentially compound meaning that spawns multiple indices) mapping. + */ + public void resolveAsMergedMapping( + String indexWildcard, + Set fieldNames, + IndicesOptions indicesOptions, + Map runtimeMappings, + ActionListener listener + ) { + FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, fieldNames, indicesOptions, runtimeMappings); + client.fieldCaps( + fieldRequest, + listener.delegateFailureAndWrap((l, response) -> l.onResponse(mergedMappings(typeRegistry, indexWildcard, response))) + ); + } + + /** + * Resolves a pattern to one (potentially compound meaning that spawns multiple indices) mapping. + */ + public void resolveAsMergedMapping( + String indexWildcard, + Set fieldNames, + boolean includeFrozen, + Map runtimeMappings, + ActionListener listener + ) { + resolveAsMergedMapping(indexWildcard, fieldNames, includeFrozen, runtimeMappings, listener, (fieldName, types) -> null); + } + + /** + * Resolves a pattern to one (potentially compound meaning that spawns multiple indices) mapping. + */ + public void resolveAsMergedMapping( + String indexWildcard, + Set fieldNames, + boolean includeFrozen, + Map runtimeMappings, + ActionListener listener, + BiFunction, InvalidMappedField> specificValidityVerifier + ) { + FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, fieldNames, includeFrozen, runtimeMappings); + client.fieldCaps( + fieldRequest, + listener.delegateFailureAndWrap( + (l, response) -> l.onResponse(mergedMappings(typeRegistry, indexWildcard, response, specificValidityVerifier, null, null)) + ) + ); + } + + public void resolveAsMergedMapping( + String indexWildcard, + Set fieldNames, + boolean includeFrozen, + Map runtimeMappings, + ActionListener listener, + BiFunction, InvalidMappedField> specificValidityVerifier, + BiConsumer fieldUpdater, + Set allowedMetadataFields + ) { + FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, fieldNames, includeFrozen, runtimeMappings); + client.fieldCaps( + fieldRequest, + listener.delegateFailureAndWrap( + (l, response) -> l.onResponse( + mergedMappings(typeRegistry, indexWildcard, response, specificValidityVerifier, fieldUpdater, allowedMetadataFields) + ) + ) + ); + } + + public static IndexResolution mergedMappings( + DataTypeRegistry typeRegistry, + String indexPattern, + FieldCapabilitiesResponse fieldCapsResponse, + BiFunction, InvalidMappedField> specificValidityVerifier + ) { + return mergedMappings(typeRegistry, indexPattern, fieldCapsResponse, specificValidityVerifier, null, null); + } + + public static IndexResolution mergedMappings( + DataTypeRegistry typeRegistry, + String indexPattern, + FieldCapabilitiesResponse fieldCapsResponse, + BiFunction, InvalidMappedField> specificValidityVerifier, + BiConsumer fieldUpdater, + Set allowedMetadataFields + ) { + + if (fieldCapsResponse.getIndices().length == 0) { + return IndexResolution.notFound(indexPattern); + } + + BiFunction, InvalidMappedField> validityVerifier = (fieldName, types) -> { + InvalidMappedField f = specificValidityVerifier.apply(fieldName, types); + if (f != null) { + return f; + } + + StringBuilder errorMessage = new StringBuilder(); + boolean hasUnmapped = types.containsKey(UNMAPPED); + + if (types.size() > (hasUnmapped ? 2 : 1)) { + // build the error message + // and create a MultiTypeField + + for (Entry type : types.entrySet()) { + // skip unmapped + if (UNMAPPED.equals(type.getKey())) { + continue; + } + + if (errorMessage.length() > 0) { + errorMessage.append(", "); + } + errorMessage.append("["); + errorMessage.append(type.getKey()); + errorMessage.append("] in "); + errorMessage.append(Arrays.toString(type.getValue().indices())); + } + + errorMessage.insert(0, "mapped as [" + (types.size() - (hasUnmapped ? 1 : 0)) + "] incompatible types: "); + + return new InvalidMappedField(fieldName, errorMessage.toString()); + } + // type is okay, check aggregation + else { + FieldCapabilities fieldCap = types.values().iterator().next(); + + // validate search/agg-able + if (fieldCap.isAggregatable() && fieldCap.nonAggregatableIndices() != null) { + errorMessage.append("mapped as aggregatable except in "); + errorMessage.append(Arrays.toString(fieldCap.nonAggregatableIndices())); + } + if (fieldCap.isSearchable() && fieldCap.nonSearchableIndices() != null) { + if (errorMessage.length() > 0) { + errorMessage.append(","); + } + errorMessage.append("mapped as searchable except in "); + errorMessage.append(Arrays.toString(fieldCap.nonSearchableIndices())); + } + + if (errorMessage.length() > 0) { + return new InvalidMappedField(fieldName, errorMessage.toString()); + } + } + + // everything checks + return null; + }; + + // merge all indices onto the same one + List indices = buildIndices( + typeRegistry, + null, + fieldCapsResponse, + null, + i -> indexPattern, + validityVerifier, + fieldUpdater, + allowedMetadataFields + ); + + if (indices.size() > 1) { + throw new QlIllegalArgumentException( + "Incorrect merging of mappings (likely due to a bug) - expect at most one but found [{}]", + indices.size() + ); + } + + String[] indexNames = fieldCapsResponse.getIndices(); + if (indices.isEmpty()) { + return IndexResolution.valid(new EsIndex(indexNames[0], emptyMap(), Set.of())); + } else { + EsIndex idx = indices.get(0); + return IndexResolution.valid(new EsIndex(idx.name(), idx.mapping(), Set.of(indexNames))); + } + } + + public static IndexResolution mergedMappings( + DataTypeRegistry typeRegistry, + String indexPattern, + FieldCapabilitiesResponse fieldCapsResponse + ) { + return mergedMappings(typeRegistry, indexPattern, fieldCapsResponse, (fieldName, types) -> null, null, null); + } + + private static EsField createField( + DataTypeRegistry typeRegistry, + String fieldName, + Map> globalCaps, + Map hierarchicalMapping, + Map flattedMapping, + Function field + ) { + + Map parentProps = hierarchicalMapping; + + int dot = fieldName.lastIndexOf('.'); + String fullFieldName = fieldName; + EsField parent = null; + + if (dot >= 0) { + String parentName = fieldName.substring(0, dot); + fieldName = fieldName.substring(dot + 1); + parent = flattedMapping.get(parentName); + if (parent == null) { + Map map = globalCaps.get(parentName); + Function fieldFunction; + + // lack of parent implies the field is an alias + if (map == null) { + // as such, create the field manually, marking the field to also be an alias + fieldFunction = s -> createField(typeRegistry, s, OBJECT.esType(), null, new TreeMap<>(), false, true); + } else { + Iterator iterator = map.values().iterator(); + FieldCapabilities parentCap = iterator.next(); + if (iterator.hasNext() && UNMAPPED.equals(parentCap.getType())) { + parentCap = iterator.next(); + } + final FieldCapabilities parentC = parentCap; + fieldFunction = s -> createField( + typeRegistry, + s, + parentC.getType(), + parentC.getMetricType(), + new TreeMap<>(), + parentC.isAggregatable(), + false + ); + } + + parent = createField(typeRegistry, parentName, globalCaps, hierarchicalMapping, flattedMapping, fieldFunction); + } + parentProps = parent.getProperties(); + } + + EsField esField = field.apply(fieldName); + + if (parent instanceof UnsupportedEsField unsupportedParent) { + String inherited = unsupportedParent.getInherited(); + String type = unsupportedParent.getOriginalType(); + + if (inherited == null) { + // mark the sub-field as unsupported, just like its parent, setting the first unsupported parent as the current one + esField = new UnsupportedEsField(esField.getName(), type, unsupportedParent.getName(), esField.getProperties()); + } else { + // mark the sub-field as unsupported, just like its parent, but setting the first unsupported parent + // as the parent's first unsupported grandparent + esField = new UnsupportedEsField(esField.getName(), type, inherited, esField.getProperties()); + } + } + + parentProps.put(fieldName, esField); + flattedMapping.put(fullFieldName, esField); + + return esField; + } + + private static EsField createField( + DataTypeRegistry typeRegistry, + String fieldName, + String typeName, + TimeSeriesParams.MetricType metricType, + Map props, + boolean isAggregateable, + boolean isAlias + ) { + DataType esType = typeRegistry.fromEs(typeName, metricType); + + if (esType == TEXT) { + return new TextEsField(fieldName, props, false, isAlias); + } + if (esType == KEYWORD) { + int length = Short.MAX_VALUE; + // TODO: to check whether isSearchable/isAggregateable takes into account the presence of the normalizer + boolean normalized = false; + return new KeywordEsField(fieldName, props, isAggregateable, length, normalized, isAlias); + } + if (esType == DATETIME) { + return DateEsField.dateEsField(fieldName, props, isAggregateable); + } + if (esType == UNSUPPORTED) { + String originalType = metricType == TimeSeriesParams.MetricType.COUNTER ? "counter" : typeName; + return new UnsupportedEsField(fieldName, originalType, null, props); + } + + return new EsField(fieldName, esType, props, isAggregateable, isAlias); + } + + private static FieldCapabilitiesRequest createFieldCapsRequest( + String index, + Set fieldNames, + IndicesOptions indicesOptions, + Map runtimeMappings + ) { + return new FieldCapabilitiesRequest().indices(Strings.commaDelimitedListToStringArray(index)) + .fields(fieldNames.toArray(String[]::new)) + .includeUnmapped(true) + .runtimeFields(runtimeMappings) + // lenient because we throw our own errors looking at the response e.g. if something was not resolved + // also because this way security doesn't throw authorization exceptions but rather honors ignore_unavailable + .indicesOptions(indicesOptions); + } + + private static FieldCapabilitiesRequest createFieldCapsRequest( + String index, + Set fieldNames, + boolean includeFrozen, + Map runtimeMappings + ) { + IndicesOptions indicesOptions = includeFrozen ? FIELD_CAPS_FROZEN_INDICES_OPTIONS : FIELD_CAPS_INDICES_OPTIONS; + return createFieldCapsRequest(index, fieldNames, indicesOptions, runtimeMappings); + } + + /** + * Resolves a pattern to multiple, separate indices. Doesn't perform validation. + */ + public void resolveAsSeparateMappings( + String indexWildcard, + String javaRegex, + boolean includeFrozen, + Map runtimeMappings, + ActionListener> listener + ) { + FieldCapabilitiesRequest fieldRequest = createFieldCapsRequest(indexWildcard, ALL_FIELDS, includeFrozen, runtimeMappings); + client.fieldCaps(fieldRequest, listener.delegateFailureAndWrap((delegate, response) -> { + client.admin().indices().getAliases(createGetAliasesRequest(response, includeFrozen), wrap(aliases -> { + delegate.onResponse(separateMappings(typeRegistry, javaRegex, response, aliases.getAliases())); + }, ex -> { + if (ex instanceof IndexNotFoundException || ex instanceof ElasticsearchSecurityException) { + delegate.onResponse(separateMappings(typeRegistry, javaRegex, response, null)); + } else { + delegate.onFailure(ex); + } + })); + })); + + } + + private static GetAliasesRequest createGetAliasesRequest(FieldCapabilitiesResponse response, boolean includeFrozen) { + return new GetAliasesRequest().aliases("*") + .indices(response.getIndices()) + .indicesOptions(includeFrozen ? FIELD_CAPS_FROZEN_INDICES_OPTIONS : FIELD_CAPS_INDICES_OPTIONS); + } + + public static List separateMappings( + DataTypeRegistry typeRegistry, + String javaRegex, + FieldCapabilitiesResponse fieldCaps, + Map> aliases + ) { + return buildIndices(typeRegistry, javaRegex, fieldCaps, aliases, Function.identity(), (s, cap) -> null, null, null); + } + + private static class Fields { + final Map hierarchicalMapping = new TreeMap<>(); + final Map flattedMapping = new LinkedHashMap<>(); + } + + /** + * Assemble an index-based mapping from the field caps (which is field based) by looking at the indices associated with + * each field. + */ + private static List buildIndices( + DataTypeRegistry typeRegistry, + String javaRegex, + FieldCapabilitiesResponse fieldCapsResponse, + Map> aliases, + Function indexNameProcessor, + BiFunction, InvalidMappedField> validityVerifier, + BiConsumer fieldUpdater, + Set allowedMetadataFields + ) { + + if ((fieldCapsResponse.getIndices() == null || fieldCapsResponse.getIndices().length == 0) + && (aliases == null || aliases.isEmpty())) { + return emptyList(); + } + + Set resolvedAliases = new HashSet<>(); + if (aliases != null) { + for (var aliasList : aliases.values()) { + for (AliasMetadata alias : aliasList) { + resolvedAliases.add(alias.getAlias()); + } + } + } + + Map indices = Maps.newLinkedHashMapWithExpectedSize(fieldCapsResponse.getIndices().length + resolvedAliases.size()); + Pattern pattern = javaRegex != null ? Pattern.compile(javaRegex) : null; + + // sort fields in reverse order to build the field hierarchy + TreeMap> sortedFields = new TreeMap<>(Collections.reverseOrder()); + final Map> fieldCaps = fieldCapsResponse.get(); + for (Entry> entry : fieldCaps.entrySet()) { + String fieldName = entry.getKey(); + // skip specific metadata fields + if ((allowedMetadataFields != null && allowedMetadataFields.contains(fieldName)) + || fieldCapsResponse.isMetadataField(fieldName) == false) { + sortedFields.put(fieldName, entry.getValue()); + } + } + + for (Entry> entry : sortedFields.entrySet()) { + String fieldName = entry.getKey(); + Map types = entry.getValue(); + final InvalidMappedField invalidField = validityVerifier.apply(fieldName, types); + // apply verification for fields belonging to index aliases + Map invalidFieldsForAliases = getInvalidFieldsForAliases(fieldName, types, aliases); + // For ESQL there are scenarios where there is no field asked from field_caps and the field_caps response only contains + // the list of indices. To be able to still have an "indices" list properly built (even if empty), the metadata fields are + // accepted but not actually added to each index hierarchy. + boolean isMetadataField = allowedMetadataFields != null && allowedMetadataFields.contains(fieldName); + + // check each type + for (Entry typeEntry : types.entrySet()) { + if (UNMAPPED.equals(typeEntry.getKey())) { + continue; + } + FieldCapabilities typeCap = typeEntry.getValue(); + String[] capIndices = typeCap.indices(); + + // compute the actual indices - if any are specified, take into account the unmapped indices + final String[] concreteIndices; + if (capIndices != null) { + concreteIndices = capIndices; + } else { + concreteIndices = fieldCapsResponse.getIndices(); + } + + Set uniqueAliases = new LinkedHashSet<>(); + // put the field in their respective mappings and collect the aliases names + for (String index : concreteIndices) { + List concreteIndexAliases = aliases != null ? aliases.get(index) : null; + if (concreteIndexAliases != null) { + for (AliasMetadata e : concreteIndexAliases) { + uniqueAliases.add(e.alias()); + } + } + // TODO is split still needed? + if (pattern == null || pattern.matcher(splitQualifiedIndex(index).v2()).matches()) { + String indexName = indexNameProcessor.apply(index); + Fields indexFields = indices.computeIfAbsent(indexName, k -> new Fields()); + EsField field = indexFields.flattedMapping.get(fieldName); + // create field hierarchy or update it in case of an invalid field + if (isMetadataField == false + && (field == null || (invalidField != null && (field instanceof InvalidMappedField) == false))) { + createField(typeRegistry, fieldName, indexFields, fieldCaps, invalidField, typeCap); + + // In evolving mappings, it is possible for a field to be promoted to an object in new indices + // meaning there are subfields associated with this *invalid* field. + // index_A: file -> keyword + // index_B: file -> object, file.name = keyword + // + // In the scenario above file is problematic but file.name is not. This scenario is addressed + // below through the dedicated callback - copy the existing properties or drop them all together. + // Note this applies for *invalid* fields (that have conflicts), not *unsupported* (those that cannot be read) + // See https://github.com/elastic/elasticsearch/pull/100875 + + // Postpone the call until is really needed + if (fieldUpdater != null && field != null) { + EsField newField = indexFields.flattedMapping.get(fieldName); + if (newField != field && newField instanceof InvalidMappedField newInvalidField) { + fieldUpdater.accept(field, newInvalidField); + } + } + } + } + } + // put the field in their respective mappings by alias name + for (String index : uniqueAliases) { + Fields indexFields = indices.computeIfAbsent(index, k -> new Fields()); + EsField field = indexFields.flattedMapping.get(fieldName); + if (isMetadataField == false && field == null && invalidFieldsForAliases.get(index) == null) { + createField(typeRegistry, fieldName, indexFields, fieldCaps, invalidField, typeCap); + } + } + } + } + + // return indices in ascending order + List foundIndices = new ArrayList<>(indices.size()); + for (Entry entry : indices.entrySet()) { + foundIndices.add(new EsIndex(entry.getKey(), entry.getValue().hierarchicalMapping, Set.of(entry.getKey()))); + } + foundIndices.sort(Comparator.comparing(EsIndex::name)); + return foundIndices; + } + + private static void createField( + DataTypeRegistry typeRegistry, + String fieldName, + Fields indexFields, + Map> fieldCaps, + InvalidMappedField invalidField, + FieldCapabilities typeCap + ) { + int dot = fieldName.lastIndexOf('.'); + /* + * Looking up the "tree" at the parent fields here to see if the field is an alias. + * When the upper elements of the "tree" have no elements in fieldcaps, then this is an alias field. But not + * always: if there are two aliases - a.b.c.alias1 and a.b.c.alias2 - only one of them will be considered alias. + */ + Holder isAliasFieldType = new Holder<>(false); + if (dot >= 0) { + String parentName = fieldName.substring(0, dot); + if (indexFields.flattedMapping.get(parentName) == null) { + // lack of parent implies the field is an alias + if (fieldCaps.get(parentName) == null) { + isAliasFieldType.set(true); + } + } + } + + createField( + typeRegistry, + fieldName, + fieldCaps, + indexFields.hierarchicalMapping, + indexFields.flattedMapping, + s -> invalidField != null + ? invalidField + : createField( + typeRegistry, + s, + typeCap.getType(), + typeCap.getMetricType(), + new TreeMap<>(), + typeCap.isAggregatable(), + isAliasFieldType.get() + ) + ); + } + + /* + * Checks if the field is valid (same type and same capabilities - searchable/aggregatable) across indices belonging to a list + * of aliases. + * A field can look like the example below (generated by field_caps API). + * "name": { + * "text": { + * "type": "text", + * "searchable": false, + * "aggregatable": false, + * "indices": [ + * "bar", + * "foo" + * ], + * "non_searchable_indices": [ + * "foo" + * ] + * }, + * "keyword": { + * "type": "keyword", + * "searchable": false, + * "aggregatable": true, + * "non_aggregatable_indices": [ + * "bar", "baz" + * ] + * } + * } + */ + private static Map getInvalidFieldsForAliases( + String fieldName, + Map types, + Map> aliases + ) { + if (aliases == null || aliases.isEmpty()) { + return emptyMap(); + } + Map invalidFields = new HashMap<>(); + Map> typesErrors = new HashMap<>(); // map holding aliases and a list of unique field types across its indices + Map> aliasToIndices = new HashMap<>(); // map with aliases and their list of indices + + for (var entry : aliases.entrySet()) { + for (AliasMetadata aliasMetadata : entry.getValue()) { + String aliasName = aliasMetadata.alias(); + aliasToIndices.putIfAbsent(aliasName, new HashSet<>()); + aliasToIndices.get(aliasName).add(entry.getKey()); + } + } + + // iterate over each type + for (Entry type : types.entrySet()) { + String esFieldType = type.getKey(); + if (Objects.equals(esFieldType, UNMAPPED)) { + continue; + } + String[] indices = type.getValue().indices(); + // if there is a list of indices where this field type is defined + if (indices != null) { + // Look at all these indices' aliases and add the type of the field to a list (Set) with unique elements. + // A valid mapping for a field in an index alias should contain only one type. If it doesn't, this means that field + // is mapped as different types across the indices in this index alias. + for (String index : indices) { + List indexAliases = aliases.get(index); + if (indexAliases == null) { + continue; + } + for (AliasMetadata aliasMetadata : indexAliases) { + String aliasName = aliasMetadata.alias(); + if (typesErrors.containsKey(aliasName)) { + typesErrors.get(aliasName).add(esFieldType); + } else { + Set fieldTypes = new HashSet<>(); + fieldTypes.add(esFieldType); + typesErrors.put(aliasName, fieldTypes); + } + } + } + } + } + + for (String aliasName : aliasToIndices.keySet()) { + // if, for the same index alias, there are multiple field types for this fieldName ie the index alias has indices where the same + // field name is of different types + Set esFieldTypes = typesErrors.get(aliasName); + if (esFieldTypes != null && esFieldTypes.size() > 1) { + // consider the field as invalid, for the currently checked index alias + // the error message doesn't actually matter + invalidFields.put(aliasName, new InvalidMappedField(fieldName)); + } else { + // if the field type is the same across all this alias' indices, check the field's capabilities (searchable/aggregatable) + for (Entry type : types.entrySet()) { + if (Objects.equals(type.getKey(), UNMAPPED)) { + continue; + } + FieldCapabilities f = type.getValue(); + + // the existence of a list of non_aggregatable_indices is an indication that not all indices have the same capabilities + // but this list can contain indices belonging to other aliases, so we need to check only for this alias + if (f.nonAggregatableIndices() != null) { + Set aliasIndices = aliasToIndices.get(aliasName); + int nonAggregatableCount = 0; + // either all or none of the non-aggregatable indices belonging to a certain alias should be in this list + for (String nonAggIndex : f.nonAggregatableIndices()) { + if (aliasIndices.contains(nonAggIndex)) { + nonAggregatableCount++; + } + } + if (nonAggregatableCount > 0 && nonAggregatableCount != aliasIndices.size()) { + invalidFields.put(aliasName, new InvalidMappedField(fieldName)); + break; + } + } + + // perform the same check for non_searchable_indices list + if (f.nonSearchableIndices() != null) { + Set aliasIndices = aliasToIndices.get(aliasName); + int nonSearchableCount = 0; + // either all or none of the non-searchable indices belonging to a certain alias should be in this list + for (String nonSearchIndex : f.nonSearchableIndices()) { + if (aliasIndices.contains(nonSearchIndex)) { + nonSearchableCount++; + } + } + if (nonSearchableCount > 0 && nonSearchableCount != aliasIndices.size()) { + invalidFields.put(aliasName, new InvalidMappedField(fieldName)); + break; + } + } + } + } + } + + if (invalidFields.size() > 0) { + return invalidFields; + } + // everything checks + return emptyMap(); + } + + /** + * Callback interface used when transitioning an already discovered EsField to an InvalidMapped one. + * By default, this interface is not used, meaning when a field is marked as invalid all its subfields + * are removed (are dropped). + * For cases where this is not desired, a different strategy can be employed such as keeping the properties: + * @see IndexResolver#PRESERVE_PROPERTIES + */ + public interface ExistingFieldInvalidCallback extends BiConsumer {}; + + /** + * Preserve the properties (sub fields) of an existing field even when marking it as invalid. + */ + public static ExistingFieldInvalidCallback PRESERVE_PROPERTIES = (oldField, newField) -> { + var oldProps = oldField.getProperties(); + if (oldProps.size() > 0) { + newField.getProperties().putAll(oldProps); + } + }; +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/MappingException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/MappingException.java new file mode 100644 index 000000000000..16a450f5b849 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/MappingException.java @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.xpack.esql.core.QlClientException; + +public class MappingException extends QlClientException { + + public MappingException(String message, Object... args) { + super(message, args); + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/RemoteClusterResolver.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/RemoteClusterResolver.java new file mode 100644 index 000000000000..e83eddc71000 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/RemoteClusterResolver.java @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.common.settings.ClusterSettings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.transport.RemoteClusterAware; +import org.elasticsearch.transport.RemoteConnectionStrategy; + +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.CopyOnWriteArraySet; + +public final class RemoteClusterResolver extends RemoteClusterAware { + private final CopyOnWriteArraySet clusters; + + public RemoteClusterResolver(Settings settings, ClusterSettings clusterSettings) { + super(settings); + clusters = new CopyOnWriteArraySet<>(getEnabledRemoteClusters(settings)); + listenForUpdates(clusterSettings); + } + + @Override + protected void updateRemoteCluster(String clusterAlias, Settings settings) { + if (RemoteConnectionStrategy.isConnectionEnabled(clusterAlias, settings)) { + clusters.add(clusterAlias); + } else { + clusters.remove(clusterAlias); + } + } + + public Set remoteClusters() { + return new TreeSet<>(clusters); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/VersionCompatibilityChecks.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/VersionCompatibilityChecks.java new file mode 100644 index 000000000000..ce6d26bc3528 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/index/VersionCompatibilityChecks.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.index; + +import org.elasticsearch.TransportVersion; +import org.elasticsearch.TransportVersions; +import org.elasticsearch.Version; +import org.elasticsearch.core.Nullable; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import static org.elasticsearch.Version.V_8_2_0; +import static org.elasticsearch.Version.V_8_4_0; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; + +public final class VersionCompatibilityChecks { + + public static final Version INTRODUCING_UNSIGNED_LONG = V_8_2_0; + public static final TransportVersion INTRODUCING_UNSIGNED_LONG_TRANSPORT = TransportVersions.V_8_2_0; + public static final Version INTRODUCING_VERSION_FIELD_TYPE = V_8_4_0; + + private VersionCompatibilityChecks() {} + + public static boolean isTypeSupportedInVersion(DataType dataType, Version version) { + if (dataType == UNSIGNED_LONG) { + return supportsUnsignedLong(version); + } + if (dataType == VERSION) { + return supportsVersionType(version); + } + return true; + } + + /** + * Does the provided {@code version} support the unsigned_long type (PR#60050)? + */ + public static boolean supportsUnsignedLong(Version version) { + return INTRODUCING_UNSIGNED_LONG.compareTo(version) <= 0; + } + + /** + * Does the provided {@code version} support the version type (PR#85502)? + */ + public static boolean supportsVersionType(Version version) { + return INTRODUCING_VERSION_FIELD_TYPE.compareTo(version) <= 0; + } + + public static @Nullable Version versionIntroducingType(DataType dataType) { + if (dataType == UNSIGNED_LONG) { + return INTRODUCING_UNSIGNED_LONG; + } + if (dataType == VERSION) { + return INTRODUCING_VERSION_FIELD_TYPE; + } + + return null; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/optimizer/OptimizerRules.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/optimizer/OptimizerRules.java new file mode 100644 index 000000000000..4ec8ae3c3570 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/optimizer/OptimizerRules.java @@ -0,0 +1,1957 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.optimizer; + +import org.elasticsearch.common.util.set.Sets; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.function.Functions; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.SurrogateFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryPredicate; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.Range; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogic; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.ArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryComparisonInversible; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Neg; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Sub; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.In; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NotEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexMatch; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.StringPattern; +import org.elasticsearch.xpack.esql.core.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.util.ReflectionUtils; + +import java.time.DateTimeException; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; + +import static java.lang.Math.signum; +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; +import static org.elasticsearch.xpack.esql.core.expression.Literal.FALSE; +import static org.elasticsearch.xpack.esql.core.expression.Literal.TRUE; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.combineAnd; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.combineOr; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.inCommon; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.splitAnd; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.splitOr; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.subtract; +import static org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.ADD; +import static org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.DIV; +import static org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.MOD; +import static org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.MUL; +import static org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.SUB; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.util.CollectionUtils.combine; + +public final class OptimizerRules { + + public static final class ConstantFolding extends OptimizerExpressionRule { + + public ConstantFolding() { + super(TransformDirection.DOWN); + } + + @Override + public Expression rule(Expression e) { + return e.foldable() ? Literal.of(e) : e; + } + } + + /** + * This rule must always be placed after {@link LiteralsOnTheRight}, since it looks at TRUE/FALSE literals' existence + * on the right hand-side of the {@link Equals}/{@link NotEquals} expressions. + */ + public static final class BooleanFunctionEqualsElimination extends OptimizerExpressionRule { + + public BooleanFunctionEqualsElimination() { + super(TransformDirection.UP); + } + + @Override + protected Expression rule(BinaryComparison bc) { + if ((bc instanceof Equals || bc instanceof NotEquals) && bc.left() instanceof Function) { + // for expression "==" or "!=" TRUE/FALSE, return the expression itself or its negated variant + + if (TRUE.equals(bc.right())) { + return bc instanceof Equals ? bc.left() : new Not(bc.left().source(), bc.left()); + } + if (FALSE.equals(bc.right())) { + return bc instanceof Equals ? new Not(bc.left().source(), bc.left()) : bc.left(); + } + } + + return bc; + } + } + + public static class BooleanSimplification extends OptimizerExpressionRule { + + public BooleanSimplification() { + super(TransformDirection.UP); + } + + @Override + public Expression rule(ScalarFunction e) { + if (e instanceof And || e instanceof Or) { + return simplifyAndOr((BinaryPredicate) e); + } + if (e instanceof Not) { + return simplifyNot((Not) e); + } + + return e; + } + + private static Expression simplifyAndOr(BinaryPredicate bc) { + Expression l = bc.left(); + Expression r = bc.right(); + + if (bc instanceof And) { + if (TRUE.equals(l)) { + return r; + } + if (TRUE.equals(r)) { + return l; + } + + if (FALSE.equals(l) || FALSE.equals(r)) { + return new Literal(bc.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + if (l.semanticEquals(r)) { + return l; + } + + // + // common factor extraction -> (a || b) && (a || c) => a || (b && c) + // + List leftSplit = splitOr(l); + List rightSplit = splitOr(r); + + List common = inCommon(leftSplit, rightSplit); + if (common.isEmpty()) { + return bc; + } + List lDiff = subtract(leftSplit, common); + List rDiff = subtract(rightSplit, common); + // (a || b || c || ... ) && (a || b) => (a || b) + if (lDiff.isEmpty() || rDiff.isEmpty()) { + return combineOr(common); + } + // (a || b || c || ... ) && (a || b || d || ... ) => ((c || ...) && (d || ...)) || a || b + Expression combineLeft = combineOr(lDiff); + Expression combineRight = combineOr(rDiff); + return combineOr(combine(common, new And(combineLeft.source(), combineLeft, combineRight))); + } + + if (bc instanceof Or) { + if (TRUE.equals(l) || TRUE.equals(r)) { + return new Literal(bc.source(), Boolean.TRUE, DataTypes.BOOLEAN); + } + + if (FALSE.equals(l)) { + return r; + } + if (FALSE.equals(r)) { + return l; + } + + if (l.semanticEquals(r)) { + return l; + } + + // + // common factor extraction -> (a && b) || (a && c) => a && (b || c) + // + List leftSplit = splitAnd(l); + List rightSplit = splitAnd(r); + + List common = inCommon(leftSplit, rightSplit); + if (common.isEmpty()) { + return bc; + } + List lDiff = subtract(leftSplit, common); + List rDiff = subtract(rightSplit, common); + // (a || b || c || ... ) && (a || b) => (a || b) + if (lDiff.isEmpty() || rDiff.isEmpty()) { + return combineAnd(common); + } + // (a || b || c || ... ) && (a || b || d || ... ) => ((c || ...) && (d || ...)) || a || b + Expression combineLeft = combineAnd(lDiff); + Expression combineRight = combineAnd(rDiff); + return combineAnd(combine(common, new Or(combineLeft.source(), combineLeft, combineRight))); + } + + // TODO: eliminate conjunction/disjunction + return bc; + } + + @SuppressWarnings("rawtypes") + private Expression simplifyNot(Not n) { + Expression c = n.field(); + + if (TRUE.semanticEquals(c)) { + return new Literal(n.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + if (FALSE.semanticEquals(c)) { + return new Literal(n.source(), Boolean.TRUE, DataTypes.BOOLEAN); + } + + Expression negated = maybeSimplifyNegatable(c); + if (negated != null) { + return negated; + } + + if (c instanceof Not) { + return ((Not) c).field(); + } + + return n; + } + + /** + * @param e + * @return the negated expression or {@code null} if the parameter is not an instance of {@code Negatable} + */ + protected Expression maybeSimplifyNegatable(Expression e) { + if (e instanceof Negatable) { + return ((Negatable) e).negate(); + } + return null; + } + } + + public static class BinaryComparisonSimplification extends OptimizerExpressionRule { + + public BinaryComparisonSimplification() { + super(TransformDirection.DOWN); + } + + @Override + protected Expression rule(BinaryComparison bc) { + Expression l = bc.left(); + Expression r = bc.right(); + + // true for equality + if (bc instanceof Equals || bc instanceof GreaterThanOrEqual || bc instanceof LessThanOrEqual) { + if (l.nullable() == Nullability.FALSE && r.nullable() == Nullability.FALSE && l.semanticEquals(r)) { + return new Literal(bc.source(), Boolean.TRUE, DataTypes.BOOLEAN); + } + } + if (bc instanceof NullEquals) { + if (l.semanticEquals(r)) { + return new Literal(bc.source(), Boolean.TRUE, DataTypes.BOOLEAN); + } + if (Expressions.isNull(r)) { + return new IsNull(bc.source(), l); + } + } + + // false for equality + if (bc instanceof NotEquals || bc instanceof GreaterThan || bc instanceof LessThan) { + if (l.nullable() == Nullability.FALSE && r.nullable() == Nullability.FALSE && l.semanticEquals(r)) { + return new Literal(bc.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + } + + return bc; + } + } + + public static final class LiteralsOnTheRight extends OptimizerExpressionRule> { + + public LiteralsOnTheRight() { + super(TransformDirection.UP); + } + + @Override + public BinaryOperator rule(BinaryOperator be) { + return be.left() instanceof Literal && (be.right() instanceof Literal) == false ? be.swapLeftAndRight() : be; + } + } + + /** + * Propagate Equals to eliminate conjuncted Ranges or BinaryComparisons. + * When encountering a different Equals, non-containing {@link Range} or {@link BinaryComparison}, the conjunction becomes false. + * When encountering a containing {@link Range}, {@link BinaryComparison} or {@link NotEquals}, these get eliminated by the equality. + * + * Since this rule can eliminate Ranges and BinaryComparisons, it should be applied before {@link CombineBinaryComparisons}. + * + * This rule doesn't perform any promotion of {@link BinaryComparison}s, that is handled by + * {@link CombineBinaryComparisons} on purpose as the resulting Range might be foldable + * (which is picked by the folding rule on the next run). + */ + public static final class PropagateEquals extends OptimizerExpressionRule { + + public PropagateEquals() { + super(TransformDirection.DOWN); + } + + @Override + public Expression rule(BinaryLogic e) { + if (e instanceof And) { + return propagate((And) e); + } else if (e instanceof Or) { + return propagate((Or) e); + } + return e; + } + + // combine conjunction + private static Expression propagate(And and) { + List ranges = new ArrayList<>(); + // Only equalities, not-equalities and inequalities with a foldable .right are extracted separately; + // the others go into the general 'exps'. + List equals = new ArrayList<>(); + List notEquals = new ArrayList<>(); + List inequalities = new ArrayList<>(); + List exps = new ArrayList<>(); + + boolean changed = false; + + for (Expression ex : Predicates.splitAnd(and)) { + if (ex instanceof Range) { + ranges.add((Range) ex); + } else if (ex instanceof Equals || ex instanceof NullEquals) { + BinaryComparison otherEq = (BinaryComparison) ex; + // equals on different values evaluate to FALSE + // ignore date/time fields as equality comparison might actually be a range check + if (otherEq.right().foldable() && DataTypes.isDateTime(otherEq.left().dataType()) == false) { + for (BinaryComparison eq : equals) { + if (otherEq.left().semanticEquals(eq.left())) { + Integer comp = BinaryComparison.compare(eq.right().fold(), otherEq.right().fold()); + if (comp != null) { + // var cannot be equal to two different values at the same time + if (comp != 0) { + return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + } + } + } + equals.add(otherEq); + } else { + exps.add(otherEq); + } + } else if (ex instanceof GreaterThan + || ex instanceof GreaterThanOrEqual + || ex instanceof LessThan + || ex instanceof LessThanOrEqual) { + BinaryComparison bc = (BinaryComparison) ex; + if (bc.right().foldable()) { + inequalities.add(bc); + } else { + exps.add(ex); + } + } else if (ex instanceof NotEquals otherNotEq) { + if (otherNotEq.right().foldable()) { + notEquals.add(otherNotEq); + } else { + exps.add(ex); + } + } else { + exps.add(ex); + } + } + + // check + for (BinaryComparison eq : equals) { + Object eqValue = eq.right().fold(); + + for (Iterator iterator = ranges.iterator(); iterator.hasNext();) { + Range range = iterator.next(); + + if (range.value().semanticEquals(eq.left())) { + // if equals is outside the interval, evaluate the whole expression to FALSE + if (range.lower().foldable()) { + Integer compare = BinaryComparison.compare(range.lower().fold(), eqValue); + if (compare != null && ( + // eq outside the lower boundary + compare > 0 || + // eq matches the boundary but should not be included + (compare == 0 && range.includeLower() == false))) { + return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + } + if (range.upper().foldable()) { + Integer compare = BinaryComparison.compare(range.upper().fold(), eqValue); + if (compare != null && ( + // eq outside the upper boundary + compare < 0 || + // eq matches the boundary but should not be included + (compare == 0 && range.includeUpper() == false))) { + return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + } + + // it's in the range and thus, remove it + iterator.remove(); + changed = true; + } + } + + // evaluate all NotEquals against the Equal + for (Iterator iter = notEquals.iterator(); iter.hasNext();) { + NotEquals neq = iter.next(); + if (eq.left().semanticEquals(neq.left())) { + Integer comp = BinaryComparison.compare(eqValue, neq.right().fold()); + if (comp != null) { + if (comp == 0) { // clashing and conflicting: a = 1 AND a != 1 + return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } else { // clashing and redundant: a = 1 AND a != 2 + iter.remove(); + changed = true; + } + } + } + } + + // evaluate all inequalities against the Equal + for (Iterator iter = inequalities.iterator(); iter.hasNext();) { + BinaryComparison bc = iter.next(); + if (eq.left().semanticEquals(bc.left())) { + Integer compare = BinaryComparison.compare(eqValue, bc.right().fold()); + if (compare != null) { + if (bc instanceof LessThan || bc instanceof LessThanOrEqual) { // a = 2 AND a />= ? + if ((compare == 0 && bc instanceof GreaterThan) || // a = 2 AND a > 2 + compare < 0) { // a = 2 AND a >/>= 3 + return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + } + + iter.remove(); + changed = true; + } + } + } + } + + return changed ? Predicates.combineAnd(CollectionUtils.combine(exps, equals, notEquals, inequalities, ranges)) : and; + } + + // combine disjunction: + // a = 2 OR a > 3 -> nop; a = 2 OR a > 1 -> a > 1 + // a = 2 OR a < 3 -> a < 3; a = 2 OR a < 1 -> nop + // a = 2 OR 3 < a < 5 -> nop; a = 2 OR 1 < a < 3 -> 1 < a < 3; a = 2 OR 0 < a < 1 -> nop + // a = 2 OR a != 2 -> TRUE; a = 2 OR a = 5 -> nop; a = 2 OR a != 5 -> a != 5 + private static Expression propagate(Or or) { + List exps = new ArrayList<>(); + List equals = new ArrayList<>(); // foldable right term Equals + List notEquals = new ArrayList<>(); // foldable right term NotEquals + List ranges = new ArrayList<>(); + List inequalities = new ArrayList<>(); // foldable right term (=limit) BinaryComparision + + // split expressions by type + for (Expression ex : Predicates.splitOr(or)) { + if (ex instanceof Equals eq) { + if (eq.right().foldable()) { + equals.add(eq); + } else { + exps.add(ex); + } + } else if (ex instanceof NotEquals neq) { + if (neq.right().foldable()) { + notEquals.add(neq); + } else { + exps.add(ex); + } + } else if (ex instanceof Range) { + ranges.add((Range) ex); + } else if (ex instanceof BinaryComparison bc) { + if (bc.right().foldable()) { + inequalities.add(bc); + } else { + exps.add(ex); + } + } else { + exps.add(ex); + } + } + + boolean updated = false; // has the expression been modified? + + // evaluate the impact of each Equal over the different types of Expressions + for (Iterator iterEq = equals.iterator(); iterEq.hasNext();) { + Equals eq = iterEq.next(); + Object eqValue = eq.right().fold(); + boolean removeEquals = false; + + // Equals OR NotEquals + for (NotEquals neq : notEquals) { + if (eq.left().semanticEquals(neq.left())) { // a = 2 OR a != ? -> ... + Integer comp = BinaryComparison.compare(eqValue, neq.right().fold()); + if (comp != null) { + if (comp == 0) { // a = 2 OR a != 2 -> TRUE + return TRUE; + } else { // a = 2 OR a != 5 -> a != 5 + removeEquals = true; + break; + } + } + } + } + if (removeEquals) { + iterEq.remove(); + updated = true; + continue; + } + + // Equals OR Range + for (int i = 0; i < ranges.size(); i++) { // might modify list, so use index loop + Range range = ranges.get(i); + if (eq.left().semanticEquals(range.value())) { + Integer lowerComp = range.lower().foldable() ? BinaryComparison.compare(eqValue, range.lower().fold()) : null; + Integer upperComp = range.upper().foldable() ? BinaryComparison.compare(eqValue, range.upper().fold()) : null; + + if (lowerComp != null && lowerComp == 0) { + if (range.includeLower() == false) { // a = 2 OR 2 < a < ? -> 2 <= a < ? + ranges.set( + i, + new Range( + range.source(), + range.value(), + range.lower(), + true, + range.upper(), + range.includeUpper(), + range.zoneId() + ) + ); + } // else : a = 2 OR 2 <= a < ? -> 2 <= a < ? + removeEquals = true; // update range with lower equality instead or simply superfluous + break; + } else if (upperComp != null && upperComp == 0) { + if (range.includeUpper() == false) { // a = 2 OR ? < a < 2 -> ? < a <= 2 + ranges.set( + i, + new Range( + range.source(), + range.value(), + range.lower(), + range.includeLower(), + range.upper(), + true, + range.zoneId() + ) + ); + } // else : a = 2 OR ? < a <= 2 -> ? < a <= 2 + removeEquals = true; // update range with upper equality instead + break; + } else if (lowerComp != null && upperComp != null) { + if (0 < lowerComp && upperComp < 0) { // a = 2 OR 1 < a < 3 + removeEquals = true; // equality is superfluous + break; + } + } + } + } + if (removeEquals) { + iterEq.remove(); + updated = true; + continue; + } + + // Equals OR Inequality + for (int i = 0; i < inequalities.size(); i++) { + BinaryComparison bc = inequalities.get(i); + if (eq.left().semanticEquals(bc.left())) { + Integer comp = BinaryComparison.compare(eqValue, bc.right().fold()); + if (comp != null) { + if (bc instanceof GreaterThan || bc instanceof GreaterThanOrEqual) { + if (comp < 0) { // a = 1 OR a > 2 -> nop + continue; + } else if (comp == 0 && bc instanceof GreaterThan) { // a = 2 OR a > 2 -> a >= 2 + inequalities.set(i, new GreaterThanOrEqual(bc.source(), bc.left(), bc.right(), bc.zoneId())); + } // else (0 < comp || bc instanceof GreaterThanOrEqual) : + // a = 3 OR a > 2 -> a > 2; a = 2 OR a => 2 -> a => 2 + + removeEquals = true; // update range with equality instead or simply superfluous + break; + } else if (bc instanceof LessThan || bc instanceof LessThanOrEqual) { + if (comp > 0) { // a = 2 OR a < 1 -> nop + continue; + } + if (comp == 0 && bc instanceof LessThan) { // a = 2 OR a < 2 -> a <= 2 + inequalities.set(i, new LessThanOrEqual(bc.source(), bc.left(), bc.right(), bc.zoneId())); + } // else (comp < 0 || bc instanceof LessThanOrEqual) : a = 2 OR a < 3 -> a < 3; a = 2 OR a <= 2 -> a <= 2 + removeEquals = true; // update range with equality instead or simply superfluous + break; + } + } + } + } + if (removeEquals) { + iterEq.remove(); + updated = true; + } + } + + return updated ? Predicates.combineOr(CollectionUtils.combine(exps, equals, notEquals, inequalities, ranges)) : or; + } + } + + public static final class CombineBinaryComparisons extends OptimizerExpressionRule { + + public CombineBinaryComparisons() { + super(TransformDirection.DOWN); + } + + @Override + public Expression rule(BinaryLogic e) { + if (e instanceof And) { + return combine((And) e); + } else if (e instanceof Or) { + return combine((Or) e); + } + return e; + } + + // combine conjunction + private static Expression combine(And and) { + List ranges = new ArrayList<>(); + List bcs = new ArrayList<>(); + List exps = new ArrayList<>(); + + boolean changed = false; + + List andExps = Predicates.splitAnd(and); + // Ranges need to show up before BinaryComparisons in list, to allow the latter be optimized away into a Range, if possible. + // NotEquals need to be last in list, to have a complete set of Ranges (ranges) and BinaryComparisons (bcs) and allow these to + // optimize the NotEquals away. + andExps.sort((o1, o2) -> { + if (o1 instanceof Range && o2 instanceof Range) { + return 0; // keep ranges' order + } else if (o1 instanceof Range || o2 instanceof Range) { + return o2 instanceof Range ? 1 : -1; // push Ranges down + } else if (o1 instanceof NotEquals && o2 instanceof NotEquals) { + return 0; // keep NotEquals' order + } else if (o1 instanceof NotEquals || o2 instanceof NotEquals) { + return o1 instanceof NotEquals ? 1 : -1; // push NotEquals up + } else { + return 0; // keep non-Ranges' and non-NotEquals' order + } + }); + for (Expression ex : andExps) { + if (ex instanceof Range r) { + if (findExistingRange(r, ranges, true)) { + changed = true; + } else { + ranges.add(r); + } + } else if (ex instanceof BinaryComparison bc && (ex instanceof Equals || ex instanceof NotEquals) == false) { + + if (bc.right().foldable() && (findConjunctiveComparisonInRange(bc, ranges) || findExistingComparison(bc, bcs, true))) { + changed = true; + } else { + bcs.add(bc); + } + } else if (ex instanceof NotEquals neq) { + if (neq.right().foldable() && notEqualsIsRemovableFromConjunction(neq, ranges, bcs)) { + // the non-equality can simply be dropped: either superfluous or has been merged with an updated range/inequality + changed = true; + } else { // not foldable OR not overlapping + exps.add(ex); + } + } else { + exps.add(ex); + } + } + + // finally try combining any left BinaryComparisons into possible Ranges + // this could be a different rule but it's clearer here wrt the order of comparisons + + for (int i = 0, step = 1; i < bcs.size() - 1; i += step, step = 1) { + BinaryComparison main = bcs.get(i); + + for (int j = i + 1; j < bcs.size(); j++) { + BinaryComparison other = bcs.get(j); + + if (main.left().semanticEquals(other.left())) { + // >/>= AND />= + else if ((other instanceof GreaterThan || other instanceof GreaterThanOrEqual) + && (main instanceof LessThan || main instanceof LessThanOrEqual)) { + bcs.remove(j); + bcs.remove(i); + + ranges.add( + new Range( + and.source(), + main.left(), + other.right(), + other instanceof GreaterThanOrEqual, + main.right(), + main instanceof LessThanOrEqual, + main.zoneId() + ) + ); + + changed = true; + step = 0; + break; + } + } + } + } + + return changed ? Predicates.combineAnd(CollectionUtils.combine(exps, bcs, ranges)) : and; + } + + // combine disjunction + private static Expression combine(Or or) { + List bcs = new ArrayList<>(); + List ranges = new ArrayList<>(); + List exps = new ArrayList<>(); + + boolean changed = false; + + for (Expression ex : Predicates.splitOr(or)) { + if (ex instanceof Range r) { + if (findExistingRange(r, ranges, false)) { + changed = true; + } else { + ranges.add(r); + } + } else if (ex instanceof BinaryComparison bc) { + if (bc.right().foldable() && findExistingComparison(bc, bcs, false)) { + changed = true; + } else { + bcs.add(bc); + } + } else { + exps.add(ex); + } + } + + return changed ? Predicates.combineOr(CollectionUtils.combine(exps, bcs, ranges)) : or; + } + + private static boolean findExistingRange(Range main, List ranges, boolean conjunctive) { + if (main.lower().foldable() == false && main.upper().foldable() == false) { + return false; + } + // NB: the loop modifies the list (hence why the int is used) + for (int i = 0; i < ranges.size(); i++) { + Range other = ranges.get(i); + + if (main.value().semanticEquals(other.value())) { + + // make sure the comparison was done + boolean compared = false; + + boolean lower = false; + boolean upper = false; + // boundary equality (useful to differentiate whether a range is included or not) + // and thus whether it should be preserved or ignored + boolean lowerEq = false; + boolean upperEq = false; + + // evaluate lower + if (main.lower().foldable() && other.lower().foldable()) { + compared = true; + + Integer comp = BinaryComparison.compare(main.lower().fold(), other.lower().fold()); + // values are comparable + if (comp != null) { + // boundary equality + lowerEq = comp == 0 && main.includeLower() == other.includeLower(); + // AND + if (conjunctive) { + // (2 < a < 3) AND (1 < a < 3) -> (2 < a < 3) + lower = comp > 0 || + // (2 < a < 3) AND (2 <= a < 3) -> (2 < a < 3) + (comp == 0 && main.includeLower() == false && other.includeLower()); + } + // OR + else { + // (1 < a < 3) OR (2 < a < 3) -> (1 < a < 3) + lower = comp < 0 || + // (2 <= a < 3) OR (2 < a < 3) -> (2 <= a < 3) + (comp == 0 && main.includeLower() && other.includeLower() == false) || lowerEq; + } + } + } + // evaluate upper + if (main.upper().foldable() && other.upper().foldable()) { + compared = true; + + Integer comp = BinaryComparison.compare(main.upper().fold(), other.upper().fold()); + // values are comparable + if (comp != null) { + // boundary equality + upperEq = comp == 0 && main.includeUpper() == other.includeUpper(); + + // AND + if (conjunctive) { + // (1 < a < 2) AND (1 < a < 3) -> (1 < a < 2) + upper = comp < 0 || + // (1 < a < 2) AND (1 < a <= 2) -> (1 < a < 2) + (comp == 0 && main.includeUpper() == false && other.includeUpper()); + } + // OR + else { + // (1 < a < 3) OR (1 < a < 2) -> (1 < a < 3) + upper = comp > 0 || + // (1 < a <= 3) OR (1 < a < 3) -> (2 < a < 3) + (comp == 0 && main.includeUpper() && other.includeUpper() == false) || upperEq; + } + } + } + + // AND - at least one of lower or upper + if (conjunctive) { + // can tighten range + if (lower || upper) { + ranges.set( + i, + new Range( + main.source(), + main.value(), + lower ? main.lower() : other.lower(), + lower ? main.includeLower() : other.includeLower(), + upper ? main.upper() : other.upper(), + upper ? main.includeUpper() : other.includeUpper(), + main.zoneId() + ) + ); + } + + // range was comparable + return compared; + } + // OR - needs both upper and lower to loosen range + else { + // can loosen range + if (lower && upper) { + ranges.set( + i, + new Range( + main.source(), + main.value(), + main.lower(), + main.includeLower(), + main.upper(), + main.includeUpper(), + main.zoneId() + ) + ); + return true; + } + + // if the range in included, no need to add it + return compared && (((lower && lowerEq == false) || (upper && upperEq == false)) == false); + } + } + } + return false; + } + + private static boolean findConjunctiveComparisonInRange(BinaryComparison main, List ranges) { + Object value = main.right().fold(); + + // NB: the loop modifies the list (hence why the int is used) + for (int i = 0; i < ranges.size(); i++) { + Range other = ranges.get(i); + + if (main.left().semanticEquals(other.value())) { + + if (main instanceof GreaterThan || main instanceof GreaterThanOrEqual) { + if (other.lower().foldable()) { + Integer comp = BinaryComparison.compare(value, other.lower().fold()); + if (comp != null) { + // 2 < a AND (2 <= a < 3) -> 2 < a < 3 + boolean lowerEq = comp == 0 && other.includeLower() && main instanceof GreaterThan; + // 2 < a AND (1 < a < 3) -> 2 < a < 3 + boolean lower = comp > 0 || lowerEq; + + if (lower) { + ranges.set( + i, + new Range( + other.source(), + other.value(), + main.right(), + lowerEq ? false : main instanceof GreaterThanOrEqual, + other.upper(), + other.includeUpper(), + other.zoneId() + ) + ); + } + + // found a match + return true; + } + } + } else if (main instanceof LessThan || main instanceof LessThanOrEqual) { + if (other.upper().foldable()) { + Integer comp = BinaryComparison.compare(value, other.upper().fold()); + if (comp != null) { + // a < 2 AND (1 < a <= 2) -> 1 < a < 2 + boolean upperEq = comp == 0 && other.includeUpper() && main instanceof LessThan; + // a < 2 AND (1 < a < 3) -> 1 < a < 2 + boolean upper = comp < 0 || upperEq; + + if (upper) { + ranges.set( + i, + new Range( + other.source(), + other.value(), + other.lower(), + other.includeLower(), + main.right(), + upperEq ? false : main instanceof LessThanOrEqual, + other.zoneId() + ) + ); + } + + // found a match + return true; + } + } + } + + return false; + } + } + return false; + } + + /** + * Find commonalities between the given comparison in the given list. + * The method can be applied both for conjunctive (AND) or disjunctive purposes (OR). + */ + private static boolean findExistingComparison(BinaryComparison main, List bcs, boolean conjunctive) { + Object value = main.right().fold(); + + // NB: the loop modifies the list (hence why the int is used) + for (int i = 0; i < bcs.size(); i++) { + BinaryComparison other = bcs.get(i); + // skip if cannot evaluate + if (other.right().foldable() == false) { + continue; + } + // if bc is a higher/lower value or gte vs gt, use it instead + if ((other instanceof GreaterThan || other instanceof GreaterThanOrEqual) + && (main instanceof GreaterThan || main instanceof GreaterThanOrEqual)) { + + if (main.left().semanticEquals(other.left())) { + Integer compare = BinaryComparison.compare(value, other.right().fold()); + + if (compare != null) { + // AND + if ((conjunctive && + // a > 3 AND a > 2 -> a > 3 + (compare > 0 || + // a > 2 AND a >= 2 -> a > 2 + (compare == 0 && main instanceof GreaterThan && other instanceof GreaterThanOrEqual))) || + // OR + (conjunctive == false && + // a > 2 OR a > 3 -> a > 2 + (compare < 0 || + // a >= 2 OR a > 2 -> a >= 2 + (compare == 0 && main instanceof GreaterThanOrEqual && other instanceof GreaterThan)))) { + bcs.remove(i); + bcs.add(i, main); + } + // found a match + return true; + } + + return false; + } + } + // if bc is a lower/higher value or lte vs lt, use it instead + else if ((other instanceof LessThan || other instanceof LessThanOrEqual) + && (main instanceof LessThan || main instanceof LessThanOrEqual)) { + + if (main.left().semanticEquals(other.left())) { + Integer compare = BinaryComparison.compare(value, other.right().fold()); + + if (compare != null) { + // AND + if ((conjunctive && + // a < 2 AND a < 3 -> a < 2 + (compare < 0 || + // a < 2 AND a <= 2 -> a < 2 + (compare == 0 && main instanceof LessThan && other instanceof LessThanOrEqual))) || + // OR + (conjunctive == false && + // a < 2 OR a < 3 -> a < 3 + (compare > 0 || + // a <= 2 OR a < 2 -> a <= 2 + (compare == 0 && main instanceof LessThanOrEqual && other instanceof LessThan)))) { + bcs.remove(i); + bcs.add(i, main); + + } + // found a match + return true; + } + + return false; + } + } + } + + return false; + } + + private static boolean notEqualsIsRemovableFromConjunction(NotEquals notEquals, List ranges, List bcs) { + Object neqVal = notEquals.right().fold(); + Integer comp; + + // check on "condition-overlapping" ranges: + // a != 2 AND 3 < a < 5 -> 3 < a < 5; a != 2 AND 0 < a < 1 -> 0 < a < 1 (discard NotEquals) + // a != 2 AND 2 <= a < 3 -> 2 < a < 3; a != 3 AND 2 < a <= 3 -> 2 < a < 3 (discard NotEquals, plus update Range) + // a != 2 AND 1 < a < 3 -> nop (do nothing) + for (int i = 0; i < ranges.size(); i++) { + Range range = ranges.get(i); + + if (notEquals.left().semanticEquals(range.value())) { + comp = range.lower().foldable() ? BinaryComparison.compare(neqVal, range.lower().fold()) : null; + if (comp != null) { + if (comp <= 0) { + if (comp == 0 && range.includeLower()) { // a != 2 AND 2 <= a < ? -> 2 < a < ? + ranges.set( + i, + new Range( + range.source(), + range.value(), + range.lower(), + false, + range.upper(), + range.includeUpper(), + range.zoneId() + ) + ); + } + // else: !.includeLower() : a != 2 AND 2 < a < 3 -> 2 < a < 3; or: + // else: comp < 0 : a != 2 AND 3 < a < ? -> 3 < a < ? + + return true; + } else { // comp > 0 : a != 4 AND 2 < a < ? : can only remove NotEquals if outside the range + comp = range.upper().foldable() ? BinaryComparison.compare(neqVal, range.upper().fold()) : null; + if (comp != null && comp >= 0) { + if (comp == 0 && range.includeUpper()) { // a != 4 AND 2 < a <= 4 -> 2 < a < 4 + ranges.set( + i, + new Range( + range.source(), + range.value(), + range.lower(), + range.includeLower(), + range.upper(), + false, + range.zoneId() + ) + ); + } + // else: !.includeUpper() : a != 4 AND 2 < a < 4 -> 2 < a < 4 + // else: comp > 0 : a != 4 AND 2 < a < 3 -> 2 < a < 3 + + return true; + } + // else: comp < 0 : a != 4 AND 2 < a < 5 -> nop; or: + // else: comp == null : upper bound not comparable -> nop + } + } // else: comp == null : lower bound not comparable: evaluate upper bound, in case non-equality value is ">=" + + comp = range.upper().foldable() ? BinaryComparison.compare(neqVal, range.upper().fold()) : null; + if (comp != null && comp >= 0) { + if (comp == 0 && range.includeUpper()) { // a != 3 AND ?? < a <= 3 -> ?? < a < 3 + ranges.set( + i, + new Range( + range.source(), + range.value(), + range.lower(), + range.includeLower(), + range.upper(), + false, + range.zoneId() + ) + ); + } + // else: !.includeUpper() : a != 3 AND ?? < a < 3 -> ?? < a < 3 + // else: comp > 0 : a != 3 and ?? < a < 2 -> ?? < a < 2 + + return true; + } + // else: comp < 0 : a != 3 AND ?? < a < 4 -> nop, as a decision can't be drawn; or: + // else: comp == null : a != 3 AND ?? < a < ?? -> nop + } + } + + // check on "condition-overlapping" inequalities: + // a != 2 AND a > 3 -> a > 3 (discard NotEquals) + // a != 2 AND a >= 2 -> a > 2 (discard NotEquals plus update inequality) + // a != 2 AND a > 1 -> nop (do nothing) + // + // a != 2 AND a < 3 -> nop + // a != 2 AND a <= 2 -> a < 2 + // a != 2 AND a < 1 -> a < 1 + for (int i = 0; i < bcs.size(); i++) { + BinaryComparison bc = bcs.get(i); + + if (notEquals.left().semanticEquals(bc.left())) { + if (bc instanceof LessThan || bc instanceof LessThanOrEqual) { + comp = bc.right().foldable() ? BinaryComparison.compare(neqVal, bc.right().fold()) : null; + if (comp != null) { + if (comp >= 0) { + if (comp == 0 && bc instanceof LessThanOrEqual) { // a != 2 AND a <= 2 -> a < 2 + bcs.set(i, new LessThan(bc.source(), bc.left(), bc.right(), bc.zoneId())); + } // else : comp > 0 (a != 2 AND a a a < 2) + return true; + } // else: comp < 0 : a != 2 AND a nop + } // else: non-comparable, nop + } else if (bc instanceof GreaterThan || bc instanceof GreaterThanOrEqual) { + comp = bc.right().foldable() ? BinaryComparison.compare(neqVal, bc.right().fold()) : null; + if (comp != null) { + if (comp <= 0) { + if (comp == 0 && bc instanceof GreaterThanOrEqual) { // a != 2 AND a >= 2 -> a > 2 + bcs.set(i, new GreaterThan(bc.source(), bc.left(), bc.right(), bc.zoneId())); + } // else: comp < 0 (a != 2 AND a >/>= 3 -> a >/>= 3), or == 0 && bc i.of ">" (a != 2 AND a > 2 -> a > 2) + return true; + } // else: comp > 0 : a != 2 AND a >/>= 1 -> nop + } // else: non-comparable, nop + } // else: other non-relevant type + } + } + + return false; + } + + } + + /** + * Combine disjunctions on the same field into an In expression. + * This rule looks for both simple equalities: + * 1. a == 1 OR a == 2 becomes a IN (1, 2) + * and combinations of In + * 2. a == 1 OR a IN (2) becomes a IN (1, 2) + * 3. a IN (1) OR a IN (2) becomes a IN (1, 2) + * + * This rule does NOT check for type compatibility as that phase has been + * already be verified in the analyzer. + */ + public static class CombineDisjunctionsToIn extends OptimizerExpressionRule { + public CombineDisjunctionsToIn() { + super(TransformDirection.UP); + } + + @Override + protected Expression rule(Or or) { + Expression e = or; + // look only at equals and In + List exps = splitOr(e); + + Map> found = new LinkedHashMap<>(); + ZoneId zoneId = null; + List ors = new LinkedList<>(); + + for (Expression exp : exps) { + if (exp instanceof Equals eq) { + // consider only equals against foldables + if (eq.right().foldable()) { + found.computeIfAbsent(eq.left(), k -> new LinkedHashSet<>()).add(eq.right()); + } else { + ors.add(exp); + } + if (zoneId == null) { + zoneId = eq.zoneId(); + } + } else if (exp instanceof In in) { + found.computeIfAbsent(in.value(), k -> new LinkedHashSet<>()).addAll(in.list()); + if (zoneId == null) { + zoneId = in.zoneId(); + } + } else { + ors.add(exp); + } + } + + if (found.isEmpty() == false) { + // combine equals alongside the existing ors + final ZoneId finalZoneId = zoneId; + found.forEach( + (k, v) -> { ors.add(v.size() == 1 ? createEquals(k, v, finalZoneId) : createIn(k, new ArrayList<>(v), finalZoneId)); } + ); + + Expression combineOr = combineOr(ors); + // check the result semantically since the result might different in order + // but be actually the same which can trigger a loop + // e.g. a == 1 OR a == 2 OR null --> null OR a in (1,2) --> literalsOnTheRight --> cycle + if (e.semanticEquals(combineOr) == false) { + e = combineOr; + } + } + + return e; + } + + protected Equals createEquals(Expression k, Set v, ZoneId finalZoneId) { + return new Equals(k.source(), k, v.iterator().next(), finalZoneId); + } + + protected In createIn(Expression key, List values, ZoneId zoneId) { + return new In(key.source(), key, values, zoneId); + } + } + + public static class PushDownAndCombineFilters extends OptimizerRule { + + @Override + protected LogicalPlan rule(Filter filter) { + LogicalPlan plan = filter; + LogicalPlan child = filter.child(); + Expression condition = filter.condition(); + + if (child instanceof Filter f) { + plan = f.with(new And(f.source(), f.condition(), condition)); + } + // as it stands, all other unary plans should allow filters to be pushed down + else if (child instanceof UnaryPlan unary) { + // in case of aggregates, worry about filters that contain aggregations + if (unary instanceof Aggregate && condition.anyMatch(Functions::isAggregate)) { + List conjunctions = new ArrayList<>(splitAnd(condition)); + List inPlace = new ArrayList<>(); + // extract all conjunctions containing aggregates + for (Iterator iterator = conjunctions.iterator(); iterator.hasNext();) { + Expression conjunction = iterator.next(); + if (conjunction.anyMatch(Functions::isAggregate)) { + inPlace.add(conjunction); + iterator.remove(); + } + } + // if at least one expression can be pushed down, update the tree + if (conjunctions.size() > 0) { + child = unary.replaceChild(filter.with(unary.child(), Predicates.combineAnd(conjunctions))); + plan = filter.with(child, Predicates.combineAnd(inPlace)); + } + } else { + // push down filter + plan = unary.replaceChild(filter.with(unary.child(), condition)); + } + } + + return plan; + } + } + + public static class ReplaceSurrogateFunction extends OptimizerExpressionRule { + + public ReplaceSurrogateFunction() { + super(TransformDirection.DOWN); + } + + @Override + protected Expression rule(Expression e) { + if (e instanceof SurrogateFunction) { + e = ((SurrogateFunction) e).substitute(); + } + return e; + } + } + + // Simplifies arithmetic expressions with BinaryComparisons and fixed point fields, such as: (int + 2) / 3 > 4 => int > 10 + public static final class SimplifyComparisonsArithmetics extends OptimizerExpressionRule { + BiFunction typesCompatible; + + public SimplifyComparisonsArithmetics(BiFunction typesCompatible) { + super(TransformDirection.UP); + this.typesCompatible = typesCompatible; + } + + @Override + protected Expression rule(BinaryComparison bc) { + // optimize only once the expression has a literal on the right side of the binary comparison + if (bc.right() instanceof Literal) { + if (bc.left() instanceof ArithmeticOperation) { + return simplifyBinaryComparison(bc); + } + if (bc.left() instanceof Neg) { + return foldNegation(bc); + } + } + return bc; + } + + private Expression simplifyBinaryComparison(BinaryComparison comparison) { + ArithmeticOperation operation = (ArithmeticOperation) comparison.left(); + // Use symbol comp: SQL operations aren't available in this package (as dependencies) + String opSymbol = operation.symbol(); + // Modulo can't be simplified. + if (opSymbol.equals(MOD.symbol())) { + return comparison; + } + OperationSimplifier simplification = null; + if (isMulOrDiv(opSymbol)) { + simplification = new MulDivSimplifier(comparison); + } else if (opSymbol.equals(ADD.symbol()) || opSymbol.equals(SUB.symbol())) { + simplification = new AddSubSimplifier(comparison); + } + + return (simplification == null || simplification.isUnsafe(typesCompatible)) ? comparison : simplification.apply(); + } + + private static boolean isMulOrDiv(String opSymbol) { + return opSymbol.equals(MUL.symbol()) || opSymbol.equals(DIV.symbol()); + } + + private static Expression foldNegation(BinaryComparison bc) { + Literal bcLiteral = (Literal) bc.right(); + Expression literalNeg = tryFolding(new Neg(bcLiteral.source(), bcLiteral)); + return literalNeg == null ? bc : bc.reverse().replaceChildren(asList(((Neg) bc.left()).field(), literalNeg)); + } + + private static Expression tryFolding(Expression expression) { + if (expression.foldable()) { + try { + expression = new Literal(expression.source(), expression.fold(), expression.dataType()); + } catch (ArithmeticException | DateTimeException e) { + // null signals that folding would result in an over-/underflow (such as Long.MAX_VALUE+1); the optimisation is skipped. + expression = null; + } + } + return expression; + } + + private abstract static class OperationSimplifier { + final BinaryComparison comparison; + final Literal bcLiteral; + final ArithmeticOperation operation; + final Expression opLeft; + final Expression opRight; + final Literal opLiteral; + + OperationSimplifier(BinaryComparison comparison) { + this.comparison = comparison; + operation = (ArithmeticOperation) comparison.left(); + bcLiteral = (Literal) comparison.right(); + + opLeft = operation.left(); + opRight = operation.right(); + + if (opLeft instanceof Literal) { + opLiteral = (Literal) opLeft; + } else if (opRight instanceof Literal) { + opLiteral = (Literal) opRight; + } else { + opLiteral = null; + } + } + + // can it be quickly fast-tracked that the operation can't be reduced? + final boolean isUnsafe(BiFunction typesCompatible) { + if (opLiteral == null) { + // one of the arithm. operands must be a literal, otherwise the operation wouldn't simplify anything + return true; + } + + // Only operations on fixed point literals are supported, since optimizing float point operations can also change the + // outcome of the filtering: + // x + 1e18 > 1e18::long will yield different results with a field value in [-2^6, 2^6], optimised vs original; + // x * (1 + 1e-15d) > 1 : same with a field value of (1 - 1e-15d) + // so consequently, int fields optimisation requiring FP arithmetic isn't possible either: (x - 1e-15) * (1 + 1e-15) > 1. + if (opLiteral.dataType().isRational() || bcLiteral.dataType().isRational()) { + return true; + } + + // the Literal will be moved to the right of the comparison, but only if data-compatible with what's there + if (typesCompatible.apply(bcLiteral.dataType(), opLiteral.dataType()) == false) { + return true; + } + + return isOpUnsafe(); + } + + final Expression apply() { + // force float point folding for FlP field + Literal bcl = operation.dataType().isRational() + ? Literal.of(bcLiteral, ((Number) bcLiteral.value()).doubleValue()) + : bcLiteral; + + Expression bcRightExpression = ((BinaryComparisonInversible) operation).binaryComparisonInverse() + .create(bcl.source(), bcl, opRight); + bcRightExpression = tryFolding(bcRightExpression); + return bcRightExpression != null + ? postProcess((BinaryComparison) comparison.replaceChildren(List.of(opLeft, bcRightExpression))) + : comparison; + } + + // operation-specific operations: + // - fast-tracking of simplification unsafety + abstract boolean isOpUnsafe(); + + // - post optimisation adjustments + Expression postProcess(BinaryComparison binaryComparison) { + return binaryComparison; + } + } + + private static class AddSubSimplifier extends OperationSimplifier { + + AddSubSimplifier(BinaryComparison comparison) { + super(comparison); + } + + @Override + boolean isOpUnsafe() { + // no ADD/SUB with floating fields + if (operation.dataType().isRational()) { + return true; + } + + if (operation.symbol().equals(SUB.symbol()) && opRight instanceof Literal == false) { // such as: 1 - x > -MAX + // if next simplification step would fail on overflow anyways, skip the optimisation already + return tryFolding(new Sub(EMPTY, opLeft, bcLiteral)) == null; + } + + return false; + } + } + + private static class MulDivSimplifier extends OperationSimplifier { + + private final boolean isDiv; // and not MUL. + private final int opRightSign; // sign of the right operand in: (left) (op) (right) (comp) (literal) + + MulDivSimplifier(BinaryComparison comparison) { + super(comparison); + isDiv = operation.symbol().equals(DIV.symbol()); + opRightSign = sign(opRight); + } + + @Override + boolean isOpUnsafe() { + // Integer divisions are not safe to optimise: x / 5 > 1 <=/=> x > 5 for x in [6, 9]; same for the `==` comp + if (operation.dataType().isInteger() && isDiv) { + return true; + } + + // If current operation is a multiplication, it's inverse will be a division: safe only if outcome is still integral. + if (isDiv == false && opLeft.dataType().isInteger()) { + long opLiteralValue = ((Number) opLiteral.value()).longValue(); + return opLiteralValue == 0 || ((Number) bcLiteral.value()).longValue() % opLiteralValue != 0; + } + + // can't move a 0 in Mul/Div comparisons + return opRightSign == 0; + } + + @Override + Expression postProcess(BinaryComparison binaryComparison) { + // negative multiplication/division changes the direction of the comparison + return opRightSign < 0 ? binaryComparison.reverse() : binaryComparison; + } + + private static int sign(Object obj) { + int sign = 1; + if (obj instanceof Number) { + sign = (int) signum(((Number) obj).doubleValue()); + } else if (obj instanceof Literal) { + sign = sign(((Literal) obj).value()); + } else if (obj instanceof Neg) { + sign = -sign(((Neg) obj).field()); + } else if (obj instanceof ArithmeticOperation operation) { + if (isMulOrDiv(operation.symbol())) { + sign = sign(operation.left()) * sign(operation.right()); + } + } + return sign; + } + } + } + + public abstract static class PruneFilters extends OptimizerRule { + + @Override + protected LogicalPlan rule(Filter filter) { + Expression condition = filter.condition().transformUp(BinaryLogic.class, PruneFilters::foldBinaryLogic); + + if (condition instanceof Literal) { + if (TRUE.equals(condition)) { + return filter.child(); + } + if (FALSE.equals(condition) || Expressions.isNull(condition)) { + return skipPlan(filter); + } + } + + if (condition.equals(filter.condition()) == false) { + return new Filter(filter.source(), filter.child(), condition); + } + return filter; + } + + protected abstract LogicalPlan skipPlan(Filter filter); + + private static Expression foldBinaryLogic(BinaryLogic binaryLogic) { + if (binaryLogic instanceof Or or) { + boolean nullLeft = Expressions.isNull(or.left()); + boolean nullRight = Expressions.isNull(or.right()); + if (nullLeft && nullRight) { + return new Literal(binaryLogic.source(), null, DataTypes.NULL); + } + if (nullLeft) { + return or.right(); + } + if (nullRight) { + return or.left(); + } + } + if (binaryLogic instanceof And and) { + if (Expressions.isNull(and.left()) || Expressions.isNull(and.right())) { + return new Literal(binaryLogic.source(), null, DataTypes.NULL); + } + } + return binaryLogic; + } + } + + public static final class PruneLiteralsInOrderBy extends OptimizerRule { + + @Override + protected LogicalPlan rule(OrderBy ob) { + List prunedOrders = new ArrayList<>(); + + for (Order o : ob.order()) { + if (o.child().foldable()) { + prunedOrders.add(o); + } + } + + // everything was eliminated, the order isn't needed anymore + if (prunedOrders.size() == ob.order().size()) { + return ob.child(); + } + if (prunedOrders.size() > 0) { + List newOrders = new ArrayList<>(ob.order()); + newOrders.removeAll(prunedOrders); + return new OrderBy(ob.source(), ob.child(), newOrders); + } + + return ob; + } + } + + // NB: it is important to start replacing casts from the bottom to properly replace aliases + public abstract static class PruneCast extends Rule { + + private final Class castType; + + public PruneCast(Class castType) { + this.castType = castType; + } + + @Override + public final LogicalPlan apply(LogicalPlan plan) { + return rule(plan); + } + + protected final LogicalPlan rule(LogicalPlan plan) { + // eliminate redundant casts + return plan.transformExpressionsUp(castType, this::maybePruneCast); + } + + protected abstract Expression maybePruneCast(C cast); + } + + public abstract static class SkipQueryOnLimitZero extends OptimizerRule { + @Override + protected LogicalPlan rule(Limit limit) { + if (limit.limit().foldable()) { + if (Integer.valueOf(0).equals((limit.limit().fold()))) { + return skipPlan(limit); + } + } + return limit; + } + + protected abstract LogicalPlan skipPlan(Limit limit); + } + + public static class ReplaceRegexMatch extends OptimizerExpressionRule> { + + public ReplaceRegexMatch() { + super(TransformDirection.DOWN); + } + + @Override + protected Expression rule(RegexMatch regexMatch) { + Expression e = regexMatch; + StringPattern pattern = regexMatch.pattern(); + if (pattern.matchesAll()) { + e = new IsNotNull(e.source(), regexMatch.field()); + } else { + String match = pattern.exactMatch(); + if (match != null) { + Literal literal = new Literal(regexMatch.source(), match, DataTypes.KEYWORD); + e = regexToEquals(regexMatch, literal); + } + } + return e; + } + + protected Expression regexToEquals(RegexMatch regexMatch, Literal literal) { + return new Equals(regexMatch.source(), regexMatch.field(), literal); + } + } + + public static class FoldNull extends OptimizerExpressionRule { + + public FoldNull() { + super(TransformDirection.UP); + } + + @Override + protected Expression rule(Expression e) { + Expression result = tryReplaceIsNullIsNotNull(e); + if (result != e) { + return result; + } else if (e instanceof In in) { + if (Expressions.isNull(in.value())) { + return Literal.of(in, null); + } + } else if (e instanceof Alias == false + && e.nullable() == Nullability.TRUE + && Expressions.anyMatch(e.children(), Expressions::isNull)) { + return Literal.of(e, null); + } + return e; + } + + protected Expression tryReplaceIsNullIsNotNull(Expression e) { + if (e instanceof IsNotNull isnn) { + if (isnn.field().nullable() == Nullability.FALSE) { + return new Literal(e.source(), Boolean.TRUE, DataTypes.BOOLEAN); + } + } else if (e instanceof IsNull isn) { + if (isn.field().nullable() == Nullability.FALSE) { + return new Literal(e.source(), Boolean.FALSE, DataTypes.BOOLEAN); + } + } + return e; + } + } + + // a IS NULL AND a IS NOT NULL -> FALSE + // a IS NULL AND a > 10 -> a IS NULL and FALSE + // can be extended to handle null conditions where available + public static class PropagateNullable extends OptimizerExpressionRule { + + public PropagateNullable() { + super(TransformDirection.DOWN); + } + + @Override + protected Expression rule(And and) { + List splits = Predicates.splitAnd(and); + + Set nullExpressions = new LinkedHashSet<>(); + Set notNullExpressions = new LinkedHashSet<>(); + List others = new LinkedList<>(); + + // first find isNull/isNotNull + for (Expression ex : splits) { + if (ex instanceof IsNull isn) { + nullExpressions.add(isn.field()); + } else if (ex instanceof IsNotNull isnn) { + notNullExpressions.add(isnn.field()); + } + // the rest + else { + others.add(ex); + } + } + + // check for is isNull and isNotNull --> FALSE + if (Sets.haveNonEmptyIntersection(nullExpressions, notNullExpressions)) { + return Literal.of(and, Boolean.FALSE); + } + + // apply nullability across relevant/matching expressions + + // first against all nullable expressions + // followed by all not-nullable expressions + boolean modified = replace(nullExpressions, others, splits, this::nullify); + modified |= replace(notNullExpressions, others, splits, this::nonNullify); + if (modified) { + // reconstruct the expression + return Predicates.combineAnd(splits); + } + return and; + } + + /** + * Replace the given 'pattern' expressions against the target expression. + * If a match is found, the matching expression will be replaced by the replacer result + * or removed if null is returned. + */ + private static boolean replace( + Iterable pattern, + List target, + List originalExpressions, + BiFunction replacer + ) { + boolean modified = false; + for (Expression s : pattern) { + for (int i = 0; i < target.size(); i++) { + Expression t = target.get(i); + // identify matching expressions + if (t.anyMatch(s::semanticEquals)) { + Expression replacement = replacer.apply(t, s); + // if the expression has changed, replace it + if (replacement != t) { + modified = true; + target.set(i, replacement); + originalExpressions.replaceAll(e -> t.semanticEquals(e) ? replacement : e); + } + } + } + } + return modified; + } + + // default implementation nullifies all nullable expressions + protected Expression nullify(Expression exp, Expression nullExp) { + return exp.nullable() == Nullability.TRUE ? Literal.of(exp, null) : exp; + } + + // placeholder for non-null + protected Expression nonNullify(Expression exp, Expression nonNullExp) { + return exp; + } + } + + /** + * Simplify IsNotNull targets by resolving the underlying expression to its root fields with unknown + * nullability. + * e.g. + * (x + 1) / 2 IS NOT NULL --> x IS NOT NULL AND (x+1) / 2 IS NOT NULL + * SUBSTRING(x, 3) > 4 IS NOT NULL --> x IS NOT NULL AND SUBSTRING(x, 3) > 4 IS NOT NULL + * When dealing with multiple fields, a conjunction/disjunction based on the predicate: + * (x + y) / 4 IS NOT NULL --> x IS NOT NULL AND y IS NOT NULL AND (x + y) / 4 IS NOT NULL + * This handles the case of fields nested inside functions or expressions in order to avoid: + * - having to evaluate the whole expression + * - not pushing down the filter due to expression evaluation + * IS NULL cannot be simplified since it leads to a disjunction which prevents the filter to be + * pushed down: + * (x + 1) IS NULL --> x IS NULL OR x + 1 IS NULL + * and x IS NULL cannot be pushed down + *
+ * Implementation-wise this rule goes bottom-up, keeping an alias up to date to the current plan + * and then looks for replacing the target. + */ + public static class InferIsNotNull extends Rule { + + @Override + public LogicalPlan apply(LogicalPlan plan) { + // the alias map is shared across the whole plan + AttributeMap aliases = new AttributeMap<>(); + // traverse bottom-up to pick up the aliases as we go + plan = plan.transformUp(p -> inspectPlan(p, aliases)); + return plan; + } + + private LogicalPlan inspectPlan(LogicalPlan plan, AttributeMap aliases) { + // inspect just this plan properties + plan.forEachExpression(Alias.class, a -> aliases.put(a.toAttribute(), a.child())); + // now go about finding isNull/isNotNull + LogicalPlan newPlan = plan.transformExpressionsOnlyUp(IsNotNull.class, inn -> inferNotNullable(inn, aliases)); + return newPlan; + } + + private Expression inferNotNullable(IsNotNull inn, AttributeMap aliases) { + Expression result = inn; + Set refs = resolveExpressionAsRootAttributes(inn.field(), aliases); + // no refs found or could not detect - return the original function + if (refs.size() > 0) { + // add IsNull for the filters along with the initial inn + var innList = CollectionUtils.combine(refs.stream().map(r -> (Expression) new IsNotNull(inn.source(), r)).toList(), inn); + result = Predicates.combineAnd(innList); + } + return result; + } + + /** + * Unroll the expression to its references to get to the root fields + * that really matter for filtering. + */ + protected Set resolveExpressionAsRootAttributes(Expression exp, AttributeMap aliases) { + Set resolvedExpressions = new LinkedHashSet<>(); + boolean changed = doResolve(exp, aliases, resolvedExpressions); + return changed ? resolvedExpressions : emptySet(); + } + + private boolean doResolve(Expression exp, AttributeMap aliases, Set resolvedExpressions) { + boolean changed = false; + // check if the expression can be skipped or is not nullabe + if (skipExpression(exp)) { + resolvedExpressions.add(exp); + } else { + for (Expression e : exp.references()) { + Expression resolved = aliases.resolve(e, e); + // found a root attribute, bail out + if (resolved instanceof Attribute a && resolved == e) { + resolvedExpressions.add(a); + // don't mark things as change if the original expression hasn't been broken down + changed |= resolved != exp; + } else { + // go further + changed |= doResolve(resolved, aliases, resolvedExpressions); + } + } + } + return changed; + } + + protected boolean skipExpression(Expression e) { + return e.nullable() == Nullability.FALSE; + } + } + + public static final class SetAsOptimized extends Rule { + + @Override + public LogicalPlan apply(LogicalPlan plan) { + plan.forEachUp(SetAsOptimized::rule); + return plan; + } + + private static void rule(LogicalPlan plan) { + if (plan.optimized() == false) { + plan.setOptimized(); + } + } + } + + public abstract static class OptimizerRule extends Rule { + + private final TransformDirection direction; + + public OptimizerRule() { + this(TransformDirection.DOWN); + } + + protected OptimizerRule(TransformDirection direction) { + this.direction = direction; + } + + @Override + public final LogicalPlan apply(LogicalPlan plan) { + return direction == TransformDirection.DOWN + ? plan.transformDown(typeToken(), this::rule) + : plan.transformUp(typeToken(), this::rule); + } + + protected abstract LogicalPlan rule(SubPlan plan); + } + + public abstract static class OptimizerExpressionRule extends Rule { + + private final TransformDirection direction; + // overriding type token which returns the correct class but does an uncheck cast to LogicalPlan due to its generic bound + // a proper solution is to wrap the Expression rule into a Plan rule but that would affect the rule declaration + // so instead this is hacked here + private final Class expressionTypeToken = ReflectionUtils.detectSuperTypeForRuleLike(getClass()); + + public OptimizerExpressionRule(TransformDirection direction) { + this.direction = direction; + } + + @Override + public final LogicalPlan apply(LogicalPlan plan) { + return direction == TransformDirection.DOWN + ? plan.transformExpressionsDown(expressionTypeToken, this::rule) + : plan.transformExpressionsUp(expressionTypeToken, this::rule); + } + + protected LogicalPlan rule(LogicalPlan plan) { + return plan; + } + + protected abstract Expression rule(E e); + + public Class expressionToken() { + return expressionTypeToken; + } + } + + public enum TransformDirection { + UP, + DOWN + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/parser/CaseChangingCharStream.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/parser/CaseChangingCharStream.java new file mode 100644 index 000000000000..f38daa472ddf --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/parser/CaseChangingCharStream.java @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.parser; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.misc.Interval; + +// Wrapping stream for handling case-insensitive grammars + +// This approach is taken from the ANTLR documentation +// https://github.com/antlr/antlr4/blob/master/doc/resources/CaseChangingCharStream.java +// https://github.com/antlr/antlr4/blob/master/doc/case-insensitive-lexing.md + +/** + * This class supports case-insensitive lexing by wrapping an existing + * {@link CharStream} and forcing the lexer to see either upper or + * lowercase characters. Grammar literals should then be either upper or + * lower case such as 'BEGIN' or 'begin'. The text of the character + * stream is unaffected. Example: input 'BeGiN' would match lexer rule + * 'BEGIN' if constructor parameter upper=true but getText() would return + * 'BeGiN'. + */ +public class CaseChangingCharStream implements CharStream { + + private final CharStream stream; + private final boolean upper; + + /** + * Constructs a new CaseChangingCharStream wrapping the given {@link CharStream} forcing + * all characters to upper case or lower case. + * @param stream The stream to wrap. + * @param upper If true force each symbol to upper case, otherwise force to lower. + */ + public CaseChangingCharStream(CharStream stream, boolean upper) { + this.stream = stream; + this.upper = upper; + } + + @Override + public String getText(Interval interval) { + return stream.getText(interval); + } + + @Override + public void consume() { + stream.consume(); + } + + @Override + public int LA(int i) { + int c = stream.LA(i); + if (c <= 0) { + return c; + } + return upper ? Character.toUpperCase(c) : Character.toLowerCase(c); + } + + @Override + public int mark() { + return stream.mark(); + } + + @Override + public void release(int marker) { + stream.release(marker); + } + + @Override + public int index() { + return stream.index(); + } + + @Override + public void seek(int index) { + stream.seek(index); + } + + @Override + public int size() { + return stream.size(); + } + + @Override + public String getSourceName() { + return stream.getSourceName(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/parser/ParserUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/parser/ParserUtils.java new file mode 100644 index 000000000000..be8b08a05d2a --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/parser/ParserUtils.java @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.parser; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Interval; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.Check; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import static java.util.Collections.emptyList; + +public final class ParserUtils { + + private ParserUtils() {} + + public static Object visit(Function visitor, ParseTree tree) { + Object result = visitor.apply(tree); + Check.notNull(result, "Don't know how to handle context [{}] with value [{}]", tree.getClass(), tree.getText()); + return result; + } + + public static List visitList(ParseTreeVisitor visitor, List contexts, Class clazz) { + if (contexts == null || contexts.isEmpty()) { + return emptyList(); + } + + List results = new ArrayList<>(contexts.size()); + for (ParserRuleContext context : contexts) { + results.add(clazz.cast(visitor.visit(context))); + } + return results; + } + + @SuppressWarnings("unchecked") + public static T typedParsing(ParseTreeVisitor visitor, ParseTree ctx, Class type) { + Object result = ctx.accept(visitor); + if (type.isInstance(result)) { + return (T) result; + } + + throw new ParsingException( + source(ctx), + "Invalid query '{}'[{}] given; expected {} but found {}", + ctx.getText(), + ctx.getClass().getSimpleName(), + type.getSimpleName(), + (result != null ? result.getClass().getSimpleName() : "null") + ); + } + + public static Source source(ParseTree ctx) { + if (ctx instanceof ParserRuleContext) { + return source((ParserRuleContext) ctx); + } + return Source.EMPTY; + } + + public static Source source(TerminalNode terminalNode) { + Check.notNull(terminalNode, "terminalNode is null"); + return source(terminalNode.getSymbol()); + } + + public static Source source(ParserRuleContext parserRuleContext) { + Check.notNull(parserRuleContext, "parserRuleContext is null"); + Token start = parserRuleContext.start; + Token stop = parserRuleContext.stop != null ? parserRuleContext.stop : start; + return source(start, stop); + } + + public static Source source(Token token) { + Check.notNull(token, "token is null"); + String text = token.getInputStream().getText(new Interval(token.getStartIndex(), token.getStopIndex())); + return new Source(new Location(token.getLine(), token.getCharPositionInLine()), text); + } + + public static Source source(ParserRuleContext begin, ParserRuleContext end) { + Check.notNull(begin, "begin is null"); + Check.notNull(end, "end is null"); + Token start = begin.start; + Token stop = end.stop != null ? end.stop : begin.stop; + return source(start, stop); + } + + public static Source source(TerminalNode begin, ParserRuleContext end) { + Check.notNull(begin, "begin is null"); + Check.notNull(end, "end is null"); + Token start = begin.getSymbol(); + Token stop = end.stop != null ? end.stop : start; + return source(start, stop); + } + + public static Source source(Token start, Token stop) { + Check.notNull(start, "start is null"); + stop = stop == null ? start : stop; + String text = start.getInputStream().getText(new Interval(start.getStartIndex(), stop.getStopIndex())); + return new Source(new Location(start.getLine(), start.getCharPositionInLine()), text); + } + + /** + * Retrieves the raw text of the node (without interpreting it as a string literal). + */ + public static String text(ParseTree node) { + return node == null ? null : node.getText(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/QueryPlan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/QueryPlan.java new file mode 100644 index 000000000000..0129ad423b0f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/QueryPlan.java @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan; + +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * There are two main types of plans, {@code LogicalPlan} and {@code PhysicalPlan} + */ +public abstract class QueryPlan> extends Node { + + private AttributeSet lazyOutputSet; + private AttributeSet lazyInputSet; + private List lazyExpressions; + private AttributeSet lazyReferences; + + public QueryPlan(Source source, List children) { + super(source, children); + } + + public abstract List output(); + + public AttributeSet outputSet() { + if (lazyOutputSet == null) { + lazyOutputSet = new AttributeSet(output()); + } + return lazyOutputSet; + } + + public AttributeSet inputSet() { + if (lazyInputSet == null) { + List attrs = new ArrayList<>(); + for (PlanType child : children()) { + attrs.addAll(child.output()); + } + lazyInputSet = new AttributeSet(attrs); + } + return lazyInputSet; + } + + /** + * Returns the top-level expressions for this query plan node. + * In other words the node properties. + */ + public List expressions() { + if (lazyExpressions == null) { + lazyExpressions = new ArrayList<>(); + forEachPropertyOnly(Object.class, e -> doForEachExpression(e, lazyExpressions::add)); + } + return lazyExpressions; + } + + /** + * Returns the expressions referenced on this query plan node. + */ + public AttributeSet references() { + if (lazyReferences == null) { + lazyReferences = Expressions.references(expressions()); + } + return lazyReferences; + } + + // + // pass Object.class as a type token to pick Collections of expressions not just expressions + // + + public PlanType transformExpressionsOnly(Function rule) { + return transformPropertiesOnly(Object.class, e -> doTransformExpression(e, exp -> exp.transformDown(rule))); + } + + public PlanType transformExpressionsOnly(Class typeToken, Function rule) { + return transformPropertiesOnly(Object.class, e -> doTransformExpression(e, exp -> exp.transformDown(typeToken, rule))); + } + + public PlanType transformExpressionsOnlyUp(Class typeToken, Function rule) { + return transformPropertiesOnly(Object.class, e -> doTransformExpression(e, exp -> exp.transformUp(typeToken, rule))); + } + + public PlanType transformExpressionsDown(Function rule) { + return transformExpressionsDown(Expression.class, rule); + } + + public PlanType transformExpressionsDown(Class typeToken, Function rule) { + return transformPropertiesDown(Object.class, e -> doTransformExpression(e, exp -> exp.transformDown(typeToken, rule))); + } + + public PlanType transformExpressionsUp(Function rule) { + return transformExpressionsUp(Expression.class, rule); + } + + public PlanType transformExpressionsUp(Class typeToken, Function rule) { + return transformPropertiesUp(Object.class, e -> doTransformExpression(e, exp -> exp.transformUp(typeToken, rule))); + } + + @SuppressWarnings("unchecked") + private static Object doTransformExpression(Object arg, Function traversal) { + if (arg instanceof Expression) { + return traversal.apply((Expression) arg); + } + + // WARNING: if the collection is typed, an incompatible function will be applied to it + // this results in CCE at runtime and additional filtering is required + // preserving the type information is hacky and weird (a lot of context needs to be passed around and the lambda itself + // has no type info so it's difficult to have automatic checking without having base classes). + + if (arg instanceof Collection c) { + List transformed = new ArrayList<>(c.size()); + boolean hasChanged = false; + for (Object e : c) { + Object next = doTransformExpression(e, traversal); + if (e.equals(next)) { + // use the initial value + next = e; + } else { + hasChanged = true; + } + transformed.add(next); + } + + return hasChanged ? transformed : arg; + } + + return arg; + } + + public void forEachExpression(Consumer rule) { + forEachExpression(Expression.class, rule); + } + + public void forEachExpression(Class typeToken, Consumer rule) { + forEachPropertyOnly(Object.class, e -> doForEachExpression(e, exp -> exp.forEachDown(typeToken, rule))); + } + + public void forEachExpressionDown(Consumer rule) { + forEachExpressionDown(Expression.class, rule); + } + + public void forEachExpressionDown(Class typeToken, Consumer rule) { + forEachPropertyDown(Object.class, e -> doForEachExpression(e, exp -> exp.forEachDown(typeToken, rule))); + } + + public void forEachExpressionUp(Consumer rule) { + forEachExpressionUp(Expression.class, rule); + } + + public void forEachExpressionUp(Class typeToken, Consumer rule) { + forEachPropertyUp(Object.class, e -> doForEachExpression(e, exp -> exp.forEachUp(typeToken, rule))); + } + + @SuppressWarnings("unchecked") + private static void doForEachExpression(Object arg, Consumer traversal) { + if (arg instanceof Expression) { + traversal.accept((Expression) arg); + } else if (arg instanceof Collection c) { + for (Object o : c) { + doForEachExpression(o, traversal); + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/TableIdentifier.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/TableIdentifier.java new file mode 100644 index 000000000000..4acbf3c92b8b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/TableIdentifier.java @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class TableIdentifier { + + private final Source source; + + private final String cluster; + private final String index; + + public TableIdentifier(Source source, String catalog, String index) { + this.source = source; + this.cluster = catalog; + this.index = index; + } + + public String cluster() { + return cluster; + } + + public String index() { + return index; + } + + @Override + public int hashCode() { + return Objects.hash(cluster, index); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + TableIdentifier other = (TableIdentifier) obj; + return Objects.equals(index, other.index) && Objects.equals(cluster, other.cluster); + } + + public Source source() { + return source; + } + + public String qualifiedIndex() { + return cluster != null ? cluster + ":" + index : index; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (cluster != null) { + builder.append(cluster); + builder.append(":"); + } + builder.append(index); + return builder.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Aggregate.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Aggregate.java new file mode 100644 index 000000000000..3fcfd61e21b4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Aggregate.java @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +public class Aggregate extends UnaryPlan { + + private final List groupings; + private final List aggregates; + + public Aggregate(Source source, LogicalPlan child, List groupings, List aggregates) { + super(source, child); + this.groupings = groupings; + this.aggregates = aggregates; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Aggregate::new, child(), groupings, aggregates); + } + + @Override + public Aggregate replaceChild(LogicalPlan newChild) { + return new Aggregate(source(), newChild, groupings, aggregates); + } + + public List groupings() { + return groupings; + } + + public List aggregates() { + return aggregates; + } + + @Override + public boolean expressionsResolved() { + return Resolvables.resolved(groupings) && Resolvables.resolved(aggregates); + } + + @Override + public List output() { + return Expressions.asAttributes(aggregates); + } + + @Override + public int hashCode() { + return Objects.hash(groupings, aggregates, child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Aggregate other = (Aggregate) obj; + return Objects.equals(groupings, other.groupings) + && Objects.equals(aggregates, other.aggregates) + && Objects.equals(child(), other.child()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/BinaryPlan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/BinaryPlan.java new file mode 100644 index 000000000000..051c3d7946b4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/BinaryPlan.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Arrays; +import java.util.Objects; + +public abstract class BinaryPlan extends LogicalPlan { + + private final LogicalPlan left, right; + + protected BinaryPlan(Source source, LogicalPlan left, LogicalPlan right) { + super(source, Arrays.asList(left, right)); + this.left = left; + this.right = right; + } + + public LogicalPlan left() { + return left; + } + + public LogicalPlan right() { + return right; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + BinaryPlan other = (BinaryPlan) obj; + + return Objects.equals(left(), other.left()) && Objects.equals(right(), other.right()); + } + + @Override + public int hashCode() { + return Objects.hash(left, right); + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/EsRelation.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/EsRelation.java new file mode 100644 index 000000000000..299898883725 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/EsRelation.java @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.EsField; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +public class EsRelation extends LeafPlan { + + private final EsIndex index; + private final List attrs; + private final boolean frozen; + + public EsRelation(Source source, EsIndex index, boolean frozen) { + this(source, index, flatten(source, index.mapping()), frozen); + } + + public EsRelation(Source source, EsIndex index, List attributes) { + this(source, index, attributes, false); + } + + public EsRelation(Source source, EsIndex index, List attributes, boolean frozen) { + super(source); + this.index = index; + this.attrs = attributes; + this.frozen = frozen; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, EsRelation::new, index, attrs, frozen); + } + + private static List flatten(Source source, Map mapping) { + return flatten(source, mapping, null); + } + + private static List flatten(Source source, Map mapping, FieldAttribute parent) { + List list = new ArrayList<>(); + + for (Entry entry : mapping.entrySet()) { + String name = entry.getKey(); + EsField t = entry.getValue(); + + if (t != null) { + FieldAttribute f = new FieldAttribute(source, parent, parent != null ? parent.name() + "." + name : name, t); + list.add(f); + // object or nested + if (t.getProperties().isEmpty() == false) { + list.addAll(flatten(source, t.getProperties(), f)); + } + } + } + return list; + } + + public EsIndex index() { + return index; + } + + public boolean frozen() { + return frozen; + } + + @Override + public List output() { + return attrs; + } + + @Override + public boolean expressionsResolved() { + return true; + } + + @Override + public int hashCode() { + return Objects.hash(index, frozen); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + EsRelation other = (EsRelation) obj; + return Objects.equals(index, other.index) && frozen == other.frozen; + } + + @Override + public String nodeString() { + return nodeName() + "[" + index + "]" + NodeUtils.limitedToString(attrs); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Filter.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Filter.java new file mode 100644 index 000000000000..a09ffb3e07c9 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Filter.java @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +/** + * A {@code Filter} is a type of Plan that performs filtering of results. In + * {@code SELECT x FROM y WHERE z ..} the "WHERE" clause is a Filter. A + * {@code Filter} has a "condition" Expression that does the filtering. + */ +public class Filter extends UnaryPlan { + + private final Expression condition; + + public Filter(Source source, LogicalPlan child, Expression condition) { + super(source, child); + this.condition = condition; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Filter::new, child(), condition); + } + + @Override + public Filter replaceChild(LogicalPlan newChild) { + return new Filter(source(), newChild, condition); + } + + public Expression condition() { + return condition; + } + + @Override + public boolean expressionsResolved() { + return condition.resolved(); + } + + @Override + public int hashCode() { + return Objects.hash(condition, child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Filter other = (Filter) obj; + + return Objects.equals(condition, other.condition) && Objects.equals(child(), other.child()); + } + + public Filter with(Expression conditionExpr) { + return new Filter(source(), child(), conditionExpr); + } + + public Filter with(LogicalPlan child, Expression conditionExpr) { + return new Filter(source(), child, conditionExpr); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/LeafPlan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/LeafPlan.java new file mode 100644 index 000000000000..4def8356b316 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/LeafPlan.java @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Collections; +import java.util.List; + +public abstract class LeafPlan extends LogicalPlan { + + protected LeafPlan(Source source) { + super(source, Collections.emptyList()); + } + + @Override + public final LogicalPlan replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Limit.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Limit.java new file mode 100644 index 000000000000..610572f1e73e --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Limit.java @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class Limit extends UnaryPlan { + + private final Expression limit; + + public Limit(Source source, Expression limit, LogicalPlan child) { + super(source, child); + this.limit = limit; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Limit::new, limit, child()); + } + + @Override + public Limit replaceChild(LogicalPlan newChild) { + return new Limit(source(), limit, newChild); + } + + public Expression limit() { + return limit; + } + + @Override + public boolean expressionsResolved() { + return limit.resolved(); + } + + @Override + public int hashCode() { + return Objects.hash(limit, child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Limit other = (Limit) obj; + + return Objects.equals(limit, other.limit) && Objects.equals(child(), other.child()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/LogicalPlan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/LogicalPlan.java new file mode 100644 index 000000000000..56e09b4e1189 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/LogicalPlan.java @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.capabilities.Resolvable; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.plan.QueryPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; + +/** + * A LogicalPlan is what (not the "how") a user told us they want to do. + * For example, a logical plan in English would be: "I want to get from DEN to SFO". + */ +public abstract class LogicalPlan extends QueryPlan implements Resolvable { + + /** + * Order is important in the enum; any values should be added at the end. + */ + public enum Stage { + PARSED, + PRE_ANALYZED, + ANALYZED, + OPTIMIZED; + } + + private Stage stage = Stage.PARSED; + private Boolean lazyChildrenResolved = null; + private Boolean lazyResolved = null; + + public LogicalPlan(Source source, List children) { + super(source, children); + } + + public boolean preAnalyzed() { + return stage.ordinal() >= Stage.PRE_ANALYZED.ordinal(); + } + + public void setPreAnalyzed() { + stage = Stage.PRE_ANALYZED; + } + + public boolean analyzed() { + return stage.ordinal() >= Stage.ANALYZED.ordinal(); + } + + public void setAnalyzed() { + stage = Stage.ANALYZED; + } + + public boolean optimized() { + return stage.ordinal() >= Stage.OPTIMIZED.ordinal(); + } + + public void setOptimized() { + stage = Stage.OPTIMIZED; + } + + public final boolean childrenResolved() { + if (lazyChildrenResolved == null) { + lazyChildrenResolved = Boolean.valueOf(Resolvables.resolved(children())); + } + return lazyChildrenResolved; + } + + @Override + public boolean resolved() { + if (lazyResolved == null) { + lazyResolved = expressionsResolved() && childrenResolved(); + } + return lazyResolved; + } + + public abstract boolean expressionsResolved(); + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/OrderBy.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/OrderBy.java new file mode 100644 index 000000000000..c13b3a028f0e --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/OrderBy.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +public class OrderBy extends UnaryPlan { + + private final List order; + + public OrderBy(Source source, LogicalPlan child, List order) { + super(source, child); + this.order = order; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, OrderBy::new, child(), order); + } + + @Override + public OrderBy replaceChild(LogicalPlan newChild) { + return new OrderBy(source(), newChild, order); + } + + public List order() { + return order; + } + + @Override + public boolean expressionsResolved() { + return Resolvables.resolved(order); + } + + @Override + public int hashCode() { + return Objects.hash(order, child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + OrderBy other = (OrderBy) obj; + return Objects.equals(order, other.order) && Objects.equals(child(), other.child()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Project.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Project.java new file mode 100644 index 000000000000..b9070f546d8d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/Project.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.function.Functions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; +import java.util.Objects; + +/** + * A {@code Project} is a {@code Plan} with one child. In {@code SELECT x FROM y}, the "SELECT" statement is a Project. + */ +public class Project extends UnaryPlan { + + private final List projections; + + public Project(Source source, LogicalPlan child, List projections) { + super(source, child); + this.projections = projections; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Project::new, child(), projections); + } + + @Override + public Project replaceChild(LogicalPlan newChild) { + return new Project(source(), newChild, projections); + } + + public List projections() { + return projections; + } + + public Project withProjections(List projections) { + return new Project(source(), child(), projections); + } + + @Override + public boolean resolved() { + return super.resolved() && Expressions.anyMatch(projections, Functions::isAggregate) == false; + } + + @Override + public boolean expressionsResolved() { + return Resolvables.resolved(projections); + } + + @Override + public List output() { + return Expressions.asAttributes(projections); + } + + @Override + public int hashCode() { + return Objects.hash(projections, child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Project other = (Project) obj; + + return Objects.equals(projections, other.projections) && Objects.equals(child(), other.child()); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/UnaryPlan.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/UnaryPlan.java new file mode 100644 index 000000000000..75ce38127394 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/UnaryPlan.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * A {@code UnaryPlan} is a {@code LogicalPlan} with exactly one child, for example, {@code WHERE x} in a + * SQL statement is an {@code UnaryPlan}. + */ +public abstract class UnaryPlan extends LogicalPlan { + + private final LogicalPlan child; + + protected UnaryPlan(Source source, LogicalPlan child) { + super(source, Collections.singletonList(child)); + this.child = child; + } + + @Override + public final UnaryPlan replaceChildren(List newChildren) { + return replaceChild(newChildren.get(0)); + } + + public abstract UnaryPlan replaceChild(LogicalPlan newChild); + + public LogicalPlan child() { + return child; + } + + @Override + public List output() { + return child.output(); + } + + @Override + public int hashCode() { + return Objects.hashCode(child()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UnaryPlan other = (UnaryPlan) obj; + + return Objects.equals(child, other.child); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/UnresolvedRelation.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/UnresolvedRelation.java new file mode 100644 index 000000000000..d969ad02a4ea --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plan/logical/UnresolvedRelation.java @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plan.logical; + +import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; + +public class UnresolvedRelation extends LeafPlan implements Unresolvable { + + private final TableIdentifier table; + private final boolean frozen; + private final String alias; + private final String unresolvedMsg; + + public UnresolvedRelation(Source source, TableIdentifier table, String alias, boolean frozen) { + this(source, table, alias, frozen, null); + } + + public UnresolvedRelation(Source source, TableIdentifier table, String alias, boolean frozen, String unresolvedMessage) { + super(source); + this.table = table; + this.alias = alias; + this.frozen = frozen; + this.unresolvedMsg = unresolvedMessage == null ? "Unknown index [" + table.index() + "]" : unresolvedMessage; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, UnresolvedRelation::new, table, alias, frozen, unresolvedMsg); + } + + public TableIdentifier table() { + return table; + } + + public String alias() { + return alias; + } + + public boolean frozen() { + return frozen; + } + + @Override + public boolean resolved() { + return false; + } + + @Override + public boolean expressionsResolved() { + return false; + } + + @Override + public List output() { + return Collections.emptyList(); + } + + @Override + public String unresolvedMessage() { + return unresolvedMsg; + } + + @Override + public int hashCode() { + return Objects.hash(source(), table, alias, unresolvedMsg); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + UnresolvedRelation other = (UnresolvedRelation) obj; + return Objects.equals(table, other.table) + && Objects.equals(alias, other.alias) + && Objects.equals(frozen, other.frozen) + && Objects.equals(unresolvedMsg, other.unresolvedMsg); + } + + @Override + public List nodeProperties() { + return singletonList(table); + } + + @Override + public String toString() { + return UNRESOLVED_PREFIX + table.index(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java new file mode 100644 index 000000000000..2efbd7fbc077 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslator.java @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.planner; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.TypedAttribute; +import org.elasticsearch.xpack.esql.core.querydsl.query.NestedQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.util.Check; +import org.elasticsearch.xpack.esql.core.util.ReflectionUtils; + +public abstract class ExpressionTranslator { + + private final Class typeToken = ReflectionUtils.detectSuperTypeForRuleLike(getClass()); + + @SuppressWarnings("unchecked") + public Query translate(Expression exp, TranslatorHandler handler) { + return (typeToken.isInstance(exp) ? asQuery((E) exp, handler) : null); + } + + protected abstract Query asQuery(E e, TranslatorHandler handler); + + public static Query wrapIfNested(Query query, Expression exp) { + if (query != null && exp instanceof FieldAttribute fa) { + if (fa.isNested()) { + return new NestedQuery(fa.source(), fa.nestedParent().name(), query); + } + } + return query; + } + + public static FieldAttribute checkIsFieldAttribute(Expression e) { + Check.isTrue(e instanceof FieldAttribute, "Expected a FieldAttribute but received [{}]", e); + return (FieldAttribute) e; + } + + public static TypedAttribute checkIsPushableAttribute(Expression e) { + Check.isTrue( + e instanceof FieldAttribute || e instanceof MetadataAttribute, + "Expected a FieldAttribute or MetadataAttribute but received [{}]", + e + ); + return (TypedAttribute) e; + } + + public static String pushableAttributeName(TypedAttribute attribute) { + return attribute instanceof FieldAttribute fa + ? fa.exactAttribute().name() // equality should always be against an exact match (which is important for strings) + : attribute.name(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java new file mode 100644 index 000000000000..7974d3eb8a3c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/ExpressionTranslators.java @@ -0,0 +1,511 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.planner; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.time.DateFormatter; +import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.TypedAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.string.StartsWith; +import org.elasticsearch.xpack.esql.core.expression.predicate.Range; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.MatchQueryPredicate; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.MultiMatchQueryPredicate; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.StringQueryPredicate; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.In; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NotEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.Like; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexMatch; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike; +import org.elasticsearch.xpack.esql.core.querydsl.query.BoolQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.ExistsQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.MatchQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.MultiMatchQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.NotQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.PrefixQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.querydsl.query.QueryStringQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.RangeQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.RegexQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.ScriptQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.TermQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.WildcardQuery; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.Check; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; +import org.elasticsearch.xpack.versionfield.Version; + +import java.time.OffsetTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.TemporalAccessor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; + +public final class ExpressionTranslators { + + public static final String DATE_FORMAT = "strict_date_optional_time_nanos"; + public static final String TIME_FORMAT = "strict_hour_minute_second_fraction"; + + public static final List> QUERY_TRANSLATORS = List.of( + new BinaryComparisons(), + new Ranges(), + new BinaryLogic(), + new IsNulls(), + new IsNotNulls(), + new Nots(), + new Likes(), + new InComparisons(), + new StringQueries(), + new Matches(), + new MultiMatches(), + new Scalars() + ); + + public static Query toQuery(Expression e) { + return toQuery(e, new QlTranslatorHandler()); + } + + public static Query toQuery(Expression e, TranslatorHandler handler) { + Query translation = null; + for (ExpressionTranslator translator : QUERY_TRANSLATORS) { + translation = translator.translate(e, handler); + if (translation != null) { + return translation; + } + } + + throw new QlIllegalArgumentException("Don't know how to translate {} {}", e.nodeName(), e); + } + + public static Object valueOf(Expression e) { + if (e.foldable()) { + return e.fold(); + } + throw new QlIllegalArgumentException("Cannot determine value for {}", e); + } + + // TODO: see whether escaping is needed + @SuppressWarnings("rawtypes") + public static class Likes extends ExpressionTranslator { + + @Override + protected Query asQuery(RegexMatch e, TranslatorHandler handler) { + return doTranslate(e, handler); + } + + public static Query doTranslate(RegexMatch e, TranslatorHandler handler) { + Query q; + Expression field = e.field(); + + if (field instanceof FieldAttribute fa) { + return handler.wrapFunctionQuery(e, fa, () -> translateField(e, handler.nameOf(fa.exactAttribute()))); + } else if (field instanceof MetadataAttribute ma) { + q = translateField(e, handler.nameOf(ma)); + } else { + q = new ScriptQuery(e.source(), e.asScript()); + } + + return wrapIfNested(q, field); + } + + private static Query translateField(RegexMatch e, String targetFieldName) { + if (e instanceof Like l) { + return new WildcardQuery(e.source(), targetFieldName, l.pattern().asLuceneWildcard(), l.caseInsensitive()); + } + if (e instanceof WildcardLike l) { + return new WildcardQuery(e.source(), targetFieldName, l.pattern().asLuceneWildcard(), l.caseInsensitive()); + } + if (e instanceof RLike rl) { + return new RegexQuery(e.source(), targetFieldName, rl.pattern().asJavaRegex(), rl.caseInsensitive()); + } + return null; + } + } + + public static class StringQueries extends ExpressionTranslator { + + @Override + protected Query asQuery(StringQueryPredicate q, TranslatorHandler handler) { + return doTranslate(q, handler); + } + + public static Query doTranslate(StringQueryPredicate q, TranslatorHandler handler) { + return new QueryStringQuery(q.source(), q.query(), q.fields(), q); + } + } + + public static class Matches extends ExpressionTranslator { + + @Override + protected Query asQuery(MatchQueryPredicate q, TranslatorHandler handler) { + return doTranslate(q, handler); + } + + public static Query doTranslate(MatchQueryPredicate q, TranslatorHandler handler) { + return new MatchQuery(q.source(), handler.nameOf(q.field()), q.query(), q); + } + } + + public static class MultiMatches extends ExpressionTranslator { + + @Override + protected Query asQuery(MultiMatchQueryPredicate q, TranslatorHandler handler) { + return doTranslate(q, handler); + } + + public static Query doTranslate(MultiMatchQueryPredicate q, TranslatorHandler handler) { + return new MultiMatchQuery(q.source(), q.query(), q.fields(), q); + } + } + + public static class BinaryLogic extends ExpressionTranslator< + org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogic> { + + @Override + protected Query asQuery(org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogic e, TranslatorHandler handler) { + if (e instanceof And) { + return and(e.source(), handler.asQuery(e.left()), handler.asQuery(e.right())); + } + if (e instanceof Or) { + return or(e.source(), handler.asQuery(e.left()), handler.asQuery(e.right())); + } + + return null; + } + } + + public static class Nots extends ExpressionTranslator { + + @Override + protected Query asQuery(Not not, TranslatorHandler handler) { + return doTranslate(not, handler); + } + + public static Query doTranslate(Not not, TranslatorHandler handler) { + Expression e = not.field(); + Query wrappedQuery = handler.asQuery(not.field()); + Query q = wrappedQuery instanceof ScriptQuery + ? new ScriptQuery(not.source(), not.asScript()) + : wrappedQuery.negate(not.source()); + + return wrapIfNested(q, e); + } + } + + public static class IsNotNulls extends ExpressionTranslator { + + @Override + protected Query asQuery(IsNotNull isNotNull, TranslatorHandler handler) { + return doTranslate(isNotNull, handler); + } + + public static Query doTranslate(IsNotNull isNotNull, TranslatorHandler handler) { + return handler.wrapFunctionQuery(isNotNull, isNotNull.field(), () -> translate(isNotNull, handler)); + } + + private static Query translate(IsNotNull isNotNull, TranslatorHandler handler) { + return new ExistsQuery(isNotNull.source(), handler.nameOf(isNotNull.field())); + } + } + + public static class IsNulls extends ExpressionTranslator { + + @Override + protected Query asQuery(IsNull isNull, TranslatorHandler handler) { + return doTranslate(isNull, handler); + } + + public static Query doTranslate(IsNull isNull, TranslatorHandler handler) { + return handler.wrapFunctionQuery(isNull, isNull.field(), () -> translate(isNull, handler)); + } + + private static Query translate(IsNull isNull, TranslatorHandler handler) { + return new NotQuery(isNull.source(), new ExistsQuery(isNull.source(), handler.nameOf(isNull.field()))); + } + } + + // assume the Optimizer properly orders the predicates to ease the translation + public static class BinaryComparisons extends ExpressionTranslator { + + @Override + protected Query asQuery(BinaryComparison bc, TranslatorHandler handler) { + return doTranslate(bc, handler); + } + + public static void checkBinaryComparison(BinaryComparison bc) { + Check.isTrue( + bc.right().foldable(), + "Line {}:{}: Comparisons against fields are not (currently) supported; offender [{}] in [{}]", + bc.right().sourceLocation().getLineNumber(), + bc.right().sourceLocation().getColumnNumber(), + Expressions.name(bc.right()), + bc.symbol() + ); + } + + public static Query doTranslate(BinaryComparison bc, TranslatorHandler handler) { + checkBinaryComparison(bc); + return handler.wrapFunctionQuery(bc, bc.left(), () -> translate(bc, handler)); + } + + static Query translate(BinaryComparison bc, TranslatorHandler handler) { + TypedAttribute attribute = checkIsPushableAttribute(bc.left()); + Source source = bc.source(); + String name = handler.nameOf(attribute); + Object value = valueOf(bc.right()); + String format = null; + boolean isDateLiteralComparison = false; + + // for a date constant comparison, we need to use a format for the date, to make sure that the format is the same + // no matter the timezone provided by the user + if (value instanceof ZonedDateTime || value instanceof OffsetTime) { + DateFormatter formatter; + if (value instanceof ZonedDateTime) { + formatter = DateFormatter.forPattern(DATE_FORMAT); + // RangeQueryBuilder accepts an Object as its parameter, but it will call .toString() on the ZonedDateTime instance + // which can have a slightly different format depending on the ZoneId used to create the ZonedDateTime + // Since RangeQueryBuilder can handle date as String as well, we'll format it as String and provide the format as well. + value = formatter.format((ZonedDateTime) value); + } else { + formatter = DateFormatter.forPattern(TIME_FORMAT); + value = formatter.format((OffsetTime) value); + } + format = formatter.pattern(); + isDateLiteralComparison = true; + } else if (attribute.dataType() == IP && value instanceof BytesRef bytesRef) { + value = DocValueFormat.IP.format(bytesRef); + } else if (attribute.dataType() == VERSION) { + // VersionStringFieldMapper#indexedValueForSearch() only accepts as input String or BytesRef with the String (i.e. not + // encoded) representation of the version as it'll do the encoding itself. + if (value instanceof BytesRef bytesRef) { + value = new Version(bytesRef).toString(); + } else if (value instanceof Version version) { + value = version.toString(); + } + } else if (attribute.dataType() == UNSIGNED_LONG && value instanceof Long ul) { + value = unsignedLongAsNumber(ul); + } + + ZoneId zoneId = null; + if (DataTypes.isDateTime(attribute.dataType())) { + zoneId = bc.zoneId(); + } + if (bc instanceof GreaterThan) { + return new RangeQuery(source, name, value, false, null, false, format, zoneId); + } + if (bc instanceof GreaterThanOrEqual) { + return new RangeQuery(source, name, value, true, null, false, format, zoneId); + } + if (bc instanceof LessThan) { + return new RangeQuery(source, name, null, false, value, false, format, zoneId); + } + if (bc instanceof LessThanOrEqual) { + return new RangeQuery(source, name, null, false, value, true, format, zoneId); + } + if (bc instanceof Equals || bc instanceof NullEquals || bc instanceof NotEquals) { + name = pushableAttributeName(attribute); + + Query query; + if (isDateLiteralComparison) { + // dates equality uses a range query because it's the one that has a "format" parameter + query = new RangeQuery(source, name, value, true, value, true, format, zoneId); + } else { + query = new TermQuery(source, name, value); + } + if (bc instanceof NotEquals) { + query = new NotQuery(source, query); + } + return query; + } + + throw new QlIllegalArgumentException("Don't know how to translate binary comparison [{}] in [{}]", bc.right().nodeString(), bc); + } + } + + public static class Ranges extends ExpressionTranslator { + + @Override + protected Query asQuery(Range r, TranslatorHandler handler) { + return doTranslate(r, handler); + } + + public static Query doTranslate(Range r, TranslatorHandler handler) { + return handler.wrapFunctionQuery(r, r.value(), () -> translate(r, handler)); + } + + private static RangeQuery translate(Range r, TranslatorHandler handler) { + Object lower = valueOf(r.lower()); + Object upper = valueOf(r.upper()); + String format = null; + + // for a date constant comparison, we need to use a format for the date, to make sure that the format is the same + // no matter the timezone provided by the user + DateFormatter formatter = null; + if (lower instanceof ZonedDateTime || upper instanceof ZonedDateTime) { + formatter = DateFormatter.forPattern(DATE_FORMAT); + } else if (lower instanceof OffsetTime || upper instanceof OffsetTime) { + formatter = DateFormatter.forPattern(TIME_FORMAT); + } + if (formatter != null) { + // RangeQueryBuilder accepts an Object as its parameter, but it will call .toString() on the ZonedDateTime + // instance which can have a slightly different format depending on the ZoneId used to create the ZonedDateTime + // Since RangeQueryBuilder can handle date as String as well, we'll format it as String and provide the format. + if (lower instanceof ZonedDateTime || lower instanceof OffsetTime) { + lower = formatter.format((TemporalAccessor) lower); + } + if (upper instanceof ZonedDateTime || upper instanceof OffsetTime) { + upper = formatter.format((TemporalAccessor) upper); + } + format = formatter.pattern(); + } + return new RangeQuery( + r.source(), + handler.nameOf(r.value()), + lower, + r.includeLower(), + upper, + r.includeUpper(), + format, + r.zoneId() + ); + } + } + + public static class InComparisons extends ExpressionTranslator { + + @Override + protected Query asQuery(In in, TranslatorHandler handler) { + return doTranslate(in, handler); + } + + public static Query doTranslate(In in, TranslatorHandler handler) { + return handler.wrapFunctionQuery(in, in.value(), () -> translate(in, handler)); + } + + private static boolean needsTypeSpecificValueHandling(DataType fieldType) { + return DataTypes.isDateTime(fieldType) || fieldType == IP || fieldType == VERSION || fieldType == UNSIGNED_LONG; + } + + private static Query translate(In in, TranslatorHandler handler) { + TypedAttribute attribute = checkIsPushableAttribute(in.value()); + + Set terms = new LinkedHashSet<>(); + List queries = new ArrayList<>(); + + for (Expression rhs : in.list()) { + if (DataTypes.isNull(rhs.dataType()) == false) { + if (needsTypeSpecificValueHandling(attribute.dataType())) { + // delegates to BinaryComparisons translator to ensure consistent handling of date and time values + Query query = BinaryComparisons.translate(new Equals(in.source(), in.value(), rhs, in.zoneId()), handler); + + if (query instanceof TermQuery) { + terms.add(((TermQuery) query).value()); + } else { + queries.add(query); + } + } else { + terms.add(valueOf(rhs)); + } + } + } + + if (terms.isEmpty() == false) { + String fieldName = pushableAttributeName(attribute); + queries.add(new TermsQuery(in.source(), fieldName, terms)); + } + + return queries.stream().reduce((q1, q2) -> or(in.source(), q1, q2)).get(); + } + } + + public static class Scalars extends ExpressionTranslator { + + @Override + protected Query asQuery(ScalarFunction f, TranslatorHandler handler) { + return doTranslate(f, handler); + } + + public static Query doTranslate(ScalarFunction f, TranslatorHandler handler) { + Query q = doKnownTranslate(f, handler); + if (q != null) { + return q; + } + return handler.wrapFunctionQuery(f, f, () -> new ScriptQuery(f.source(), f.asScript())); + } + + public static Query doKnownTranslate(ScalarFunction f, TranslatorHandler handler) { + if (f instanceof StartsWith sw) { + if (sw.input() instanceof FieldAttribute && sw.pattern().foldable()) { + String targetFieldName = handler.nameOf(((FieldAttribute) sw.input()).exactAttribute()); + String pattern = (String) sw.pattern().fold(); + + return new PrefixQuery(f.source(), targetFieldName, pattern, sw.isCaseInsensitive()); + } + } + return null; + } + } + + public static Query or(Source source, Query left, Query right) { + return boolQuery(source, left, right, false); + } + + public static Query and(Source source, Query left, Query right) { + return boolQuery(source, left, right, true); + } + + private static Query boolQuery(Source source, Query left, Query right, boolean isAnd) { + Check.isTrue(left != null || right != null, "Both expressions are null"); + if (left == null) { + return right; + } + if (right == null) { + return left; + } + List queries; + // check if either side is already a bool query to an extra bool query + if (left instanceof BoolQuery bool && bool.isAnd() == isAnd) { + queries = CollectionUtils.combine(bool.queries(), right); + } else if (right instanceof BoolQuery bool && bool.isAnd() == isAnd) { + queries = CollectionUtils.combine(bool.queries(), left); + } else { + queries = Arrays.asList(left, right); + } + return new BoolQuery(source, isAnd, queries); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/QlTranslatorHandler.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/QlTranslatorHandler.java new file mode 100644 index 000000000000..e754681892b7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/QlTranslatorHandler.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.planner; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; + +public class QlTranslatorHandler implements TranslatorHandler { + + @Override + public Query asQuery(Expression e) { + return ExpressionTranslators.toQuery(e, this); + } + + @Override + public String nameOf(Expression e) { + return Expressions.name(e); + } + + @Override + public Object convert(Object value, DataType dataType) { + return DataTypeConverter.convert(value, dataType); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java new file mode 100644 index 000000000000..d18b467e918c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/planner/TranslatorHandler.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.planner; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.querydsl.query.ScriptQuery; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.function.Supplier; + +/** + * Parameterized handler used during query translation. + * + * Provides contextual utilities for an individual query to be performed. + */ +public interface TranslatorHandler { + + Query asQuery(Expression e); + + default Query wrapFunctionQuery(ScalarFunction sf, Expression field, Supplier querySupplier) { + if (field instanceof FieldAttribute) { + return ExpressionTranslator.wrapIfNested(querySupplier.get(), field); + } + return new ScriptQuery(sf.source(), sf.asScript()); + } + + String nameOf(Expression e); + + Object convert(Object value, DataType dataType); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/AbstractTransportQlAsyncGetResultsAction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/AbstractTransportQlAsyncGetResultsAction.java new file mode 100644 index 000000000000..154f4d2eaca1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/AbstractTransportQlAsyncGetResultsAction.java @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plugin; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionListenerResponseHandler; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackPlugin; +import org.elasticsearch.xpack.core.async.AsyncResultsService; +import org.elasticsearch.xpack.core.async.AsyncTaskIndexService; +import org.elasticsearch.xpack.core.async.GetAsyncResultRequest; +import org.elasticsearch.xpack.core.async.StoredAsyncResponse; +import org.elasticsearch.xpack.core.async.StoredAsyncTask; +import org.elasticsearch.xpack.esql.core.async.AsyncTaskManagementService; + +import static org.elasticsearch.xpack.core.ClientHelper.ASYNC_SEARCH_ORIGIN; + +public abstract class AbstractTransportQlAsyncGetResultsAction> + extends HandledTransportAction { + private final String actionName; + private final AsyncResultsService> resultsService; + private final TransportService transportService; + + @SuppressWarnings("this-escape") + public AbstractTransportQlAsyncGetResultsAction( + String actionName, + TransportService transportService, + ActionFilters actionFilters, + ClusterService clusterService, + NamedWriteableRegistry registry, + Client client, + ThreadPool threadPool, + BigArrays bigArrays, + Class asynkTaskClass + ) { + super(actionName, transportService, actionFilters, GetAsyncResultRequest::new, EsExecutors.DIRECT_EXECUTOR_SERVICE); + this.actionName = actionName; + this.transportService = transportService; + this.resultsService = createResultsService( + transportService, + clusterService, + registry, + client, + threadPool, + bigArrays, + asynkTaskClass + ); + } + + AsyncResultsService> createResultsService( + TransportService transportService, + ClusterService clusterService, + NamedWriteableRegistry registry, + Client client, + ThreadPool threadPool, + BigArrays bigArrays, + Class asyncTaskClass + ) { + Writeable.Reader> reader = in -> new StoredAsyncResponse<>(responseReader(), in); + AsyncTaskIndexService> store = new AsyncTaskIndexService<>( + XPackPlugin.ASYNC_RESULTS_INDEX, + clusterService, + threadPool.getThreadContext(), + client, + ASYNC_SEARCH_ORIGIN, + reader, + registry, + bigArrays + ); + return new AsyncResultsService<>( + store, + false, + asyncTaskClass, + (task, listener, timeout) -> AsyncTaskManagementService.addCompletionListener(threadPool, task, listener, timeout), + transportService.getTaskManager(), + clusterService + ); + } + + @Override + protected void doExecute(Task task, GetAsyncResultRequest request, ActionListener listener) { + DiscoveryNode node = resultsService.getNode(request.getId()); + if (node == null || resultsService.isLocalNode(node)) { + resultsService.retrieveResult(request, listener.delegateFailureAndWrap((l, r) -> { + if (r.getException() != null) { + l.onFailure(r.getException()); + } else { + l.onResponse(r.getResponse()); + } + })); + } else { + transportService.sendRequest( + node, + actionName, + request, + new ActionListenerResponseHandler<>(listener, responseReader(), EsExecutors.DIRECT_EXECUTOR_SERVICE) + ); + } + } + + public abstract Writeable.Reader responseReader(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/AbstractTransportQlAsyncGetStatusAction.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/AbstractTransportQlAsyncGetStatusAction.java new file mode 100644 index 000000000000..cb21272758d1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/AbstractTransportQlAsyncGetStatusAction.java @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plugin; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionListenerResponseHandler; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.client.internal.Client; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.concurrent.EsExecutors; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.XPackPlugin; +import org.elasticsearch.xpack.core.async.AsyncExecutionId; +import org.elasticsearch.xpack.core.async.AsyncTaskIndexService; +import org.elasticsearch.xpack.core.async.GetAsyncStatusRequest; +import org.elasticsearch.xpack.core.async.StoredAsyncResponse; +import org.elasticsearch.xpack.core.async.StoredAsyncTask; +import org.elasticsearch.xpack.esql.core.async.QlStatusResponse; + +import java.util.Objects; + +import static org.elasticsearch.xpack.core.ClientHelper.ASYNC_SEARCH_ORIGIN; + +public abstract class AbstractTransportQlAsyncGetStatusAction< + Response extends ActionResponse & QlStatusResponse.AsyncStatus, + AsyncTask extends StoredAsyncTask> extends HandledTransportAction { + private final String actionName; + private final TransportService transportService; + private final ClusterService clusterService; + private final Class asyncTaskClass; + private final AsyncTaskIndexService> store; + + @SuppressWarnings("this-escape") + public AbstractTransportQlAsyncGetStatusAction( + String actionName, + TransportService transportService, + ActionFilters actionFilters, + ClusterService clusterService, + NamedWriteableRegistry registry, + Client client, + ThreadPool threadPool, + BigArrays bigArrays, + Class asyncTaskClass + ) { + super(actionName, transportService, actionFilters, GetAsyncStatusRequest::new, EsExecutors.DIRECT_EXECUTOR_SERVICE); + this.actionName = actionName; + this.transportService = transportService; + this.clusterService = clusterService; + this.asyncTaskClass = asyncTaskClass; + Writeable.Reader> reader = in -> new StoredAsyncResponse<>(responseReader(), in); + this.store = new AsyncTaskIndexService<>( + XPackPlugin.ASYNC_RESULTS_INDEX, + clusterService, + threadPool.getThreadContext(), + client, + ASYNC_SEARCH_ORIGIN, + reader, + registry, + bigArrays + ); + } + + @Override + protected void doExecute(Task task, GetAsyncStatusRequest request, ActionListener listener) { + AsyncExecutionId searchId = AsyncExecutionId.decode(request.getId()); + DiscoveryNode node = clusterService.state().nodes().get(searchId.getTaskId().getNodeId()); + DiscoveryNode localNode = clusterService.state().getNodes().getLocalNode(); + if (node == null || Objects.equals(node, localNode)) { + store.retrieveStatus( + request, + taskManager, + asyncTaskClass, + AbstractTransportQlAsyncGetStatusAction::getStatusResponse, + QlStatusResponse::getStatusFromStoredSearch, + listener + ); + } else { + transportService.sendRequest( + node, + actionName, + request, + new ActionListenerResponseHandler<>(listener, QlStatusResponse::new, EsExecutors.DIRECT_EXECUTOR_SERVICE) + ); + } + } + + private static QlStatusResponse getStatusResponse(StoredAsyncTask asyncTask) { + return new QlStatusResponse( + asyncTask.getExecutionId().getEncoded(), + true, + true, + asyncTask.getStartTime(), + asyncTask.getExpirationTimeMillis(), + null + ); + } + + protected abstract Writeable.Reader responseReader(); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/EsqlCorePlugin.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/EsqlCorePlugin.java new file mode 100644 index 000000000000..1b2a59b5c688 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/EsqlCorePlugin.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.plugin; + +import org.elasticsearch.plugins.ExtensiblePlugin; +import org.elasticsearch.plugins.Plugin; + +public class EsqlCorePlugin extends Plugin implements ExtensiblePlugin { + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/TransportActionUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/TransportActionUtils.java new file mode 100644 index 000000000000..4d6fc9d1d18d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/TransportActionUtils.java @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.plugin; + +import org.apache.logging.log4j.Logger; +import org.elasticsearch.action.search.SearchPhaseExecutionException; +import org.elasticsearch.action.search.VersionMismatchException; +import org.elasticsearch.cluster.node.DiscoveryNode; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.xpack.esql.core.util.Holder; + +import java.util.function.Consumer; + +public final class TransportActionUtils { + + /** + * Execute a *QL request and re-try it in case the first request failed with a {@code VersionMismatchException} + * + * @param clusterService The cluster service instance + * @param onFailure On-failure handler in case the request doesn't fail with a {@code VersionMismatchException} + * @param queryRunner *QL query execution code, typically a Plan Executor running the query + * @param retryRequest Re-trial logic + * @param log Log4j logger + */ + public static void executeRequestWithRetryAttempt( + ClusterService clusterService, + Consumer onFailure, + Consumer> queryRunner, + Consumer retryRequest, + Logger log + ) { + + Holder retrySecondTime = new Holder(false); + queryRunner.accept(e -> { + // the search request likely ran on nodes with different versions of ES + // we will retry on a node with an older version that should generate a backwards compatible _search request + if (e instanceof SearchPhaseExecutionException + && ((SearchPhaseExecutionException) e).getCause() instanceof VersionMismatchException) { + if (log.isDebugEnabled()) { + log.debug("Caught exception type [{}] with cause [{}].", e.getClass().getName(), e.getCause()); + } + DiscoveryNode localNode = clusterService.state().nodes().getLocalNode(); + DiscoveryNode candidateNode = null; + for (DiscoveryNode node : clusterService.state().nodes()) { + // find the first node that's older than the current node + if (node != localNode && node.getVersion().before(localNode.getVersion())) { + candidateNode = node; + break; + } + } + if (candidateNode != null) { + if (log.isDebugEnabled()) { + log.debug( + "Candidate node to resend the request to: address [{}], id [{}], name [{}], version [{}]", + candidateNode.getAddress(), + candidateNode.getId(), + candidateNode.getName(), + candidateNode.getVersion() + ); + } + // re-send the request to the older node + retryRequest.accept(candidateNode); + } else { + retrySecondTime.set(true); + } + } else { + onFailure.accept(e); + } + }); + if (retrySecondTime.get()) { + if (log.isDebugEnabled()) { + log.debug("No candidate node found, likely all were upgraded in the meantime. Re-trying the original request."); + } + queryRunner.accept(onFailure); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/AttributeSort.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/AttributeSort.java new file mode 100644 index 000000000000..7c87ee2d2959 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/AttributeSort.java @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.container; + +import org.elasticsearch.xpack.esql.core.expression.Attribute; + +import java.util.Objects; + +public class AttributeSort extends Sort { + + private final Attribute attribute; + + public AttributeSort(Attribute attribute, Direction direction, Missing missing) { + super(direction, missing); + this.attribute = attribute; + } + + public Attribute attribute() { + return attribute; + } + + @Override + public int hashCode() { + return Objects.hash(attribute, direction(), missing()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + AttributeSort other = (AttributeSort) obj; + return Objects.equals(direction(), other.direction()) + && Objects.equals(missing(), other.missing()) + && Objects.equals(attribute, other.attribute); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/ScriptSort.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/ScriptSort.java new file mode 100644 index 000000000000..e8d71ab21094 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/ScriptSort.java @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.container; + +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; + +import java.util.Objects; + +public class ScriptSort extends Sort { + + private final ScriptTemplate script; + + public ScriptSort(ScriptTemplate script, Direction direction, Missing missing) { + super(direction, missing); + this.script = Scripts.nullSafeSort(script); + } + + public ScriptTemplate script() { + return script; + } + + @Override + public int hashCode() { + return Objects.hash(direction(), missing(), script); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + ScriptSort other = (ScriptSort) obj; + return Objects.equals(direction(), other.direction()) + && Objects.equals(missing(), other.missing()) + && Objects.equals(script, other.script); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/Sort.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/Sort.java new file mode 100644 index 000000000000..e6b3926745ea --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/container/Sort.java @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.container; + +import org.elasticsearch.search.aggregations.bucket.composite.MissingOrder; +import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition; +import org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection; + +public abstract class Sort { + + public enum Direction { + ASC, + DESC; + + public static Direction from(OrderDirection dir) { + return dir == null || dir == OrderDirection.ASC ? ASC : DESC; + } + + public SortOrder asOrder() { + return this == Direction.ASC ? SortOrder.ASC : SortOrder.DESC; + } + } + + public enum Missing { + FIRST("_first", MissingOrder.FIRST), + LAST("_last", MissingOrder.LAST), + /** + * Nulls position has not been specified by the user and an appropriate default will be used. + * + * The default values are chosen such that it stays compatible with previous behavior. Unfortunately, this results in + * inconsistencies across different types of queries (see https://github.com/elastic/elasticsearch/issues/77068). + */ + ANY(null, null); + + private final String searchOrder; + private final MissingOrder aggregationOrder; + + Missing(String searchOrder, MissingOrder aggregationOrder) { + this.searchOrder = searchOrder; + this.aggregationOrder = aggregationOrder; + } + + public static Missing from(NullsPosition pos) { + return switch (pos) { + case FIRST -> FIRST; + case LAST -> LAST; + default -> ANY; + }; + } + + public String searchOrder() { + return searchOrder(null); + } + + /** + * Preferred order of null values in non-aggregation queries. + */ + public String searchOrder(Direction fallbackDirection) { + if (searchOrder != null) { + return searchOrder; + } else { + return switch (fallbackDirection) { + case ASC -> LAST.searchOrder; + case DESC -> FIRST.searchOrder; + }; + } + } + + /** + * Preferred order of null values in aggregation queries. + */ + public MissingOrder aggregationOrder() { + return aggregationOrder; + } + } + + private final Direction direction; + private final Missing missing; + + protected Sort(Direction direction, Missing nulls) { + this.direction = direction; + this.missing = nulls; + } + + public Direction direction() { + return direction; + } + + public Missing missing() { + return missing; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java new file mode 100644 index 000000000000..3c0723b62d71 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQuery.java @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.StringJoiner; + +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; + +/** + * Query representing boolean AND or boolean OR. + */ +public class BoolQuery extends Query { + /** + * {@code true} for boolean {@code AND}, {@code false} for boolean {@code OR}. + */ + private final boolean isAnd; + private final List queries; + + public BoolQuery(Source source, boolean isAnd, Query left, Query right) { + this(source, isAnd, Arrays.asList(left, right)); + } + + public BoolQuery(Source source, boolean isAnd, List queries) { + super(source); + if (CollectionUtils.isEmpty(queries) || queries.size() < 2) { + throw new QlIllegalArgumentException("At least two queries required by bool query"); + } + this.isAnd = isAnd; + this.queries = queries; + } + + @Override + public boolean containsNestedField(String path, String field) { + for (Query query : queries) { + if (query.containsNestedField(path, field)) { + return true; + } + } + return false; + } + + @Override + public Query addNestedField(String path, String field, String format, boolean hasDocValues) { + boolean unchanged = true; + List rewritten = new ArrayList<>(queries.size()); + for (Query query : queries) { + var rewrittenQuery = query.addNestedField(path, field, format, hasDocValues); + unchanged &= rewrittenQuery == query; + rewritten.add(rewrittenQuery); + } + return unchanged ? this : new BoolQuery(source(), isAnd, rewritten); + } + + @Override + public void enrichNestedSort(NestedSortBuilder sort) { + for (Query query : queries) { + query.enrichNestedSort(sort); + } + } + + @Override + public QueryBuilder asBuilder() { + BoolQueryBuilder boolQuery = boolQuery(); + for (Query query : queries) { + if (isAnd) { + boolQuery.must(query.asBuilder()); + } else { + boolQuery.should(query.asBuilder()); + } + } + return boolQuery; + } + + public boolean isAnd() { + return isAnd; + } + + public List queries() { + return queries; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), isAnd, queries); + } + + @Override + public boolean equals(Object obj) { + if (false == super.equals(obj)) { + return false; + } + BoolQuery other = (BoolQuery) obj; + return isAnd == other.isAnd && queries.equals(other.queries); + } + + @Override + protected String innerToString() { + StringJoiner sb = new StringJoiner(isAnd ? " AND " : " OR "); + for (Query query : queries) { + sb.add(query.toString()); + } + return sb.toString(); + } + + @Override + public Query negate(Source source) { + List negated = queries.stream().map(q -> q.negate(q.source())).toList(); + if (negated.stream().allMatch(q -> q instanceof NotQuery)) { + return new NotQuery(source, this); + } + return new BoolQuery(source, isAnd == false, negated); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java new file mode 100644 index 000000000000..7633f7f3f1e9 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ExistsQuery.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import static org.elasticsearch.index.query.QueryBuilders.existsQuery; + +public class ExistsQuery extends LeafQuery { + + private final String name; + + public ExistsQuery(Source source, String name) { + super(source); + this.name = name; + } + + @Override + public QueryBuilder asBuilder() { + return existsQuery(name); + } + + @Override + protected String innerToString() { + return name; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java new file mode 100644 index 000000000000..f3c8829c2159 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/GeoDistanceQuery.java @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +public class GeoDistanceQuery extends LeafQuery { + + private final String field; + private final double lat; + private final double lon; + private final double distance; + + public GeoDistanceQuery(Source source, String field, double distance, double lat, double lon) { + super(source); + this.field = field; + this.distance = distance; + this.lat = lat; + this.lon = lon; + } + + public String field() { + return field; + } + + public double lat() { + return lat; + } + + public double lon() { + return lon; + } + + public double distance() { + return distance; + } + + @Override + public QueryBuilder asBuilder() { + return QueryBuilders.geoDistanceQuery(field).distance(distance, DistanceUnit.METERS).point(lat, lon); + } + + @Override + public int hashCode() { + return Objects.hash(field, distance, lat, lon); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + GeoDistanceQuery other = (GeoDistanceQuery) obj; + return Objects.equals(field, other.field) + && Objects.equals(distance, other.distance) + && Objects.equals(lat, other.lat) + && Objects.equals(lon, other.lon); + } + + @Override + protected String innerToString() { + return field + ":" + "(" + distance + "," + "(" + lat + ", " + lon + "))"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java new file mode 100644 index 000000000000..786114a52c7d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQuery.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +abstract class LeafQuery extends Query { + LeafQuery(Source source) { + super(source); + } + + @Override + public final boolean containsNestedField(String path, String field) { + // No leaf queries are nested + return false; + } + + @Override + public Query addNestedField(String path, String field, String format, boolean hasDocValues) { + // No leaf queries are nested + return this; + } + + @Override + public void enrichNestedSort(NestedSortBuilder sort) { + // No leaf queries are nested + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java new file mode 100644 index 000000000000..13f624a283b1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchAll.java @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; + +public class MatchAll extends LeafQuery { + public MatchAll(Source source) { + super(source); + } + + @Override + public QueryBuilder asBuilder() { + return matchAllQuery(); + } + + @Override + protected String innerToString() { + return ""; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java new file mode 100644 index 000000000000..8c9934af9dfa --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQuery.java @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.common.unit.Fuzziness; +import org.elasticsearch.core.Booleans; +import org.elasticsearch.index.query.MatchQueryBuilder; +import org.elasticsearch.index.query.Operator; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.MatchQueryPredicate; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; + +import static java.util.Map.entry; + +public class MatchQuery extends LeafQuery { + + private static final Map> BUILDER_APPLIERS; + + static { + // TODO: it'd be great if these could be constants instead of Strings, needs a core change to make the fields public first + // TODO: add zero terms query support, I'm not sure the best way to parse it yet... + // appliers.put("zero_terms_query", (qb, s) -> qb.zeroTermsQuery(s)); + BUILDER_APPLIERS = Map.ofEntries( + entry("analyzer", MatchQueryBuilder::analyzer), + entry("auto_generate_synonyms_phrase_query", (qb, s) -> qb.autoGenerateSynonymsPhraseQuery(Booleans.parseBoolean(s))), + entry("fuzziness", (qb, s) -> qb.fuzziness(Fuzziness.fromString(s))), + entry("fuzzy_transpositions", (qb, s) -> qb.fuzzyTranspositions(Booleans.parseBoolean(s))), + entry("fuzzy_rewrite", MatchQueryBuilder::fuzzyRewrite), + entry("lenient", (qb, s) -> qb.lenient(Booleans.parseBoolean(s))), + entry("max_expansions", (qb, s) -> qb.maxExpansions(Integer.valueOf(s))), + entry("minimum_should_match", MatchQueryBuilder::minimumShouldMatch), + entry("operator", (qb, s) -> qb.operator(Operator.fromString(s))), + entry("prefix_length", (qb, s) -> qb.prefixLength(Integer.valueOf(s))) + ); + } + + private final String name; + private final Object text; + private final MatchQueryPredicate predicate; + private final Map options; + + public MatchQuery(Source source, String name, Object text) { + this(source, name, text, null); + } + + public MatchQuery(Source source, String name, Object text, MatchQueryPredicate predicate) { + super(source); + this.name = name; + this.text = text; + this.predicate = predicate; + this.options = predicate == null ? Collections.emptyMap() : predicate.optionMap(); + } + + @Override + public QueryBuilder asBuilder() { + final MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery(name, text); + options.forEach((k, v) -> { + if (BUILDER_APPLIERS.containsKey(k)) { + BUILDER_APPLIERS.get(k).accept(queryBuilder, v); + } else { + throw new IllegalArgumentException("illegal match option [" + k + "]"); + } + }); + return queryBuilder; + } + + public String name() { + return name; + } + + public Object text() { + return text; + } + + MatchQueryPredicate predicate() { + return predicate; + } + + @Override + public int hashCode() { + return Objects.hash(text, name, predicate); + } + + @Override + public boolean equals(Object obj) { + if (false == super.equals(obj)) { + return false; + } + + MatchQuery other = (MatchQuery) obj; + return Objects.equals(text, other.text) && Objects.equals(name, other.name) && Objects.equals(predicate, other.predicate); + } + + @Override + protected String innerToString() { + return name + ":" + text; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java new file mode 100644 index 000000000000..8bede4f16d00 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQuery.java @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.common.unit.Fuzziness; +import org.elasticsearch.core.Booleans; +import org.elasticsearch.index.query.MultiMatchQueryBuilder; +import org.elasticsearch.index.query.Operator; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.MultiMatchQueryPredicate; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; + +import static java.util.Map.entry; + +public class MultiMatchQuery extends LeafQuery { + + private static final Map> BUILDER_APPLIERS; + + static { + // TODO: it'd be great if these could be constants instead of Strings, needs a core change to make the fields public first + BUILDER_APPLIERS = Map.ofEntries( + entry("slop", (qb, s) -> qb.slop(Integer.valueOf(s))), + // TODO: add zero terms query support, I'm not sure the best way to parse it yet... + // appliers.put("zero_terms_query", (qb, s) -> qb.zeroTermsQuery(s)); + entry("analyzer", MultiMatchQueryBuilder::analyzer), + entry("auto_generate_synonyms_phrase_query", (qb, s) -> qb.autoGenerateSynonymsPhraseQuery(Booleans.parseBoolean(s))), + entry("fuzziness", (qb, s) -> qb.fuzziness(Fuzziness.fromString(s))), + entry("fuzzy_rewrite", MultiMatchQueryBuilder::fuzzyRewrite), + entry("fuzzy_transpositions", (qb, s) -> qb.fuzzyTranspositions(Booleans.parseBoolean(s))), + entry("lenient", (qb, s) -> qb.lenient(Booleans.parseBoolean(s))), + entry("max_expansions", (qb, s) -> qb.maxExpansions(Integer.valueOf(s))), + entry("minimum_should_match", MultiMatchQueryBuilder::minimumShouldMatch), + entry("operator", (qb, s) -> qb.operator(Operator.fromString(s))), + entry("prefix_length", (qb, s) -> qb.prefixLength(Integer.valueOf(s))), + entry("tie_breaker", (qb, s) -> qb.tieBreaker(Float.valueOf(s))), + entry("type", MultiMatchQueryBuilder::type) + ); + } + + private final String query; + private final Map fields; + private final Map options; + private final MultiMatchQueryPredicate predicate; + + public MultiMatchQuery(Source source, String query, Map fields, MultiMatchQueryPredicate predicate) { + super(source); + this.query = query; + this.fields = fields; + this.predicate = predicate; + this.options = predicate.optionMap(); + } + + @Override + public QueryBuilder asBuilder() { + final MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(query); + queryBuilder.fields(fields); + queryBuilder.analyzer(predicate.analyzer()); + options.forEach((k, v) -> { + if (BUILDER_APPLIERS.containsKey(k)) { + BUILDER_APPLIERS.get(k).accept(queryBuilder, v); + } else { + throw new IllegalArgumentException("illegal multi_match option [" + k + "]"); + } + }); + return queryBuilder; + } + + @Override + public int hashCode() { + return Objects.hash(query, fields, predicate); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + MultiMatchQuery other = (MultiMatchQuery) obj; + return Objects.equals(query, other.query) && Objects.equals(fields, other.fields) && Objects.equals(predicate, other.predicate); + } + + @Override + protected String innerToString() { + return fields + ":" + query; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java new file mode 100644 index 000000000000..65c953cdf818 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQuery.java @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.apache.lucene.search.join.ScoreMode; +import org.elasticsearch.common.util.Maps; +import org.elasticsearch.index.query.InnerHitBuilder; +import org.elasticsearch.index.query.NestedQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.search.fetch.StoredFieldsContext; +import org.elasticsearch.search.fetch.subphase.FetchSourceContext; +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; +import static java.util.Collections.unmodifiableMap; +import static org.elasticsearch.index.query.QueryBuilders.nestedQuery; + +/** + * A query to a nested document. + */ +public class NestedQuery extends Query { + private static long COUNTER = 0; + // TODO: make this configurable + private static final int MAX_INNER_HITS = 99; + private static final List NO_STORED_FIELD = singletonList(StoredFieldsContext._NONE_); + + private final String path; + private final Map> fields; // field -> (useDocValues, format) + private final Query child; + + public NestedQuery(Source source, String path, Query child) { + this(source, path, emptyMap(), child); + } + + public NestedQuery(Source source, String path, Map> fields, Query child) { + super(source); + if (path == null) { + throw new IllegalArgumentException("path is required"); + } + if (fields == null) { + throw new IllegalArgumentException("fields is required"); + } + if (child == null) { + throw new IllegalArgumentException("child is required"); + } + this.path = path; + this.fields = fields; + this.child = child; + } + + @Override + public boolean containsNestedField(String otherPath, String field) { + boolean iContainThisField = this.path.equals(otherPath) && fields.containsKey(field); + boolean myChildContainsThisField = child.containsNestedField(otherPath, field); + return iContainThisField || myChildContainsThisField; + } + + @Override + public Query addNestedField(String otherPath, String field, String format, boolean hasDocValues) { + if (false == this.path.equals(otherPath)) { + // I'm not at the right path so let my child query have a crack at it + Query rewrittenChild = child.addNestedField(otherPath, field, format, hasDocValues); + if (rewrittenChild == child) { + return this; + } + return new NestedQuery(source(), otherPath, fields, rewrittenChild); + } + if (fields.containsKey(field)) { + // I already have the field, no rewriting needed + return this; + } + Map> newFields = Maps.newMapWithExpectedSize(fields.size() + 1); + newFields.putAll(fields); + newFields.put(field, new AbstractMap.SimpleImmutableEntry<>(hasDocValues, format)); + return new NestedQuery(source(), otherPath, unmodifiableMap(newFields), child); + } + + @Override + public void enrichNestedSort(NestedSortBuilder sort) { + child.enrichNestedSort(sort); + if (false == sort.getPath().equals(path)) { + return; + } + + // TODO: Add all filters in nested sorting when https://github.com/elastic/elasticsearch/issues/33079 is implemented + // Adding multiple filters to sort sections makes sense for nested queries where multiple conditions belong to the same + // nested query. The current functionality creates one nested query for each condition involving a nested field. + QueryBuilder childAsBuilder = child.asBuilder(); + if (sort.getFilter() != null && false == sort.getFilter().equals(childAsBuilder)) { + // throw new SqlIllegalArgumentException("nested query should have been grouped in one place"); + return; + } + sort.setFilter(childAsBuilder); + } + + @Override + public QueryBuilder asBuilder() { + // disable score + NestedQueryBuilder query = nestedQuery(path, child.asBuilder(), ScoreMode.None); + + if (fields.isEmpty() == false) { + InnerHitBuilder ihb = new InnerHitBuilder(); + ihb.setSize(0); + ihb.setSize(MAX_INNER_HITS); + ihb.setName(path + "_" + COUNTER++); + + for (Map.Entry> entry : fields.entrySet()) { + if (entry.getValue().getKey()) { + ihb.addFetchField(entry.getKey(), entry.getValue().getValue()); + } else { + ihb.addFetchField(entry.getKey()); + } + } + ihb.setFetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE); + ihb.setStoredFieldNames(NO_STORED_FIELD); + + query.innerHit(ihb); + } + + return query; + } + + String path() { + return path; + } + + Map> fields() { + return fields; + } + + Query child() { + return child; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), path, fields, child); + } + + @Override + public boolean equals(Object obj) { + if (false == super.equals(obj)) { + return false; + } + NestedQuery other = (NestedQuery) obj; + return path.equals(other.path) && fields.equals(other.fields) && child.equals(other.child); + } + + @Override + protected String innerToString() { + return path + "." + fields + "[" + child + "]"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java new file mode 100644 index 000000000000..4b87bbed80d7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/NotQuery.java @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; + +/** + * Query that inverts the set of matched documents. + */ +public class NotQuery extends Query { + private final Query child; + + public NotQuery(Source source, Query child) { + super(source); + if (child == null) { + throw new IllegalArgumentException("child is required"); + } + this.child = child; + } + + public Query child() { + return child; + } + + @Override + public boolean containsNestedField(String path, String field) { + return child.containsNestedField(path, field); + } + + @Override + public Query addNestedField(String path, String field, String format, boolean hasDocValues) { + Query rewrittenChild = child.addNestedField(path, field, format, hasDocValues); + if (child == rewrittenChild) { + return this; + } + return new NotQuery(source(), child); + } + + @Override + public void enrichNestedSort(NestedSortBuilder sort) { + child.enrichNestedSort(sort); + } + + @Override + public QueryBuilder asBuilder() { + return boolQuery().mustNot(child.asBuilder()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), child.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (false == super.equals(obj)) { + return false; + } + NotQuery other = (NotQuery) obj; + return child.equals(other.child); + } + + @Override + protected String innerToString() { + return child.toString(); + } + + @Override + public Query negate(Source source) { + return child; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java new file mode 100644 index 000000000000..65dd014e72b7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/PrefixQuery.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.prefixQuery; + +public class PrefixQuery extends LeafQuery { + + private final String field, query; + private final boolean caseInsensitive; + + public PrefixQuery(Source source, String field, String query, boolean caseInsensitive) { + super(source); + this.field = field; + this.query = query; + this.caseInsensitive = caseInsensitive; + } + + public String field() { + return field; + } + + public String query() { + return query; + } + + @Override + public QueryBuilder asBuilder() { + return prefixQuery(field, query).caseInsensitive(caseInsensitive); + } + + @Override + public int hashCode() { + return Objects.hash(field, query, caseInsensitive); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + PrefixQuery other = (PrefixQuery) obj; + return caseInsensitive == other.caseInsensitive && Objects.equals(field, other.field) && Objects.equals(query, other.query); + } + + @Override + protected String innerToString() { + return field + ":" + query; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java new file mode 100644 index 000000000000..19db6aa79846 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/Query.java @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * Intermediate representation of queries that is rewritten to fetch + * otherwise unreferenced nested fields and then used to build + * Elasticsearch {@link QueryBuilder}s. + *

+ * Our expression language spits out one of three values for any + * comparison, {@code true}, {@code false}, and {@code null}. + * Lucene's queries either match or don't match. They don't have + * a concept of {@code null}, at least not in the sense we need. + * The Lucene queries produced by {@link #asBuilder()} produce + * queries that do not match documents who's comparison would + * return {@code null}. This is what we want in {@code WHERE} + * style operations. But when you need to negate the matches you + * need to make only {@code false} return values into matches - + * {@code null} returns should continue to not match. You can + * do that with the {@link #negate} method. + *

+ */ +public abstract class Query { + private final Source source; + + protected Query(Source source) { + if (source == null) { + throw new IllegalArgumentException("location must be specified"); + } + this.source = source; + } + + /** + * Location in the source statement. + */ + public Source source() { + return source; + } + + /** + * Does this query contain a particular nested field? + */ + public abstract boolean containsNestedField(String path, String field); + + /** + * Rewrite this query to one that contains the specified nested field. + *

+ * Used to make sure that we fetch nested fields even if they aren't + * explicitly part of the query. + * @return a new query if we could add the nested field, the same query + * instance otherwise + */ + public abstract Query addNestedField(String path, String field, String format, boolean hasDocValues); + + /** + * Attach the one and only one matching nested query's filter to this + * sort. + */ + public abstract void enrichNestedSort(NestedSortBuilder sort); + + /** + * Convert to an Elasticsearch {@link QueryBuilder} all set up to execute + * the query. + */ + public abstract QueryBuilder asBuilder(); + + /** + * Used by {@link Query#toString()} to produce a pretty string. + */ + protected abstract String innerToString(); + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + Query other = (Query) obj; + return source.equals(other.source); + } + + @Override + public int hashCode() { + return source.hashCode(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + source + "[" + innerToString() + "]"; + } + + /** + * Negate this query, returning a query that includes documents that would + * return {@code false} when running the represented operation. The default + * implementation just returns a {@link NotQuery} wrapping {@code this} because + * most queries don't model underlying operations that can return {@code null}. + * Queries that model expressions that can return {@code null} must make sure + * all documents that would return {@code null} are still excluded from the match. + */ + public Query negate(Source source) { + return new NotQuery(source, this); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java new file mode 100644 index 000000000000..32cd661cab57 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQuery.java @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.common.unit.Fuzziness; +import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; +import org.elasticsearch.core.Booleans; +import org.elasticsearch.index.query.MultiMatchQueryBuilder; +import org.elasticsearch.index.query.Operator; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.QueryStringQueryBuilder; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.StringQueryPredicate; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; + +import static java.util.Map.entry; + +public class QueryStringQuery extends LeafQuery { + + // TODO: it'd be great if these could be constants instead of Strings, needs a core change to make the fields public first + private static final Map> BUILDER_APPLIERS = Map.ofEntries( + entry("allow_leading_wildcard", (qb, s) -> qb.allowLeadingWildcard(Booleans.parseBoolean(s))), + entry("analyze_wildcard", (qb, s) -> qb.analyzeWildcard(Booleans.parseBoolean(s))), + entry("analyzer", QueryStringQueryBuilder::analyzer), + entry("auto_generate_synonyms_phrase_query", (qb, s) -> qb.autoGenerateSynonymsPhraseQuery(Booleans.parseBoolean(s))), + entry("default_field", QueryStringQueryBuilder::defaultField), + entry("default_operator", (qb, s) -> qb.defaultOperator(Operator.fromString(s))), + entry("enable_position_increments", (qb, s) -> qb.enablePositionIncrements(Booleans.parseBoolean(s))), + entry("escape", (qb, s) -> qb.escape(Booleans.parseBoolean(s))), + entry("fuzziness", (qb, s) -> qb.fuzziness(Fuzziness.fromString(s))), + entry("fuzzy_max_expansions", (qb, s) -> qb.fuzzyMaxExpansions(Integer.valueOf(s))), + entry("fuzzy_prefix_length", (qb, s) -> qb.fuzzyPrefixLength(Integer.valueOf(s))), + entry("fuzzy_rewrite", QueryStringQueryBuilder::fuzzyRewrite), + entry("fuzzy_transpositions", (qb, s) -> qb.fuzzyTranspositions(Booleans.parseBoolean(s))), + entry("lenient", (qb, s) -> qb.lenient(Booleans.parseBoolean(s))), + entry("max_determinized_states", (qb, s) -> qb.maxDeterminizedStates(Integer.valueOf(s))), + entry("minimum_should_match", QueryStringQueryBuilder::minimumShouldMatch), + entry("phrase_slop", (qb, s) -> qb.phraseSlop(Integer.valueOf(s))), + entry("rewrite", QueryStringQueryBuilder::rewrite), + entry("quote_analyzer", QueryStringQueryBuilder::quoteAnalyzer), + entry("quote_field_suffix", QueryStringQueryBuilder::quoteFieldSuffix), + entry("tie_breaker", (qb, s) -> qb.tieBreaker(Float.valueOf(s))), + entry("time_zone", QueryStringQueryBuilder::timeZone), + entry("type", (qb, s) -> qb.type(MultiMatchQueryBuilder.Type.parse(s, LoggingDeprecationHandler.INSTANCE))) + ); + + private final String query; + private final Map fields; + private StringQueryPredicate predicate; + private final Map options; + + // dedicated constructor for QueryTranslator + public QueryStringQuery(Source source, String query, String fieldName) { + this(source, query, Collections.singletonMap(fieldName, Float.valueOf(1.0f)), null); + } + + public QueryStringQuery(Source source, String query, Map fields, StringQueryPredicate predicate) { + super(source); + this.query = query; + this.fields = fields; + this.predicate = predicate; + this.options = predicate == null ? Collections.emptyMap() : predicate.optionMap(); + } + + @Override + public QueryBuilder asBuilder() { + final QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery(query); + queryBuilder.fields(fields); + options.forEach((k, v) -> { + if (BUILDER_APPLIERS.containsKey(k)) { + BUILDER_APPLIERS.get(k).accept(queryBuilder, v); + } else { + throw new IllegalArgumentException("illegal query_string option [" + k + "]"); + } + }); + return queryBuilder; + } + + public Map fields() { + return fields; + } + + public String query() { + return query; + } + + @Override + public int hashCode() { + return Objects.hash(query, fields, predicate); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + QueryStringQuery other = (QueryStringQuery) obj; + return Objects.equals(query, other.query) && Objects.equals(fields, other.fields) && Objects.equals(predicate, other.predicate); + } + + @Override + protected String innerToString() { + return fields + ":" + query; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java new file mode 100644 index 000000000000..745e24fe52fc --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RangeQuery.java @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.RangeQueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.time.ZoneId; +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.rangeQuery; + +public class RangeQuery extends LeafQuery { + + private final String field; + private final Object lower, upper; + private final boolean includeLower, includeUpper; + private final String format; + private final ZoneId zoneId; + + public RangeQuery(Source source, String field, Object lower, boolean includeLower, Object upper, boolean includeUpper, ZoneId zoneId) { + this(source, field, lower, includeLower, upper, includeUpper, null, zoneId); + } + + public RangeQuery( + Source source, + String field, + Object lower, + boolean includeLower, + Object upper, + boolean includeUpper, + String format, + ZoneId zoneId + ) { + super(source); + this.field = field; + this.lower = lower; + this.upper = upper; + this.includeLower = includeLower; + this.includeUpper = includeUpper; + this.format = format; + this.zoneId = zoneId; + } + + public String field() { + return field; + } + + public Object lower() { + return lower; + } + + public Object upper() { + return upper; + } + + public boolean includeLower() { + return includeLower; + } + + public boolean includeUpper() { + return includeUpper; + } + + public String format() { + return format; + } + + public ZoneId zoneId() { + return zoneId; + } + + @Override + public QueryBuilder asBuilder() { + RangeQueryBuilder queryBuilder = rangeQuery(field).from(lower, includeLower).to(upper, includeUpper); + if (Strings.hasText(format)) { + queryBuilder.format(format); + } + if (zoneId != null) { + queryBuilder.timeZone(zoneId.getId()); + } + + return queryBuilder; + } + + @Override + public int hashCode() { + return Objects.hash(field, lower, upper, includeLower, includeUpper, format, zoneId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + RangeQuery other = (RangeQuery) obj; + return Objects.equals(field, other.field) + && Objects.equals(includeLower, other.includeLower) + && Objects.equals(includeUpper, other.includeUpper) + && Objects.equals(lower, other.lower) + && Objects.equals(upper, other.upper) + && Objects.equals(format, other.format) + && Objects.equals(zoneId, other.zoneId); + } + + @Override + protected String innerToString() { + return field + ":" + (includeLower ? "[" : "(") + lower + ", " + upper + (includeUpper ? "]" : ")") + "@" + zoneId.getId(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java new file mode 100644 index 000000000000..9117c32723d7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/RegexQuery.java @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.regexpQuery; + +public class RegexQuery extends LeafQuery { + + private final String field, regex; + private final boolean caseInsensitive; + + public RegexQuery(Source source, String field, String regex) { + this(source, field, regex, false); + } + + public RegexQuery(Source source, String field, String regex, boolean caseInsensitive) { + super(source); + this.field = field; + this.regex = regex; + this.caseInsensitive = caseInsensitive; + } + + public String field() { + return field; + } + + public String regex() { + return regex; + } + + public Boolean caseInsensitive() { + return caseInsensitive; + } + + @Override + public QueryBuilder asBuilder() { + return regexpQuery(field, regex).caseInsensitive(caseInsensitive); + } + + @Override + public int hashCode() { + return Objects.hash(field, regex, caseInsensitive); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + RegexQuery other = (RegexQuery) obj; + return Objects.equals(field, other.field) && Objects.equals(regex, other.regex) && caseInsensitive == other.caseInsensitive; + } + + @Override + protected String innerToString() { + return field + "~ /" + regex + "/"; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ScriptQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ScriptQuery.java new file mode 100644 index 000000000000..30100092053d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/ScriptQuery.java @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.expression.gen.script.Scripts; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.scriptQuery; + +public class ScriptQuery extends LeafQuery { + + private final ScriptTemplate script; + + @SuppressWarnings("this-escape") + public ScriptQuery(Source source, ScriptTemplate script) { + super(source); + // make script null safe + this.script = nullSafeScript(script); + } + + public ScriptTemplate script() { + return script; + } + + @Override + public QueryBuilder asBuilder() { + return scriptQuery(script.toPainless()); + } + + @Override + public int hashCode() { + return Objects.hash(script); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + ScriptQuery other = (ScriptQuery) obj; + return Objects.equals(script, other.script); + } + + @Override + protected String innerToString() { + return script.toString(); + } + + protected ScriptTemplate nullSafeScript(ScriptTemplate scriptTemplate) { + return Scripts.nullSafeFilter(scriptTemplate); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java new file mode 100644 index 000000000000..b195be3741ad --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermQuery.java @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.termQuery; + +public class TermQuery extends LeafQuery { + + private final String term; + private final Object value; + private final boolean caseInsensitive; + + public TermQuery(Source source, String term, Object value) { + this(source, term, value, false); + } + + public TermQuery(Source source, String term, Object value, boolean caseInsensitive) { + super(source); + this.term = term; + this.value = value; + this.caseInsensitive = caseInsensitive; + } + + public String term() { + return term; + } + + public Object value() { + return value; + } + + public Boolean caseInsensitive() { + return caseInsensitive; + } + + @Override + public QueryBuilder asBuilder() { + TermQueryBuilder qb = termQuery(term, value); + // ES does not allow case_insensitive to be set to "false", it should be either "true" or not specified + return caseInsensitive == false ? qb : qb.caseInsensitive(caseInsensitive); + } + + @Override + public int hashCode() { + return Objects.hash(term, value, caseInsensitive); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + TermQuery other = (TermQuery) obj; + return Objects.equals(term, other.term) + && Objects.equals(value, other.value) + && Objects.equals(caseInsensitive, other.caseInsensitive); + } + + @Override + protected String innerToString() { + return term + ":" + value; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java new file mode 100644 index 000000000000..a35a41ef09aa --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/TermsQuery.java @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.index.query.QueryBuilders.termsQuery; + +public class TermsQuery extends LeafQuery { + + private final String term; + private final Set values; + + public TermsQuery(Source source, String term, Set values) { + super(source); + this.term = term; + this.values = values; + } + + @Override + public QueryBuilder asBuilder() { + return termsQuery(term, values); + } + + @Override + public int hashCode() { + return Objects.hash(term, values); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + TermsQuery other = (TermsQuery) obj; + return Objects.equals(term, other.term) && Objects.equals(values, other.values); + } + + @Override + protected String innerToString() { + return term + ":" + values; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java new file mode 100644 index 000000000000..be2c771ced81 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.WildcardQueryBuilder; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Objects; + +import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery; + +public class WildcardQuery extends LeafQuery { + + private final String field, query; + private final boolean caseInsensitive; + + public WildcardQuery(Source source, String field, String query) { + this(source, field, query, false); + } + + public WildcardQuery(Source source, String field, String query, boolean caseInsensitive) { + super(source); + this.field = field; + this.query = query; + this.caseInsensitive = caseInsensitive; + } + + public String field() { + return field; + } + + public String query() { + return query; + } + + public Boolean caseInsensitive() { + return caseInsensitive; + } + + @Override + public QueryBuilder asBuilder() { + WildcardQueryBuilder wb = wildcardQuery(field, query); + // ES does not allow case_insensitive to be set to "false", it should be either "true" or not specified + return caseInsensitive == false ? wb : wb.caseInsensitive(caseInsensitive); + } + + @Override + public int hashCode() { + return Objects.hash(field, query, caseInsensitive); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + WildcardQuery other = (WildcardQuery) obj; + return Objects.equals(field, other.field) + && Objects.equals(query, other.query) + && Objects.equals(caseInsensitive, other.caseInsensitive); + } + + @Override + protected String innerToString() { + return field + ":" + query; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/ParameterizedRule.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/ParameterizedRule.java new file mode 100644 index 000000000000..5aa7318cb74b --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/ParameterizedRule.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.rule; + +import org.elasticsearch.xpack.esql.core.tree.Node; + +public abstract class ParameterizedRule, P> extends Rule { + + public abstract T apply(T t, P p); + + public T apply(T t) { + throw new RuleExecutionException("Cannot call parameterized rule without parameter"); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/ParameterizedRuleExecutor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/ParameterizedRuleExecutor.java new file mode 100644 index 000000000000..bfce2b42c032 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/ParameterizedRuleExecutor.java @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.rule; + +import org.elasticsearch.xpack.esql.core.tree.Node; + +import java.util.function.Function; + +public abstract class ParameterizedRuleExecutor, Context> extends RuleExecutor { + + private final Context context; + + protected ParameterizedRuleExecutor(Context context) { + this.context = context; + } + + protected Context context() { + return context; + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected Function transform(Rule rule) { + return (rule instanceof ParameterizedRule pr) ? t -> (TreeType) pr.apply(t, context) : t -> rule.apply(t); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/Rule.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/Rule.java new file mode 100644 index 000000000000..6121c9b36442 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/Rule.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.rule; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.util.ReflectionUtils; + +/** + * Rules that apply transformation to a tree. In addition, performs + * type filtering so that a rule that the rule implementation doesn't + * have to manually filter. + *

+ * Rules could could be built as lambdas but most + * rules are much larger, so we keep them as full-blown subclasses. + */ +public abstract class Rule> { + + protected Logger log = LogManager.getLogger(getClass()); + + private final String name; + private final Class typeToken = ReflectionUtils.detectSuperTypeForRuleLike(getClass()); + + protected Rule() { + this(null); + } + + protected Rule(String name) { + this.name = (name == null ? ReflectionUtils.ruleLikeNaming(getClass()) : name); + } + + public Class typeToken() { + return typeToken; + } + + public String name() { + return name; + } + + @Override + public String toString() { + return name(); + } + + public abstract T apply(T t); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/RuleExecutionException.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/RuleExecutionException.java new file mode 100644 index 000000000000..393fd3765a01 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/RuleExecutionException.java @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.rule; + +import org.elasticsearch.xpack.esql.core.QlServerException; + +public class RuleExecutionException extends QlServerException { + + public RuleExecutionException(String message, Object... args) { + super(message, args); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/RuleExecutor.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/RuleExecutor.java new file mode 100644 index 000000000000..ba873e690be7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/rule/RuleExecutor.java @@ -0,0 +1,213 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.rule; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public abstract class RuleExecutor> { + + private final Logger log = LogManager.getLogger(getClass()); + + public static class Limiter { + public static final Limiter DEFAULT = new Limiter(100); + public static final Limiter ONCE = new Limiter(1) { + + @Override + boolean reached(int runs) { + return runs >= 1; + } + }; + + private final int runs; + + public Limiter(int maximumRuns) { + this.runs = maximumRuns; + } + + boolean reached(int numberOfRuns) { + if (numberOfRuns >= this.runs) { + throw new RuleExecutionException("Rule execution limit [{}] reached", numberOfRuns); + } + return false; + } + } + + public static class Batch> { + private final String name; + private final Rule[] rules; + private final Limiter limit; + + @SafeVarargs + @SuppressWarnings("varargs") + public Batch(String name, Limiter limit, Rule... rules) { + this.name = name; + this.limit = limit; + this.rules = rules; + } + + @SafeVarargs + public Batch(String name, Rule... rules) { + this(name, Limiter.DEFAULT, rules); + } + + public String name() { + return name; + } + + public Rule[] rules() { + return rules; + } + } + + private Iterable> batches = null; + + protected abstract Iterable> batches(); + + public class Transformation { + private final TreeType before, after; + private final String name; + private Boolean lazyHasChanged; + + Transformation(String name, TreeType plan, Function transform) { + this.name = name; + this.before = plan; + this.after = transform.apply(before); + } + + public boolean hasChanged() { + if (lazyHasChanged == null) { + lazyHasChanged = before.equals(after) == false; + } + return lazyHasChanged; + } + + public String name() { + return name; + } + + public TreeType before() { + return before; + } + + public TreeType after() { + return after; + } + } + + public class ExecutionInfo { + + private final TreeType before, after; + private final Map, List> transformations; + + ExecutionInfo(TreeType before, TreeType after, Map, List> transformations) { + this.before = before; + this.after = after; + this.transformations = transformations; + } + + public TreeType before() { + return before; + } + + public TreeType after() { + return after; + } + + public Map, List> transformations() { + return transformations; + } + } + + protected final TreeType execute(TreeType plan) { + return executeWithInfo(plan).after; + } + + protected final ExecutionInfo executeWithInfo(TreeType plan) { + TreeType currentPlan = plan; + + long totalDuration = 0; + + Map, List> transformations = new LinkedHashMap<>(); + if (batches == null) { + batches = batches(); + } + + for (Batch batch : batches) { + int batchRuns = 0; + List tfs = new ArrayList<>(); + transformations.put(batch, tfs); + + boolean hasChanged = false; + long batchStart = System.currentTimeMillis(); + long batchDuration = 0; + + // run each batch until no change occurs or the limit is reached + do { + hasChanged = false; + batchRuns++; + + for (Rule rule : batch.rules) { + if (log.isTraceEnabled()) { + log.trace("About to apply rule {}", rule); + } + Transformation tf = new Transformation(rule.name(), currentPlan, transform(rule)); + tfs.add(tf); + currentPlan = tf.after; + + if (tf.hasChanged()) { + hasChanged = true; + if (log.isTraceEnabled()) { + log.trace("Rule {} applied\n{}", rule, NodeUtils.diffString(tf.before, tf.after)); + } + } else { + if (log.isTraceEnabled()) { + log.trace("Rule {} applied w/o changes", rule); + } + } + } + batchDuration = System.currentTimeMillis() - batchStart; + } while (hasChanged && batch.limit.reached(batchRuns) == false); + + totalDuration += batchDuration; + + if (log.isTraceEnabled()) { + TreeType before = plan; + TreeType after = plan; + if (tfs.isEmpty() == false) { + before = tfs.get(0).before; + after = tfs.get(tfs.size() - 1).after; + } + log.trace( + "Batch {} applied took {}\n{}", + batch.name, + TimeValue.timeValueMillis(batchDuration), + NodeUtils.diffString(before, after) + ); + } + } + + if (false == currentPlan.equals(plan) && log.isDebugEnabled()) { + log.debug("Tree transformation took {}\n{}", TimeValue.timeValueMillis(totalDuration), NodeUtils.diffString(plan, currentPlan)); + } + + return new ExecutionInfo(plan, currentPlan, transformations); + } + + protected Function transform(Rule rule) { + return rule::apply; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/session/Configuration.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/session/Configuration.java new file mode 100644 index 000000000000..b671edf685b5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/session/Configuration.java @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.session; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Objects; + +public class Configuration { + + protected final String clusterName; + protected final String username; + protected final ZonedDateTime now; + protected final ZoneId zoneId; + + public Configuration(ZoneId zi, String username, String clusterName) { + this(zi, null, username, clusterName); + } + + protected Configuration(ZoneId zi, Instant now, String username, String clusterName) { + this.zoneId = zi.normalized(); + this.now = now != null ? now.atZone(zi) : ZonedDateTime.now(Clock.tick(Clock.system(zoneId), Duration.ofNanos(1))); + this.username = username; + this.clusterName = clusterName; + } + + public ZoneId zoneId() { + return zoneId; + } + + public ZonedDateTime now() { + return now; + } + + public String clusterName() { + return clusterName; + } + + public String username() { + return username; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Configuration that = (Configuration) o; + return Objects.equals(zoneId, that.zoneId) + && Objects.equals(now, that.now) + && Objects.equals(username, that.username) + && Objects.equals(clusterName, that.clusterName); + } + + @Override + public int hashCode() { + return Objects.hash(zoneId, now, username, clusterName); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Location.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Location.java new file mode 100644 index 000000000000..5e6a8028d68f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Location.java @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import java.util.Objects; + +public final class Location { + private final int line; + private final int charPositionInLine; + + public static final Location EMPTY = new Location(-1, -2); + + public Location(int line, int charPositionInLine) { + this.line = line; + this.charPositionInLine = charPositionInLine; + } + + public int getLineNumber() { + return line; + } + + public int getColumnNumber() { + return charPositionInLine + 1; + } + + @Override + public String toString() { + return "@" + getLineNumber() + ":" + getColumnNumber(); + } + + @Override + public int hashCode() { + return Objects.hash(line, charPositionInLine); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + Location other = (Location) obj; + return line == other.line && charPositionInLine == other.charPositionInLine; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Node.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Node.java new file mode 100644 index 000000000000..f7561d0c2b34 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Node.java @@ -0,0 +1,444 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import static java.util.Collections.emptyList; + +/** + * Immutable tree structure. + * The traversal is done depth-first, pre-order (first the node then its children), that is seeks up and then goes down. + * Alternative method for post-order (children first, then node) is also offered, that is seeks down and then goes up. + * + * Allows transformation which returns the same tree (if no change has been performed) or a new tree otherwise. + * + * While it tries as much as possible to use functional Java, due to lack of parallelism, + * the use of streams and iterators is not really useful and brings too much baggage which + * might be used incorrectly. + * + * @param node type + */ +public abstract class Node> { + private static final int TO_STRING_MAX_PROP = 10; + private static final int TO_STRING_MAX_WIDTH = 110; + + private final Source source; + private final List children; + + public Node(Source source, List children) { + this.source = (source != null ? source : Source.EMPTY); + if (containsNull(children)) { + throw new QlIllegalArgumentException("Null children are not allowed"); + } + this.children = children; + } + + public Source source() { + return source; + } + + public Location sourceLocation() { + return source.source(); + } + + public String sourceText() { + return source.text(); + } + + public List children() { + return children; + } + + @SuppressWarnings("unchecked") + public void forEachDown(Consumer action) { + action.accept((T) this); + children().forEach(c -> c.forEachDown(action)); + } + + @SuppressWarnings("unchecked") + public void forEachDown(Class typeToken, Consumer action) { + forEachDown(t -> { + if (typeToken.isInstance(t)) { + action.accept((E) t); + } + }); + } + + @SuppressWarnings("unchecked") + public void forEachUp(Consumer action) { + children().forEach(c -> c.forEachUp(action)); + action.accept((T) this); + } + + @SuppressWarnings("unchecked") + public void forEachUp(Class typeToken, Consumer action) { + forEachUp(t -> { + if (typeToken.isInstance(t)) { + action.accept((E) t); + } + }); + } + + public void forEachPropertyOnly(Class typeToken, Consumer rule) { + forEachProperty(typeToken, rule); + } + + public void forEachPropertyDown(Class typeToken, Consumer rule) { + forEachDown(e -> e.forEachProperty(typeToken, rule)); + } + + public void forEachPropertyUp(Class typeToken, Consumer rule) { + forEachUp(e -> e.forEachProperty(typeToken, rule)); + } + + @SuppressWarnings("unchecked") + protected void forEachProperty(Class typeToken, Consumer rule) { + for (Object prop : info().properties()) { + // skip children (only properties are interesting) + if (prop != children && children.contains(prop) == false && typeToken.isInstance(prop)) { + rule.accept((E) prop); + } + } + } + + @SuppressWarnings("unchecked") + public boolean anyMatch(Predicate predicate) { + boolean result = predicate.test((T) this); + if (result == false) { + for (T child : children) { + if (child.anyMatch(predicate)) { + return true; + } + } + } + return result; + } + + public List collect(Predicate predicate) { + List l = new ArrayList<>(); + forEachDown(n -> { + if (predicate.test(n)) { + l.add(n); + } + }); + return l.isEmpty() ? emptyList() : l; + } + + public List collectLeaves() { + return collect(n -> n.children().isEmpty()); + } + + // parse the list in pre-order and on match, skip the child/branch and move on to the next child/branch + public List collectFirstChildren(Predicate predicate) { + List matches = new ArrayList<>(); + doCollectFirst(predicate, matches); + return matches; + } + + @SuppressWarnings("unchecked") + protected void doCollectFirst(Predicate predicate, List matches) { + T t = (T) this; + if (predicate.test(t)) { + matches.add(t); + } else { + for (T child : children()) { + child.doCollectFirst(predicate, matches); + } + } + } + + // TODO: maybe add a flatMap (need to double check the Stream bit) + + // + // Transform methods + // + + // + // transform the node itself and its children + // + + @SuppressWarnings("unchecked") + public T transformDown(Function rule) { + T root = rule.apply((T) this); + Node node = this.equals(root) ? this : root; + + return node.transformChildren(child -> child.transformDown(rule)); + } + + @SuppressWarnings("unchecked") + public T transformDown(Class typeToken, Function rule) { + // type filtering function + return transformDown((t) -> (typeToken.isInstance(t) ? rule.apply((E) t) : t)); + } + + @SuppressWarnings("unchecked") + public T transformUp(Function rule) { + T transformed = transformChildren(child -> child.transformUp(rule)); + T node = this.equals(transformed) ? (T) this : transformed; + return rule.apply(node); + } + + @SuppressWarnings("unchecked") + public T transformUp(Class typeToken, Function rule) { + // type filtering function + return transformUp((t) -> (typeToken.isInstance(t) ? rule.apply((E) t) : t)); + } + + @SuppressWarnings("unchecked") + protected > T transformChildren(Function traversalOperation) { + boolean childrenChanged = false; + + // stream() could be used but the code is just as complicated without any advantages + // further more, it would include bring in all the associated stream/collector object creation even though in + // most cases the immediate tree would be quite small (0,1,2 elements) + List transformedChildren = new ArrayList<>(children().size()); + + for (T child : children) { + T next = traversalOperation.apply(child); + if (child.equals(next)) { + // use the initial value + next = child; + } else { + childrenChanged = true; + } + transformedChildren.add(next); + } + + return (childrenChanged ? replaceChildrenSameSize(transformedChildren) : (T) this); + } + + public final T replaceChildrenSameSize(List newChildren) { + if (newChildren.size() != children.size()) { + throw new QlIllegalArgumentException( + "Expected the same number of children [" + children.size() + "], but received [" + newChildren.size() + "]" + ); + } + return replaceChildren(newChildren); + } + + public abstract T replaceChildren(List newChildren); + + // + // transform the node properties and use the tree only for navigation + // + + public T transformPropertiesOnly(Class typeToken, Function rule) { + return transformNodeProps(typeToken, rule); + } + + public T transformPropertiesDown(Class typeToken, Function rule) { + return transformDown(t -> t.transformNodeProps(typeToken, rule)); + } + + public T transformPropertiesUp(Class typeToken, Function rule) { + return transformUp(t -> t.transformNodeProps(typeToken, rule)); + } + + /** + * Transform this node's properties. + *

+ * This always returns something of the same type as the current + * node but since {@link Node} doesn't have a {@code SelfT} parameter + * we return the closest thing we do have: {@code T}, which is the + * root of the hierarchy for the this node. + */ + protected final T transformNodeProps(Class typeToken, Function rule) { + return info().transform(rule, typeToken); + } + + /** + * Return the information about this node. + */ + protected abstract NodeInfo info(); + + @Override + public int hashCode() { + return Objects.hash(children); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Node other = (Node) obj; + return Objects.equals(children(), other.children()); + } + + public String nodeName() { + return getClass().getSimpleName(); + } + + /** + * The values of all the properties that are important + * to this {@link Node}. + */ + public List nodeProperties() { + return info().properties(); + } + + public String nodeString() { + StringBuilder sb = new StringBuilder(); + sb.append(nodeName()); + sb.append("["); + sb.append(propertiesToString(true)); + sb.append("]"); + return sb.toString(); + } + + @Override + public String toString() { + return treeString(new StringBuilder(), 0, new BitSet()).toString(); + } + + /** + * Render this {@link Node} as a tree like + *
+     * {@code
+     * Project[[i{f}#0]]
+     * \_Filter[i{f}#1]
+     *   \_SubQueryAlias[test]
+     *     \_EsRelation[test][i{f}#2]
+     * }
+     * 
+ */ + final StringBuilder treeString(StringBuilder sb, int depth, BitSet hasParentPerDepth) { + if (depth > 0) { + // draw children + for (int column = 0; column < depth; column++) { + if (hasParentPerDepth.get(column)) { + sb.append("|"); + // if not the last elder, adding padding (since each column has two chars ("|_" or "\_") + if (column < depth - 1) { + sb.append(" "); + } + } else { + // if the child has no parent (elder on the previous level), it means its the last sibling + sb.append((column == depth - 1) ? "\\" : " "); + } + } + + sb.append("_"); + } + + sb.append(nodeString()); + + @SuppressWarnings("HiddenField") + List children = children(); + if (children.isEmpty() == false) { + sb.append("\n"); + } + for (int i = 0; i < children.size(); i++) { + T t = children.get(i); + hasParentPerDepth.set(depth, i < children.size() - 1); + t.treeString(sb, depth + 1, hasParentPerDepth); + if (i < children.size() - 1) { + sb.append("\n"); + } + } + return sb; + } + + /** + * Render the properties of this {@link Node} one by + * one like {@code foo bar baz}. These go inside the + * {@code [} and {@code ]} of the output of {@link #treeString}. + */ + public String propertiesToString(boolean skipIfChild) { + StringBuilder sb = new StringBuilder(); + + @SuppressWarnings("HiddenField") + List children = children(); + // eliminate children (they are rendered as part of the tree) + int remainingProperties = TO_STRING_MAX_PROP; + int maxWidth = 0; + boolean needsComma = false; + + List props = nodeProperties(); + for (Object prop : props) { + // consider a property if it is not ignored AND + // it's not a child (optional) + if ((skipIfChild && (children.contains(prop) || children.equals(prop))) == false) { + if (remainingProperties-- < 0) { + sb.append("...").append(props.size() - TO_STRING_MAX_PROP).append("fields not shown"); + break; + } + + if (needsComma) { + sb.append(","); + } + + String stringValue = toString(prop); + + // : Objects.toString(prop); + if (maxWidth + stringValue.length() > TO_STRING_MAX_WIDTH) { + int cutoff = Math.max(0, TO_STRING_MAX_WIDTH - maxWidth); + sb.append(stringValue.substring(0, cutoff)); + sb.append("\n"); + stringValue = stringValue.substring(cutoff); + maxWidth = 0; + } + maxWidth += stringValue.length(); + sb.append(stringValue); + + needsComma = true; + } + } + + return sb.toString(); + } + + private static String toString(Object obj) { + StringBuilder sb = new StringBuilder(); + toString(sb, obj); + return sb.toString(); + } + + private static void toString(StringBuilder sb, Object obj) { + if (obj instanceof Iterable) { + sb.append("["); + for (Iterator it = ((Iterable) obj).iterator(); it.hasNext();) { + Object o = it.next(); + toString(sb, o); + if (it.hasNext()) { + sb.append(", "); + } + } + sb.append("]"); + } else if (obj instanceof Node) { + sb.append(((Node) obj).nodeString()); + } else { + sb.append(Objects.toString(obj)); + } + } + + private boolean containsNull(List us) { + // Use custom implementation because some implementations of `List.contains` (e.g. ImmutableCollections$AbstractImmutableList) throw + // a NPE if any of the elements is null. + for (U u : us) { + if (u == null) { + return true; + } + } + return false; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/NodeInfo.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/NodeInfo.java new file mode 100644 index 000000000000..e8ce23bc20fd --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/NodeInfo.java @@ -0,0 +1,511 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static java.util.Collections.emptyList; +import static java.util.Collections.unmodifiableList; + +/** + * Information about a {@link Node}. + *

+ * All the uses of this are fairly non-OO and we're looking + * for ways to use this less and less. + *

+ * The implementations of this class are super copy-and-paste-ish + * but they are better then the sneaky reflection tricks we had + * earlier. Still terrifying. + * + * @param actual subclass of node that produced this {@linkplain NodeInfo} + */ +public abstract class NodeInfo> { + protected final T node; + + private NodeInfo(T node) { + this.node = node; + } + + /** + * Values for all properties on the instance that created + * this {@linkplain NodeInfo}. + */ + public final List properties() { + return unmodifiableList(innerProperties()); + } + + protected abstract List innerProperties(); + + /** + * Transform the properties on {@code node}, returning a new instance + * of {@code N} if any properties change. + */ + final T transform(Function rule, Class typeToken) { + List children = node.children(); + + Function realRule = p -> { + if (p != children && false == children.contains(p) && (p == null || typeToken.isInstance(p))) { + return rule.apply(typeToken.cast(p)); + } + return p; + }; + return innerTransform(realRule); + } + + protected abstract T innerTransform(Function rule); + + /** + * Builds a {@link NodeInfo} for Nodes without any properties. + */ + public static > NodeInfo create(T n) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return emptyList(); + } + + protected T innerTransform(Function rule) { + return node; + } + }; + } + + public static , P1> NodeInfo create(T n, BiFunction ctor, P1 p1) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + + return same ? node : ctor.apply(node.source(), newP1); + } + }; + } + + public static , P1, P2> NodeInfo create(T n, NodeCtor2 ctor, P1 p1, P2 p2) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + + return same ? node : ctor.apply(node.source(), newP1, newP2); + } + }; + } + + public interface NodeCtor2 { + T apply(Source l, P1 p1, P2 p2); + } + + public static , P1, P2, P3> NodeInfo create(T n, NodeCtor3 ctor, P1 p1, P2 p2, P3 p3) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3); + } + }; + } + + public interface NodeCtor3 { + T apply(Source l, P1 p1, P2 p2, P3 p3); + } + + public static , P1, P2, P3, P4> NodeInfo create( + T n, + NodeCtor4 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4); + } + }; + } + + public interface NodeCtor4 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4); + } + + public static , P1, P2, P3, P4, P5> NodeInfo create( + T n, + NodeCtor5 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4, p5); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + @SuppressWarnings("unchecked") + P5 newP5 = (P5) rule.apply(p5); + same &= Objects.equals(p5, newP5); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4, newP5); + } + }; + } + + public interface NodeCtor5 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); + } + + public static , P1, P2, P3, P4, P5, P6> NodeInfo create( + T n, + NodeCtor6 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5, + P6 p6 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4, p5, p6); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + @SuppressWarnings("unchecked") + P5 newP5 = (P5) rule.apply(p5); + same &= Objects.equals(p5, newP5); + @SuppressWarnings("unchecked") + P6 newP6 = (P6) rule.apply(p6); + same &= Objects.equals(p6, newP6); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4, newP5, newP6); + } + }; + } + + public interface NodeCtor6 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6); + } + + public static , P1, P2, P3, P4, P5, P6, P7> NodeInfo create( + T n, + NodeCtor7 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5, + P6 p6, + P7 p7 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4, p5, p6, p7); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + @SuppressWarnings("unchecked") + P5 newP5 = (P5) rule.apply(p5); + same &= Objects.equals(p5, newP5); + @SuppressWarnings("unchecked") + P6 newP6 = (P6) rule.apply(p6); + same &= Objects.equals(p6, newP6); + @SuppressWarnings("unchecked") + P7 newP7 = (P7) rule.apply(p7); + same &= Objects.equals(p7, newP7); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4, newP5, newP6, newP7); + } + }; + } + + public interface NodeCtor7 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7); + } + + public static , P1, P2, P3, P4, P5, P6, P7, P8> NodeInfo create( + T n, + NodeCtor8 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5, + P6 p6, + P7 p7, + P8 p8 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4, p5, p6, p7, p8); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + @SuppressWarnings("unchecked") + P5 newP5 = (P5) rule.apply(p5); + same &= Objects.equals(p5, newP5); + @SuppressWarnings("unchecked") + P6 newP6 = (P6) rule.apply(p6); + same &= Objects.equals(p6, newP6); + @SuppressWarnings("unchecked") + P7 newP7 = (P7) rule.apply(p7); + same &= Objects.equals(p7, newP7); + @SuppressWarnings("unchecked") + P8 newP8 = (P8) rule.apply(p8); + same &= Objects.equals(p8, newP8); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4, newP5, newP6, newP7, newP8); + } + }; + } + + public interface NodeCtor8 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8); + } + + public static , P1, P2, P3, P4, P5, P6, P7, P8, P9> NodeInfo create( + T n, + NodeCtor9 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5, + P6 p6, + P7 p7, + P8 p8, + P9 p9 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + @SuppressWarnings("unchecked") + P5 newP5 = (P5) rule.apply(p5); + same &= Objects.equals(p5, newP5); + @SuppressWarnings("unchecked") + P6 newP6 = (P6) rule.apply(p6); + same &= Objects.equals(p6, newP6); + @SuppressWarnings("unchecked") + P7 newP7 = (P7) rule.apply(p7); + same &= Objects.equals(p7, newP7); + @SuppressWarnings("unchecked") + P8 newP8 = (P8) rule.apply(p8); + same &= Objects.equals(p8, newP8); + @SuppressWarnings("unchecked") + P9 newP9 = (P9) rule.apply(p9); + same &= Objects.equals(p9, newP9); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4, newP5, newP6, newP7, newP8, newP9); + } + }; + } + + public interface NodeCtor9 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9); + } + + public static , P1, P2, P3, P4, P5, P6, P7, P8, P9, P10> NodeInfo create( + T n, + NodeCtor10 ctor, + P1 p1, + P2 p2, + P3 p3, + P4 p4, + P5 p5, + P6 p6, + P7 p7, + P8 p8, + P9 p9, + P10 p10 + ) { + return new NodeInfo(n) { + @Override + protected List innerProperties() { + return Arrays.asList(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } + + protected T innerTransform(Function rule) { + boolean same = true; + + @SuppressWarnings("unchecked") + P1 newP1 = (P1) rule.apply(p1); + same &= Objects.equals(p1, newP1); + @SuppressWarnings("unchecked") + P2 newP2 = (P2) rule.apply(p2); + same &= Objects.equals(p2, newP2); + @SuppressWarnings("unchecked") + P3 newP3 = (P3) rule.apply(p3); + same &= Objects.equals(p3, newP3); + @SuppressWarnings("unchecked") + P4 newP4 = (P4) rule.apply(p4); + same &= Objects.equals(p4, newP4); + @SuppressWarnings("unchecked") + P5 newP5 = (P5) rule.apply(p5); + same &= Objects.equals(p5, newP5); + @SuppressWarnings("unchecked") + P6 newP6 = (P6) rule.apply(p6); + same &= Objects.equals(p6, newP6); + @SuppressWarnings("unchecked") + P7 newP7 = (P7) rule.apply(p7); + same &= Objects.equals(p7, newP7); + @SuppressWarnings("unchecked") + P8 newP8 = (P8) rule.apply(p8); + same &= Objects.equals(p8, newP8); + @SuppressWarnings("unchecked") + P9 newP9 = (P9) rule.apply(p9); + same &= Objects.equals(p9, newP9); + @SuppressWarnings("unchecked") + P10 newP10 = (P10) rule.apply(p10); + same &= Objects.equals(p10, newP10); + + return same ? node : ctor.apply(node.source(), newP1, newP2, newP3, newP4, newP5, newP6, newP7, newP8, newP9, newP10); + } + }; + } + + public interface NodeCtor10 { + T apply(Source l, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/NodeUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/NodeUtils.java new file mode 100644 index 000000000000..e6a296b41d5a --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/NodeUtils.java @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import java.util.Collection; +import java.util.Iterator; + +public abstract class NodeUtils { + public static , B extends Node> String diffString(A left, B right) { + return diffString(left.toString(), right.toString()); + } + + public static String diffString(String left, String right) { + // break the strings into lines + // then compare each line + String[] leftSplit = left.split("\\n"); + String[] rightSplit = right.split("\\n"); + + // find max - we could use streams but autoboxing is not cool + int leftMaxPadding = 0; + for (String string : leftSplit) { + leftMaxPadding = Math.max(string.length(), leftMaxPadding); + } + + // try to allocate the buffer - 5 represents the column comparison chars + StringBuilder sb = new StringBuilder(left.length() + right.length() + Math.max(left.length(), right.length()) * 3); + + boolean leftAvailable = true, rightAvailable = true; + for (int leftIndex = 0, rightIndex = 0; leftAvailable || rightAvailable; leftIndex++, rightIndex++) { + String leftRow = "", rightRow = leftRow; + if (leftIndex < leftSplit.length) { + leftRow = leftSplit[leftIndex]; + } else { + leftAvailable = false; + } + sb.append(leftRow); + for (int i = leftRow.length(); i < leftMaxPadding; i++) { + sb.append(" "); + } + // right side still available + if (rightIndex < rightSplit.length) { + rightRow = rightSplit[rightIndex]; + } else { + rightAvailable = false; + } + if (leftAvailable || rightAvailable) { + sb.append(leftRow.equals(rightRow) ? " = " : " ! "); + sb.append(rightRow); + sb.append("\n"); + } + } + return sb.toString(); + } + + private static final int TO_STRING_LIMIT = 52; + + public static String limitedToString(Collection c) { + Iterator it = c.iterator(); + if (it.hasNext() == false) { + return "[]"; + } + + // ..] + StringBuilder sb = new StringBuilder(TO_STRING_LIMIT + 4); + sb.append('['); + for (;;) { + E e = it.next(); + String next = e == c ? "(this Collection)" : String.valueOf(e); + if (next.length() + sb.length() > TO_STRING_LIMIT) { + sb.append(next.substring(0, Math.max(0, TO_STRING_LIMIT - sb.length()))); + sb.append('.').append('.').append(']'); + return sb.toString(); + } else { + sb.append(next); + } + if (it.hasNext() == false) { + return sb.append(']').toString(); + } + sb.append(',').append(' '); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java new file mode 100644 index 000000000000..23d05bdf9927 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/tree/Source.java @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.tree; + +import java.util.Objects; + +public final class Source { + + public static final Source EMPTY = new Source(Location.EMPTY, ""); + + private final Location location; + private final String text; + + public Source(int line, int charPositionInLine, String text) { + this(new Location(line, charPositionInLine), text); + } + + public Source(Location location, String text) { + this.location = location; + this.text = text; + } + + // TODO: rename to location() + public Location source() { + return location; + } + + public String text() { + return text; + } + + @Override + public int hashCode() { + return Objects.hash(location, text); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + Source other = (Source) obj; + return Objects.equals(location, other.location) && Objects.equals(text, other.text); + } + + @Override + public String toString() { + return text + location; + } + + public static Source synthetic(String text) { + return new Source(Location.EMPTY, text); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Converter.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Converter.java new file mode 100644 index 000000000000..995971b9173d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Converter.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.common.io.stream.NamedWriteable; + +public interface Converter extends NamedWriteable { + + Object convert(Object value); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java new file mode 100644 index 000000000000..d1749ac3bf3e --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.search.sort.ScriptSortBuilder; + +import java.util.Locale; +import java.util.Objects; + +public class DataType { + + private final String typeName; + + private final String name; + + private final String esType; + + private final int size; + + /** + * True if the type represents an integer number + */ + private final boolean isInteger; + + /** + * True if the type represents a rational number + */ + private final boolean isRational; + + /** + * True if the type supports doc values by default + */ + private final boolean docValues; + + public DataType(String esName, int size, boolean isInteger, boolean isRational, boolean hasDocValues) { + this(null, esName, size, isInteger, isRational, hasDocValues); + } + + public DataType(String typeName, String esType, int size, boolean isInteger, boolean isRational, boolean hasDocValues) { + String typeString = typeName != null ? typeName : esType; + this.typeName = typeString.toLowerCase(Locale.ROOT); + this.name = typeString.toUpperCase(Locale.ROOT); + this.esType = esType; + this.size = size; + this.isInteger = isInteger; + this.isRational = isRational; + this.docValues = hasDocValues; + } + + public String name() { + return name; + } + + public String typeName() { + return typeName; + } + + public String esType() { + return esType; + } + + public ScriptSortBuilder.ScriptSortType scriptSortType() { + return isNumeric() ? ScriptSortBuilder.ScriptSortType.NUMBER + : this == DataTypes.VERSION ? ScriptSortBuilder.ScriptSortType.VERSION + : ScriptSortBuilder.ScriptSortType.STRING; + } + + public boolean isInteger() { + return isInteger; + } + + public boolean isRational() { + return isRational; + } + + public boolean isNumeric() { + return isInteger || isRational; + } + + public int size() { + return size; + } + + public boolean hasDocValues() { + return docValues; + } + + @Override + public int hashCode() { + return Objects.hash(typeName, esType, size, isInteger, isRational, docValues); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null || getClass() != obj.getClass()) { + return false; + } + + DataType other = (DataType) obj; + return Objects.equals(typeName, other.typeName) + && Objects.equals(esType, other.esType) + && size == other.size + && isInteger == other.isInteger + && isRational == other.isRational + && docValues == other.docValues; + } + + @Override + public String toString() { + return name; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeConverter.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeConverter.java new file mode 100644 index 000000000000..03466655ccc3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeConverter.java @@ -0,0 +1,633 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.network.InetAddresses; +import org.elasticsearch.core.Booleans; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.versionfield.Version; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.Locale; +import java.util.function.DoubleFunction; +import java.util.function.Function; + +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BYTE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SHORT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isDateTime; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isPrimitive; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isString; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.UNSIGNED_LONG_MAX; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.inUnsignedLongRange; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.isUnsignedLong; + +/** + * Conversion utility from one Elasticsearch data type to another Elasticsearch data types. + */ +public final class DataTypeConverter { + + private DataTypeConverter() {} + + /** + * Returns the type compatible with both left and right types + *

+ * If one of the types is null - returns another type + * If both types are numeric - returns type with the highest precision int < long < float < double + * If one of the types is string and another numeric - returns numeric + */ + public static DataType commonType(DataType left, DataType right) { + if (left == right) { + return left; + } + if (left == NULL) { + return right; + } + if (right == NULL) { + return left; + } + if (isString(left) && isString(right)) { + if (left == TEXT || right == TEXT) { + return TEXT; + } + if (left == KEYWORD) { + return KEYWORD; + } + return right; + } + if (left.isNumeric() && right.isNumeric()) { + // if one is int + if (left.isInteger()) { + // promote the highest int + if (right.isInteger()) { + if (left == UNSIGNED_LONG || right == UNSIGNED_LONG) { + return UNSIGNED_LONG; + } + return left.size() > right.size() ? left : right; + } + // promote the rational + return right; + } + // try the other side + if (right.isInteger()) { + return left; + } + // promote the highest rational + return left.size() > right.size() ? left : right; + } + if (isString(left)) { + if (right.isNumeric()) { + return right; + } + } + if (isString(right)) { + if (left.isNumeric()) { + return left; + } + } + + if (isDateTime(left) && isDateTime(right)) { + return DATETIME; + } + + // none found + return null; + } + + /** + * Returns true if the from type can be converted to the to type, false - otherwise + */ + public static boolean canConvert(DataType from, DataType to) { + // Special handling for nulls and if conversion is not requires + if (from == to || from == NULL) { + return true; + } + // only primitives are supported so far + return isPrimitive(from) && isPrimitive(to) && converterFor(from, to) != null; + } + + /** + * Get the conversion from one type to another. + */ + public static Converter converterFor(DataType from, DataType to) { + // Special handling for nulls and if conversion is not requires + if (from == to || (isDateTime(from) && isDateTime(to))) { + return DefaultConverter.IDENTITY; + } + if (to == NULL || from == NULL) { + return DefaultConverter.TO_NULL; + } + // proper converters + if (to == KEYWORD || to == TEXT) { + return conversionToString(from); + } + if (to == LONG) { + return conversionToLong(from); + } + if (to == UNSIGNED_LONG) { + return conversionToUnsignedLong(from); + } + if (to == INTEGER) { + return conversionToInt(from); + } + if (to == SHORT) { + return conversionToShort(from); + } + if (to == BYTE) { + return conversionToByte(from); + } + if (to == FLOAT) { + return conversionToFloat(from); + } + if (to == DOUBLE) { + return conversionToDouble(from); + } + if (isDateTime(to)) { + return conversionToDateTime(from); + } + if (to == BOOLEAN) { + return conversionToBoolean(from); + } + if (to == IP) { + return conversionToIp(from); + } + if (to == VERSION) { + return conversionToVersion(from); + } + return null; + } + + private static Converter conversionToString(DataType from) { + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_STRING; + } + return DefaultConverter.OTHER_TO_STRING; + } + + private static Converter conversionToIp(DataType from) { + if (isString(from)) { + return DefaultConverter.STRING_TO_IP; + } + return null; + } + + private static Converter conversionToVersion(DataType from) { + if (isString(from)) { + return DefaultConverter.STRING_TO_VERSION; + } + return null; + } + + private static Converter conversionToUnsignedLong(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_UNSIGNED_LONG; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_UNSIGNED_LONG; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_UNSIGNED_LONG; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_UNSIGNED_LONG; + } + if (from == DATETIME) { + return DefaultConverter.DATETIME_TO_UNSIGNED_LONG; + } + return null; + } + + private static Converter conversionToLong(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_LONG; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_LONG; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_LONG; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_LONG; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_LONG; + } + return null; + } + + private static Converter conversionToInt(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_INT; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_INT; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_INT; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_INT; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_INT; + } + return null; + } + + private static Converter conversionToShort(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_SHORT; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_SHORT; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_SHORT; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_SHORT; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_SHORT; + } + return null; + } + + private static Converter conversionToByte(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_BYTE; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_BYTE; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_BYTE; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_BYTE; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_BYTE; + } + return null; + } + + private static DefaultConverter conversionToFloat(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_FLOAT; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_FLOAT; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_FLOAT; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_FLOAT; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_FLOAT; + } + return null; + } + + private static DefaultConverter conversionToDouble(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_DOUBLE; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_DOUBLE; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_DOUBLE; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_DOUBLE; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_DOUBLE; + } + return null; + } + + private static DefaultConverter conversionToDateTime(DataType from) { + if (from.isRational()) { + return DefaultConverter.RATIONAL_TO_DATETIME; + } + if (from.isInteger()) { + return DefaultConverter.INTEGER_TO_DATETIME; + } + if (from == BOOLEAN) { + return DefaultConverter.BOOL_TO_DATETIME; // We emit an int here which is ok because of Java's casting rules + } + if (isString(from)) { + return DefaultConverter.STRING_TO_DATETIME; + } + return null; + } + + private static DefaultConverter conversionToBoolean(DataType from) { + if (from.isNumeric()) { + return DefaultConverter.NUMERIC_TO_BOOLEAN; + } + if (isString(from)) { + return DefaultConverter.STRING_TO_BOOLEAN; + } + if (isDateTime(from)) { + return DefaultConverter.DATETIME_TO_BOOLEAN; + } + return null; + } + + public static byte safeToByte(long x) { + if (x > Byte.MAX_VALUE || x < Byte.MIN_VALUE) { + throw new InvalidArgumentException("[{}] out of [byte] range", x); + } + return (byte) x; + } + + public static short safeToShort(long x) { + if (x > Short.MAX_VALUE || x < Short.MIN_VALUE) { + throw new InvalidArgumentException("[{}] out of [short] range", x); + } + return (short) x; + } + + public static int safeToInt(long x) { + if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) { + throw new InvalidArgumentException("[{}] out of [integer] range", x); + } + return (int) x; + } + + public static int safeToInt(double x) { + if (x > Integer.MAX_VALUE || x < Integer.MIN_VALUE) { + throw new InvalidArgumentException("[{}] out of [integer] range", x); + } + // cast is safe, double can represent all of int's range + return (int) Math.round(x); + } + + public static long safeDoubleToLong(double x) { + if (x > Long.MAX_VALUE || x < Long.MIN_VALUE) { + throw new InvalidArgumentException("[{}] out of [long] range", x); + } + return Math.round(x); + } + + public static Long safeToLong(Number x) { + try { + if (x instanceof BigInteger) { + return ((BigInteger) x).longValueExact(); + } + // integer converters are also provided double values (aggs generated on integer fields) + if (x instanceof Double || x instanceof Float) { + return safeDoubleToLong(x.doubleValue()); + } + return x.longValue(); + } catch (ArithmeticException ae) { + throw new InvalidArgumentException(ae, "[{}] out of [long] range", x); + } + } + + public static BigInteger safeToUnsignedLong(Double x) { + if (inUnsignedLongRange(x) == false) { + throw new InvalidArgumentException("[{}] out of [unsigned_long] range", x); + } + return BigDecimal.valueOf(x).toBigInteger(); + } + + public static BigInteger safeToUnsignedLong(Long x) { + if (x < 0) { + throw new InvalidArgumentException("[{}] out of [unsigned_long] range", x); + } + return BigInteger.valueOf(x); + } + + public static BigInteger safeToUnsignedLong(String x) { + BigInteger bi = new BigDecimal(x).toBigInteger(); + if (isUnsignedLong(bi) == false) { + throw new InvalidArgumentException("[{}] out of [unsigned_long] range", x); + } + return bi; + } + + // "unsafe" value conversion to unsigned long (vs. "safe", type-only conversion of safeToUnsignedLong()); + // -1L -> 18446744073709551615 (=UNSIGNED_LONG_MAX) + public static BigInteger toUnsignedLong(Number number) { + BigInteger bi = BigInteger.valueOf(number.longValue()); + return bi.signum() < 0 ? bi.and(UNSIGNED_LONG_MAX) : bi; + } + + public static Number toInteger(double x, DataType dataType) { + long l = safeDoubleToLong(x); + + if (dataType == BYTE) { + return safeToByte(l); + } + if (dataType == SHORT) { + return safeToShort(l); + } + if (dataType == INTEGER) { + return safeToInt(l); + } + return l; + } + + public static boolean convertToBoolean(String val) { + String lowVal = val.toLowerCase(Locale.ROOT); + if (Booleans.isBoolean(lowVal) == false) { + throw new InvalidArgumentException("cannot cast [{}] to [boolean]", val); + } + return Booleans.parseBoolean(lowVal); + } + + /** + * Converts arbitrary object to the desired data type. + *

+ * Throws InvalidArgumentException if such conversion is not possible + */ + public static Object convert(Object value, DataType dataType) { + DataType detectedType = DataTypes.fromJava(value); + if (detectedType == dataType || value == null) { + return value; + } + Converter converter = converterFor(detectedType, dataType); + + if (converter == null) { + throw new InvalidArgumentException( + "cannot convert from [{}], type [{}] to [{}]", + value, + detectedType.typeName(), + dataType.typeName() + ); + } + + return converter.convert(value); + } + + /** + * Reference to a data type conversion that can be serialized. Note that the position in the enum + * is important because it is used for serialization. + */ + public enum DefaultConverter implements Converter { + IDENTITY(Function.identity()), + TO_NULL(value -> null), + + DATETIME_TO_STRING(o -> DateUtils.toString((ZonedDateTime) o)), + OTHER_TO_STRING(String::valueOf), + + RATIONAL_TO_UNSIGNED_LONG(fromDouble(DataTypeConverter::safeToUnsignedLong)), + INTEGER_TO_UNSIGNED_LONG(fromNumber(value -> DataTypeConverter.safeToUnsignedLong(value.longValue()))), + STRING_TO_UNSIGNED_LONG(fromString(DataTypeConverter::safeToUnsignedLong, "unsigned_long")), + DATETIME_TO_UNSIGNED_LONG(fromDateTime(DataTypeConverter::safeToUnsignedLong)), + + RATIONAL_TO_LONG(fromDouble(DataTypeConverter::safeDoubleToLong)), + INTEGER_TO_LONG(fromNumber(DataTypeConverter::safeToLong)), + STRING_TO_LONG(fromString(Long::valueOf, "long")), + DATETIME_TO_LONG(fromDateTime(value -> value)), + + RATIONAL_TO_INT(fromDouble(value -> safeToInt(safeDoubleToLong(value)))), + INTEGER_TO_INT(fromNumber(value -> safeToInt(safeToLong(value)))), + BOOL_TO_INT(fromBool(value -> value ? 1 : 0)), + STRING_TO_INT(fromString(Integer::valueOf, "integer")), + DATETIME_TO_INT(fromDateTime(DataTypeConverter::safeToInt)), + + RATIONAL_TO_SHORT(fromDouble(value -> safeToShort(safeDoubleToLong(value)))), + INTEGER_TO_SHORT(fromNumber(value -> safeToShort(safeToLong(value)))), + BOOL_TO_SHORT(fromBool(value -> value ? (short) 1 : (short) 0)), + STRING_TO_SHORT(fromString(Short::valueOf, "short")), + DATETIME_TO_SHORT(fromDateTime(DataTypeConverter::safeToShort)), + + RATIONAL_TO_BYTE(fromDouble(value -> safeToByte(safeDoubleToLong(value)))), + INTEGER_TO_BYTE(fromNumber(value -> safeToByte(safeToLong(value)))), + BOOL_TO_BYTE(fromBool(value -> value ? (byte) 1 : (byte) 0)), + STRING_TO_BYTE(fromString(Byte::valueOf, "byte")), + DATETIME_TO_BYTE(fromDateTime(DataTypeConverter::safeToByte)), + + // TODO floating point conversions are lossy but conversions to integer are not. Are we ok with that? + RATIONAL_TO_FLOAT(fromDouble(value -> (float) value)), + INTEGER_TO_FLOAT(fromNumber(Number::floatValue)), + BOOL_TO_FLOAT(fromBool(value -> value ? 1f : 0f)), + STRING_TO_FLOAT(fromString(Float::valueOf, "float")), + DATETIME_TO_FLOAT(fromDateTime(value -> (float) value)), + + RATIONAL_TO_DOUBLE(fromDouble(Double::valueOf)), + INTEGER_TO_DOUBLE(fromNumber(Number::doubleValue)), + BOOL_TO_DOUBLE(fromBool(value -> value ? 1d : 0d)), + STRING_TO_DOUBLE(fromString(Double::valueOf, "double")), + DATETIME_TO_DOUBLE(fromDateTime(Double::valueOf)), + + RATIONAL_TO_DATETIME(toDateTime(RATIONAL_TO_LONG)), + INTEGER_TO_DATETIME(toDateTime(INTEGER_TO_LONG)), + BOOL_TO_DATETIME(toDateTime(BOOL_TO_INT)), + STRING_TO_DATETIME(fromString(DateUtils::asDateTime, "datetime")), + + NUMERIC_TO_BOOLEAN(fromDouble(value -> value != 0)), + STRING_TO_BOOLEAN(fromString(DataTypeConverter::convertToBoolean, "boolean")), + DATETIME_TO_BOOLEAN(fromDateTime(value -> value != 0)), + + BOOL_TO_UNSIGNED_LONG(fromBool(value -> value ? BigInteger.ONE : BigInteger.ZERO)), + BOOL_TO_LONG(fromBool(value -> value ? 1L : 0L)), + + STRING_TO_IP(o -> { + if (InetAddresses.isInetAddress(o.toString()) == false) { + throw new InvalidArgumentException("[{}] is not a valid IPv4 or IPv6 address", o); + } + return o; + }), + STRING_TO_VERSION(o -> new Version(o.toString())); + + public static final String NAME = "dtc-def"; + + private final Function converter; + + DefaultConverter(Function converter) { + this.converter = converter; + } + + private static Function fromDouble(DoubleFunction converter) { + return (Object l) -> converter.apply(((Number) l).doubleValue()); + } + + private static Function fromNumber(Function converter) { + return l -> converter.apply((Number) l); + } + + public static Function fromString(Function converter, String to) { + return (Object value) -> { + try { + return converter.apply(value.toString()); + } catch (NumberFormatException e) { + throw new InvalidArgumentException(e, "cannot cast [{}] to [{}]", value, to); + } catch (DateTimeParseException | IllegalArgumentException e) { + throw new InvalidArgumentException(e, "cannot cast [{}] to [{}]: {}", value, to, e.getMessage()); + } + }; + } + + private static Function fromBool(Function converter) { + return (Object l) -> converter.apply(((Boolean) l)); + } + + private static Function fromDateTime(Function converter) { + return l -> converter.apply(((ZonedDateTime) l).toInstant().toEpochMilli()); + } + + private static Function toDateTime(Converter conversion) { + return l -> DateUtils.asDateTime(((Number) conversion.convert(l)).longValue()); + } + + @Override + public Object convert(Object l) { + if (l == null) { + return null; + } + return converter.apply(l); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeEnum(this); + } + + public static Converter read(StreamInput in) throws IOException { + return in.readEnum(DefaultConverter.class); + } + } + + public static DataType asInteger(DataType dataType) { + if (dataType.isNumeric() == false) { + return dataType; + } + + return dataType.isInteger() ? dataType : LONG; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeRegistry.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeRegistry.java new file mode 100644 index 000000000000..b96c187deeb3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypeRegistry.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.index.mapper.TimeSeriesParams; + +import java.util.Collection; + +/** + * Central class for {@link DataType} creation and conversion. + */ +public interface DataTypeRegistry { + + // + // Discovery + // + Collection dataTypes(); + + DataType fromEs(String typeName, TimeSeriesParams.MetricType metricType); + + DataType fromJava(Object value); + + boolean isUnsupported(DataType type); + + // + // Conversion methods + // + boolean canConvert(DataType from, DataType to); + + Object convert(Object value, DataType type); + + DataType commonType(DataType left, DataType right); +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypes.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypes.java new file mode 100644 index 000000000000..77f143dd3b20 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataTypes.java @@ -0,0 +1,190 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.index.mapper.SourceFieldMapper; + +import java.math.BigInteger; +import java.time.ZonedDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toUnmodifiableMap; + +public final class DataTypes { + + // tag::noformat + public static final DataType UNSUPPORTED = new DataType("UNSUPPORTED", null, 0, false, false, false); + + public static final DataType NULL = new DataType("null", 0, false, false, false); + + public static final DataType BOOLEAN = new DataType("boolean", 1, false, false, false); + // integer numeric + public static final DataType BYTE = new DataType("byte", Byte.BYTES, true, false, true); + public static final DataType SHORT = new DataType("short", Short.BYTES, true, false, true); + public static final DataType INTEGER = new DataType("integer", Integer.BYTES, true, false, true); + public static final DataType LONG = new DataType("long", Long.BYTES, true, false, true); + public static final DataType UNSIGNED_LONG = new DataType("unsigned_long", Long.BYTES, true, false, true); + // decimal numeric + public static final DataType DOUBLE = new DataType("double", Double.BYTES, false, true, true); + public static final DataType FLOAT = new DataType("float", Float.BYTES, false, true, true); + public static final DataType HALF_FLOAT = new DataType("half_float", Float.BYTES, false, true, true); + public static final DataType SCALED_FLOAT = new DataType("scaled_float", Long.BYTES, false, true, true); + // string + public static final DataType KEYWORD = new DataType("keyword", Integer.MAX_VALUE, false, false, true); + public static final DataType TEXT = new DataType("text", Integer.MAX_VALUE, false, false, false); + // date + public static final DataType DATETIME = new DataType("DATETIME", "date", Long.BYTES, false, false, true); + // ip + public static final DataType IP = new DataType("ip", 45, false, false, true); + // version + public static final DataType VERSION = new DataType("version", Integer.MAX_VALUE, false, false, true); + // binary + public static final DataType BINARY = new DataType("binary", Integer.MAX_VALUE, false, false, true); + // complex types + public static final DataType OBJECT = new DataType("object", 0, false, false, false); + public static final DataType NESTED = new DataType("nested", 0, false, false, false); + //end::noformat + public static final DataType SOURCE = new DataType( + SourceFieldMapper.NAME, + SourceFieldMapper.NAME, + Integer.MAX_VALUE, + false, + false, + false + ); + + private static final Collection TYPES = Stream.of( + UNSUPPORTED, + NULL, + BOOLEAN, + BYTE, + SHORT, + INTEGER, + LONG, + UNSIGNED_LONG, + DOUBLE, + FLOAT, + HALF_FLOAT, + SCALED_FLOAT, + KEYWORD, + TEXT, + DATETIME, + IP, + VERSION, + BINARY, + OBJECT, + NESTED + ).sorted(Comparator.comparing(DataType::typeName)).toList(); + + private static final Map NAME_TO_TYPE = TYPES.stream().collect(toUnmodifiableMap(DataType::typeName, t -> t)); + + private static Map ES_TO_TYPE; + + static { + Map map = TYPES.stream().filter(e -> e.esType() != null).collect(toMap(DataType::esType, t -> t)); + map.put("date_nanos", DATETIME); + ES_TO_TYPE = Collections.unmodifiableMap(map); + } + + private DataTypes() {} + + public static Collection types() { + return TYPES; + } + + public static DataType fromTypeName(String name) { + return NAME_TO_TYPE.get(name.toLowerCase(Locale.ROOT)); + } + + public static DataType fromEs(String name) { + DataType type = ES_TO_TYPE.get(name); + return type != null ? type : UNSUPPORTED; + } + + public static DataType fromJava(Object value) { + if (value == null) { + return NULL; + } + if (value instanceof Integer) { + return INTEGER; + } + if (value instanceof Long) { + return LONG; + } + if (value instanceof BigInteger) { + return UNSIGNED_LONG; + } + if (value instanceof Boolean) { + return BOOLEAN; + } + if (value instanceof Double) { + return DOUBLE; + } + if (value instanceof Float) { + return FLOAT; + } + if (value instanceof Byte) { + return BYTE; + } + if (value instanceof Short) { + return SHORT; + } + if (value instanceof ZonedDateTime) { + return DATETIME; + } + if (value instanceof String || value instanceof Character) { + return KEYWORD; + } + + return null; + } + + public static boolean isUnsupported(DataType from) { + return from == UNSUPPORTED; + } + + public static boolean isString(DataType t) { + return t == KEYWORD || t == TEXT; + } + + public static boolean isPrimitive(DataType t) { + return t != OBJECT && t != NESTED && t != UNSUPPORTED; + } + + public static boolean isNull(DataType t) { + return t == NULL; + } + + public static boolean isNullOrNumeric(DataType t) { + return t.isNumeric() || isNull(t); + } + + public static boolean isSigned(DataType t) { + return t.isNumeric() && t.equals(UNSIGNED_LONG) == false; + } + + public static boolean isDateTime(DataType type) { + return type == DATETIME; + } + + public static boolean areCompatible(DataType left, DataType right) { + if (left == right) { + return true; + } else { + return (left == NULL || right == NULL) + || (isString(left) && isString(right)) + || (left.isNumeric() && right.isNumeric()) + || (isDateTime(left) && isDateTime(right)); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DateEsField.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DateEsField.java new file mode 100644 index 000000000000..a8c5ca7f1280 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DateEsField.java @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import java.util.Map; + +/** + * SQL-related information about an index field with date type + */ +public class DateEsField extends EsField { + + public static DateEsField dateEsField(String name, Map properties, boolean hasDocValues) { + return new DateEsField(name, DataTypes.DATETIME, properties, hasDocValues); + } + + private DateEsField(String name, DataType dataType, Map properties, boolean hasDocValues) { + super(name, dataType, properties, hasDocValues); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DateUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DateUtils.java new file mode 100644 index 000000000000..29d96dcb8201 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DateUtils.java @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.common.time.DateFormatters; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.Locale; + +import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; +import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME; + +//NB: Taken from sql-proto. +public final class DateUtils { + + public static final ZoneId UTC = ZoneId.of("Z"); + + private static final DateTimeFormatter DATE_OPTIONAL_TIME_FORMATTER_WHITESPACE = new DateTimeFormatterBuilder().append(ISO_LOCAL_DATE) + .optionalStart() + .appendLiteral(' ') + .append(ISO_LOCAL_TIME) + .optionalStart() + .appendZoneOrOffsetId() + .optionalEnd() + .toFormatter(Locale.ROOT) + .withZone(UTC); + private static final DateTimeFormatter DATE_OPTIONAL_TIME_FORMATTER_T_LITERAL = new DateTimeFormatterBuilder().append(ISO_LOCAL_DATE) + .optionalStart() + .appendLiteral('T') + .append(ISO_LOCAL_TIME) + .optionalStart() + .appendZoneOrOffsetId() + .optionalEnd() + .toFormatter(Locale.ROOT) + .withZone(UTC); + + private DateUtils() {} + + /** + * Creates a datetime from the millis since epoch (thus the time-zone is UTC). + */ + public static ZonedDateTime asDateTime(long millis) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), UTC); + } + + public static long asMillis(ZonedDateTime zonedDateTime) { + return zonedDateTime.toInstant().toEpochMilli(); + } + + /** + * Parses the given string into a DateTime using UTC as a default timezone. + */ + public static ZonedDateTime asDateTime(String dateFormat) { + int separatorIdx = dateFormat.indexOf('-'); // Find the first `-` date separator + if (separatorIdx == 0) { // first char = `-` denotes a negative year + separatorIdx = dateFormat.indexOf('-', 1); // Find the first `-` date separator past the negative year + } + // Find the second `-` date separator and move 3 places past the dayOfYear to find the time separator + // e.g. 2020-06-01T10:20:30.... + // ^ + // +3 = ^ + separatorIdx = dateFormat.indexOf('-', separatorIdx + 1) + 3; + + // Avoid index out of bounds - it will lead to DateTimeParseException anyways + if (separatorIdx >= dateFormat.length() || dateFormat.charAt(separatorIdx) == 'T') { + return DateFormatters.from(DATE_OPTIONAL_TIME_FORMATTER_T_LITERAL.parse(dateFormat)).withZoneSameInstant(UTC); + } else { + return DateFormatters.from(DATE_OPTIONAL_TIME_FORMATTER_WHITESPACE.parse(dateFormat)).withZoneSameInstant(UTC); + } + } + + public static String toString(ZonedDateTime dateTime) { + return StringUtils.toString(dateTime); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DefaultDataTypeRegistry.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DefaultDataTypeRegistry.java new file mode 100644 index 000000000000..cba409236e8c --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DefaultDataTypeRegistry.java @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.index.mapper.TimeSeriesParams; + +import java.util.Collection; + +public class DefaultDataTypeRegistry implements DataTypeRegistry { + + public static final DataTypeRegistry INSTANCE = new DefaultDataTypeRegistry(); + + private DefaultDataTypeRegistry() {} + + @Override + public Collection dataTypes() { + return DataTypes.types(); + } + + @Override + public DataType fromEs(String typeName, TimeSeriesParams.MetricType metricType) { + return DataTypes.fromEs(typeName); + } + + @Override + public DataType fromJava(Object value) { + return DataTypes.fromJava(value); + } + + @Override + public boolean isUnsupported(DataType type) { + return DataTypes.isUnsupported(type); + } + + @Override + public boolean canConvert(DataType from, DataType to) { + return DataTypeConverter.canConvert(from, to); + } + + @Override + public Object convert(Object value, DataType type) { + return DataTypeConverter.convert(value, type); + } + + @Override + public DataType commonType(DataType left, DataType right) { + return DataTypeConverter.commonType(left, right); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/EsField.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/EsField.java new file mode 100644 index 000000000000..6cb5c97545fd --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/EsField.java @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.core.Nullable; + +import java.util.Map; +import java.util.Objects; + +/** + * SQL-related information about an index field + */ +public class EsField { + + private final DataType esDataType; + private final boolean aggregatable; + private final Map properties; + private final String name; + private final boolean isAlias; + + public EsField(String name, DataType esDataType, Map properties, boolean aggregatable) { + this(name, esDataType, properties, aggregatable, false); + } + + public EsField(String name, DataType esDataType, Map properties, boolean aggregatable, boolean isAlias) { + this.name = name; + this.esDataType = esDataType; + this.aggregatable = aggregatable; + this.properties = properties; + this.isAlias = isAlias; + } + + /** + * Returns the field path + */ + public String getName() { + return name; + } + + /** + * The field type + */ + public DataType getDataType() { + return esDataType; + } + + /** + * This field can be aggregated + */ + public boolean isAggregatable() { + return aggregatable; + } + + /** + * Returns list of properties for the nested and object fields, list of subfield if the field + * was indexed in a few different ways or null otherwise + */ + @Nullable + public Map getProperties() { + return properties; + } + + /** + * This field is an alias to another field + */ + public boolean isAlias() { + return isAlias; + } + + /** + * Returns the path to the keyword version of this field if this field is text and it has a subfield that is + * indexed as keyword, throws an exception if such field is not found or the field name itself in all other cases. + * To avoid the exception {@link EsField#getExactInfo()} should be used beforehand, to check if an exact field exists + * and if not get the errorMessage which explains why is that. + */ + public EsField getExactField() { + return this; + } + + /** + * Returns and {@link Exact} object with all the necessary info about the field: + *
    + *
  • If it has an exact underlying field or not
  • + *
  • and if not an error message why it doesn't
  • + *
+ */ + public Exact getExactInfo() { + return Exact.EXACT_FIELD; + } + + @Override + public String toString() { + return name + "@" + esDataType.typeName() + "=" + properties; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EsField field = (EsField) o; + return aggregatable == field.aggregatable + && isAlias == field.isAlias + && esDataType == field.esDataType + && Objects.equals(name, field.name) + && Objects.equals(properties, field.properties); + } + + @Override + public int hashCode() { + return Objects.hash(esDataType, aggregatable, properties, name, isAlias); + } + + public static final class Exact { + + private static Exact EXACT_FIELD = new Exact(true, null); + + private boolean hasExact; + private String errorMsg; + + public Exact(boolean hasExact, String errorMsg) { + this.hasExact = hasExact; + this.errorMsg = errorMsg; + } + + public boolean hasExact() { + return hasExact; + } + + public String errorMsg() { + return errorMsg; + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/InvalidMappedField.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/InvalidMappedField.java new file mode 100644 index 000000000000..47f883c9ff1d --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/InvalidMappedField.java @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; + +/** + * Representation of field mapped differently across indices. + * Used during mapping discovery only. + */ +public class InvalidMappedField extends EsField { + + private final String errorMessage; + + public InvalidMappedField(String name, String errorMessage, Map properties) { + super(name, DataTypes.UNSUPPORTED, properties, false); + this.errorMessage = errorMessage; + } + + public InvalidMappedField(String name, String errorMessage) { + this(name, errorMessage, new TreeMap()); + } + + public InvalidMappedField(String name) { + this(name, StringUtils.EMPTY, new TreeMap()); + } + + public String errorMessage() { + return errorMessage; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), errorMessage); + } + + @Override + public boolean equals(Object obj) { + if (super.equals(obj)) { + InvalidMappedField other = (InvalidMappedField) obj; + return Objects.equals(errorMessage, other.errorMessage); + } + + return false; + } + + @Override + public EsField getExactField() { + throw new QlIllegalArgumentException("Field [" + getName() + "] is invalid, cannot access it"); + + } + + @Override + public Exact getExactInfo() { + return new Exact(false, "Field [" + getName() + "] is invalid, cannot access it"); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/KeywordEsField.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/KeywordEsField.java new file mode 100644 index 000000000000..f041890ed0e5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/KeywordEsField.java @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; + +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; + +/** + * SQL-related information about an index field with keyword type + */ +public class KeywordEsField extends EsField { + + private final int precision; + private final boolean normalized; + + public KeywordEsField(String name) { + this(name, Collections.emptyMap(), true, Short.MAX_VALUE, false); + } + + public KeywordEsField(String name, Map properties, boolean hasDocValues, int precision, boolean normalized) { + this(name, properties, hasDocValues, precision, normalized, false); + } + + public KeywordEsField( + String name, + Map properties, + boolean hasDocValues, + int precision, + boolean normalized, + boolean isAlias + ) { + this(name, KEYWORD, properties, hasDocValues, precision, normalized, isAlias); + } + + protected KeywordEsField( + String name, + DataType esDataType, + Map properties, + boolean hasDocValues, + int precision, + boolean normalized, + boolean isAlias + ) { + super(name, esDataType, properties, hasDocValues, isAlias); + this.precision = precision; + this.normalized = normalized; + } + + public int getPrecision() { + return precision; + } + + public boolean getNormalized() { + return normalized; + } + + @Override + public Exact getExactInfo() { + return new Exact(normalized == false, "Normalized keyword field cannot be used for exact match operations"); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (super.equals(o) == false) { + return false; + } + KeywordEsField that = (KeywordEsField) o; + return precision == that.precision && normalized == that.normalized; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), precision, normalized); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Schema.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Schema.java new file mode 100644 index 000000000000..fa7c1d7e1e3e --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Schema.java @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.xpack.esql.core.util.Check; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static java.util.Collections.emptyList; + +public class Schema implements Iterable { + + public interface Entry { + String name(); + + DataType type(); + } + + static class DefaultEntry implements Entry { + private final String name; + private final DataType type; + + DefaultEntry(String name, DataType type) { + this.name = name; + this.type = type; + } + + @Override + public String name() { + return name; + } + + @Override + public DataType type() { + return type; + } + } + + public static final Schema EMPTY = new Schema(emptyList(), emptyList()); + + private final List names; + private final List types; + + public Schema(List names, List types) { + Check.isTrue(names.size() == types.size(), "Different # of names {} vs types {}", names, types); + this.types = types; + this.names = names; + } + + public List names() { + return names; + } + + public List types() { + return types; + } + + public int size() { + return names.size(); + } + + public Entry get(int i) { + return new DefaultEntry(names.get(i), types.get(i)); + } + + public DataType type(String name) { + int indexOf = names.indexOf(name); + if (indexOf < 0) { + return null; + } + return types.get(indexOf); + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + private final int size = size(); + private int pos = -1; + + @Override + public boolean hasNext() { + return pos < size - 1; + } + + @Override + public Entry next() { + if (pos++ >= size) { + throw new NoSuchElementException(); + } + return get(pos); + } + }; + } + + public Stream stream() { + return StreamSupport.stream(spliterator(), false); + } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(iterator(), size(), 0); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int i = 0; i < names.size(); i++) { + if (i > 0) { + sb.append(","); + } + sb.append(names.get(i)); + sb.append(":"); + sb.append(types.get(i).typeName()); + } + sb.append("]"); + return sb.toString(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/StringUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/StringUtils.java new file mode 100644 index 000000000000..a833a302ade0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/StringUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.type; + +import java.sql.Timestamp; +import java.time.Duration; +import java.time.OffsetTime; +import java.time.Period; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; + +//FIXME: this class comes from sql-proto +// find a way to share it across or potentially just copy it over +final class StringUtils { + + public static final String EMPTY = ""; + + public static final DateTimeFormatter ISO_DATE_WITH_NANOS = new DateTimeFormatterBuilder().parseCaseInsensitive() + .append(ISO_LOCAL_DATE) + .appendLiteral('T') + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .appendFraction(NANO_OF_SECOND, 3, 9, true) + .appendOffsetId() + .toFormatter(Locale.ROOT); + + public static final DateTimeFormatter ISO_TIME_WITH_NANOS = new DateTimeFormatterBuilder().parseCaseInsensitive() + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .appendFraction(NANO_OF_SECOND, 3, 9, true) + .appendOffsetId() + .toFormatter(Locale.ROOT); + + private static final int SECONDS_PER_MINUTE = 60; + private static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 60; + private static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * 24; + + private StringUtils() {} + + public static String toString(Object value) { + if (value == null) { + return "null"; + } + + if (value instanceof ZonedDateTime) { + return ((ZonedDateTime) value).format(ISO_DATE_WITH_NANOS); + } + if (value instanceof OffsetTime) { + return ((OffsetTime) value).format(ISO_TIME_WITH_NANOS); + } + if (value instanceof Timestamp ts) { + return ts.toInstant().toString(); + } + + // handle intervals + // YEAR/MONTH/YEAR TO MONTH -> YEAR TO MONTH + if (value instanceof Period p) { + // +yyy-mm - 7 chars + StringBuilder sb = new StringBuilder(7); + if (p.isNegative()) { + sb.append("-"); + p = p.negated(); + } else { + sb.append("+"); + } + sb.append(p.getYears()); + sb.append("-"); + sb.append(p.getMonths()); + return sb.toString(); + } + + // DAY/HOUR/MINUTE/SECOND (and variations) -> DAY_TO_SECOND + if (value instanceof Duration d) { + // +ddd hh:mm:ss.mmmmmmmmm - 23 chars + StringBuilder sb = new StringBuilder(23); + if (d.isNegative()) { + sb.append("-"); + d = d.negated(); + } else { + sb.append("+"); + } + + long durationInSec = d.getSeconds(); + + sb.append(durationInSec / SECONDS_PER_DAY); + sb.append(" "); + durationInSec = durationInSec % SECONDS_PER_DAY; + sb.append(indent(durationInSec / SECONDS_PER_HOUR)); + sb.append(":"); + durationInSec = durationInSec % SECONDS_PER_HOUR; + sb.append(indent(durationInSec / SECONDS_PER_MINUTE)); + sb.append(":"); + durationInSec = durationInSec % SECONDS_PER_MINUTE; + sb.append(indent(durationInSec)); + sb.append("."); + sb.append(TimeUnit.NANOSECONDS.toMillis(d.getNano())); + return sb.toString(); + } + + return Objects.toString(value); + } + + private static String indent(long timeUnit) { + return timeUnit < 10 ? "0" + timeUnit : Long.toString(timeUnit); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/TextEsField.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/TextEsField.java new file mode 100644 index 000000000000..38b78a2714c1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/TextEsField.java @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.core.Tuple; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.util.Map; +import java.util.function.Function; + +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; + +/** + * SQL-related information about an index field with text type + */ +public class TextEsField extends EsField { + + public TextEsField(String name, Map properties, boolean hasDocValues) { + this(name, properties, hasDocValues, false); + } + + public TextEsField(String name, Map properties, boolean hasDocValues, boolean isAlias) { + super(name, TEXT, properties, hasDocValues, isAlias); + } + + @Override + public EsField getExactField() { + Tuple findExact = findExact(); + if (findExact.v1() == null) { + throw new QlIllegalArgumentException(findExact.v2()); + } + return findExact.v1(); + } + + @Override + public Exact getExactInfo() { + return PROCESS_EXACT_FIELD.apply(findExact()); + } + + private Tuple findExact() { + EsField field = null; + for (EsField property : getProperties().values()) { + if (property.getDataType() == KEYWORD && property.getExactInfo().hasExact()) { + if (field != null) { + return new Tuple<>( + null, + "Multiple exact keyword candidates available for [" + getName() + "]; specify which one to use" + ); + } + field = property; + } + } + if (field == null) { + return new Tuple<>( + null, + "No keyword/multi-field defined exact matches for [" + getName() + "]; define one or use MATCH/QUERY instead" + ); + } + return new Tuple<>(field, null); + } + + private Function, Exact> PROCESS_EXACT_FIELD = tuple -> { + if (tuple.v1() == null) { + return new Exact(false, tuple.v2()); + } else { + return new Exact(true, null); + } + }; +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Types.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Types.java new file mode 100644 index 000000000000..a5a457207ba8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/Types.java @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.core.Booleans; +import org.elasticsearch.index.mapper.TimeSeriesParams; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import static java.util.Collections.emptyMap; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NESTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.OBJECT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSUPPORTED; + +public abstract class Types { + + @SuppressWarnings("unchecked") + public static Map fromEs(DataTypeRegistry typeRegistry, Map asMap) { + Map props = null; + if (asMap != null && asMap.isEmpty() == false) { + props = (Map) asMap.get("properties"); + } + return props == null || props.isEmpty() ? emptyMap() : startWalking(typeRegistry, props); + } + + private static Map startWalking(DataTypeRegistry typeRegistry, Map mapping) { + Map types = new LinkedHashMap<>(); + + if (mapping == null) { + return emptyMap(); + } + for (Entry entry : mapping.entrySet()) { + walkMapping(typeRegistry, entry.getKey(), entry.getValue(), types); + } + + return types; + } + + private static DataType getType(DataTypeRegistry typeRegistry, Map content) { + if (content.containsKey("type")) { + String typeName = content.get("type").toString(); + if ("constant_keyword".equals(typeName) || "wildcard".equals(typeName)) { + return KEYWORD; + } + final Object metricsTypeParameter = content.get(TimeSeriesParams.TIME_SERIES_METRIC_PARAM); + final TimeSeriesParams.MetricType metricType; + if (metricsTypeParameter instanceof String str) { + metricType = TimeSeriesParams.MetricType.fromString(str); + } else { + metricType = (TimeSeriesParams.MetricType) metricsTypeParameter; + } + try { + return typeRegistry.fromEs(typeName, metricType); + } catch (IllegalArgumentException ex) { + return UNSUPPORTED; + } + } else if (content.containsKey("properties")) { + return OBJECT; + } else { + return UNSUPPORTED; + } + } + + @SuppressWarnings("unchecked") + private static void walkMapping(DataTypeRegistry typeRegistry, String name, Object value, Map mapping) { + // object type - only root or nested docs supported + if (value instanceof Map) { + Map content = (Map) value; + + // extract field type + DataType esDataType = getType(typeRegistry, content); + final Map properties; + if (esDataType == OBJECT || esDataType == NESTED) { + properties = fromEs(typeRegistry, content); + } else if (content.containsKey("fields")) { + // Check for multifields + Object fields = content.get("fields"); + if (fields instanceof Map) { + properties = startWalking(typeRegistry, (Map) fields); + } else { + properties = Collections.emptyMap(); + } + } else { + properties = fromEs(typeRegistry, content); + } + boolean docValues = boolSetting(content.get("doc_values"), esDataType.hasDocValues()); + final EsField field; + if (esDataType == TEXT) { + field = new TextEsField(name, properties, docValues); + } else if (esDataType == KEYWORD) { + int length = intSetting(content.get("ignore_above"), Short.MAX_VALUE); + boolean normalized = Strings.hasText(textSetting(content.get("normalizer"), null)); + field = new KeywordEsField(name, properties, docValues, length, normalized); + } else if (esDataType == DATETIME) { + field = DateEsField.dateEsField(name, properties, docValues); + } else if (esDataType == UNSUPPORTED) { + String type = content.get("type").toString(); + field = new UnsupportedEsField(name, type, null, properties); + propagateUnsupportedType(name, type, properties); + } else { + field = new EsField(name, esDataType, properties, docValues); + } + mapping.put(name, field); + } else { + throw new IllegalArgumentException("Unrecognized mapping " + value); + } + } + + private static String textSetting(Object value, String defaultValue) { + return value == null ? defaultValue : value.toString(); + } + + private static boolean boolSetting(Object value, boolean defaultValue) { + return value == null ? defaultValue : Booleans.parseBoolean(value.toString(), defaultValue); + } + + private static int intSetting(Object value, int defaultValue) { + return value == null ? defaultValue : Integer.parseInt(value.toString()); + } + + public static void propagateUnsupportedType(String inherited, String originalType, Map properties) { + if (properties != null && properties.isEmpty() == false) { + for (Entry entry : properties.entrySet()) { + EsField field = entry.getValue(); + UnsupportedEsField u; + if (field instanceof UnsupportedEsField) { + u = (UnsupportedEsField) field; + u = new UnsupportedEsField(u.getName(), originalType, inherited, u.getProperties()); + } else { + u = new UnsupportedEsField(field.getName(), originalType, inherited, field.getProperties()); + } + entry.setValue(u); + propagateUnsupportedType(inherited, originalType, u.getProperties()); + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/UnsupportedEsField.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/UnsupportedEsField.java new file mode 100644 index 000000000000..1eb558020d23 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/UnsupportedEsField.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; + +/** + * SQL-related information about an index field that cannot be supported by SQL. + * All the subfields (properties) of an unsupported type should also be unsupported. + */ +public class UnsupportedEsField extends EsField { + + private final String originalType; + private final String inherited; // for fields belonging to parents (or grandparents) that have an unsupported type + + public UnsupportedEsField(String name, String originalType) { + this(name, originalType, null, new TreeMap<>()); + } + + public UnsupportedEsField(String name, String originalType, String inherited, Map properties) { + super(name, DataTypes.UNSUPPORTED, properties, false); + this.originalType = originalType; + this.inherited = inherited; + } + + public String getOriginalType() { + return originalType; + } + + public String getInherited() { + return inherited; + } + + public boolean hasInherited() { + return inherited != null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (super.equals(o) == false) { + return false; + } + UnsupportedEsField that = (UnsupportedEsField) o; + return Objects.equals(originalType, that.originalType) && Objects.equals(inherited, that.inherited); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), originalType, inherited); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/ActionListeners.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/ActionListeners.java new file mode 100644 index 000000000000..025f9c2b6fd7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/ActionListeners.java @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.core.CheckedConsumer; +import org.elasticsearch.core.CheckedFunction; + +import java.util.function.Consumer; + +public class ActionListeners { + + private ActionListeners() {} + + /** + * Combination of {@link ActionListener#wrap(CheckedConsumer, Consumer)} and {@link ActionListener#map} + */ + public static ActionListener map(ActionListener delegate, CheckedFunction fn) { + return delegate.delegateFailureAndWrap((l, r) -> l.onResponse(fn.apply(r))); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Check.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Check.java new file mode 100644 index 000000000000..bea9a631c1e8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Check.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +/** + * Utility class used for checking various conditions at runtime, with minimum amount of code. + */ +public abstract class Check { + + public static void isTrue(boolean expression, String message, Object... values) { + if (expression == false) { + throw new QlIllegalArgumentException(message, values); + } + } + + public static void isTrue(boolean expression, String message) { + if (expression == false) { + throw new QlIllegalArgumentException(message); + } + } + + public static void notNull(Object object, String message) { + if (object == null) { + throw new QlIllegalArgumentException(message); + } + } + + public static void notNull(Object object, String message, Object... values) { + if (object == null) { + throw new QlIllegalArgumentException(message, values); + } + } + + public static void isString(Object obj) { + if ((obj instanceof String || obj instanceof Character) == false) { + throw new QlIllegalArgumentException("A string/char is required; received [{}]", obj); + } + } + + public static void isBoolean(Object obj) { + if ((obj instanceof Boolean) == false) { + throw new QlIllegalArgumentException("A boolean is required; received [{}]", obj); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/CollectionUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/CollectionUtils.java new file mode 100644 index 000000000000..48b5fd1605ed --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/CollectionUtils.java @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static java.util.Collections.emptyList; + +public abstract class CollectionUtils { + + public static boolean isEmpty(Collection col) { + return col == null || col.isEmpty(); + } + + @SuppressWarnings("unchecked") + public static List combine(List left, List right) { + if (right.isEmpty()) { + return (List) left; + } + if (left.isEmpty()) { + return (List) right; + } + + List list = new ArrayList<>(left.size() + right.size()); + if (left.isEmpty() == false) { + list.addAll(left); + } + if (right.isEmpty() == false) { + list.addAll(right); + } + return list; + } + + @SafeVarargs + @SuppressWarnings("varargs") + public static List combine(Collection... collections) { + if (org.elasticsearch.common.util.CollectionUtils.isEmpty(collections)) { + return emptyList(); + } + + List list = new ArrayList<>(); + for (Collection col : collections) { + // typically AttributeSet which ends up iterating anyway plus creating a redundant array + if (col instanceof Set) { + for (T t : col) { + list.add(t); + } + } else { + list.addAll(col); + } + } + return list; + } + + @SafeVarargs + @SuppressWarnings("varargs") + public static List combine(Collection left, T... entries) { + List list = new ArrayList<>(left.size() + entries.length); + if (left.isEmpty() == false) { + list.addAll(left); + } + if (entries.length > 0) { + Collections.addAll(list, entries); + } + return list; + } + + public static int mapSize(int size) { + if (size < 2) { + return size + 1; + } + return (int) (size / 0.75f + 1f); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/DateUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/DateUtils.java new file mode 100644 index 000000000000..fa39a502ae1e --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/DateUtils.java @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.common.time.DateFormatter; +import org.elasticsearch.common.time.DateFormatters; + +import java.sql.Timestamp; +import java.time.Duration; +import java.time.OffsetTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; + +//FIXME: Taken from sql-proto (StringUtils) +//Ideally it should be shared but the dependencies across projects and and SQL-client make it tricky. +// Maybe a gradle task would fix that... +public class DateUtils { + + public static final ZoneId UTC = ZoneId.of("Z"); + + public static final String EMPTY = ""; + + public static final DateTimeFormatter ISO_DATE_WITH_NANOS = new DateTimeFormatterBuilder().parseCaseInsensitive() + .append(ISO_LOCAL_DATE) + .appendLiteral('T') + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .appendFraction(NANO_OF_SECOND, 3, 9, true) + .appendOffsetId() + .toFormatter(Locale.ROOT); + + public static final DateTimeFormatter ISO_TIME_WITH_NANOS = new DateTimeFormatterBuilder().parseCaseInsensitive() + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .appendFraction(NANO_OF_SECOND, 3, 9, true) + .appendOffsetId() + .toFormatter(Locale.ROOT); + + public static final DateFormatter UTC_DATE_TIME_FORMATTER = DateFormatter.forPattern("strict_date_optional_time").withZone(UTC); + + public static final int SECONDS_PER_MINUTE = 60; + public static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 60; + public static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * 24; + + private DateUtils() {} + + /** + * Parses the given string into a ZonedDateTime using the provided timezone. + */ + public static ZonedDateTime asDateTimeWithNanos(String dateFormat, ZoneId zoneId) { + return DateFormatters.from(ISO_DATE_WITH_NANOS.parse(dateFormat)).withZoneSameInstant(zoneId); + } + + public static String toString(Object value) { + if (value == null) { + return "null"; + } + + if (value instanceof ZonedDateTime) { + return ((ZonedDateTime) value).format(ISO_DATE_WITH_NANOS); + } + if (value instanceof OffsetTime) { + return ((OffsetTime) value).format(ISO_TIME_WITH_NANOS); + } + if (value instanceof Timestamp ts) { + return ts.toInstant().toString(); + } + + // handle intervals + // YEAR/MONTH/YEAR TO MONTH -> YEAR TO MONTH + if (value instanceof Period p) { + // +yyy-mm - 7 chars + StringBuilder sb = new StringBuilder(7); + if (p.isNegative()) { + sb.append("-"); + p = p.negated(); + } else { + sb.append("+"); + } + sb.append(p.getYears()); + sb.append("-"); + sb.append(p.getMonths()); + return sb.toString(); + } + + // DAY/HOUR/MINUTE/SECOND (and variations) -> DAY_TO_SECOND + if (value instanceof Duration d) { + // +ddd hh:mm:ss.mmmmmmmmm - 23 chars + StringBuilder sb = new StringBuilder(23); + if (d.isNegative()) { + sb.append("-"); + d = d.negated(); + } else { + sb.append("+"); + } + + long durationInSec = d.getSeconds(); + + sb.append(durationInSec / SECONDS_PER_DAY); + sb.append(" "); + durationInSec = durationInSec % SECONDS_PER_DAY; + sb.append(indent(durationInSec / SECONDS_PER_HOUR)); + sb.append(":"); + durationInSec = durationInSec % SECONDS_PER_HOUR; + sb.append(indent(durationInSec / SECONDS_PER_MINUTE)); + sb.append(":"); + durationInSec = durationInSec % SECONDS_PER_MINUTE; + sb.append(indent(durationInSec)); + long millis = TimeUnit.NANOSECONDS.toMillis(d.getNano()); + if (millis > 0) { + sb.append("."); + while (millis % 10 == 0) { + millis /= 10; + } + sb.append(millis); + } + return sb.toString(); + } + + return Objects.toString(value); + } + + private static String indent(long timeUnit) { + return timeUnit < 10 ? "0" + timeUnit : Long.toString(timeUnit); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Graphviz.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Graphviz.java new file mode 100644 index 000000000000..5502f04549ce --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Graphviz.java @@ -0,0 +1,313 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.xpack.esql.core.tree.Node; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; + +// use the awesome http://mdaines.github.io/viz.js/ to visualize and play around with the various options +public abstract class Graphviz { + + private static final int NODE_LABEL_INDENT = 12; + private static final int CLUSTER_INDENT = 2; + private static final int INDENT = 1; + + public static String dot(String name, Node root) { + StringBuilder sb = new StringBuilder(); + // name + sb.append(String.format(Locale.ROOT, """ + digraph G { rankdir=BT; + label="%s"; + node[shape=plaintext, color=azure1]; + edge[color=black,arrowsize=0.5]; + """, name)); + handleNode(sb, root, new AtomicInteger(0), INDENT, true); + sb.append("}"); + return sb.toString(); + } + + public static String dot(Map> clusters, boolean drawSubTrees) { + AtomicInteger nodeCounter = new AtomicInteger(0); + + StringBuilder sb = new StringBuilder(); + // name + sb.append(""" + digraph G { rankdir=BT; + node[shape=plaintext, color=azure1]; + edge[color=black]; + graph[compound=true]; + + """); + + int clusterNodeStart = 1; + int clusterId = 0; + + StringBuilder clusterEdges = new StringBuilder(); + + for (Entry> entry : clusters.entrySet()) { + indent(sb, INDENT); + // draw cluster + sb.append("subgraph cluster"); + sb.append(++clusterId); + sb.append(" {\n"); + indent(sb, CLUSTER_INDENT); + sb.append("color=blue;\n"); + indent(sb, CLUSTER_INDENT); + sb.append("label="); + sb.append(quoteGraphviz(entry.getKey())); + sb.append(";\n\n"); + + /* to help align the clusters, add an invisible node (that could + * otherwise be used for labeling but it consumes too much space) + * used for alignment */ + indent(sb, CLUSTER_INDENT); + sb.append("c" + clusterId); + sb.append("[style=invis]\n"); + // add edge to the first node in the cluster + indent(sb, CLUSTER_INDENT); + sb.append("node" + (nodeCounter.get() + 1)); + sb.append(" -> "); + sb.append("c" + clusterId); + sb.append(" [style=invis];\n"); + + handleNode(sb, entry.getValue(), nodeCounter, CLUSTER_INDENT, drawSubTrees); + + int clusterNodeStop = nodeCounter.get(); + + indent(sb, INDENT); + sb.append("}\n"); + + // connect cluster only if there are at least two + if (clusterId > 1) { + indent(clusterEdges, INDENT); + clusterEdges.append("node" + clusterNodeStart); + clusterEdges.append(" -> "); + clusterEdges.append("node" + clusterNodeStop); + clusterEdges.append("[ltail=cluster"); + clusterEdges.append(clusterId - 1); + clusterEdges.append(" lhead=cluster"); + clusterEdges.append(clusterId); + clusterEdges.append("];\n"); + } + clusterNodeStart = clusterNodeStop; + } + + sb.append("\n"); + + // connecting the clusters arranges them in a weird position + // so don't + // sb.append(clusterEdges.toString()); + + // align the cluster by requiring the invisible nodes in each cluster to be of the same rank + indent(sb, INDENT); + sb.append("{ rank=same"); + for (int i = 1; i <= clusterId; i++) { + sb.append(" c" + i); + } + sb.append(" };\n}"); + + return sb.toString(); + } + + private static void handleNode(StringBuilder output, Node n, AtomicInteger nodeId, int currentIndent, boolean drawSubTrees) { + // each node has its own id + int thisId = nodeId.incrementAndGet(); + + // first determine node info + StringBuilder nodeInfo = new StringBuilder(); + nodeInfo.append("\n"); + indent(nodeInfo, currentIndent + NODE_LABEL_INDENT); + nodeInfo.append(""" + + """); + indent(nodeInfo, currentIndent + NODE_LABEL_INDENT); + nodeInfo.append(String.format(Locale.ROOT, """ + + """, n.nodeName())); + indent(nodeInfo, currentIndent + NODE_LABEL_INDENT); + + List props = n.nodeProperties(); + List parsed = new ArrayList<>(props.size()); + List> subTrees = new ArrayList<>(); + + for (Object v : props) { + // skip null values, children and location + if (v != null && n.children().contains(v) == false) { + if (v instanceof Collection c) { + StringBuilder colS = new StringBuilder(); + for (Object o : c) { + if (drawSubTrees && isAnotherTree(o)) { + subTrees.add((Node) o); + } else { + colS.append(o); + colS.append("\n"); + } + } + if (colS.length() > 0) { + parsed.add(colS.toString()); + } + } else { + if (drawSubTrees && isAnotherTree(v)) { + subTrees.add((Node) v); + } else { + parsed.add(v.toString()); + } + } + } + } + + for (String line : parsed) { + nodeInfo.append("\n"); + indent(nodeInfo, currentIndent + NODE_LABEL_INDENT); + } + + nodeInfo.append("
%s
"); + nodeInfo.append(escapeHtml(line)); + nodeInfo.append("
\n"); + + // check any subtrees + if (subTrees.isEmpty() == false) { + // write nested trees + output.append(String.format(Locale.ROOT, """ + subgraph cluster_%s{ + style=filled; color=white; fillcolor=azure2; label=""; + """, thisId)); + } + + // write node info + indent(output, currentIndent); + output.append("node"); + output.append(thisId); + output.append("[label="); + output.append(quoteGraphviz(nodeInfo.toString())); + output.append("];\n"); + + if (subTrees.isEmpty() == false) { + indent(output, currentIndent + INDENT); + output.append("node[shape=ellipse, color=black]\n"); + + for (Node node : subTrees) { + indent(output, currentIndent + INDENT); + drawNodeTree(output, node, "st_" + thisId + "_", 0); + } + + output.append("\n}\n"); + } + + indent(output, currentIndent + 1); + // output.append("{ rankdir=LR; rank=same; \n"); + int prevId = -1; + // handle children + for (Node c : n.children()) { + // the child will always have the next id + int childId = nodeId.get() + 1; + handleNode(output, c, nodeId, currentIndent + INDENT, drawSubTrees); + indent(output, currentIndent + 1); + output.append("node"); + output.append(childId); + output.append(" -> "); + output.append("node"); + output.append(thisId); + output.append(";\n"); + + // add invisible connection between children for ordering + if (prevId != -1) { + indent(output, currentIndent + 1); + output.append("node"); + output.append(prevId); + output.append(" -> "); + output.append("node"); + output.append(childId); + output.append(";\n"); + } + prevId = childId; + } + indent(output, currentIndent); + // output.append("}\n"); + } + + private static void drawNodeTree(StringBuilder sb, Node node, String prefix, int counter) { + String nodeName = prefix + counter; + prefix = nodeName; + + // draw node + drawNode(sb, node, nodeName); + // then draw all children nodes and connections between them to be on the same level + sb.append("{ rankdir=LR; rank=same;\n"); + int prevId = -1; + int saveId = counter; + for (Node child : node.children()) { + int currId = ++counter; + drawNode(sb, child, prefix + currId); + if (prevId > -1) { + sb.append(prefix + prevId + " -> " + prefix + currId + " [style=invis];\n"); + } + prevId = currId; + } + sb.append("}\n"); + + // now draw connections to the parent + for (int i = saveId; i < counter; i++) { + sb.append(prefix + (i + 1) + " -> " + nodeName + ";\n"); + } + + // draw the child + counter = saveId; + for (Node child : node.children()) { + drawNodeTree(sb, child, prefix, ++counter); + } + } + + private static void drawNode(StringBuilder sb, Node node, String nodeName) { + if (node.children().isEmpty()) { + sb.append(nodeName + " [label=\"" + node.toString() + "\"];\n"); + } else { + sb.append(nodeName + " [label=\"" + node.nodeName() + "\"];\n"); + } + } + + private static boolean isAnotherTree(Object value) { + if (value instanceof Node n) { + // create a subgraph + if (n.children().size() > 0) { + return true; + } + } + return false; + } + + private static String escapeHtml(Object value) { + return String.valueOf(value) + .replace("&", "&") + .replace("\"", """) + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") + .replace("\n", "
"); + } + + private static String quoteGraphviz(String value) { + if (value.contains("<")) { + return "<" + value + ">"; + } + + return "\"" + value + "\""; + } + + private static void indent(StringBuilder sb, int indent) { + for (int i = 0; i < indent; i++) { + sb.append(" "); + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Holder.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Holder.java new file mode 100644 index 000000000000..1290bbca59ee --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Holder.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +/** + * Simply utility class used for setting a state, typically + * for closures (which require outside variables to be final). + */ +public class Holder { + + private T value = null; + + public Holder() {} + + public Holder(T value) { + this.value = value; + } + + @SuppressWarnings("HiddenField") + public void set(T value) { + this.value = value; + } + + public T get() { + return value; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/LoggingUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/LoggingUtils.java new file mode 100644 index 000000000000..09b80b25ca5f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/LoggingUtils.java @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.logging.Level; +import org.elasticsearch.logging.Logger; +import org.elasticsearch.rest.RestStatus; + +public final class LoggingUtils { + + private LoggingUtils() {} + + public static void logOnFailure(Logger logger, Throwable throwable) { + RestStatus status = ExceptionsHelper.status(throwable); + logger.log(status.getStatus() >= 500 ? Level.WARN : Level.DEBUG, () -> "Request failed with status [" + status + "]: ", throwable); + } + +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/NumericUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/NumericUtils.java new file mode 100644 index 000000000000..3bff45db5023 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/NumericUtils.java @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import java.math.BigInteger; + +public abstract class NumericUtils { + // 18446744073709551615 + public static final BigInteger UNSIGNED_LONG_MAX = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE); + + // 18446744073709551615.0 + public static final double UNSIGNED_LONG_MAX_AS_DOUBLE = UNSIGNED_LONG_MAX.doubleValue(); + + // 0x8000000000000000 + public static final long TWOS_COMPLEMENT_BITMASK = Long.MIN_VALUE; + // 9223372036854775808 == 0x8000000000000000 + public static final BigInteger LONG_MAX_PLUS_ONE_AS_BIGINTEGER = BigInteger.ONE.shiftLeft(Long.SIZE - 1); + // 9223372036854775808.0 + public static final double LONG_MAX_PLUS_ONE_AS_DOUBLE = LONG_MAX_PLUS_ONE_AS_BIGINTEGER.doubleValue(); + public static final long ONE_AS_UNSIGNED_LONG = asLongUnsigned(BigInteger.ONE); + public static final long ZERO_AS_UNSIGNED_LONG = asLongUnsigned(BigInteger.ZERO); + + private static final String UNSIGNED_LONG_OVERFLOW = "unsigned_long overflow"; + + public static boolean isUnsignedLong(BigInteger bi) { + return bi.signum() >= 0 && bi.compareTo(UNSIGNED_LONG_MAX) <= 0; + } + + public static boolean inUnsignedLongRange(double d) { + // UNSIGNED_LONG_MAX can't be represented precisely enough on a double, being converted as a rounded up value. + // Converting it to a double and back will yield a larger unsigned long, so the double comparison is still preferred, but + // it'll require the equality check. (BigDecimal comparisons only make sense for string-recovered floating point numbers.) + // This also means that 18446744073709551615.0 is actually a double too high to be converted as an unsigned long. + return d >= 0 && d < UNSIGNED_LONG_MAX_AS_DOUBLE; + } + + public static BigInteger asUnsignedLong(BigInteger bi) { + if (isUnsignedLong(bi) == false) { + throw new ArithmeticException(UNSIGNED_LONG_OVERFLOW); + } + return bi; + } + + /** + * Converts a BigInteger holding an unsigned_long to its (signed) long representation. + * There's no checking on the input value, if this is negative or exceeds unsigned_long range -- call + * {@link #isUnsignedLong(BigInteger)} if needed. + * @param ul The unsigned_long value to convert. + * @return The long representation of the unsigned_long. + */ + public static long asLongUnsigned(BigInteger ul) { + if (ul.bitLength() < Long.SIZE) { + return twosComplement(ul.longValue()); + } else { + return ul.subtract(LONG_MAX_PLUS_ONE_AS_BIGINTEGER).longValue(); + } + } + + /** + * Converts a long value to an unsigned long stored as a (signed) long. + * @param ul Long value to convert to unsigned long + * @return The long representation of the converted unsigned long. + */ + public static long asLongUnsigned(long ul) { + return twosComplement(ul); + } + + /** + * Converts an unsigned long value "encoded" into a (signed) long to a Number, holding the "expanded" value. This can be either a + * Long (if original value fits), or a BigInteger, otherwise. + *

+ * An unsigned long is converted to a (signed) long by adding Long.MIN_VALUE (or subtracting "abs"(Long.MIN_VALUE), so that + * [0, "abs"(MIN_VALUE) + MAX_VALUE] becomes [MIN_VALUE, MAX_VALUE]) before storing the result. When recovering the original value: + * - if the result is negative, the unsigned long value has been less than Long.MAX_VALUE, so recovering it requires adding the + * Long.MIN_VALUE back; this is equivalent to 2-complementing it; the function returns a Long; + * - if the result remained positive, the value was greater than Long.MAX_VALUE, so we need to add that back; the function returns + * a BigInteger. + *

+ * @param l "Encoded" unsigned long. + * @return Number, holding the "decoded" value. + */ + public static Number unsignedLongAsNumber(long l) { + return l < 0 ? twosComplement(l) : LONG_MAX_PLUS_ONE_AS_BIGINTEGER.add(BigInteger.valueOf(l)); + } + + public static BigInteger unsignedLongAsBigInteger(long l) { + return l < 0 ? BigInteger.valueOf(twosComplement(l)) : LONG_MAX_PLUS_ONE_AS_BIGINTEGER.add(BigInteger.valueOf(l)); + } + + public static double unsignedLongToDouble(long l) { + return l < 0 ? twosComplement(l) : LONG_MAX_PLUS_ONE_AS_DOUBLE + l; + } + + public static long unsignedLongAddExact(long x, long y) { + long s; + if ( + // both operands are positive, so the UL equivalents are >= Long.MAX_VALUE + 1, so sum will be above UNSIGNED_LONG_MAX + (x | y) >= 0 + // if operands have opposing signs, the UL corresponding to the positive one is >= Long.MAX_VALUE + 1 and + // the UL corresponding to the negative one between [0, Long.MAX_VALUE] ==> non-negative sum means value wrap, i.e. overflow + || ((s = (x + y)) >= 0 && (x ^ y) < 0)) { + throw new ArithmeticException(UNSIGNED_LONG_OVERFLOW); + } + return asLongUnsigned(s); + } + + public static long unsignedLongSubtractExact(long x, long y) { + if (x < y) { // UL keeps the ordering after shifting to fit into long range + throw new ArithmeticException(UNSIGNED_LONG_OVERFLOW); + } + return asLongUnsigned(x - y); + } + + public static long unsignedLongMultiplyExact(long x, long y) { + long ux = asLongUnsigned(x); + long uy = asLongUnsigned(y); + if (unsignedLongMultiplyHigh(ux, uy) != 0) { // TODO: replace with Math#unsignedMultiplyHigh() in JDK 18 when available + throw new ArithmeticException(UNSIGNED_LONG_OVERFLOW); + } + return asLongUnsigned(ux * uy); + } + + public static long unsignedLongMultiplyHigh(long x, long y) { + return Math.multiplyHigh(x, y) + (y & (x >> 63)) + (x & (y >> 63)); + } + + private static long twosComplement(long l) { + return l ^ TWOS_COMPLEMENT_BITMASK; + } + + /** + * Check if the provided double is both finite and a number (i.e. not Double.NaN). + * @param dbl The double to verify. + * @return The input value. + * @throws ArithmeticException if the provided double is either infinite or not a number. + */ + public static double asFiniteNumber(double dbl) { + if (Double.isNaN(dbl) || Double.isInfinite(dbl)) { + throw new ArithmeticException("not a finite double number: " + dbl); + } + return dbl; + } + + /** + * Converts a number to an integer, saturating that integer if the number doesn't fit naturally. That is to say, values + * greater than Integer.MAX_VALUE yield Integer.MAX_VALUE and values less than Integer.MIN_VALUE yield Integer.MIN_VALUE + * + * This function exists because Long::intValue() yields -1 and 0 for Long.MAX_VALUE and Long.MIN_VALUE, respectively. + * + * @param n the nubmer to convert + * @return a valid integer + */ + public static int saturatingIntValue(Number n) { + if (n instanceof Long ln) { + if (ln > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + if (ln < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + } + return n.intValue(); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Queries.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Queries.java new file mode 100644 index 000000000000..9403c3c6a0bc --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/Queries.java @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; + +import java.util.List; +import java.util.function.Function; + +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; + +/** + * Utilities for Elasticsearch queries. + */ +public class Queries { + + public enum Clause { + FILTER(BoolQueryBuilder::filter), + MUST(BoolQueryBuilder::must), + MUST_NOT(BoolQueryBuilder::mustNot), + SHOULD(BoolQueryBuilder::should); + + final Function> innerQueries; + + Clause(Function> innerQueries) { + this.innerQueries = innerQueries; + } + } + + /** + * Combines the given queries while attempting to NOT create a new bool query and avoid + * unnecessary nested queries. + * The method tries to detect if the first query is a bool query - if that is the case it will + * reuse that for adding the rest of the clauses. + */ + public static QueryBuilder combine(Clause clause, List queries) { + QueryBuilder firstQuery = null; + BoolQueryBuilder bool = null; + + for (QueryBuilder query : queries) { + if (query == null) { + continue; + } + if (firstQuery == null) { + firstQuery = query; + if (firstQuery instanceof BoolQueryBuilder bqb) { + bool = bqb; + } + } + // at least two entries, start copying + else { + // lazy init the root bool + if (bool == null) { + bool = combine(clause, boolQuery(), firstQuery); + } + // keep adding queries to it + bool = combine(clause, bool, query); + } + } + + return bool == null ? firstQuery : bool; + } + + private static BoolQueryBuilder combine(Clause clause, BoolQueryBuilder bool, QueryBuilder query) { + var list = clause.innerQueries.apply(bool); + if (list.contains(query) == false) { + list.add(query); + } + return bool; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/ReflectionUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/ReflectionUtils.java new file mode 100644 index 000000000000..0d7e1c83971f --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/ReflectionUtils.java @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Arrays; + +public class ReflectionUtils { + + @SuppressWarnings("unchecked") + public static Class detectSuperTypeForRuleLike(Class c) { + Class clazz = c; + for (Type type = clazz.getGenericSuperclass(); clazz != Object.class; type = clazz.getGenericSuperclass()) { + if (type instanceof ParameterizedType) { + Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); + if (typeArguments.length > 3 || typeArguments.length < 1) { + throw new QlIllegalArgumentException( + "Unexpected number of type arguments {} for {}", + Arrays.toString(typeArguments), + c + ); + } + + Type tp = typeArguments[0]; + + if (tp instanceof Class) { + return (Class) tp; + } else if (tp instanceof ParameterizedType) { + Type rawType = ((ParameterizedType) tp).getRawType(); + if (rawType instanceof Class) { + return (Class) rawType; + } + } + throw new QlIllegalArgumentException("Unexpected class structure for class {}", c); + } + clazz = clazz.getSuperclass(); + } + throw new QlIllegalArgumentException("Unexpected class structure for class {}", c); + } + + // remove packaging from the name - strategy used for naming rules by default + public static String ruleLikeNaming(Class c) { + String className = c.getName(); + int parentPackage = className.lastIndexOf('.'); + if (parentPackage > 0) { + int grandParentPackage = className.substring(0, parentPackage).lastIndexOf('.'); + return (grandParentPackage > 0 ? className.substring(grandParentPackage + 1) : className.substring(parentPackage)); + } else { + return className; + } + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java new file mode 100644 index 000000000000..cbcb31c7a3b5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SourceUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.core.Nullable; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.io.IOException; + +public final class SourceUtils { + + private SourceUtils() {} + + public static void writeSource(StreamOutput out, Source source) throws IOException { + writeSource(out, source, true); + } + + public static void writeSourceNoText(StreamOutput out, Source source) throws IOException { + writeSource(out, source, false); + } + + public static Source readSource(StreamInput in) throws IOException { + return readSource(in, null); + } + + public static Source readSourceWithText(StreamInput in, String queryText) throws IOException { + return readSource(in, queryText); + } + + private static void writeSource(StreamOutput out, Source source, boolean writeText) throws IOException { + out.writeInt(source.source().getLineNumber()); + out.writeInt(source.source().getColumnNumber()); + if (writeText) { + out.writeString(source.text()); + } else { + out.writeInt(source.text().length()); + } + } + + private static Source readSource(StreamInput in, @Nullable String queryText) throws IOException { + int line = in.readInt(); + int column = in.readInt(); + int charPositionInLine = column - 1; + + String text; + if (queryText == null) { + text = in.readString(); + } else { + int length = in.readInt(); + text = sourceText(queryText, line, column, length); + } + return new Source(new Location(line, charPositionInLine), text); + } + + private static String sourceText(String query, int line, int column, int length) { + if (line <= 0 || column <= 0 || query.isEmpty()) { + return StringUtils.EMPTY; + } + int offset = textOffset(query, line, column); + if (offset + length > query.length()) { + throw new QlIllegalArgumentException( + "location [@" + line + ":" + column + "] and length [" + length + "] overrun query size [" + query.length() + "]" + ); + } + return query.substring(offset, offset + length); + } + + private static int textOffset(String query, int line, int column) { + int offset = 0; + if (line > 1) { + String[] lines = query.split("\n"); + if (line > lines.length) { + throw new QlIllegalArgumentException( + "line location [" + line + "] higher than max [" + lines.length + "] in query [" + query + "]" + ); + } + for (int i = 0; i < line - 1; i++) { + offset += lines[i].length() + 1; // +1 accounts for the removed \n + } + } + offset += column - 1; // -1 since column is 1-based indexed + return offset; + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SpatialCoordinateTypes.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SpatialCoordinateTypes.java new file mode 100644 index 000000000000..7927e831ebd9 --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/SpatialCoordinateTypes.java @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.apache.lucene.geo.GeoEncodingUtils; +import org.apache.lucene.geo.XYEncodingUtils; +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.geometry.Point; +import org.elasticsearch.geometry.utils.GeometryValidator; +import org.elasticsearch.geometry.utils.WellKnownBinary; +import org.elasticsearch.geometry.utils.WellKnownText; + +import java.nio.ByteOrder; + +import static org.apache.lucene.geo.GeoEncodingUtils.encodeLatitude; +import static org.apache.lucene.geo.GeoEncodingUtils.encodeLongitude; + +public enum SpatialCoordinateTypes { + GEO { + public Point longAsPoint(long encoded) { + return new Point(GeoEncodingUtils.decodeLongitude((int) encoded), GeoEncodingUtils.decodeLatitude((int) (encoded >>> 32))); + } + + public long pointAsLong(double x, double y) { + int latitudeEncoded = encodeLatitude(y); + int longitudeEncoded = encodeLongitude(x); + return (((long) latitudeEncoded) << 32) | (longitudeEncoded & 0xFFFFFFFFL); + } + }, + CARTESIAN { + + private static final int MAX_VAL_ENCODED = XYEncodingUtils.encode((float) XYEncodingUtils.MAX_VAL_INCL); + private static final int MIN_VAL_ENCODED = XYEncodingUtils.encode((float) XYEncodingUtils.MIN_VAL_INCL); + + public Point longAsPoint(long encoded) { + final int x = checkCoordinate((int) (encoded >>> 32)); + final int y = checkCoordinate((int) (encoded & 0xFFFFFFFF)); + return new Point(XYEncodingUtils.decode(x), XYEncodingUtils.decode(y)); + } + + private int checkCoordinate(int i) { + if (i > MAX_VAL_ENCODED || i < MIN_VAL_ENCODED) { + throw new IllegalArgumentException("Failed to convert invalid encoded value to cartesian point"); + } + return i; + } + + public long pointAsLong(double x, double y) { + final long xi = XYEncodingUtils.encode((float) x); + final long yi = XYEncodingUtils.encode((float) y); + return (yi & 0xFFFFFFFFL) | xi << 32; + } + }, + UNSPECIFIED { + public Point longAsPoint(long encoded) { + throw new UnsupportedOperationException("Cannot convert long to point without specifying coordinate type"); + } + + public long pointAsLong(double x, double y) { + throw new UnsupportedOperationException("Cannot convert point to long without specifying coordinate type"); + } + }; + + public abstract Point longAsPoint(long encoded); + + public abstract long pointAsLong(double x, double y); + + public long wkbAsLong(BytesRef wkb) { + Point point = wkbAsPoint(wkb); + return pointAsLong(point.getX(), point.getY()); + } + + public Point wkbAsPoint(BytesRef wkb) { + Geometry geometry = WellKnownBinary.fromWKB(GeometryValidator.NOOP, false, wkb.bytes, wkb.offset, wkb.length); + if (geometry instanceof Point point) { + return point; + } else { + throw new IllegalArgumentException("Unsupported geometry: " + geometry.type()); + } + } + + public BytesRef longAsWkb(long encoded) { + return asWkb(longAsPoint(encoded)); + } + + public String asWkt(Geometry geometry) { + return WellKnownText.toWKT(geometry); + } + + public BytesRef asWkb(Geometry geometry) { + return new BytesRef(WellKnownBinary.toWKB(geometry, ByteOrder.LITTLE_ENDIAN)); + } + + public BytesRef wktToWkb(String wkt) { + // TODO: we should be able to transform WKT to WKB without building the geometry + // we should as well use different validator for cartesian and geo? + try { + Geometry geometry = WellKnownText.fromWKT(GeometryValidator.NOOP, false, wkt); + return new BytesRef(WellKnownBinary.toWKB(geometry, ByteOrder.LITTLE_ENDIAN)); + } catch (Exception e) { + throw new IllegalArgumentException("Failed to parse WKT: " + e.getMessage(), e); + } + } + + public Geometry wktToGeometry(String wkt) { + try { + return WellKnownText.fromWKT(GeometryValidator.NOOP, false, wkt); + } catch (Exception e) { + throw new IllegalArgumentException("Failed to parse WKT: " + e.getMessage(), e); + } + } + + public String wkbToWkt(BytesRef wkb) { + return WellKnownText.fromWKB(wkb.bytes, wkb.offset, wkb.length); + } + + public Geometry wkbToGeometry(BytesRef wkb) { + return WellKnownBinary.fromWKB(GeometryValidator.NOOP, false, wkb.bytes, wkb.offset, wkb.length); + } +} diff --git a/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/StringUtils.java b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/StringUtils.java new file mode 100644 index 000000000000..1eb7e1cce5cb --- /dev/null +++ b/x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/util/StringUtils.java @@ -0,0 +1,395 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.util; + +import org.apache.lucene.document.InetAddressPoint; +import org.apache.lucene.search.spell.LevenshteinDistance; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.CollectionUtil; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.network.InetAddresses; +import org.elasticsearch.core.Tuple; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentFactory; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.StringJoiner; + +import static java.util.stream.Collectors.toList; +import static org.elasticsearch.transport.RemoteClusterAware.REMOTE_CLUSTER_INDEX_SEPARATOR; +import static org.elasticsearch.transport.RemoteClusterAware.buildRemoteIndexName; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.isUnsignedLong; + +public final class StringUtils { + + private StringUtils() {} + + public static final String EMPTY = ""; + public static final String NEW_LINE = "\n"; + public static final String SQL_WILDCARD = "%"; + public static final String WILDCARD = "*"; + + private static final String[] INTEGER_ORDINALS = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" }; + + private static final String INVALID_REGEX_SEQUENCE = "Invalid sequence - escape character is not followed by special wildcard char"; + + // CamelCase to camel_case (and isNaN to is_nan) + public static String camelCaseToUnderscore(String string) { + if (Strings.hasText(string) == false) { + return EMPTY; + } + StringBuilder sb = new StringBuilder(); + String s = string.trim(); + + boolean previousCharWasUp = false; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (Character.isAlphabetic(ch)) { + if (Character.isUpperCase(ch)) { + // append `_` when encountering a capital after a small letter, but only if not the last letter. + if (i > 0 && i < s.length() - 1 && previousCharWasUp == false) { + sb.append("_"); + } + previousCharWasUp = true; + } else { + previousCharWasUp = (ch == '_'); + } + } else { + previousCharWasUp = true; + } + sb.append(ch); + } + return sb.toString().toUpperCase(Locale.ROOT); + } + + // CAMEL_CASE to camelCase + public static String underscoreToLowerCamelCase(String string) { + if (Strings.hasText(string) == false) { + return EMPTY; + } + StringBuilder sb = new StringBuilder(); + String s = string.trim().toLowerCase(Locale.ROOT); + + boolean previousCharWasUnderscore = false; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (ch == '_') { + previousCharWasUnderscore = true; + } else { + if (previousCharWasUnderscore) { + sb.append(Character.toUpperCase(ch)); + previousCharWasUnderscore = false; + } else { + sb.append(ch); + } + } + } + return sb.toString(); + } + + // % -> .* + // _ -> . + // escape character - can be 0 (in which case no regex gets escaped) or + // should be followed by % or _ (otherwise an exception is thrown) + public static String likeToJavaPattern(String pattern, char escape) { + StringBuilder regex = new StringBuilder(pattern.length() + 4); + + boolean escaped = false; + regex.append('^'); + for (int i = 0; i < pattern.length(); i++) { + char curr = pattern.charAt(i); + if (escaped == false && (curr == escape) && escape != 0) { + escaped = true; + if (i + 1 == pattern.length()) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + } else { + switch (curr) { + case '%' -> regex.append(escaped ? SQL_WILDCARD : ".*"); + case '_' -> regex.append(escaped ? "_" : "."); + default -> { + if (escaped) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + // escape special regex characters + switch (curr) { + case '\\', '^', '$', '.', '*', '?', '+', '|', '(', ')', '[', ']', '{', '}' -> regex.append('\\'); + } + regex.append(curr); + } + } + escaped = false; + } + } + regex.append('$'); + + return regex.toString(); + } + + // * -> .* + // ? -> . + // escape character - can be 0 (in which case no regex gets escaped) or + // should be followed by * or ? or the escape character itself (otherwise an exception is thrown). + // Using * or ? as escape characters should be avoided because it will make it impossible to enter them as literals + public static String wildcardToJavaPattern(String pattern, char escape) { + StringBuilder regex = new StringBuilder(pattern.length() + 4); + + boolean escaped = false; + regex.append('^'); + for (int i = 0; i < pattern.length(); i++) { + char curr = pattern.charAt(i); + if (escaped == false && (curr == escape) && escape != 0) { + escaped = true; + if (i + 1 == pattern.length()) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + } else { + switch (curr) { + case '*' -> regex.append(escaped ? "\\*" : ".*"); + case '?' -> regex.append(escaped ? "\\?" : "."); + default -> { + if (escaped && escape != curr) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + // escape special regex characters + switch (curr) { + case '\\', '^', '$', '.', '*', '?', '+', '|', '(', ')', '[', ']', '{', '}' -> regex.append('\\'); + } + regex.append(curr); + } + } + escaped = false; + } + } + regex.append('$'); + + return regex.toString(); + } + + /** + * Translates a like pattern to a Lucene wildcard. + * This methods pays attention to the custom escape char which gets converted into \ (used by Lucene). + *
+     * % -> *
+     * _ -> ?
+     * escape character - can be 0 (in which case no regex gets escaped) or should be followed by
+     * % or _ (otherwise an exception is thrown)
+     * 
+ */ + public static String likeToLuceneWildcard(String pattern, char escape) { + StringBuilder wildcard = new StringBuilder(pattern.length() + 4); + + boolean escaped = false; + for (int i = 0; i < pattern.length(); i++) { + char curr = pattern.charAt(i); + + if (escaped == false && (curr == escape) && escape != 0) { + if (i + 1 == pattern.length()) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + escaped = true; + } else { + switch (curr) { + case '%' -> wildcard.append(escaped ? SQL_WILDCARD : WILDCARD); + case '_' -> wildcard.append(escaped ? "_" : "?"); + default -> { + if (escaped) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + // escape special regex characters + switch (curr) { + case '\\', '*', '?' -> wildcard.append('\\'); + } + wildcard.append(curr); + } + } + escaped = false; + } + } + return wildcard.toString(); + } + + /** + * Translates a like pattern to pattern for ES index name expression resolver. + * + * Note the resolver only supports * (not ?) and has no notion of escaping. This is not really an issue since we don't allow * + * anyway in the pattern. + */ + public static String likeToIndexWildcard(String pattern, char escape) { + StringBuilder wildcard = new StringBuilder(pattern.length() + 4); + + boolean escaped = false; + for (int i = 0; i < pattern.length(); i++) { + char curr = pattern.charAt(i); + + if (escaped == false && (curr == escape) && escape != 0) { + if (i + 1 == pattern.length()) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + escaped = true; + } else { + switch (curr) { + case '%' -> wildcard.append(escaped ? SQL_WILDCARD : WILDCARD); + case '_' -> wildcard.append(escaped ? "_" : "*"); + default -> { + if (escaped) { + throw new InvalidArgumentException(INVALID_REGEX_SEQUENCE); + } + // the resolver doesn't support escaping... + wildcard.append(curr); + } + } + escaped = false; + } + } + return wildcard.toString(); + } + + public static String likeToUnescaped(String pattern, char escape) { + StringBuilder wildcard = new StringBuilder(pattern.length()); + + boolean escaped = false; + for (int i = 0; i < pattern.length(); i++) { + char curr = pattern.charAt(i); + + if (escaped == false && curr == escape && escape != 0) { + escaped = true; + } else { + if (escaped && (curr == '%' || curr == '_' || curr == escape)) { + wildcard.append(curr); + } else { + if (escaped) { + wildcard.append(escape); + } + wildcard.append(curr); + } + escaped = false; + } + } + // corner-case when the escape char is the last char + if (escaped) { + wildcard.append(escape); + } + return wildcard.toString(); + } + + public static String toString(SearchSourceBuilder source) { + try (XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint().humanReadable(true)) { + source.toXContent(builder, ToXContent.EMPTY_PARAMS); + return Strings.toString(builder); + } catch (IOException e) { + throw new RuntimeException("error rendering", e); + } + } + + public static List findSimilar(String match, Iterable potentialMatches) { + LevenshteinDistance ld = new LevenshteinDistance(); + List> scoredMatches = new ArrayList<>(); + for (String potentialMatch : potentialMatches) { + float distance = ld.getDistance(match, potentialMatch); + if (distance >= 0.5f) { + scoredMatches.add(new Tuple<>(distance, potentialMatch)); + } + } + CollectionUtil.timSort(scoredMatches, (a, b) -> b.v1().compareTo(a.v1())); + return scoredMatches.stream().map(a -> a.v2()).collect(toList()); + } + + public static double parseDouble(String string) throws InvalidArgumentException { + double value; + try { + value = Double.parseDouble(string); + } catch (NumberFormatException nfe) { + throw new InvalidArgumentException(nfe, "Cannot parse number [{}]", string); + } + + if (Double.isInfinite(value)) { + throw new InvalidArgumentException("Number [{}] is too large", string); + } + if (Double.isNaN(value)) { + throw new InvalidArgumentException("[{}] cannot be parsed as a number (NaN)", string); + } + return value; + } + + public static long parseLong(String string) throws InvalidArgumentException { + try { + return Long.parseLong(string); + } catch (NumberFormatException nfe) { + try { + BigInteger bi = new BigInteger(string); + try { + bi.longValueExact(); + } catch (ArithmeticException ae) { + throw new InvalidArgumentException("Number [{}] is too large", string); + } + } catch (NumberFormatException ex) { + // parsing fails, go through + } + throw new InvalidArgumentException("Cannot parse number [{}]", string); + } + } + + public static Number parseIntegral(String string) throws InvalidArgumentException { + BigInteger bi; + try { + bi = new BigInteger(string); + } catch (NumberFormatException ex) { + throw new InvalidArgumentException(ex, "Cannot parse number [{}]", string); + } + if (bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { + if (isUnsignedLong(bi) == false) { + throw new InvalidArgumentException("Number [{}] is too large", string); + } + return bi; + } + // try to downsize to int if possible (since that's the most common type) + if (bi.intValue() == bi.longValue()) { // ternary operator would always promote to Long + return bi.intValueExact(); + } else { + return bi.longValueExact(); + } + } + + public static BytesRef parseIP(String string) { + var inetAddress = InetAddresses.forString(string); + return new BytesRef(InetAddressPoint.encode(inetAddress)); + } + + public static String ordinal(int i) { + return switch (i % 100) { + case 11, 12, 13 -> i + "th"; + default -> i + INTEGER_ORDINALS[i % 10]; + }; + } + + public static Tuple splitQualifiedIndex(String indexName) { + int separatorOffset = indexName.indexOf(REMOTE_CLUSTER_INDEX_SEPARATOR); + return separatorOffset > 0 + ? Tuple.tuple(indexName.substring(0, separatorOffset), indexName.substring(separatorOffset + 1)) + : Tuple.tuple(null, indexName); + } + + public static String qualifyAndJoinIndices(String cluster, String[] indices) { + StringJoiner sj = new StringJoiner(","); + for (String index : indices) { + sj.add(cluster != null ? buildRemoteIndexName(cluster, index) : index); + } + return sj.toString(); + } + + public static boolean isQualified(String indexWildcard) { + return indexWildcard.indexOf(REMOTE_CLUSTER_INDEX_SEPARATOR) > 0; + } +} diff --git a/x-pack/plugin/esql-core/src/main/resources/file.txt b/x-pack/plugin/esql-core/src/main/resources/file.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/action/QlStatusResponseTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/action/QlStatusResponseTests.java new file mode 100644 index 000000000000..e38755b70391 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/action/QlStatusResponseTests.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.action; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xpack.esql.core.async.QlStatusResponse; + +import java.io.IOException; +import java.util.Date; + +import static org.elasticsearch.xpack.core.async.GetAsyncResultRequestTests.randomSearchId; + +public class QlStatusResponseTests extends AbstractWireSerializingTestCase { + + @Override + protected QlStatusResponse createTestInstance() { + String id = randomSearchId(); + boolean isRunning = randomBoolean(); + boolean isPartial = isRunning ? randomBoolean() : false; + long randomDate = (new Date(randomLongBetween(0, 3000000000000L))).getTime(); + Long startTimeMillis = randomBoolean() ? null : randomDate; + long expirationTimeMillis = startTimeMillis == null ? randomDate : startTimeMillis + 3600000L; + RestStatus completionStatus = isRunning ? null : randomBoolean() ? RestStatus.OK : RestStatus.SERVICE_UNAVAILABLE; + return new QlStatusResponse(id, isRunning, isPartial, startTimeMillis, expirationTimeMillis, completionStatus); + } + + @Override + protected Writeable.Reader instanceReader() { + return QlStatusResponse::new; + } + + @Override + protected QlStatusResponse mutateInstance(QlStatusResponse instance) { + // return a response with the opposite running status + boolean isRunning = instance.isRunning() == false; + boolean isPartial = isRunning ? randomBoolean() : false; + RestStatus completionStatus = isRunning ? null : randomBoolean() ? RestStatus.OK : RestStatus.SERVICE_UNAVAILABLE; + return new QlStatusResponse( + instance.getId(), + isRunning, + isPartial, + instance.getStartTime(), + instance.getExpirationTime(), + completionStatus + ); + } + + public void testToXContent() throws IOException { + QlStatusResponse response = createTestInstance(); + try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) { + Object[] args = new Object[] { + response.getId(), + response.isRunning(), + response.isPartial(), + response.getStartTime() != null ? "\"start_time_in_millis\" : " + response.getStartTime() + "," : "", + response.getExpirationTime(), + response.getCompletionStatus() != null ? ", \"completion_status\" : " + response.getCompletionStatus().getStatus() : "" }; + String expectedJson = Strings.format(""" + { + "id" : "%s", + "is_running" : %s, + "is_partial" : %s, + %s + "expiration_time_in_millis" : %s + %s + } + """, args); + response.toXContent(builder, ToXContent.EMPTY_PARAMS); + assertEquals(XContentHelper.stripWhitespace(expectedJson), Strings.toString(builder)); + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/analyzer/PreAnalyzerTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/analyzer/PreAnalyzerTests.java new file mode 100644 index 000000000000..f48d766c0ded --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/analyzer/PreAnalyzerTests.java @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.analyzer; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.analyzer.PreAnalyzer.PreAnalysis; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnresolvedRelation; + +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; + +public class PreAnalyzerTests extends ESTestCase { + + private PreAnalyzer preAnalyzer = new PreAnalyzer(); + + public void testBasicIndex() { + LogicalPlan plan = new UnresolvedRelation(EMPTY, new TableIdentifier(EMPTY, null, "index"), null, false); + PreAnalysis result = preAnalyzer.preAnalyze(plan); + assertThat(plan.preAnalyzed(), is(true)); + assertThat(result.indices, hasSize(1)); + assertThat(result.indices.get(0).id().cluster(), nullValue()); + assertThat(result.indices.get(0).id().index(), is("index")); + } + + public void testBasicIndexWithCatalog() { + LogicalPlan plan = new UnresolvedRelation(EMPTY, new TableIdentifier(EMPTY, "elastic", "index"), null, false); + PreAnalysis result = preAnalyzer.preAnalyze(plan); + assertThat(plan.preAnalyzed(), is(true)); + assertThat(result.indices, hasSize(1)); + assertThat(result.indices.get(0).id().cluster(), is("elastic")); + assertThat(result.indices.get(0).id().index(), is("index")); + } + + public void testComplicatedQuery() { + LogicalPlan plan = new Limit( + EMPTY, + new Literal(EMPTY, 10, INTEGER), + new UnresolvedRelation(EMPTY, new TableIdentifier(EMPTY, null, "aaa"), null, false) + ); + PreAnalysis result = preAnalyzer.preAnalyze(plan); + assertThat(plan.preAnalyzed(), is(true)); + assertThat(result.indices, hasSize(1)); + assertThat(result.indices.get(0).id().cluster(), nullValue()); + assertThat(result.indices.get(0).id().index(), is("aaa")); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/async/AsyncTaskManagementServiceTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/async/AsyncTaskManagementServiceTests.java new file mode 100644 index 000000000000..5361f1e8d197 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/async/AsyncTaskManagementServiceTests.java @@ -0,0 +1,351 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.async; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.support.ActionTestUtils; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.core.TimeValue; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.tasks.TaskId; +import org.elasticsearch.test.ESSingleNodeTestCase; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.core.async.AsyncExecutionId; +import org.elasticsearch.xpack.core.async.AsyncResultsService; +import org.elasticsearch.xpack.core.async.AsyncTaskIndexService; +import org.elasticsearch.xpack.core.async.GetAsyncResultRequest; +import org.elasticsearch.xpack.core.async.StoredAsyncResponse; +import org.elasticsearch.xpack.core.async.StoredAsyncTask; +import org.junit.After; +import org.junit.Before; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.elasticsearch.xpack.esql.core.async.AsyncTaskManagementService.addCompletionListener; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +public class AsyncTaskManagementServiceTests extends ESSingleNodeTestCase { + private ClusterService clusterService; + private TransportService transportService; + private AsyncResultsService> results; + + private final ExecutorService executorService = Executors.newFixedThreadPool(1); + + public static class TestRequest extends ActionRequest { + private final String string; + + public TestRequest(String string) { + this.string = string; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + } + + public static class TestResponse extends ActionResponse { + private final String string; + private final String id; + + public TestResponse(String string, String id) { + this.string = string; + this.id = id; + } + + public TestResponse(StreamInput input) throws IOException { + this.string = input.readOptionalString(); + this.id = input.readOptionalString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeOptionalString(string); + out.writeOptionalString(id); + } + } + + public static class TestTask extends StoredAsyncTask { + public volatile AtomicReference finalResponse = new AtomicReference<>(); + + public TestTask( + long id, + String type, + String action, + String description, + TaskId parentTaskId, + Map headers, + Map originHeaders, + AsyncExecutionId asyncExecutionId, + TimeValue keepAlive + ) { + super(id, type, action, description, parentTaskId, headers, originHeaders, asyncExecutionId, keepAlive); + } + + @Override + public TestResponse getCurrentResult() { + return Objects.requireNonNullElseGet(finalResponse.get(), () -> new TestResponse(null, getExecutionId().getEncoded())); + } + } + + public static class TestOperation implements AsyncTaskManagementService.AsyncOperation { + + @Override + public TestTask createTask( + TestRequest request, + long id, + String type, + String action, + TaskId parentTaskId, + Map headers, + Map originHeaders, + AsyncExecutionId asyncExecutionId + ) { + return new TestTask( + id, + type, + action, + request.getDescription(), + parentTaskId, + headers, + originHeaders, + asyncExecutionId, + TimeValue.timeValueDays(5) + ); + } + + @Override + public void execute(TestRequest request, TestTask task, ActionListener listener) { + if (request.string.equals("die")) { + listener.onFailure(new IllegalArgumentException("test exception")); + } else { + listener.onResponse(new TestResponse("response for [" + request.string + "]", task.getExecutionId().getEncoded())); + } + } + + @Override + public TestResponse initialResponse(TestTask task) { + return new TestResponse(null, task.getExecutionId().getEncoded()); + } + + @Override + public TestResponse readResponse(StreamInput inputStream) throws IOException { + return new TestResponse(inputStream); + } + } + + public String index = "test-index"; + + @Before + public void setup() { + clusterService = getInstanceFromNode(ClusterService.class); + transportService = getInstanceFromNode(TransportService.class); + BigArrays bigArrays = getInstanceFromNode(BigArrays.class); + AsyncTaskIndexService> store = new AsyncTaskIndexService<>( + index, + clusterService, + transportService.getThreadPool().getThreadContext(), + client(), + "test", + in -> new StoredAsyncResponse<>(TestResponse::new, in), + writableRegistry(), + bigArrays + ); + results = new AsyncResultsService<>( + store, + true, + TestTask.class, + (task, listener, timeout) -> addCompletionListener(transportService.getThreadPool(), task, listener, timeout), + transportService.getTaskManager(), + clusterService + ); + } + + /** + * Shutdown the executor so we don't leak threads into other test runs. + */ + @After + public void shutdownExec() { + executorService.shutdown(); + } + + private AsyncTaskManagementService createManagementService( + AsyncTaskManagementService.AsyncOperation operation + ) { + BigArrays bigArrays = getInstanceFromNode(BigArrays.class); + return new AsyncTaskManagementService<>( + index, + client(), + "test_origin", + writableRegistry(), + transportService.getTaskManager(), + "test_action", + operation, + TestTask.class, + clusterService, + transportService.getThreadPool(), + bigArrays + ); + } + + public void testReturnBeforeTimeout() throws Exception { + AsyncTaskManagementService service = createManagementService(new TestOperation()); + boolean success = randomBoolean(); + boolean keepOnCompletion = randomBoolean(); + CountDownLatch latch = new CountDownLatch(1); + TestRequest request = new TestRequest(success ? randomAlphaOfLength(10) : "die"); + service.asyncExecute( + request, + TimeValue.timeValueMinutes(1), + TimeValue.timeValueMinutes(10), + keepOnCompletion, + ActionListener.wrap(r -> { + assertThat(success, equalTo(true)); + assertThat(r.string, equalTo("response for [" + request.string + "]")); + assertThat(r.id, notNullValue()); + latch.countDown(); + }, e -> { + assertThat(success, equalTo(false)); + assertThat(e.getMessage(), equalTo("test exception")); + latch.countDown(); + }) + ); + assertThat(latch.await(10, TimeUnit.SECONDS), equalTo(true)); + } + + public void testReturnAfterTimeout() throws Exception { + CountDownLatch executionLatch = new CountDownLatch(1); + AsyncTaskManagementService service = createManagementService(new TestOperation() { + @Override + public void execute(TestRequest request, TestTask task, ActionListener listener) { + executorService.submit(() -> { + try { + assertThat(executionLatch.await(10, TimeUnit.SECONDS), equalTo(true)); + } catch (InterruptedException ex) { + fail("Shouldn't be here"); + } + super.execute(request, task, listener); + }); + } + }); + boolean success = randomBoolean(); + boolean keepOnCompletion = randomBoolean(); + boolean timeoutOnFirstAttempt = randomBoolean(); + boolean waitForCompletion = randomBoolean(); + CountDownLatch latch = new CountDownLatch(1); + TestRequest request = new TestRequest(success ? randomAlphaOfLength(10) : "die"); + AtomicReference responseHolder = new AtomicReference<>(); + service.asyncExecute( + request, + TimeValue.timeValueMillis(1), + TimeValue.timeValueMinutes(10), + keepOnCompletion, + ActionTestUtils.assertNoFailureListener(r -> { + assertThat(r.string, nullValue()); + assertThat(r.id, notNullValue()); + assertThat(responseHolder.getAndSet(r), nullValue()); + latch.countDown(); + }) + ); + assertThat(latch.await(20, TimeUnit.SECONDS), equalTo(true)); + + if (timeoutOnFirstAttempt) { + logger.trace("Getting an in-flight response"); + // try getting results, but fail with timeout because it is not ready yet + StoredAsyncResponse response = getResponse(responseHolder.get().id, TimeValue.timeValueMillis(2)); + assertThat(response.getException(), nullValue()); + assertThat(response.getResponse(), notNullValue()); + assertThat(response.getResponse().id, equalTo(responseHolder.get().id)); + assertThat(response.getResponse().string, nullValue()); + } + + if (waitForCompletion) { + // now we are waiting for the task to finish + logger.trace("Waiting for response to complete"); + AtomicReference> responseRef = new AtomicReference<>(); + CountDownLatch getResponseCountDown = getResponse( + responseHolder.get().id, + TimeValue.timeValueSeconds(5), + ActionTestUtils.assertNoFailureListener(responseRef::set) + ); + + executionLatch.countDown(); + assertThat(getResponseCountDown.await(10, TimeUnit.SECONDS), equalTo(true)); + + StoredAsyncResponse response = responseRef.get(); + if (success) { + assertThat(response.getException(), nullValue()); + assertThat(response.getResponse(), notNullValue()); + assertThat(response.getResponse().id, equalTo(responseHolder.get().id)); + assertThat(response.getResponse().string, equalTo("response for [" + request.string + "]")); + } else { + assertThat(response.getException(), notNullValue()); + assertThat(response.getResponse(), nullValue()); + assertThat(response.getException().getMessage(), equalTo("test exception")); + } + } else { + executionLatch.countDown(); + } + + // finally wait until the task disappears and get the response from the index + logger.trace("Wait for task to disappear "); + assertBusy(() -> { + Task task = transportService.getTaskManager().getTask(AsyncExecutionId.decode(responseHolder.get().id).getTaskId().getId()); + assertThat(task, nullValue()); + }); + + logger.trace("Getting the the final response from the index"); + StoredAsyncResponse response = getResponse(responseHolder.get().id, TimeValue.ZERO); + if (success) { + assertThat(response.getException(), nullValue()); + assertThat(response.getResponse(), notNullValue()); + assertThat(response.getResponse().string, equalTo("response for [" + request.string + "]")); + } else { + assertThat(response.getException(), notNullValue()); + assertThat(response.getResponse(), nullValue()); + assertThat(response.getException().getMessage(), equalTo("test exception")); + } + } + + private StoredAsyncResponse getResponse(String id, TimeValue timeout) throws InterruptedException { + AtomicReference> response = new AtomicReference<>(); + assertThat( + getResponse(id, timeout, ActionTestUtils.assertNoFailureListener(response::set)).await(10, TimeUnit.SECONDS), + equalTo(true) + ); + return response.get(); + } + + private CountDownLatch getResponse(String id, TimeValue timeout, ActionListener> listener) { + CountDownLatch responseLatch = new CountDownLatch(1); + GetAsyncResultRequest getResultsRequest = new GetAsyncResultRequest(id).setWaitForCompletionTimeout(timeout); + results.retrieveResult(getResultsRequest, ActionListener.wrap(r -> { + listener.onResponse(r); + responseLatch.countDown(); + }, e -> { + listener.onFailure(e); + responseLatch.countDown(); + })); + return responseLatch; + } + +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/async/StoredAsyncResponseTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/async/StoredAsyncResponseTests.java new file mode 100644 index 000000000000..f94749c26630 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/async/StoredAsyncResponseTests.java @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.async; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.search.SearchModule; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xcontent.NamedXContentRegistry; +import org.elasticsearch.xpack.core.async.StoredAsyncResponse; + +import java.io.IOException; +import java.util.Collections; +import java.util.Objects; + +public class StoredAsyncResponseTests extends AbstractWireSerializingTestCase> { + + public static class TestResponse implements Writeable { + private final String string; + + public TestResponse(String string) { + this.string = string; + } + + public TestResponse(StreamInput input) throws IOException { + this.string = input.readString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(string); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TestResponse that = (TestResponse) o; + return Objects.equals(string, that.string); + } + + @Override + public int hashCode() { + return Objects.hash(string); + } + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + SearchModule searchModule = new SearchModule(Settings.EMPTY, Collections.emptyList()); + return new NamedWriteableRegistry(searchModule.getNamedWriteables()); + } + + @Override + protected NamedXContentRegistry xContentRegistry() { + SearchModule searchModule = new SearchModule(Settings.EMPTY, Collections.emptyList()); + return new NamedXContentRegistry(searchModule.getNamedXContents()); + } + + @Override + protected StoredAsyncResponse createTestInstance() { + if (randomBoolean()) { + return new StoredAsyncResponse<>(new IllegalArgumentException(randomAlphaOfLength(10)), randomNonNegativeLong()); + } else { + return new StoredAsyncResponse<>(new TestResponse(randomAlphaOfLength(10)), randomNonNegativeLong()); + } + } + + @Override + protected StoredAsyncResponse mutateInstance(StoredAsyncResponse instance) { + return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 + } + + @Override + protected Writeable.Reader> instanceReader() { + return in -> new StoredAsyncResponse<>(TestResponse::new, in); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ConstantExtractorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ConstantExtractorTests.java new file mode 100644 index 000000000000..a7b55ba38be1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/execution/search/extractor/ConstantExtractorTests.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.execution.search.extractor; + +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.test.AbstractWireSerializingTestCase; + +import java.util.function.Supplier; + +public class ConstantExtractorTests extends AbstractWireSerializingTestCase { + public static ConstantExtractor randomConstantExtractor() { + return new ConstantExtractor(randomValidConstant()); + } + + private static Object randomValidConstant() { + @SuppressWarnings("unchecked") + Supplier valueSupplier = randomFrom(() -> randomInt(), () -> randomDouble(), () -> randomAlphaOfLengthBetween(1, 140)); + return valueSupplier.get(); + } + + @Override + protected ConstantExtractor createTestInstance() { + return randomConstantExtractor(); + } + + @Override + protected Reader instanceReader() { + return ConstantExtractor::new; + } + + @Override + protected ConstantExtractor mutateInstance(ConstantExtractor instance) { + return new ConstantExtractor(instance.extract((SearchHit) null) + "mutated"); + } + + public void testGet() { + Object expected = randomValidConstant(); + int times = between(1, 1000); + for (int i = 0; i < times; i++) { + assertSame(expected, new ConstantExtractor(expected).extract((SearchHit) null)); + } + } + + public void testToString() { + assertEquals("^foo", new ConstantExtractor("foo").toString()); + assertEquals("^42", new ConstantExtractor("42").toString()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/AttributeMapTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/AttributeMapTests.java new file mode 100644 index 000000000000..7e8ba58285fd --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/AttributeMapTests.java @@ -0,0 +1,333 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; +import static org.elasticsearch.xpack.esql.core.TestUtils.fieldAttribute; +import static org.elasticsearch.xpack.esql.core.TestUtils.of; +import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.arrayWithSize; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.sameInstance; + +public class AttributeMapTests extends ESTestCase { + + private static Attribute a(String name) { + return new UnresolvedAttribute(Source.EMPTY, name); + } + + private static AttributeMap threeMap() { + AttributeMap.Builder builder = AttributeMap.builder(); + builder.put(a("one"), "one"); + builder.put(a("two"), "two"); + builder.put(a("three"), "three"); + + return builder.build(); + } + + public void testAttributeMapWithSameAliasesCanResolveAttributes() { + Alias param1 = createIntParameterAlias(1, 100); + Alias param2 = createIntParameterAlias(2, 100); + assertTrue(param1.equals(param2)); + assertTrue(param1.semanticEquals(param2)); + // equality on literals + assertTrue(param1.child().equals(param2.child())); + assertTrue(param1.child().semanticEquals(param2.child())); + assertTrue(param1.toAttribute().equals(param2.toAttribute())); + assertFalse(param1.toAttribute().semanticEquals(param2.toAttribute())); + + AttributeMap.Builder mapBuilder = AttributeMap.builder(); + for (Alias a : List.of(param1, param2)) { + mapBuilder.put(a.toAttribute(), a.child()); + } + AttributeMap newAttributeMap = mapBuilder.build(); + + assertTrue(newAttributeMap.containsKey(param1.toAttribute())); + assertTrue(newAttributeMap.get(param1.toAttribute()) == param1.child()); + assertTrue(newAttributeMap.containsKey(param2.toAttribute())); + assertTrue(newAttributeMap.get(param2.toAttribute()) == param2.child()); + } + + public void testResolve() { + AttributeMap.Builder builder = AttributeMap.builder(); + Attribute one = a("one"); + Attribute two = fieldAttribute("two", DataTypes.INTEGER); + Attribute three = fieldAttribute("three", DataTypes.INTEGER); + Alias threeAlias = new Alias(Source.EMPTY, "three_alias", three); + Alias threeAliasAlias = new Alias(Source.EMPTY, "three_alias_alias", threeAlias); + builder.put(one, of("one")); + builder.put(two, "two"); + builder.put(three, of("three")); + builder.put(threeAlias.toAttribute(), threeAlias.child()); + builder.put(threeAliasAlias.toAttribute(), threeAliasAlias.child()); + AttributeMap map = builder.build(); + + assertEquals(of("one"), map.resolve(one)); + assertEquals("two", map.resolve(two)); + assertEquals(of("three"), map.resolve(three)); + assertEquals(of("three"), map.resolve(threeAlias)); + assertEquals(of("three"), map.resolve(threeAliasAlias)); + assertEquals(of("three"), map.resolve(threeAliasAlias, threeAlias)); + Attribute four = a("four"); + assertEquals("not found", map.resolve(four, "not found")); + assertNull(map.resolve(four)); + assertEquals(four, map.resolve(four, four)); + } + + public void testResolveOneHopCycle() { + AttributeMap.Builder builder = AttributeMap.builder(); + Attribute a = fieldAttribute("a", DataTypes.INTEGER); + Attribute b = fieldAttribute("b", DataTypes.INTEGER); + builder.put(a, a); + builder.put(b, a); + AttributeMap map = builder.build(); + + assertEquals(a, map.resolve(a, "default")); + assertEquals(a, map.resolve(b, "default")); + assertEquals("default", map.resolve("non-existing-key", "default")); + } + + public void testResolveMultiHopCycle() { + AttributeMap.Builder builder = AttributeMap.builder(); + Attribute a = fieldAttribute("a", DataTypes.INTEGER); + Attribute b = fieldAttribute("b", DataTypes.INTEGER); + Attribute c = fieldAttribute("c", DataTypes.INTEGER); + Attribute d = fieldAttribute("d", DataTypes.INTEGER); + builder.put(a, b); + builder.put(b, c); + builder.put(c, d); + builder.put(d, a); + AttributeMap map = builder.build(); + + // note: multi hop cycles should not happen, unless we have a + // bug in the code that populates the AttributeMaps + expectThrows(QlIllegalArgumentException.class, () -> { assertEquals(a, map.resolve(a, c)); }); + } + + private Alias createIntParameterAlias(int index, int value) { + Source source = new Source(1, index * 5, "?"); + Literal literal = new Literal(source, value, DataTypes.INTEGER); + Alias alias = new Alias(literal.source(), literal.source().text(), literal); + return alias; + } + + public void testEmptyConstructor() { + AttributeMap m = new AttributeMap<>(); + assertThat(m.size(), is(0)); + assertThat(m.isEmpty(), is(true)); + } + + public void testBuilder() { + AttributeMap.Builder builder = AttributeMap.builder(); + builder.put(a("one"), "one"); + builder.put(a("two"), "two"); + builder.put(a("three"), "three"); + + AttributeMap m = builder.build(); + assertThat(m.size(), is(3)); + assertThat(m.isEmpty(), is(false)); + + Attribute one = m.keySet().iterator().next(); + assertThat(m.containsKey(one), is(true)); + assertThat(m.containsKey(a("one")), is(false)); + assertThat(m.containsValue("one"), is(true)); + assertThat(m.containsValue("on"), is(false)); + assertThat(m.attributeNames(), contains("one", "two", "three")); + assertThat(m.values(), contains("one", "two", "three")); + } + + public void testSingleItemConstructor() { + Attribute one = a("one"); + AttributeMap m = new AttributeMap<>(one, "one"); + assertThat(m.size(), is(1)); + assertThat(m.isEmpty(), is(false)); + + assertThat(m.containsKey(one), is(true)); + assertThat(m.containsKey(a("one")), is(false)); + assertThat(m.containsValue("one"), is(true)); + assertThat(m.containsValue("on"), is(false)); + } + + public void testSubtract() { + AttributeMap m = threeMap(); + AttributeMap mo = new AttributeMap<>(m.keySet().iterator().next(), "one"); + AttributeMap empty = new AttributeMap<>(); + + assertThat(m.subtract(empty), is(m)); + assertThat(m.subtract(m), is(empty)); + assertThat(mo.subtract(m), is(empty)); + + AttributeMap subtract = m.subtract(mo); + + assertThat(subtract.size(), is(2)); + assertThat(subtract.attributeNames(), contains("two", "three")); + } + + public void testIntersect() { + AttributeMap m = threeMap(); + AttributeMap mo = new AttributeMap<>(m.keySet().iterator().next(), "one"); + AttributeMap empty = new AttributeMap<>(); + + assertThat(m.intersect(empty), is(empty)); + assertThat(m.intersect(m), is(m)); + assertThat(mo.intersect(m), is(mo)); + } + + public void testSubsetOf() { + AttributeMap m = threeMap(); + AttributeMap mo = new AttributeMap<>(m.keySet().iterator().next(), "one"); + AttributeMap empty = new AttributeMap<>(); + + assertThat(m.subsetOf(empty), is(false)); + assertThat(m.subsetOf(m), is(true)); + assertThat(mo.subsetOf(m), is(true)); + + assertThat(empty.subsetOf(m), is(true)); + assertThat(mo.subsetOf(m), is(true)); + } + + public void testKeySet() { + Attribute one = a("one"); + Attribute two = a("two"); + Attribute three = a("three"); + + Set keySet = threeMap().keySet(); + assertThat(keySet, contains(one, two, three)); + + // toObject + Object[] array = keySet.toArray(); + + assertThat(array, arrayWithSize(3)); + assertThat(array, arrayContaining(one, two, three)); + } + + public void testValues() { + AttributeMap m = threeMap(); + Collection values = m.values(); + + assertThat(values, hasSize(3)); + assertThat(values, contains("one", "two", "three")); + } + + public void testEntrySet() { + Attribute one = a("one"); + Attribute two = a("two"); + Attribute three = a("three"); + + Set> set = threeMap().entrySet(); + + assertThat(set, hasSize(3)); + + List keys = set.stream().map(Map.Entry::getKey).collect(toList()); + List values = set.stream().map(Map.Entry::getValue).collect(toList()); + + assertThat(keys, hasSize(3)); + + assertThat(values, hasSize(3)); + assertThat(values, contains("one", "two", "three")); + } + + public void testCopy() { + AttributeMap m = threeMap(); + AttributeMap copy = AttributeMap.builder().putAll(m).build(); + + assertThat(m, is(copy)); + } + + public void testEmptyMapIsImmutable() { + var empty = AttributeMap.emptyAttributeMap(); + var ex = expectThrows(UnsupportedOperationException.class, () -> empty.add(a("one"), new Object())); + } + + public void testAddPutEntriesIntoMap() { + var map = new AttributeMap(); + var one = a("one"); + var two = a("two"); + var three = a("three"); + + for (var i : asList(one, two, three)) { + map.add(i, i.name()); + } + + assertThat(map.size(), is(3)); + + assertThat(map.remove(one), is("one")); + assertThat(map.remove(two), is("two")); + + assertThat(map.size(), is(1)); + } + + public void testKeyIteratorRemoval() { + var map = new AttributeMap(); + var one = a("one"); + var two = a("two"); + var three = a("three"); + + for (var i : asList(one, two, three)) { + map.add(i, i.name()); + } + + assertThat(map.attributeNames(), contains("one", "two", "three")); + assertThat(map.size(), is(3)); + + var it = map.keySet().iterator(); + var next = it.next(); + assertThat(next, sameInstance(one)); + it.remove(); + assertThat(map.size(), is(2)); + next = it.next(); + assertThat(next, sameInstance(two)); + next = it.next(); + + assertThat(next, sameInstance(three)); + it.remove(); + assertThat(map.size(), is(1)); + + assertThat(it.hasNext(), is(false)); + } + + public void testValuesIteratorRemoval() { + var map = new AttributeMap(); + var one = a("one"); + var two = a("two"); + var three = a("three"); + + for (var i : asList(one, two, three)) { + map.add(i, i.name()); + } + + assertThat(map.values(), contains("one", "two", "three")); + + map.values().removeIf(v -> v.contains("o")); + assertThat(map.size(), is(1)); + assertThat(map.containsKey(three), is(true)); + assertThat(map.containsValue("three"), is(true)); + + assertThat(map.containsKey("two"), is(false)); + assertThat(map.containsKey(one), is(false)); + + var it = map.values().iterator(); + assertThat(it.hasNext(), is(true)); + assertThat(it.next(), is("three")); + it.remove(); + assertThat(it.hasNext(), is(false)); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/CanonicalTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/CanonicalTests.java new file mode 100644 index 000000000000..9d76efa78edd --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/CanonicalTests.java @@ -0,0 +1,260 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Add; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Div; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mod; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mul; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Sub; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.In; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NotEquals; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; + +import static java.util.Arrays.asList; +import static org.elasticsearch.xpack.esql.core.TestUtils.equalsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.fieldAttribute; +import static org.elasticsearch.xpack.esql.core.TestUtils.greaterThanOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.greaterThanOrEqualOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.lessThanOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.notEqualsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.of; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class CanonicalTests extends ESTestCase { + + Comparator comparator = Comparator.comparingInt(Object::hashCode); + + public void testNonCommutativeBinary() throws Exception { + Div div = new Div(EMPTY, of(2), of(1)); + Sub sub = new Sub(EMPTY, of(2), of(1)); + Mod mod = new Mod(EMPTY, div, sub); + assertEquals(mod, mod.canonical()); + } + + public void testNonCommutativeMixedWithCommutative() throws Exception { + // (0+1) / 1 + Div div = new Div(EMPTY, new Add(EMPTY, of(0), of(1)), of(1)); + // 1*2 - 1+2 + Sub sub = new Sub(EMPTY, new Mul(EMPTY, of(1), new Add(EMPTY, of(1), of(2))), new Add(EMPTY, of(1), of(2))); + + Div shuffledDiv = new Div(EMPTY, new Add(EMPTY, of(1), of(0)), of(1)); + Sub shuffledSub = new Sub(EMPTY, new Mul(EMPTY, new Add(EMPTY, of(2), of(1)), of(1)), new Add(EMPTY, of(2), of(1))); + + And and = new And(EMPTY, div, sub); + And shuffledAnd = new And(EMPTY, shuffledDiv, shuffledSub); + + assertNotEquals(and, shuffledAnd); + assertEquals(and.canonical(), shuffledAnd.canonical()); + } + + public void testAndManually() throws Exception { + FieldAttribute a = fieldAttribute(); + FieldAttribute b = fieldAttribute(); + FieldAttribute c = fieldAttribute(); + FieldAttribute d = fieldAttribute(); + And one = new And(EMPTY, new And(EMPTY, a, b), new And(EMPTY, c, d)); + And two = new And(EMPTY, new And(EMPTY, c, a), new And(EMPTY, b, d)); + + assertEquals(one.canonical(), two.canonical()); + assertEquals(one.semanticHash(), two.semanticHash()); + } + + public void testBasicSymmetricalAdd() throws Exception { + Expression left = new Add(EMPTY, new Add(EMPTY, of(1), of(2)), new Add(EMPTY, of(3), of(4))); + Expression right = new Add(EMPTY, new Add(EMPTY, of(4), of(2)), new Add(EMPTY, of(1), of(3))); + + assertEquals(left.canonical(), right.canonical()); + assertEquals(left.semanticHash(), right.semanticHash()); + } + + public void testBasicASymmetricalAdd() throws Exception { + Expression left = new Add(EMPTY, new Add(EMPTY, of(1), of(2)), of(3)); + Expression right = new Add(EMPTY, of(1), new Add(EMPTY, of(2), of(3))); + + assertEquals(left.canonical(), right.canonical()); + assertEquals(left.semanticHash(), right.semanticHash()); + } + + public void testBasicAnd() throws Exception { + testBinaryLogic(Predicates::combineAnd); + } + + public void testBasicOr() throws Exception { + testBinaryLogic(Predicates::combineAnd); + } + + private void testBinaryLogic(Function, Expression> combiner) { + List children = randomList(2, 128, TestUtils::fieldAttribute); + Expression expression = combiner.apply(children); + Collections.shuffle(children, random()); + Expression shuffledExpression = combiner.apply(children); + assertTrue(expression.semanticEquals(shuffledExpression)); + assertEquals(expression.semanticHash(), shuffledExpression.semanticHash()); + } + + public void testBinaryOperatorCombinations() throws Exception { + FieldAttribute a = fieldAttribute(); + FieldAttribute b = fieldAttribute(); + FieldAttribute c = fieldAttribute(); + FieldAttribute d = fieldAttribute(); + + And ab = new And(EMPTY, greaterThanOf(a, of(1)), lessThanOf(b, of(2))); + And cd = new And(EMPTY, equalsOf(new Add(EMPTY, c, of(20)), of(3)), greaterThanOrEqualOf(d, of(4))); + + And and = new And(EMPTY, ab, cd); + + // swap d comparison + And db = new And(EMPTY, greaterThanOrEqualOf(d, of(4)).swapLeftAndRight(), lessThanOf(b, of(2))); + // swap order for c and swap a comparison + And ca = new And(EMPTY, equalsOf(new Add(EMPTY, of(20), c), of(3)), greaterThanOf(a, of(1))); + + And shuffleAnd = new And(EMPTY, db, ca); + + assertEquals(and.canonical(), shuffleAnd.canonical()); + } + + public void testNot() throws Exception { + FieldAttribute a = fieldAttribute(); + FieldAttribute b = fieldAttribute(); + FieldAttribute c = fieldAttribute(); + FieldAttribute d = fieldAttribute(); + + And ab = new And(EMPTY, greaterThanOf(a, of(1)), lessThanOf(b, of(2))); + And cd = new And(EMPTY, equalsOf(new Add(EMPTY, c, of(20)), of(3)), greaterThanOrEqualOf(d, of(4))); + And and = new And(EMPTY, ab, cd); + + // swap d comparison + Or db = new Or(EMPTY, new Not(EMPTY, greaterThanOrEqualOf(d, of(4))), lessThanOf(b, of(2)).negate()); + // swap order for c and swap a comparison + Or ca = new Or(EMPTY, notEqualsOf(new Add(EMPTY, of(20), c), of(3)), new Not(EMPTY, greaterThanOf(a, of(1)))); + + Not not = new Not(EMPTY, new Or(EMPTY, db, ca)); + + Expression expected = and.canonical(); + Expression actual = not.canonical(); + assertEquals(and.canonical(), not.canonical()); + } + + public void testLiteralHashSorting() throws Exception { + DataType type = randomFrom(DataTypes.types()); + List list = randomList(10, 1024, () -> new Literal(EMPTY, randomInt(), type)); + List shuffle = new ArrayList<>(list); + Collections.shuffle(shuffle, random()); + + assertNotEquals(list, shuffle); + + list.sort(comparator); + shuffle.sort(comparator); + + assertEquals(list, shuffle); + } + + public void testInManual() throws Exception { + FieldAttribute value = fieldAttribute(); + + Literal a = new Literal(EMPTY, 1, DataTypes.INTEGER); + Literal b = new Literal(EMPTY, 2, DataTypes.INTEGER); + Literal c = new Literal(EMPTY, 3, DataTypes.INTEGER); + + In in = new In(EMPTY, value, asList(a, b, c)); + In anotherIn = new In(EMPTY, value, asList(b, a, c)); + + assertTrue(in.semanticEquals(anotherIn)); + assertEquals(in.semanticHash(), anotherIn.semanticHash()); + } + + public void testIn() throws Exception { + FieldAttribute value = fieldAttribute(); + List list = randomList(randomInt(1024), () -> new Literal(EMPTY, randomInt(), DataTypes.INTEGER)); + In in = new In(EMPTY, value, list); + List shuffledList = new ArrayList<>(list); + Collections.shuffle(shuffledList, random()); + In shuffledIn = new In(EMPTY, value, shuffledList); + + assertEquals(in.semanticHash(), shuffledIn.semanticHash()); + assertTrue(in.semanticEquals(shuffledIn)); + } + + interface BinaryOperatorFactory { + BinaryOperator create(Source source, Expression left, Expression right); + } + + public void testBasicOperators() throws Exception { + List list = Arrays.asList( + // arithmetic + Add::new, + Mul::new, + // logical + Or::new, + And::new + ); + + for (BinaryOperatorFactory factory : list) { + Literal left = of(randomInt()); + Literal right = of(randomInt()); + + BinaryOperator first = factory.create(Source.EMPTY, left, right); + BinaryOperator second = factory.create(Source.EMPTY, right, left); + + assertNotEquals(first, second); + assertTrue(first.semanticEquals(second)); + assertEquals(first, second.swapLeftAndRight()); + assertEquals(second, first.swapLeftAndRight()); + } + } + + interface BinaryOperatorWithTzFactory { + BinaryOperator create(Source source, Expression left, Expression right, ZoneId zoneId); + } + + public void testTimeZoneOperators() throws Exception { + List list = Arrays.asList( + LessThan::new, + LessThanOrEqual::new, + Equals::new, + NotEquals::new, + GreaterThan::new, + GreaterThanOrEqual::new + ); + + for (BinaryOperatorWithTzFactory factory : list) { + Literal left = of(randomInt()); + Literal right = of(randomInt()); + ZoneId zoneId = randomZone(); + + BinaryOperator first = factory.create(Source.EMPTY, left, right, zoneId); + BinaryOperator swap = first.swapLeftAndRight(); + + assertNotEquals(first, swap); + assertTrue(first.semanticEquals(swap)); + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/ExpressionIdTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/ExpressionIdTests.java new file mode 100644 index 000000000000..8ab1b47fd8db --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/ExpressionIdTests.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.test.ESTestCase; + +import java.util.concurrent.atomic.AtomicLong; + +public class ExpressionIdTests extends ESTestCase { + /** + * Each {@link NameId} should be unique. Technically + * you can roll the {@link AtomicLong} that backs them but + * that is not going to happen within a single query. + */ + public void testUnique() { + assertNotEquals(new NameId(), new NameId()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/LiteralTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/LiteralTests.java new file mode 100644 index 000000000000..32a953165b53 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/LiteralTests.java @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.AbstractNodeTestCase; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.type.Converter; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.util.Collections.emptyList; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BYTE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SHORT; + +public class LiteralTests extends AbstractNodeTestCase { + static class ValueAndCompatibleTypes { + final Supplier valueSupplier; + final List validDataTypes; + + ValueAndCompatibleTypes(Supplier valueSupplier, DataType... validDataTypes) { + this.valueSupplier = valueSupplier; + this.validDataTypes = Arrays.asList(validDataTypes); + } + } + + /** + * Generators for values and data types. The first valid + * data type is special it is used when picking a generator + * for a specific data type. So the first valid data type + * after a generators is its "native" type. + */ + private static final List GENERATORS = Arrays.asList( + new ValueAndCompatibleTypes(() -> randomBoolean() ? randomBoolean() : randomFrom("true", "false"), BOOLEAN), + new ValueAndCompatibleTypes(ESTestCase::randomByte, BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN), + new ValueAndCompatibleTypes(ESTestCase::randomShort, SHORT, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN), + new ValueAndCompatibleTypes(ESTestCase::randomInt, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN), + new ValueAndCompatibleTypes(ESTestCase::randomLong, LONG, FLOAT, DOUBLE, BOOLEAN), + new ValueAndCompatibleTypes(ESTestCase::randomFloat, FLOAT, LONG, DOUBLE, BOOLEAN), + new ValueAndCompatibleTypes(ESTestCase::randomDouble, DOUBLE, LONG, FLOAT, BOOLEAN), + new ValueAndCompatibleTypes(() -> randomAlphaOfLength(5), KEYWORD) + ); + + public static Literal randomLiteral() { + ValueAndCompatibleTypes gen = randomFrom(GENERATORS); + DataType dataType = randomFrom(gen.validDataTypes); + return new Literal(SourceTests.randomSource(), DataTypeConverter.convert(gen.valueSupplier.get(), dataType), dataType); + } + + @Override + protected Literal randomInstance() { + return randomLiteral(); + } + + @Override + protected Literal copy(Literal instance) { + return new Literal(instance.source(), instance.value(), instance.dataType()); + } + + @Override + protected Literal mutate(Literal instance) { + List> mutators = new ArrayList<>(); + // Changing the location doesn't count as mutation because..... it just doesn't, ok?! + // Change the value to another valid value + mutators.add(l -> new Literal(l.source(), randomValueOfTypeOtherThan(l.value(), l.dataType()), l.dataType())); + // If we can change the data type then add that as an option as well + List validDataTypes = validReplacementDataTypes(instance.value(), instance.dataType()); + if (validDataTypes.size() > 1) { + mutators.add(l -> new Literal(l.source(), l.value(), randomValueOtherThan(l.dataType(), () -> randomFrom(validDataTypes)))); + } + return randomFrom(mutators).apply(instance); + } + + @Override + public void testTransform() { + Literal literal = randomInstance(); + + // Replace value + Object newValue = randomValueOfTypeOtherThan(literal.value(), literal.dataType()); + assertEquals( + new Literal(literal.source(), newValue, literal.dataType()), + literal.transformPropertiesOnly(Object.class, p -> p == literal.value() ? newValue : p) + ); + + // Replace data type if there are more compatible data types + List validDataTypes = validReplacementDataTypes(literal.value(), literal.dataType()); + if (validDataTypes.size() > 1) { + DataType newDataType = randomValueOtherThan(literal.dataType(), () -> randomFrom(validDataTypes)); + assertEquals( + new Literal(literal.source(), literal.value(), newDataType), + literal.transformPropertiesOnly(DataType.class, p -> newDataType) + ); + } + } + + @Override + public void testReplaceChildren() { + Exception e = expectThrows(UnsupportedOperationException.class, () -> randomInstance().replaceChildrenSameSize(emptyList())); + assertEquals("this type of node doesn't have any children to replace", e.getMessage()); + } + + private Object randomValueOfTypeOtherThan(Object original, DataType type) { + for (ValueAndCompatibleTypes gen : GENERATORS) { + if (gen.validDataTypes.get(0) == type) { + return randomValueOtherThan(original, () -> DataTypeConverter.convert(gen.valueSupplier.get(), type)); + } + } + throw new IllegalArgumentException("No native generator for [" + type + "]"); + } + + private List validReplacementDataTypes(Object value, DataType type) { + List validDataTypes = new ArrayList<>(); + List options = Arrays.asList(BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN); + for (DataType candidate : options) { + try { + Converter c = DataTypeConverter.converterFor(type, candidate); + c.convert(value); + validDataTypes.add(candidate); + } catch (InvalidArgumentException e) { + // invalid conversion then.... + } + } + return validDataTypes; + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/NullabilityTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/NullabilityTests.java new file mode 100644 index 000000000000..53132fe1c4b8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/NullabilityTests.java @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import static java.util.Arrays.asList; +import static org.elasticsearch.xpack.esql.core.expression.Nullability.FALSE; +import static org.elasticsearch.xpack.esql.core.expression.Nullability.TRUE; +import static org.elasticsearch.xpack.esql.core.expression.Nullability.UNKNOWN; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class NullabilityTests extends ESTestCase { + + public static class Nullable extends LeafExpression { + + private final Nullability nullability; + + public Nullable(Source source, Nullability nullability) { + super(source); + this.nullability = nullability; + } + + @Override + public Nullability nullable() { + return nullability; + } + + @Override + public DataType dataType() { + return DataTypes.BOOLEAN; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, Nullable::new, nullability); + } + } + + private Nullable YES = new Nullable(EMPTY, TRUE); + private Nullable NO = new Nullable(EMPTY, FALSE); + private Nullable MAYBE = new Nullable(EMPTY, UNKNOWN); + + public void testLogicalAndOfNullabilities() { + assertEquals(TRUE, Expressions.nullable(asList(YES))); + assertEquals(FALSE, Expressions.nullable(asList(NO))); + assertEquals(UNKNOWN, Expressions.nullable(asList(MAYBE))); + + assertEquals(UNKNOWN, Expressions.nullable(asList(MAYBE, MAYBE))); + assertEquals(UNKNOWN, Expressions.nullable(asList(MAYBE, YES))); + assertEquals(UNKNOWN, Expressions.nullable(asList(MAYBE, NO))); + + assertEquals(FALSE, Expressions.nullable(asList(NO, NO))); + assertEquals(TRUE, Expressions.nullable(asList(NO, YES))); + assertEquals(UNKNOWN, Expressions.nullable(asList(NO, MAYBE))); + + assertEquals(TRUE, Expressions.nullable(asList(YES, YES))); + assertEquals(TRUE, Expressions.nullable(asList(YES, NO))); + assertEquals(UNKNOWN, Expressions.nullable(asList(YES, MAYBE))); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/TyperResolutionTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/TyperResolutionTests.java new file mode 100644 index 000000000000..213c29040a4b --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/TyperResolutionTests.java @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression.TypeResolution; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mul; + +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class TyperResolutionTests extends ESTestCase { + + public void testMulNumeric() { + Mul m = new Mul(EMPTY, L(1), L(2)); + assertEquals(TypeResolution.TYPE_RESOLVED, m.typeResolved()); + } + + private static Literal L(Object value) { + return TestUtils.of(EMPTY, value); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAttributeTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAttributeTests.java new file mode 100644 index 000000000000..e7cd38b8f938 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/UnresolvedAttributeTests.java @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression; + +import org.elasticsearch.xpack.esql.core.tree.AbstractNodeTestCase; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Supplier; + +public class UnresolvedAttributeTests extends AbstractNodeTestCase { + public static UnresolvedAttribute randomUnresolvedAttribute() { + Source source = SourceTests.randomSource(); + String name = randomAlphaOfLength(5); + String qualifier = randomQualifier(); + NameId id = randomBoolean() ? null : new NameId(); + String unresolvedMessage = randomUnresolvedMessage(); + Object resolutionMetadata = new Object(); + return new UnresolvedAttribute(source, name, qualifier, id, unresolvedMessage, resolutionMetadata); + } + + /** + * A random qualifier. It is important that this be distinct + * from the name and the unresolvedMessage for testing transform. + */ + private static String randomQualifier() { + return randomBoolean() ? null : randomAlphaOfLength(6); + } + + /** + * A random qualifier. It is important that this be distinct + * from the name and the qualifier for testing transform. + */ + private static String randomUnresolvedMessage() { + return randomAlphaOfLength(7); + } + + @Override + protected UnresolvedAttribute randomInstance() { + return randomUnresolvedAttribute(); + } + + @Override + protected UnresolvedAttribute mutate(UnresolvedAttribute a) { + Supplier option = randomFrom( + Arrays.asList( + () -> new UnresolvedAttribute( + a.source(), + randomValueOtherThan(a.name(), () -> randomAlphaOfLength(5)), + a.qualifier(), + a.id(), + a.unresolvedMessage(), + a.resolutionMetadata() + ), + () -> new UnresolvedAttribute( + a.source(), + a.name(), + randomValueOtherThan(a.qualifier(), UnresolvedAttributeTests::randomQualifier), + a.id(), + a.unresolvedMessage(), + a.resolutionMetadata() + ), + () -> new UnresolvedAttribute( + a.source(), + a.name(), + a.qualifier(), + a.id(), + randomValueOtherThan(a.unresolvedMessage(), () -> randomUnresolvedMessage()), + a.resolutionMetadata() + ), + () -> new UnresolvedAttribute(a.source(), a.name(), a.qualifier(), a.id(), a.unresolvedMessage(), new Object()) + ) + ); + return option.get(); + } + + @Override + protected UnresolvedAttribute copy(UnresolvedAttribute a) { + return new UnresolvedAttribute(a.source(), a.name(), a.qualifier(), a.id(), a.unresolvedMessage(), a.resolutionMetadata()); + } + + @Override + public void testTransform() { + UnresolvedAttribute a = randomUnresolvedAttribute(); + + String newName = randomValueOtherThan(a.name(), () -> randomAlphaOfLength(5)); + assertEquals( + new UnresolvedAttribute(a.source(), newName, a.qualifier(), a.id(), a.unresolvedMessage(), a.resolutionMetadata()), + a.transformPropertiesOnly(Object.class, v -> Objects.equals(v, a.name()) ? newName : v) + ); + + String newQualifier = randomValueOtherThan(a.qualifier(), UnresolvedAttributeTests::randomQualifier); + assertEquals( + new UnresolvedAttribute(a.source(), a.name(), newQualifier, a.id(), a.unresolvedMessage(), a.resolutionMetadata()), + a.transformPropertiesOnly(Object.class, v -> Objects.equals(v, a.qualifier()) ? newQualifier : v) + ); + + NameId newId = new NameId(); + assertEquals( + new UnresolvedAttribute(a.source(), a.name(), a.qualifier(), newId, a.unresolvedMessage(), a.resolutionMetadata()), + a.transformPropertiesOnly(Object.class, v -> Objects.equals(v, a.id()) ? newId : v) + ); + + String newMessage = randomValueOtherThan(a.unresolvedMessage(), UnresolvedAttributeTests::randomUnresolvedMessage); + assertEquals( + new UnresolvedAttribute(a.source(), a.name(), a.qualifier(), a.id(), newMessage, a.resolutionMetadata()), + a.transformPropertiesOnly(Object.class, v -> Objects.equals(v, a.unresolvedMessage()) ? newMessage : v) + ); + + Object newMeta = new Object(); + assertEquals( + new UnresolvedAttribute(a.source(), a.name(), a.qualifier(), a.id(), a.unresolvedMessage(), newMeta), + a.transformPropertiesOnly(Object.class, v -> Objects.equals(v, a.resolutionMetadata()) ? newMeta : v) + ); + } + + @Override + public void testReplaceChildren() { + // UnresolvedAttribute doesn't have any children + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionRegistryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionRegistryTests.java new file mode 100644 index 000000000000..75754d77d68a --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/FunctionRegistryTests.java @@ -0,0 +1,250 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ConfigurationFunction; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.type.DataType; + +import java.util.Arrays; +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.elasticsearch.xpack.esql.core.TestUtils.randomConfiguration; +import static org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry.def; +import static org.elasticsearch.xpack.esql.core.expression.function.FunctionResolutionStrategy.DEFAULT; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; + +public class FunctionRegistryTests extends ESTestCase { + + public void testNoArgFunction() { + UnresolvedFunction ur = uf(DEFAULT); + FunctionRegistry r = new FunctionRegistry(defineDummyNoArgFunction()); + FunctionDefinition def = r.resolveFunction(ur.name()); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + } + + public static FunctionDefinition defineDummyNoArgFunction() { + return def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION"); + } + + public void testUnaryFunction() { + UnresolvedFunction ur = uf(DEFAULT, mock(Expression.class)); + FunctionRegistry r = new FunctionRegistry(defineDummyUnaryFunction(ur)); + FunctionDefinition def = r.resolveFunction(ur.name()); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + // No children aren't supported + ParsingException e = expectThrows(ParsingException.class, () -> uf(DEFAULT).buildResolved(randomConfiguration(), def)); + assertThat(e.getMessage(), endsWith("expects exactly one argument")); + + // Multiple children aren't supported + e = expectThrows( + ParsingException.class, + () -> uf(DEFAULT, mock(Expression.class), mock(Expression.class)).buildResolved(randomConfiguration(), def) + ); + assertThat(e.getMessage(), endsWith("expects exactly one argument")); + } + + public static FunctionDefinition defineDummyUnaryFunction(UnresolvedFunction ur) { + return def(DummyFunction.class, (Source l, Expression e) -> { + assertSame(e, ur.children().get(0)); + return new DummyFunction(l); + }, "DUMMY_FUNCTION"); + } + + public void testBinaryFunction() { + UnresolvedFunction ur = uf(DEFAULT, mock(Expression.class), mock(Expression.class)); + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Source l, Expression lhs, Expression rhs) -> { + assertSame(lhs, ur.children().get(0)); + assertSame(rhs, ur.children().get(1)); + return new DummyFunction(l); + }, "DUMMY_FUNCTION")); + FunctionDefinition def = r.resolveFunction(ur.name()); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + // No children aren't supported + ParsingException e = expectThrows(ParsingException.class, () -> uf(DEFAULT).buildResolved(randomConfiguration(), def)); + assertThat(e.getMessage(), endsWith("expects exactly two arguments")); + + // One child isn't supported + e = expectThrows(ParsingException.class, () -> uf(DEFAULT, mock(Expression.class)).buildResolved(randomConfiguration(), def)); + assertThat(e.getMessage(), endsWith("expects exactly two arguments")); + + // Many children aren't supported + e = expectThrows( + ParsingException.class, + () -> uf(DEFAULT, mock(Expression.class), mock(Expression.class), mock(Expression.class)).buildResolved( + randomConfiguration(), + def + ) + ); + assertThat(e.getMessage(), endsWith("expects exactly two arguments")); + } + + public void testAliasNameIsTheSameAsAFunctionName() { + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS")); + QlIllegalArgumentException iae = expectThrows( + QlIllegalArgumentException.class, + () -> r.register(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "DUMMY_FUNCTION")) + ); + assertEquals("alias [DUMMY_FUNCTION] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]", iae.getMessage()); + } + + public void testDuplicateAliasInTwoDifferentFunctionsFromTheSameBatch() { + QlIllegalArgumentException iae = expectThrows( + QlIllegalArgumentException.class, + () -> new FunctionRegistry( + def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS"), + def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "ALIAS") + ) + ); + assertEquals("alias [ALIAS] is used by [DUMMY_FUNCTION(ALIAS)] and [DUMMY_FUNCTION2]", iae.getMessage()); + } + + public void testDuplicateAliasInTwoDifferentFunctionsFromTwoDifferentBatches() { + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS")); + QlIllegalArgumentException iae = expectThrows( + QlIllegalArgumentException.class, + () -> r.register(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "ALIAS")) + ); + assertEquals("alias [ALIAS] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]", iae.getMessage()); + } + + public void testFunctionResolving() { + UnresolvedFunction ur = uf(DEFAULT, mock(Expression.class)); + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Source l, Expression e) -> { + assertSame(e, ur.children().get(0)); + return new DummyFunction(l); + }, "DUMMY_FUNCTION", "DUMMY_FUNC")); + + // Resolve by primary name + FunctionDefinition def = r.resolveFunction(r.resolveAlias("DuMMy_FuncTIon")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + def = r.resolveFunction(r.resolveAlias("Dummy_Function")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + def = r.resolveFunction(r.resolveAlias("dummy_function")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + def = r.resolveFunction(r.resolveAlias("DUMMY_FUNCTION")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + // Resolve by alias + def = r.resolveFunction(r.resolveAlias("DumMy_FunC")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + def = r.resolveFunction(r.resolveAlias("dummy_func")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + def = r.resolveFunction(r.resolveAlias("DUMMY_FUNC")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + + // Not resolved + QlIllegalArgumentException e = expectThrows( + QlIllegalArgumentException.class, + () -> r.resolveFunction(r.resolveAlias("DummyFunction")) + ); + assertThat(e.getMessage(), is("Cannot find function DUMMYFUNCTION; this should have been caught during analysis")); + + e = expectThrows(QlIllegalArgumentException.class, () -> r.resolveFunction(r.resolveAlias("dummyFunction"))); + assertThat(e.getMessage(), is("Cannot find function DUMMYFUNCTION; this should have been caught during analysis")); + } + + public void testConfigurationOptionalFunction() { + UnresolvedFunction ur = uf(DEFAULT, mock(Expression.class)); + FunctionRegistry r = new FunctionRegistry( + def(DummyConfigurationOptionalArgumentFunction.class, (Source l, Expression e, Configuration c) -> { + assertSame(e, ur.children().get(0)); + return new DummyConfigurationOptionalArgumentFunction(l, List.of(ur), c); + }, "DUMMY") + ); + FunctionDefinition def = r.resolveFunction(r.resolveAlias("DUMMY")); + assertEquals(ur.source(), ur.buildResolved(randomConfiguration(), def).source()); + } + + public static UnresolvedFunction uf(FunctionResolutionStrategy resolutionStrategy, Expression... children) { + return new UnresolvedFunction(SourceTests.randomSource(), "DUMMY_FUNCTION", resolutionStrategy, Arrays.asList(children)); + } + + public static class DummyFunction extends ScalarFunction { + public DummyFunction(Source source) { + super(source, emptyList()); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this); + } + + @Override + public Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + @Override + public DataType dataType() { + return null; + } + + @Override + public ScriptTemplate asScript() { + return null; + } + + @Override + protected Pipe makePipe() { + return null; + } + } + + public static class DummyFunction2 extends DummyFunction { + public DummyFunction2(Source source) { + super(source); + } + } + + public static class DummyConfigurationOptionalArgumentFunction extends ConfigurationFunction implements OptionalArgument { + + public DummyConfigurationOptionalArgumentFunction(Source source, List fields, Configuration configuration) { + super(source, fields, configuration); + } + + @Override + public DataType dataType() { + return null; + } + + @Override + public ScriptTemplate asScript() { + return null; + } + + @Override + public Expression replaceChildren(List newChildren) { + return new DummyConfigurationOptionalArgumentFunction(source(), newChildren, configuration()); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, DummyConfigurationOptionalArgumentFunction::new, children(), configuration()); + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/NamedExpressionTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/NamedExpressionTests.java new file mode 100644 index 000000000000..0bbead373ffe --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/NamedExpressionTests.java @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Add; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Div; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mod; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mul; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Neg; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Sub; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; + +import static java.util.Collections.emptyMap; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class NamedExpressionTests extends ESTestCase { + + public void testArithmeticFunctionName() { + String e = "5 + 2"; + Add add = new Add(s(e), l(5), l(2)); + assertEquals(e, add.sourceText()); + + e = "5 / 2"; + Div div = new Div(s(e), l(5), l(2)); + assertEquals(e, div.sourceText()); + + e = "5%2"; + Mod mod = new Mod(s(e), l(5), l(2)); + assertEquals(e, mod.sourceText()); + + e = "5 * 2"; + Mul mul = new Mul(s(e), l(5), l(2)); + assertEquals(e, mul.sourceText()); + + e = "5 -2"; + Sub sub = new Sub(s(e), l(5), l(2)); + assertEquals(e, sub.sourceText()); + + e = " - 5"; + Neg neg = new Neg(s(e), l(5)); + assertEquals(e, neg.sourceText()); + } + + public void testNameForArithmeticFunctionAppliedOnTableColumn() { + FieldAttribute fa = new FieldAttribute(EMPTY, "myField", new EsField("myESField", DataTypes.INTEGER, emptyMap(), true)); + String e = "myField + 10"; + Add add = new Add(s(e), fa, l(10)); + assertEquals(e, add.sourceText()); + } + + private static Source s(String text) { + return new Source(Location.EMPTY, text); + } + + private static Literal l(Object value) { + return TestUtils.of(EMPTY, value); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/TestFunctionRegistry.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/TestFunctionRegistry.java new file mode 100644 index 000000000000..3d17a6ea7962 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/TestFunctionRegistry.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function; + +public class TestFunctionRegistry extends FunctionRegistry { + + public TestFunctionRegistry(FunctionDefinition... definitions) { + super(definitions); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/UnresolvedFunctionTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/UnresolvedFunctionTests.java new file mode 100644 index 000000000000..9d29aaf63139 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/UnresolvedFunctionTests.java @@ -0,0 +1,183 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.function; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.AbstractNodeTestCase; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.expression.UnresolvedAttributeTests.randomUnresolvedAttribute; +import static org.elasticsearch.xpack.esql.core.tree.SourceTests.randomSource; + +public class UnresolvedFunctionTests extends AbstractNodeTestCase { + + public static UnresolvedFunction randomUnresolvedFunction() { + return innerRandomUnresolvedFunction(resolutionStrategies()); + } + + static UnresolvedFunction innerRandomUnresolvedFunction(List resolutionStrategies) { + /* Pick an UnresolvedFunction where the name and the + * message don't happen to be the same String. If they + * matched then transform would get them confused. */ + Source source = randomSource(); + String name = randomAlphaOfLength(5); + FunctionResolutionStrategy resolutionStrategy = randomFrom(resolutionStrategies); + List args = randomFunctionArgs(); + boolean analyzed = randomBoolean(); + String unresolvedMessage = randomUnresolvedMessage(); + return new UnresolvedFunction(source, name, resolutionStrategy, args, analyzed, unresolvedMessage); + } + + private static List resolutionStrategies() { + return asList(FunctionResolutionStrategy.DEFAULT, new FunctionResolutionStrategy() { + }); + } + + protected List pluggableResolutionStrategies() { + return resolutionStrategies(); + } + + private static List randomFunctionArgs() { + // At this point we only support functions with 0, 1, or 2 arguments. + Supplier> option = randomFrom( + asList( + Collections::emptyList, + () -> singletonList(randomUnresolvedAttribute()), + () -> asList(randomUnresolvedAttribute(), randomUnresolvedAttribute()) + ) + ); + return option.get(); + } + + /** + * Pick a random value for the unresolved message. + * It is important that this value is not the same + * as the value for the name for tests like the {@link #testTransform} + * and for general ease of reading. + */ + private static String randomUnresolvedMessage() { + return randomBoolean() ? null : randomAlphaOfLength(6); + } + + @Override + protected UnresolvedFunction randomInstance() { + return innerRandomUnresolvedFunction(pluggableResolutionStrategies()); + } + + @Override + protected UnresolvedFunction mutate(UnresolvedFunction uf) { + Supplier option = randomFrom( + asList( + () -> new UnresolvedFunction( + uf.source(), + randomValueOtherThan(uf.name(), () -> randomAlphaOfLength(5)), + uf.resolutionStrategy(), + uf.children(), + uf.analyzed(), + uf.unresolvedMessage() + ), + () -> new UnresolvedFunction( + uf.source(), + uf.name(), + randomValueOtherThan(uf.resolutionStrategy(), () -> randomFrom(resolutionStrategies())), + uf.children(), + uf.analyzed(), + uf.unresolvedMessage() + ), + () -> new UnresolvedFunction( + uf.source(), + uf.name(), + uf.resolutionStrategy(), + randomValueOtherThan(uf.children(), UnresolvedFunctionTests::randomFunctionArgs), + uf.analyzed(), + uf.unresolvedMessage() + ), + () -> new UnresolvedFunction( + uf.source(), + uf.name(), + uf.resolutionStrategy(), + uf.children(), + uf.analyzed() == false, + uf.unresolvedMessage() + ), + () -> new UnresolvedFunction( + uf.source(), + uf.name(), + uf.resolutionStrategy(), + uf.children(), + uf.analyzed(), + randomValueOtherThan(uf.unresolvedMessage(), () -> randomAlphaOfLength(5)) + ) + ) + ); + return option.get(); + } + + @Override + protected UnresolvedFunction copy(UnresolvedFunction uf) { + return new UnresolvedFunction( + uf.source(), + uf.name(), + uf.resolutionStrategy(), + uf.children(), + uf.analyzed(), + uf.unresolvedMessage() + ); + } + + @Override + public void testTransform() { + UnresolvedFunction uf = innerRandomUnresolvedFunction(pluggableResolutionStrategies()); + + String newName = randomValueOtherThan(uf.name(), () -> randomAlphaOfLength(5)); + assertEquals( + new UnresolvedFunction(uf.source(), newName, uf.resolutionStrategy(), uf.children(), uf.analyzed(), uf.unresolvedMessage()), + uf.transformPropertiesOnly(Object.class, p -> Objects.equals(p, uf.name()) ? newName : p) + ); + FunctionResolutionStrategy newResolution = randomValueOtherThan(uf.resolutionStrategy(), () -> randomFrom(resolutionStrategies())); + assertEquals( + new UnresolvedFunction(uf.source(), uf.name(), newResolution, uf.children(), uf.analyzed(), uf.unresolvedMessage()), + uf.transformPropertiesOnly(Object.class, p -> Objects.equals(p, uf.resolutionStrategy()) ? newResolution : p) + ); + String newUnresolvedMessage = randomValueOtherThan(uf.unresolvedMessage(), UnresolvedFunctionTests::randomUnresolvedMessage); + assertEquals( + new UnresolvedFunction(uf.source(), uf.name(), uf.resolutionStrategy(), uf.children(), uf.analyzed(), newUnresolvedMessage), + uf.transformPropertiesOnly(Object.class, p -> Objects.equals(p, uf.unresolvedMessage()) ? newUnresolvedMessage : p) + ); + + assertEquals( + new UnresolvedFunction( + uf.source(), + uf.name(), + uf.resolutionStrategy(), + uf.children(), + uf.analyzed() == false, + uf.unresolvedMessage() + ), + uf.transformPropertiesOnly(Object.class, p -> Objects.equals(p, uf.analyzed()) ? uf.analyzed() == false : p) + ); + + } + + @Override + public void testReplaceChildren() { + UnresolvedFunction uf = innerRandomUnresolvedFunction(pluggableResolutionStrategies()); + + List newChildren = randomValueOtherThan(uf.children(), UnresolvedFunctionTests::randomFunctionArgs); + assertEquals( + new UnresolvedFunction(uf.source(), uf.name(), uf.resolutionStrategy(), newChildren, uf.analyzed(), uf.unresolvedMessage()), + uf.replaceChildren(newChildren) + ); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/FunctionTestUtils.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/FunctionTestUtils.java new file mode 100644 index 000000000000..eba95df9d6dd --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/FunctionTestUtils.java @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.time.Instant; +import java.time.ZonedDateTime; +import java.util.BitSet; +import java.util.Iterator; + +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; + +public final class FunctionTestUtils { + + public static Literal l(Object value) { + return new Literal(EMPTY, value, DataTypes.fromJava(value)); + } + + public static Literal l(Object value, DataType type) { + return new Literal(EMPTY, value, type); + } + + public static Literal randomStringLiteral() { + return l(ESTestCase.randomRealisticUnicodeOfLength(10), KEYWORD); + } + + public static Literal randomIntLiteral() { + return l(ESTestCase.randomInt(), INTEGER); + } + + public static Literal randomBooleanLiteral() { + return l(ESTestCase.randomBoolean(), BOOLEAN); + } + + public static Literal randomDatetimeLiteral() { + return l(ZonedDateTime.ofInstant(Instant.ofEpochMilli(ESTestCase.randomLong()), ESTestCase.randomZone()), DATETIME); + } + + public static class Combinations implements Iterable { + private int n; + private int k; + + public Combinations(int n, int k) { + this.n = n; + this.k = k; + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + BitSet bs = new BitSet(n); + + { + bs.set(0, k); + } + + @Override + public boolean hasNext() { + return bs != null; + } + + @Override + public BitSet next() { + BitSet old = (BitSet) bs.clone(); + int b = bs.previousClearBit(n - 1); + int b1 = bs.previousSetBit(b); + if (b1 == -1) { + bs = null; + } else { + bs.clear(b1); + bs.set(b1 + 1, b1 + (n - b) + 1); + bs.clear(b1 + (n - b) + 1, n); + } + return old; + } + }; + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionPipeTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionPipeTests.java new file mode 100644 index 000000000000..8ddf3a84fc1f --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithFunctionPipeTests.java @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.FunctionTestUtils.Combinations; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.tree.AbstractNodeTestCase; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +import static org.elasticsearch.xpack.esql.core.expression.Expressions.pipe; +import static org.elasticsearch.xpack.esql.core.expression.function.scalar.FunctionTestUtils.randomStringLiteral; +import static org.elasticsearch.xpack.esql.core.tree.SourceTests.randomSource; + +public class StartsWithFunctionPipeTests extends AbstractNodeTestCase { + + public static class StartsWithTest extends StartsWith { + public StartsWithTest(Source source, Expression input, Expression pattern, boolean caseInsensitive) { + super(source, input, pattern, caseInsensitive); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new StartsWithTest(source(), newChildren.get(0), newChildren.get(1), isCaseInsensitive()); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, StartsWithTest::new, input(), pattern(), isCaseInsensitive()); + } + } + + @Override + protected StartsWithFunctionPipe randomInstance() { + return randomStartsWithFunctionPipe(); + } + + private Expression randomStartsWithFunctionExpression() { + return randomStartsWithFunctionPipe().expression(); + } + + public static StartsWithFunctionPipe randomStartsWithFunctionPipe() { + return (StartsWithFunctionPipe) new StartsWithTest(randomSource(), randomStringLiteral(), randomStringLiteral(), randomBoolean()) + .makePipe(); + } + + @Override + public void testTransform() { + // test transforming only the properties (source, expression), + // skipping the children (the two parameters of the binary function) which are tested separately + StartsWithFunctionPipe b1 = randomInstance(); + Expression newExpression = randomValueOtherThan(b1.expression(), this::randomStartsWithFunctionExpression); + StartsWithFunctionPipe newB = new StartsWithFunctionPipe( + b1.source(), + newExpression, + b1.input(), + b1.pattern(), + b1.isCaseSensitive() + ); + + assertEquals(newB, b1.transformPropertiesOnly(Expression.class, v -> Objects.equals(v, b1.expression()) ? newExpression : v)); + + StartsWithFunctionPipe b2 = randomInstance(); + Source newLoc = randomValueOtherThan(b2.source(), SourceTests::randomSource); + newB = new StartsWithFunctionPipe(newLoc, b2.expression(), b2.input(), b2.pattern(), b2.isCaseSensitive()); + + assertEquals(newB, b2.transformPropertiesOnly(Source.class, v -> Objects.equals(v, b2.source()) ? newLoc : v)); + } + + @Override + public void testReplaceChildren() { + StartsWithFunctionPipe b = randomInstance(); + Pipe newInput = randomValueOtherThan(b.input(), () -> pipe(randomStringLiteral())); + Pipe newPattern = randomValueOtherThan(b.pattern(), () -> pipe(randomStringLiteral())); + + StartsWithFunctionPipe newB = new StartsWithFunctionPipe(b.source(), b.expression(), b.input(), b.pattern(), b.isCaseSensitive()); + StartsWithFunctionPipe transformed = (StartsWithFunctionPipe) newB.replaceChildren(newInput, b.pattern()); + assertEquals(transformed.input(), newInput); + assertEquals(transformed.source(), b.source()); + assertEquals(transformed.expression(), b.expression()); + assertEquals(transformed.pattern(), b.pattern()); + + transformed = (StartsWithFunctionPipe) newB.replaceChildren(b.input(), newPattern); + assertEquals(transformed.input(), b.input()); + assertEquals(transformed.source(), b.source()); + assertEquals(transformed.expression(), b.expression()); + assertEquals(transformed.pattern(), newPattern); + + transformed = (StartsWithFunctionPipe) newB.replaceChildren(newInput, newPattern); + assertEquals(transformed.input(), newInput); + assertEquals(transformed.source(), b.source()); + assertEquals(transformed.expression(), b.expression()); + assertEquals(transformed.pattern(), newPattern); + } + + @Override + protected StartsWithFunctionPipe mutate(StartsWithFunctionPipe instance) { + List> randoms = new ArrayList<>(); + for (int i = 1; i < 4; i++) { + for (BitSet comb : new Combinations(3, i)) { + randoms.add( + f -> new StartsWithFunctionPipe( + f.source(), + f.expression(), + comb.get(0) ? randomValueOtherThan(f.input(), () -> pipe(randomStringLiteral())) : f.input(), + comb.get(1) ? randomValueOtherThan(f.pattern(), () -> pipe(randomStringLiteral())) : f.pattern(), + comb.get(2) ? randomValueOtherThan(f.isCaseSensitive(), ESTestCase::randomBoolean) : f.isCaseSensitive() + ) + ); + } + } + + return randomFrom(randoms).apply(instance); + } + + @Override + protected StartsWithFunctionPipe copy(StartsWithFunctionPipe instance) { + return new StartsWithFunctionPipe( + instance.source(), + instance.expression(), + instance.input(), + instance.pattern(), + instance.isCaseSensitive() + ); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithProcessorTests.java new file mode 100644 index 000000000000..23a52082b9b1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/function/scalar/string/StartsWithProcessorTests.java @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.function.scalar.string; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.LiteralTests; +import org.hamcrest.Matchers; + +import static org.elasticsearch.xpack.esql.core.expression.function.scalar.FunctionTestUtils.l; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; + +public class StartsWithProcessorTests extends ESTestCase { + + public void testSensitiveStartsWithFunctionWithValidInput() { + assertTrue(sensitiveStartsWith("foobarbar", "f")); + assertFalse(sensitiveStartsWith("foobar", "bar")); + assertFalse(sensitiveStartsWith("foo", "foobar")); + assertTrue(sensitiveStartsWith("foobar", "")); + assertTrue(sensitiveStartsWith("foo", "foo")); + assertTrue(sensitiveStartsWith("FOoBar", "FOo")); + assertFalse(sensitiveStartsWith("", "bar")); + assertNull(sensitiveStartsWith(null, "bar")); + assertNull(sensitiveStartsWith("foo", null)); + assertNull(sensitiveStartsWith(null, null)); + + assertFalse(sensitiveStartsWith("foo", "FO")); + assertFalse(sensitiveStartsWith("foo", "FOo")); + } + + private Boolean sensitiveStartsWith(String left, String right) { + return startsWith(false, left, right); + } + + public void testInsensitiveStartsWithFunctionWithValidInput() { + assertTrue(insensitiveStartsWith("foobarbar", "f")); + assertFalse(insensitiveStartsWith("foobar", "bar")); + assertFalse(insensitiveStartsWith("foo", "foobar")); + assertTrue(insensitiveStartsWith("foobar", "")); + assertTrue(insensitiveStartsWith("foo", "foo")); + assertTrue(insensitiveStartsWith("FOoBar", "FOo")); + assertFalse(insensitiveStartsWith("", "bar")); + assertNull(insensitiveStartsWith(null, "bar")); + assertNull(insensitiveStartsWith("foo", null)); + assertNull(insensitiveStartsWith(null, null)); + + assertTrue(insensitiveStartsWith("foo", "FO")); + assertTrue(insensitiveStartsWith("foo", "FOo")); + } + + private Boolean insensitiveStartsWith(String left, String right) { + return startsWith(true, left, right); + } + + private Boolean startsWith(boolean caseInsensitive, String left, String right) { + return (Boolean) new StartsWithFunctionPipeTests.StartsWithTest(EMPTY, l(left), l(right), caseInsensitive).makePipe() + .asProcessor() + .process(null); + } + + private Boolean untypedStartsWith(Object left, Object right) { + return (Boolean) new StartsWithFunctionPipeTests.StartsWithTest(EMPTY, l(left), l(right), randomBoolean()).makePipe() + .asProcessor() + .process(null); + } + + public void testStartsWithFunctionInputsValidation() { + QlIllegalArgumentException siae = expectThrows(QlIllegalArgumentException.class, () -> untypedStartsWith(5, "foo")); + assertEquals("A string/char is required; received [5]", siae.getMessage()); + siae = expectThrows(QlIllegalArgumentException.class, () -> untypedStartsWith("bar", false)); + assertEquals("A string/char is required; received [false]", siae.getMessage()); + } + + public void testStartsWithFunctionWithRandomInvalidDataType() { + Literal literal = randomValueOtherThanMany(v -> v.dataType() == KEYWORD, () -> LiteralTests.randomLiteral()); + QlIllegalArgumentException siae = expectThrows(QlIllegalArgumentException.class, () -> untypedStartsWith(literal, "foo")); + assertThat(siae.getMessage(), Matchers.startsWith("A string/char is required; received")); + siae = expectThrows(QlIllegalArgumentException.class, () -> untypedStartsWith("foo", literal)); + assertThat(siae.getMessage(), Matchers.startsWith("A string/char is required; received")); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AttributeInputTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AttributeInputTests.java new file mode 100644 index 000000000000..b101b26d7140 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/AttributeInputTests.java @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.execution.search.FieldExtraction; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; + +import static org.mockito.Mockito.mock; + +public class AttributeInputTests extends ESTestCase { + public void testResolveAttributes() { + FieldExtraction column = mock(FieldExtraction.class); + Expression expression = mock(Expression.class); + Attribute attribute = mock(Attribute.class); + + ReferenceInput expected = new ReferenceInput(expression.source(), expression, column); + + assertEquals(expected, new AttributeInput(expression.source(), expression, attribute).resolveAttributes(a -> { + assertSame(attribute, a); + return column; + })); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/BinaryPipesTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/BinaryPipesTests.java new file mode 100644 index 000000000000..a212245631d5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/BinaryPipesTests.java @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe.AttributeResolver; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; + +public class BinaryPipesTests extends ESTestCase { + public void testSupportedByAggsOnlyQuery() { + Pipe supported = new DummyPipe(true); + Pipe unsupported = new DummyPipe(false); + + assertFalse(new DummyBinaryPipe(unsupported, unsupported).supportedByAggsOnlyQuery()); + assertTrue(new DummyBinaryPipe(unsupported, supported).supportedByAggsOnlyQuery()); + assertTrue(new DummyBinaryPipe(supported, unsupported).supportedByAggsOnlyQuery()); + assertTrue(new DummyBinaryPipe(supported, supported).supportedByAggsOnlyQuery()); + } + + public void testResolveAttributes() { + Pipe needsNothing = new DummyPipe(randomBoolean()); + Pipe resolvesTo = new DummyPipe(randomBoolean()); + Pipe needsResolution = new DummyPipe(randomBoolean()) { + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return resolvesTo; + } + }; + AttributeResolver resolver = a -> { + fail("not exepected"); + return null; + }; + + Pipe d = new DummyBinaryPipe(needsNothing, needsNothing); + assertSame(d, d.resolveAttributes(resolver)); + + d = new DummyBinaryPipe(needsNothing, needsResolution); + Pipe expected = new DummyBinaryPipe(needsNothing, resolvesTo); + assertEquals(expected, d.resolveAttributes(resolver)); + + d = new DummyBinaryPipe(needsResolution, needsNothing); + expected = new DummyBinaryPipe(resolvesTo, needsNothing); + assertEquals(expected, d.resolveAttributes(resolver)); + } + + public void testCollectFields() { + DummyPipe wantsScore = new DummyPipe(randomBoolean()) { + @Override + public void collectFields(QlSourceBuilder sourceBuilder) { + sourceBuilder.trackScores(); + } + }; + DummyPipe wantsNothing = new DummyPipe(randomBoolean()); + assertFalse(tracksScores(new DummyBinaryPipe(wantsNothing, wantsNothing))); + assertTrue(tracksScores(new DummyBinaryPipe(wantsScore, wantsNothing))); + assertTrue(tracksScores(new DummyBinaryPipe(wantsNothing, wantsScore))); + } + + /** + * Returns {@code true} if the processor defintion builds a query that + * tracks scores, {@code false} otherwise. Used for testing + * {@link Pipe#collectFields(QlSourceBuilder)}. + */ + static boolean tracksScores(Pipe d) { + QlSourceBuilder b = new QlSourceBuilder(); + d.collectFields(b); + SearchSourceBuilder source = new SearchSourceBuilder(); + b.build(source); + return source.trackScores(); + } + + public static BinaryPipe randomBinaryPipe() { + return new DummyBinaryPipe(randomUnaryPipe(), randomUnaryPipe()); + } + + public static Pipe randomUnaryPipe() { + return new ConstantInput(Source.EMPTY, new Literal(Source.EMPTY, randomAlphaOfLength(16), KEYWORD), randomAlphaOfLength(16)); + } + + public static final class DummyBinaryPipe extends BinaryPipe { + public DummyBinaryPipe(Pipe left, Pipe right) { + this(Source.EMPTY, left, right); + } + + public DummyBinaryPipe(Source source, Pipe left, Pipe right) { + super(source, null, left, right); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, DummyBinaryPipe::new, left(), right()); + } + + @Override + public Processor asProcessor() { + return null; + } + + @Override + protected BinaryPipe replaceChildren(Pipe left, Pipe right) { + return new DummyBinaryPipe(source(), left, right); + } + } + + public static class DummyPipe extends Pipe { + private final boolean supportedByAggsOnlyQuery; + + public DummyPipe(boolean supportedByAggsOnlyQuery) { + this(Source.EMPTY, supportedByAggsOnlyQuery); + } + + public DummyPipe(Source source, boolean supportedByAggsOnlyQuery) { + super(source, null, emptyList()); + this.supportedByAggsOnlyQuery = supportedByAggsOnlyQuery; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, DummyPipe::new, supportedByAggsOnlyQuery); + } + + @Override + public Pipe replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children to replace"); + } + + @Override + public boolean supportedByAggsOnlyQuery() { + return supportedByAggsOnlyQuery; + } + + @Override + public boolean resolved() { + return true; + } + + @Override + public Processor asProcessor() { + return null; + } + + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return this; + } + + @Override + public void collectFields(QlSourceBuilder sourceBuilder) {} + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/UnaryPipeTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/UnaryPipeTests.java new file mode 100644 index 000000000000..81b1b497abf4 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/pipeline/UnaryPipeTests.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.pipeline; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.execution.search.QlSourceBuilder; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.BinaryPipesTests.DummyPipe; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe.AttributeResolver; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import static org.elasticsearch.xpack.esql.core.expression.gen.pipeline.BinaryPipesTests.tracksScores; + +public class UnaryPipeTests extends ESTestCase { + public void testSupportedByAggsOnlyQuery() { + Pipe supported = new DummyPipe(true); + Pipe unsupported = new DummyPipe(false); + + assertFalse(newUnaryProcessor(unsupported).supportedByAggsOnlyQuery()); + assertTrue(newUnaryProcessor(supported).supportedByAggsOnlyQuery()); + } + + public void testResolveAttributes() { + Pipe needsNothing = new DummyPipe(randomBoolean()); + Pipe resolvesTo = new DummyPipe(randomBoolean()); + Pipe needsResolution = new DummyPipe(randomBoolean()) { + @Override + public Pipe resolveAttributes(AttributeResolver resolver) { + return resolvesTo; + } + }; + AttributeResolver resolver = a -> { + fail("not exepected"); + return null; + }; + + Pipe d = newUnaryProcessor(needsNothing); + assertSame(d, d.resolveAttributes(resolver)); + + d = newUnaryProcessor(needsResolution); + Pipe expected = newUnaryProcessor(resolvesTo); + assertEquals(expected, d.resolveAttributes(resolver)); + } + + public void testCollectFields() { + DummyPipe wantsScore = new DummyPipe(randomBoolean()) { + @Override + public void collectFields(QlSourceBuilder sourceBuilder) { + sourceBuilder.trackScores(); + } + }; + DummyPipe wantsNothing = new DummyPipe(randomBoolean()); + assertFalse(tracksScores(newUnaryProcessor(wantsNothing))); + assertTrue(tracksScores(newUnaryProcessor(wantsScore))); + } + + private Pipe newUnaryProcessor(Pipe child) { + return new UnaryPipe(Source.EMPTY, null, child, null); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ChainingProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ChainingProcessorTests.java new file mode 100644 index 000000000000..50c5dcc228fd --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ChainingProcessorTests.java @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogicProcessorTests; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryArithmeticProcessorTests; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessorTests; +import org.elasticsearch.xpack.esql.core.expression.processor.Processors; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class ChainingProcessorTests extends AbstractWireSerializingTestCase { + public static ChainingProcessor randomComposeProcessor() { + return new ChainingProcessor(randomProcessor(), randomProcessor()); + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(Processors.getNamedWriteables()); + } + + @Override + protected ChainingProcessor createTestInstance() { + return randomComposeProcessor(); + } + + @Override + protected Reader instanceReader() { + return ChainingProcessor::new; + } + + @Override + protected ChainingProcessor mutateInstance(ChainingProcessor instance) { + @SuppressWarnings("unchecked") + Supplier supplier = randomFrom( + () -> new ChainingProcessor(instance.first(), randomValueOtherThan(instance.second(), () -> randomProcessor())), + () -> new ChainingProcessor(randomValueOtherThan(instance.first(), () -> randomProcessor()), instance.second()) + ); + return supplier.get(); + } + + public static Processor randomProcessor() { + List> options = new ArrayList<>(); + options.add(ChainingProcessorTests::randomComposeProcessor); + options.add(BinaryLogicProcessorTests::randomProcessor); + options.add(BinaryArithmeticProcessorTests::randomProcessor); + options.add(BinaryComparisonProcessorTests::randomProcessor); + return randomFrom(options).get(); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantProcessorTests.java new file mode 100644 index 000000000000..00ca460920d0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/processor/ConstantProcessorTests.java @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.processor; + +import org.elasticsearch.common.io.stream.ByteArrayStreamInput; +import org.elasticsearch.common.io.stream.OutputStreamStreamOutput; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.versionfield.Version; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.Clock; +import java.time.Duration; +import java.time.ZonedDateTime; + +public class ConstantProcessorTests extends AbstractWireSerializingTestCase { + + public static ConstantProcessor randomConstantProcessor() { + if (randomBoolean()) { + Clock clock = Clock.tickMillis(randomZone()); + if (randomBoolean()) { + clock = Clock.tick(clock, Duration.ofNanos(1)); + } + return new ConstantProcessor(ZonedDateTime.now(clock)); + } else { + return new ConstantProcessor(randomAlphaOfLength(5)); + } + } + + @Override + protected ConstantProcessor createTestInstance() { + return randomConstantProcessor(); + } + + @Override + protected Reader instanceReader() { + return ConstantProcessor::new; + } + + @Override + protected ConstantProcessor mutateInstance(ConstantProcessor instance) { + return new ConstantProcessor(randomValueOtherThan(instance.process(null), () -> randomLong())); + } + + public void testApply() { + ConstantProcessor proc = new ConstantProcessor("test"); + assertEquals("test", proc.process(null)); + assertEquals("test", proc.process("cat")); + } + + public void testReadWriteVersion() throws IOException { + ConstantProcessor original = new ConstantProcessor(new Version("1.2.3")); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); StreamOutput out = new OutputStreamStreamOutput(baos)) { + original.writeTo(out); + try (StreamInput is = new ByteArrayStreamInput(baos.toByteArray())) { + ConstantProcessor result = new ConstantProcessor(is); + assertEquals(Version.class, result.process(null).getClass()); + assertEquals("1.2.3", result.process(null).toString()); + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ScriptsTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ScriptsTests.java new file mode 100644 index 000000000000..2892fedec90a --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/gen/script/ScriptsTests.java @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.gen.script; + +import org.elasticsearch.test.ESTestCase; + +import java.util.regex.Pattern; + +public class ScriptsTests extends ESTestCase { + + public void testSplitWithMatches() { + String input = "A1B2C3"; + Pattern pattern = Pattern.compile("[0-9]+"); + + assertArrayEquals(new String[] { "A", "1", "B", "2", "C", "3" }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesNoMatches() { + String input = "AxBxCx"; + Pattern pattern = Pattern.compile("[0-9]+"); + + assertArrayEquals(new String[] { input }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesOneMatch() { + String input = "ABC"; + Pattern pattern = Pattern.compile("ABC"); + + assertArrayEquals(new String[] { input }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesSameMatch() { + String input = "xxxx"; + Pattern pattern = Pattern.compile("x"); + + assertArrayEquals(new String[] { "x", "x", "x", "x" }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesTwoPatterns() { + String input = "xyxy"; + Pattern pattern = Pattern.compile("x|y"); + + assertArrayEquals(new String[] { "x", "y", "x", "y" }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesTwoPatterns2() { + String input = "A1B2C3"; + Pattern pattern = Pattern.compile("[0-9]{1}|[A-F]{1}"); + + assertArrayEquals(new String[] { "A", "1", "B", "2", "C", "3" }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesTwoPatterns3() { + String input = "A111BBB2C3"; + Pattern pattern = Pattern.compile("[0-9]+|[A-F]+"); + + assertArrayEquals(new String[] { "A", "111", "BBB", "2", "C", "3" }, Scripts.splitWithMatches(input, pattern)); + } + + public void testSplitWithMatchesTwoPatterns4() { + String input = "xA111BxBB2C3x"; + Pattern pattern = Pattern.compile("[0-9]+|[A-F]+"); + + assertArrayEquals(new String[] { "x", "A", "111", "B", "x", "BB", "2", "C", "3", "x" }, Scripts.splitWithMatches(input, pattern)); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/RangeTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/RangeTests.java new file mode 100644 index 000000000000..f7e650b7727b --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/RangeTests.java @@ -0,0 +1,230 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DateUtils; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; + +import static org.elasticsearch.xpack.esql.core.expression.function.scalar.FunctionTestUtils.l; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SHORT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; + +public class RangeTests extends ESTestCase { + + public void testAreBoundariesInvalid() { + // value, value type, lower, lower type, lower included, higher, higher type, higher included, boundaries invalid + Object[][] tests = { + // dates + { + d("2021-01-01"), + DATETIME, + "2021-01-01", + randomTextType(), + randomBoolean(), + "2022-01-01", + randomTextType(), + randomBoolean(), + false }, + { + d("2021-01-01"), + DATETIME, + "2022-01-01", + randomTextType(), + randomBoolean(), + "2021-01-01", + randomTextType(), + randomBoolean(), + true }, + { + d("2021-01-01"), + DATETIME, + "now-10y", + randomTextType(), + randomBoolean(), + "2022-01-01", + randomTextType(), + randomBoolean(), + false }, + { + d("2021-01-01"), + DATETIME, + "2021-01-01", + randomTextType(), + randomBoolean(), + "now+10y", + randomTextType(), + randomBoolean(), + false }, + { + d("2021-01-01"), + DATETIME, + "2021-01-01", + randomTextType(), + randomBoolean(), + "now-100y", + randomTextType(), + randomBoolean(), + false }, + { d("2021-01-01"), DATETIME, "2021-01-01", randomTextType(), true, "2021-01-01", randomTextType(), true, false }, + { d("2021-01-01"), DATETIME, "2021-01-01", randomTextType(), false, "2021-01-01", randomTextType(), true, true }, + { d("2021-01-01"), DATETIME, "2021-01-01", randomTextType(), true, "2021-01-01", randomTextType(), false, true }, + { d("2021-01-01"), DATETIME, "2021-01-01", randomTextType(), false, "2021-01-01", randomTextType(), false, true }, + { + d("2021-01-01"), + DATETIME, + d("2022-01-01"), + DATETIME, + randomBoolean(), + "2021-01-01", + randomTextType(), + randomBoolean(), + true }, + { d("2021-01-01"), DATETIME, d("2021-01-01"), DATETIME, false, "2021-01-01", randomTextType(), false, true }, + { d("2021-01-01"), DATETIME, d("2021-01-01"), DATETIME, false, d("2021-01-01"), DATETIME, false, true }, + { d("2021-01-01"), DATETIME, d("2021-01-01"), DATETIME, true, "2021-01-01", randomTextType(), true, false }, + { d("2021-01-01"), DATETIME, d("2021-01-01"), DATETIME, true, d("2021-01-01"), DATETIME, true, false }, + { + randomAlphaOfLength(10), + randomTextType(), + d("2021-01-01"), + DATETIME, + randomBoolean(), + "2022-01-01", + randomTextType(), + randomBoolean(), + false }, + { + randomAlphaOfLength(10), + randomTextType(), + "2021-01-01", + randomTextType(), + randomBoolean(), + d("2022-01-01"), + DATETIME, + randomBoolean(), + false }, + { + randomAlphaOfLength(10), + randomTextType(), + d("2022-01-01"), + DATETIME, + randomBoolean(), + "2021-01-01", + randomTextType(), + randomBoolean(), + true }, + { + randomAlphaOfLength(10), + randomTextType(), + "2022-01-01", + randomTextType(), + randomBoolean(), + d("2021-01-01"), + DATETIME, + randomBoolean(), + true }, + { + randomAlphaOfLength(10), + randomTextType(), + d("2022-01-01"), + DATETIME, + randomBoolean(), + d("2021-01-01"), + DATETIME, + randomBoolean(), + true }, + { + randomAlphaOfLength(10), + randomTextType(), + "now-10y", + randomTextType(), + randomBoolean(), + d("2022-01-01"), + DATETIME, + randomBoolean(), + false }, + { randomAlphaOfLength(10), randomTextType(), d("2021-01-01"), DATETIME, true, "2021-01-01", randomTextType(), true, false }, + { randomAlphaOfLength(10), randomTextType(), d("2021-01-01"), DATETIME, false, "2021-01-01", randomTextType(), true, true }, + { randomAlphaOfLength(10), randomTextType(), "2021-01-01", randomTextType(), true, d("2021-01-01"), DATETIME, false, true }, + { randomAlphaOfLength(10), randomTextType(), d("2021-01-01"), DATETIME, false, d("2021-01-01"), DATETIME, false, true }, + + // strings + { + randomAlphaOfLength(10), + randomTextType(), + "a", + randomTextType(), + randomBoolean(), + "b", + randomTextType(), + randomBoolean(), + false }, + { + randomAlphaOfLength(10), + randomTextType(), + "b", + randomTextType(), + randomBoolean(), + "a", + randomTextType(), + randomBoolean(), + true }, + { randomAlphaOfLength(10), randomTextType(), "a", randomTextType(), false, "a", randomTextType(), false, true }, + + // numbers + { 10, randomNumericType(), 1, randomNumericType(), randomBoolean(), 10, randomNumericType(), randomBoolean(), false }, + { 10, randomNumericType(), 10, randomNumericType(), randomBoolean(), 1, randomNumericType(), randomBoolean(), true }, + { 10, randomNumericType(), 1, randomNumericType(), false, 1, randomNumericType(), randomBoolean(), true }, + { 10, randomNumericType(), 1, randomNumericType(), randomBoolean(), 1, randomNumericType(), false, true }, + { 10, randomNumericType(), 1.0, randomNumericType(), randomBoolean(), 10, randomNumericType(), randomBoolean(), false }, + { 10, randomNumericType(), 1, randomNumericType(), randomBoolean(), 10.D, randomNumericType(), randomBoolean(), false }, + { 10, randomNumericType(), 10.0, randomNumericType(), randomBoolean(), 1, randomNumericType(), randomBoolean(), true }, + + }; + + for (int i = 0; i < tests.length; i++) { + Object[] test = tests[i]; + Range range = new Range( + Source.EMPTY, + l(test[0], (DataType) test[1]), + l(test[2], (DataType) test[3]), + (Boolean) test[4], + l(test[5], (DataType) test[6]), + (Boolean) test[7], + ZoneId.systemDefault() + ); + assertEquals("failed on test " + i + ": " + Arrays.toString(test), test[8], range.areBoundariesInvalid()); + } + } + + private static ZonedDateTime d(String date) { + return DateUtils.asDateTime(date); + } + + private static DataType randomNumericType() { + return randomFrom(INTEGER, SHORT, LONG, UNSIGNED_LONG, FLOAT, DOUBLE); + } + + private static DataType randomTextType() { + return randomFrom(KEYWORD, TEXT); + } + +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextUtilsTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextUtilsTests.java new file mode 100644 index 000000000000..c6358b4682a7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/fulltext/FullTextUtilsTests.java @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.fulltext; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.tree.Source; + +import java.util.Map; + +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.is; + +public class FullTextUtilsTests extends ESTestCase { + + private final Source source = new Source(1, 1, ""); + + public void testColonDelimited() { + Map options = FullTextUtils.parseSettings("k1=v1;k2=v2", source); + assertThat(options.size(), is(2)); + assertThat(options, hasEntry("k1", "v1")); + assertThat(options, hasEntry("k2", "v2")); + } + + public void testColonDelimitedErrorString() { + ParsingException e = expectThrows(ParsingException.class, () -> FullTextUtils.parseSettings("k1=v1;k2v2", source)); + assertThat(e.getMessage(), is("line 1:3: Cannot parse entry k2v2 in options k1=v1;k2v2")); + assertThat(e.getLineNumber(), is(1)); + assertThat(e.getColumnNumber(), is(3)); + } + + public void testColonDelimitedErrorDuplicate() { + ParsingException e = expectThrows(ParsingException.class, () -> FullTextUtils.parseSettings("k1=v1;k1=v2", source)); + assertThat(e.getMessage(), is("line 1:3: Duplicate option k1=v2 detected in options k1=v1;k1=v2")); + assertThat(e.getLineNumber(), is(1)); + assertThat(e.getColumnNumber(), is(3)); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicProcessorTests.java new file mode 100644 index 000000000000..83a9ca0a8ee3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/logical/BinaryLogicProcessorTests.java @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.logical; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.processor.Processors; + +public class BinaryLogicProcessorTests extends AbstractWireSerializingTestCase { + + private static final Processor FALSE = new ConstantProcessor(false); + private static final Processor TRUE = new ConstantProcessor(true); + private static final Processor NULL = new ConstantProcessor((Object) null); + + public static BinaryLogicProcessor randomProcessor() { + return new BinaryLogicProcessor( + new ConstantProcessor(randomFrom(Boolean.FALSE, Boolean.TRUE, null)), + new ConstantProcessor(randomFrom(Boolean.FALSE, Boolean.TRUE, null)), + randomFrom(BinaryLogicProcessor.BinaryLogicOperation.values()) + ); + } + + @Override + protected BinaryLogicProcessor createTestInstance() { + return randomProcessor(); + } + + @Override + protected BinaryLogicProcessor mutateInstance(BinaryLogicProcessor instance) { + return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 + } + + @Override + protected Reader instanceReader() { + return BinaryLogicProcessor::new; + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(Processors.getNamedWriteables()); + } + + public void testOR() { + assertEquals(true, new BinaryLogicProcessor(TRUE, FALSE, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertEquals(true, new BinaryLogicProcessor(FALSE, TRUE, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertEquals(false, new BinaryLogicProcessor(FALSE, FALSE, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertEquals(true, new BinaryLogicProcessor(TRUE, TRUE, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + } + + public void testORNullHandling() { + assertEquals(true, new BinaryLogicProcessor(TRUE, NULL, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertEquals(true, new BinaryLogicProcessor(NULL, TRUE, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertNull(new BinaryLogicProcessor(FALSE, NULL, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertNull(new BinaryLogicProcessor(NULL, FALSE, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + assertNull(new BinaryLogicProcessor(NULL, NULL, BinaryLogicProcessor.BinaryLogicOperation.OR).process(null)); + } + + public void testAnd() { + assertEquals(false, new BinaryLogicProcessor(TRUE, FALSE, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertEquals(false, new BinaryLogicProcessor(FALSE, TRUE, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertEquals(false, new BinaryLogicProcessor(FALSE, FALSE, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertEquals(true, new BinaryLogicProcessor(TRUE, TRUE, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + } + + public void testAndNullHandling() { + assertNull(new BinaryLogicProcessor(TRUE, NULL, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertNull(new BinaryLogicProcessor(NULL, TRUE, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertEquals(false, new BinaryLogicProcessor(FALSE, NULL, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertEquals(false, new BinaryLogicProcessor(NULL, FALSE, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + assertNull(new BinaryLogicProcessor(NULL, NULL, BinaryLogicProcessor.BinaryLogicOperation.AND).process(null)); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/CheckNullProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/CheckNullProcessorTests.java new file mode 100644 index 000000000000..69104c7601f6 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/nulls/CheckNullProcessorTests.java @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.nulls; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.processor.Processors; + +public class CheckNullProcessorTests extends AbstractWireSerializingTestCase { + + private static final Processor FALSE = new ConstantProcessor(false); + private static final Processor TRUE = new ConstantProcessor(true); + private static final Processor NULL = new ConstantProcessor((Object) null); + + public static CheckNullProcessor randomProcessor() { + return new CheckNullProcessor(randomFrom(CheckNullProcessor.CheckNullOperation.values())); + } + + @Override + protected CheckNullProcessor createTestInstance() { + return randomProcessor(); + } + + @Override + protected CheckNullProcessor mutateInstance(CheckNullProcessor instance) { + return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 + } + + @Override + protected Reader instanceReader() { + return CheckNullProcessor::new; + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(Processors.getNamedWriteables()); + } + + public void testIsNull() { + assertEquals(true, new CheckNullProcessor(CheckNullProcessor.CheckNullOperation.IS_NULL).process(null)); + assertEquals(false, new CheckNullProcessor(CheckNullProcessor.CheckNullOperation.IS_NULL).process("foo")); + assertEquals(false, new CheckNullProcessor(CheckNullProcessor.CheckNullOperation.IS_NULL).process(1)); + } + + public void testIsNotNull() { + assertEquals(false, new CheckNullProcessor(CheckNullProcessor.CheckNullOperation.IS_NOT_NULL).process(null)); + assertEquals(true, new CheckNullProcessor(CheckNullProcessor.CheckNullOperation.IS_NOT_NULL).process("foo")); + assertEquals(true, new CheckNullProcessor(CheckNullProcessor.CheckNullOperation.IS_NOT_NULL).process(1)); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticProcessorTests.java new file mode 100644 index 000000000000..759acc29a5e5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/arithmetic/BinaryArithmeticProcessorTests.java @@ -0,0 +1,196 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.processor.Processors; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; + +import java.math.BigInteger; + +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class BinaryArithmeticProcessorTests extends AbstractWireSerializingTestCase { + public static BinaryArithmeticProcessor randomProcessor() { + return new BinaryArithmeticProcessor( + new ConstantProcessor(randomLong()), + new ConstantProcessor(randomLong()), + randomFrom(DefaultBinaryArithmeticOperation.values()) + ); + } + + @Override + protected BinaryArithmeticProcessor createTestInstance() { + return randomProcessor(); + } + + @Override + protected BinaryArithmeticProcessor mutateInstance(BinaryArithmeticProcessor instance) { + return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 + } + + @Override + protected Reader instanceReader() { + return BinaryArithmeticProcessor::new; + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(Processors.getNamedWriteables()); + } + + public void testAdd() { + Processor ba = new Add(EMPTY, l(7), l(3)).makePipe().asProcessor(); + assertEquals(10, ba.process(null)); + } + + public void testAddUnsignedLong() { + Processor ba = new Add(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(10), ba.process(null)); + + ba = new Add(EMPTY, l(BigInteger.ONE), l(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE))).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.TWO), ba.process(null)); + + ba = new Add(EMPTY, l(BigInteger.valueOf(7)), l((short) -3)).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(4), ba.process(null)); + + ba = new Add(EMPTY, l(BigInteger.valueOf(7)), l(-3f)).makePipe().asProcessor(); + assertEquals(4f, ba.process(null)); + + Processor pn = new Add(EMPTY, l(BigInteger.valueOf(7)), l(-8)).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> pn.process(null)); + + Processor pm = new Add(EMPTY, l(NumericUtils.UNSIGNED_LONG_MAX), l(1)).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> pm.process(null)); + } + + public void testSub() { + Processor ba = new Sub(EMPTY, l(7), l(3)).makePipe().asProcessor(); + assertEquals(4, ba.process(null)); + } + + public void testSubUnsignedLong() { + Processor bs = new Sub(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(4), bs.process(null)); + + bs = new Sub(EMPTY, l(BigInteger.valueOf(7)), l((short) -3)).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(10), bs.process(null)); + + bs = new Sub(EMPTY, l(BigInteger.valueOf(7)), l(3f)).makePipe().asProcessor(); + assertEquals(4f, bs.process(null)); + + Processor proc = new Sub(EMPTY, l(BigInteger.valueOf(7)), l(8)).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> proc.process(null)); + } + + public void testMul() { + Processor ba = new Mul(EMPTY, l(7), l(3)).makePipe().asProcessor(); + assertEquals(21, ba.process(null)); + } + + public void testMulUnsignedLong() { + Processor bm = new Mul(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(21), bm.process(null)); + + bm = new Mul(EMPTY, l(BigInteger.valueOf(7)), l(3f)).makePipe().asProcessor(); + assertEquals(21f, bm.process(null)); + + Processor proc = new Mul(EMPTY, l(BigInteger.valueOf(7)), l(-8)).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> proc.process(null)); + } + + public void testDiv() { + Processor ba = new Div(EMPTY, l(7), l(3)).makePipe().asProcessor(); + assertEquals(2, ((Number) ba.process(null)).longValue()); + ba = new Div(EMPTY, l((double) 7), l(3)).makePipe().asProcessor(); + assertEquals(2.33, ((Number) ba.process(null)).doubleValue(), 0.01d); + } + + public void testDivUnsignedLong() { + Processor bd = new Div(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor(); + assertEquals(BigInteger.TWO, bd.process(null)); + + bd = new Div(EMPTY, l(7), l(BigInteger.valueOf(8))).makePipe().asProcessor(); + assertEquals(BigInteger.ZERO, bd.process(null)); + + bd = new Div(EMPTY, l(BigInteger.valueOf(7)), l(3f)).makePipe().asProcessor(); + assertEquals(7 / 3f, bd.process(null)); + + Processor proc = new Div(EMPTY, l(BigInteger.valueOf(7)), l(-2)).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> proc.process(null)); + } + + public void testMod() { + Processor ba = new Mod(EMPTY, l(7), l(3)).makePipe().asProcessor(); + assertEquals(1, ba.process(null)); + } + + public void testModUnsignedLong() { + Processor bm = new Mod(EMPTY, l(BigInteger.valueOf(7)), l(3)).makePipe().asProcessor(); + assertEquals(BigInteger.valueOf(1), bm.process(null)); + + Processor proc = new Mod(EMPTY, l(-7), l(BigInteger.valueOf(3))).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> proc.process(null)); + } + + public void testNegate() { + Processor ba = new Neg(EMPTY, l(7)).asPipe().asProcessor(); + assertEquals(-7, ba.process(null)); + } + + public void testNegateUnsignedLong() { + Processor nm = new Neg(EMPTY, l(BigInteger.valueOf(0))).makePipe().asProcessor(); + assertEquals(BigInteger.ZERO, nm.process(null)); + + Processor proc = new Neg(EMPTY, l(BigInteger.valueOf(3))).makePipe().asProcessor(); + expectThrows(ArithmeticException.class, () -> proc.process(null)); + } + + // ((3*2+4)/2-2)%2 + public void testTree() { + Expression mul = new Mul(EMPTY, l(3), l(2)); + Expression add = new Add(EMPTY, mul, l(4)); + Expression div = new Div(EMPTY, add, l(2)); + Expression sub = new Sub(EMPTY, div, l(2)); + Mod mod = new Mod(EMPTY, sub, l(2)); + + Processor proc = mod.makePipe().asProcessor(); + assertEquals(1, proc.process(null)); + } + + // ((3*2+4)/2-2)%2 + public void testTreeUnsignedLong() { + Expression mul = new Mul(EMPTY, l(3), l(BigInteger.TWO)); + Expression add = new Add(EMPTY, mul, l(4)); + Expression div = new Div(EMPTY, add, l(2)); + Expression sub = new Sub(EMPTY, div, l(2)); + Mod mod = new Mod(EMPTY, sub, l(2)); + + Processor proc = mod.makePipe().asProcessor(); + assertEquals(BigInteger.ONE, proc.process(null)); + } + + public void testHandleNull() { + assertNull(new Add(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); + assertNull(new Sub(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); + assertNull(new Mul(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); + assertNull(new Div(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); + assertNull(new Mod(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); + assertNull(new Neg(EMPTY, l(null)).makePipe().asProcessor().process(null)); + } + + private static Literal l(Object value) { + return TestUtils.of(EMPTY, value); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java new file mode 100644 index 000000000000..22b2702a0ca3 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.processor.Processors; + +import java.math.BigInteger; + +import static org.elasticsearch.xpack.esql.core.TestUtils.equalsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.greaterThanOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.greaterThanOrEqualOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.lessThanOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.lessThanOrEqualOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.notEqualsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.nullEqualsOf; +import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class BinaryComparisonProcessorTests extends AbstractWireSerializingTestCase { + public static BinaryComparisonProcessor randomProcessor() { + return new BinaryComparisonProcessor( + new ConstantProcessor(randomLong()), + new ConstantProcessor(randomLong()), + randomFrom(BinaryComparisonProcessor.BinaryComparisonOperation.values()) + ); + } + + @Override + protected BinaryComparisonProcessor createTestInstance() { + return randomProcessor(); + } + + @Override + protected BinaryComparisonProcessor mutateInstance(BinaryComparisonProcessor instance) { + return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 + } + + @Override + protected Reader instanceReader() { + return BinaryComparisonProcessor::new; + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(Processors.getNamedWriteables()); + } + + public void testEq() { + assertEquals(true, equalsOf(l(4), l(4)).makePipe().asProcessor().process(null)); + assertEquals(false, equalsOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, equalsOf(l(BigInteger.valueOf(4)), l(4L)).makePipe().asProcessor().process(null)); + assertEquals(false, equalsOf(l(BigInteger.valueOf(3)), l(4L)).makePipe().asProcessor().process(null)); + } + + public void testNullEq() { + assertEquals(true, nullEqualsOf(l(4), l(4)).makePipe().asProcessor().process(null)); + assertEquals(false, nullEqualsOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, nullEqualsOf(NULL, NULL).makePipe().asProcessor().process(null)); + assertEquals(false, nullEqualsOf(l(4), NULL).makePipe().asProcessor().process(null)); + assertEquals(false, nullEqualsOf(NULL, l(4)).makePipe().asProcessor().process(null)); + } + + public void testNEq() { + assertEquals(false, notEqualsOf(l(4), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, notEqualsOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, notEqualsOf(l(BigInteger.valueOf(3)), l(4)).makePipe().asProcessor().process(null)); + } + + public void testGt() { + assertEquals(true, greaterThanOf(l(4), l(3)).makePipe().asProcessor().process(null)); + assertEquals(false, greaterThanOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(false, greaterThanOf(l(3), l(3)).makePipe().asProcessor().process(null)); + assertEquals(true, greaterThanOf(l(4), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null)); + } + + public void testGte() { + assertEquals(true, greaterThanOrEqualOf(l(4), l(3)).makePipe().asProcessor().process(null)); + assertEquals(false, greaterThanOrEqualOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, greaterThanOrEqualOf(l(3), l(3)).makePipe().asProcessor().process(null)); + assertEquals(true, greaterThanOrEqualOf(l(BigInteger.valueOf(3)), l(3L)).makePipe().asProcessor().process(null)); + assertEquals(true, greaterThanOrEqualOf(l(BigInteger.valueOf(4)), l(3L)).makePipe().asProcessor().process(null)); + assertEquals(false, greaterThanOrEqualOf(l(BigInteger.valueOf(3)), l(4L)).makePipe().asProcessor().process(null)); + } + + public void testLt() { + assertEquals(false, lessThanOf(l(4), l(3)).makePipe().asProcessor().process(null)); + assertEquals(true, lessThanOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(false, lessThanOf(l(3), l(3)).makePipe().asProcessor().process(null)); + assertEquals(false, lessThanOf(l(3), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null)); + } + + public void testLte() { + assertEquals(false, lessThanOrEqualOf(l(4), l(3)).makePipe().asProcessor().process(null)); + assertEquals(true, lessThanOrEqualOf(l(3), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, lessThanOrEqualOf(l(3), l(3)).makePipe().asProcessor().process(null)); + assertEquals(false, lessThanOrEqualOf(l(4), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null)); + assertEquals(true, lessThanOrEqualOf(l(3), l(BigInteger.valueOf(4))).makePipe().asProcessor().process(null)); + assertEquals(true, lessThanOrEqualOf(l(3), l(BigInteger.valueOf(3))).makePipe().asProcessor().process(null)); + } + + public void testHandleNull() { + assertNull(equalsOf(NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(notEqualsOf(NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(greaterThanOf(NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(greaterThanOrEqualOf(NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(lessThanOf(NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(lessThanOrEqualOf(NULL, l(3)).makePipe().asProcessor().process(null)); + } + + private static Literal l(Object value) { + return TestUtils.of(EMPTY, value); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InProcessorTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InProcessorTests.java new file mode 100644 index 000000000000..fa8563b914e1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InProcessorTests.java @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.processor.Processors; + +import java.util.Arrays; + +import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class InProcessorTests extends AbstractWireSerializingTestCase { + + private static final Literal ONE = L(1); + private static final Literal TWO = L(2); + private static final Literal THREE = L(3); + + public static InProcessor randomProcessor() { + return new InProcessor(Arrays.asList(new ConstantProcessor(randomLong()), new ConstantProcessor(randomLong()))); + } + + @Override + protected InProcessor createTestInstance() { + return randomProcessor(); + } + + @Override + protected InProcessor mutateInstance(InProcessor instance) { + return null;// TODO implement https://github.com/elastic/elasticsearch/issues/25929 + } + + @Override + protected Reader instanceReader() { + return InProcessor::new; + } + + @Override + protected NamedWriteableRegistry getNamedWriteableRegistry() { + return new NamedWriteableRegistry(Processors.getNamedWriteables()); + } + + public void testEq() { + assertEquals(true, new In(EMPTY, TWO, Arrays.asList(ONE, TWO, THREE)).makePipe().asProcessor().process(null)); + assertEquals(false, new In(EMPTY, THREE, Arrays.asList(ONE, TWO)).makePipe().asProcessor().process(null)); + } + + public void testHandleNullOnLeftValue() { + assertNull(new In(EMPTY, NULL, Arrays.asList(ONE, TWO, THREE)).makePipe().asProcessor().process(null)); + assertNull(new In(EMPTY, NULL, Arrays.asList(ONE, NULL, TWO)).makePipe().asProcessor().process(null)); + } + + public void testHandleNullOnRightValue() { + assertEquals(true, new In(EMPTY, THREE, Arrays.asList(ONE, NULL, THREE)).makePipe().asProcessor().process(null)); + assertNull(new In(EMPTY, TWO, Arrays.asList(ONE, NULL, THREE)).makePipe().asProcessor().process(null)); + } + + private static Literal L(Object value) { + return TestUtils.of(EMPTY, value); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InTests.java new file mode 100644 index 000000000000..a6abe4e923c1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/operator/comparison/InTests.java @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Literal; + +import java.util.Arrays; + +import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; + +public class InTests extends ESTestCase { + + private static final Literal ONE = L(1); + private static final Literal TWO = L(2); + private static final Literal THREE = L(3); + + public void testInWithContainedValue() { + In in = new In(EMPTY, TWO, Arrays.asList(ONE, TWO, THREE)); + assertTrue(in.fold()); + } + + public void testInWithNotContainedValue() { + In in = new In(EMPTY, THREE, Arrays.asList(ONE, TWO)); + assertFalse(in.fold()); + } + + public void testHandleNullOnLeftValue() { + In in = new In(EMPTY, NULL, Arrays.asList(ONE, TWO, THREE)); + assertNull(in.fold()); + in = new In(EMPTY, NULL, Arrays.asList(ONE, NULL, THREE)); + assertNull(in.fold()); + + } + + public void testHandleNullsOnRightValue() { + In in = new In(EMPTY, THREE, Arrays.asList(ONE, NULL, THREE)); + assertTrue(in.fold()); + in = new In(EMPTY, ONE, Arrays.asList(TWO, NULL, THREE)); + assertNull(in.fold()); + } + + private static Literal L(Object value) { + return TestUtils.of(EMPTY, value); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/StringPatternTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/StringPatternTests.java new file mode 100644 index 000000000000..43cae475cff7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/expression/predicate/regex/StringPatternTests.java @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.expression.predicate.regex; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +public class StringPatternTests extends ESTestCase { + + private LikePattern like(String pattern, char escape) { + return new LikePattern(pattern, escape); + } + + private RLikePattern rlike(String pattern) { + return new RLikePattern(pattern); + } + + private boolean matchesAll(String pattern, char escape) { + return like(pattern, escape).matchesAll(); + } + + private boolean exactMatch(String pattern, char escape) { + String escaped = pattern.replace(Character.toString(escape), StringUtils.EMPTY); + return escaped.equals(like(pattern, escape).exactMatch()); + } + + private boolean matchesAll(String pattern) { + return rlike(pattern).matchesAll(); + } + + private boolean exactMatch(String pattern) { + return pattern.equals(rlike(pattern).exactMatch()); + } + + public void testWildcardMatchAll() throws Exception { + assertTrue(matchesAll("%", '0')); + assertTrue(matchesAll("%%", '0')); + + assertFalse(matchesAll("a%", '0')); + assertFalse(matchesAll("%_", '0')); + assertFalse(matchesAll("%_%_%", '0')); + assertFalse(matchesAll("_%", '0')); + assertFalse(matchesAll("0%", '0')); + } + + public void testRegexMatchAll() throws Exception { + assertTrue(matchesAll(".*")); + assertTrue(matchesAll(".*.*")); + assertTrue(matchesAll(".*.?")); + assertTrue(matchesAll(".?.*")); + assertTrue(matchesAll(".*.?.*")); + + assertFalse(matchesAll("..*")); + assertFalse(matchesAll("ab.")); + assertFalse(matchesAll("..?")); + } + + public void testWildcardExactMatch() throws Exception { + assertTrue(exactMatch("0%", '0')); + assertTrue(exactMatch("0_", '0')); + assertTrue(exactMatch("123", '0')); + assertTrue(exactMatch("1230_", '0')); + assertTrue(exactMatch("1230_321", '0')); + + assertFalse(exactMatch("%", '0')); + assertFalse(exactMatch("%%", '0')); + assertFalse(exactMatch("a%", '0')); + assertFalse(exactMatch("a_", '0')); + } + + public void testRegexExactMatch() throws Exception { + assertFalse(exactMatch(".*")); + assertFalse(exactMatch(".*.*")); + assertFalse(exactMatch(".*.?")); + assertFalse(exactMatch(".?.*")); + assertFalse(exactMatch(".*.?.*")); + assertFalse(exactMatch("..*")); + assertFalse(exactMatch("ab.")); + assertFalse(exactMatch("..?")); + + assertTrue(exactMatch("abc")); + assertTrue(exactMatch("12345")); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/optimizer/OptimizerRulesTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/optimizer/OptimizerRulesTests.java new file mode 100644 index 000000000000..0b00a0408a34 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/optimizer/OptimizerRulesTests.java @@ -0,0 +1,1861 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.optimizer; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.Count; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.string.StartsWith; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.Range; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Add; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Div; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mod; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Mul; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Sub; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.In; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NotEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.Like; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.LikePattern; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.BinaryComparisonSimplification; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.BooleanFunctionEqualsElimination; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.BooleanSimplification; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.CombineBinaryComparisons; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.ConstantFolding; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.FoldNull; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.LiteralsOnTheRight; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.PropagateEquals; +import org.elasticsearch.xpack.esql.core.plan.logical.Aggregate; +import org.elasticsearch.xpack.esql.core.plan.logical.EsRelation; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.Project; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.time.ZoneId; +import java.util.Collections; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.TestUtils.equalsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.fieldAttribute; +import static org.elasticsearch.xpack.esql.core.TestUtils.greaterThanOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.greaterThanOrEqualOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.lessThanOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.lessThanOrEqualOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.notEqualsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.nullEqualsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.of; +import static org.elasticsearch.xpack.esql.core.TestUtils.rangeOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.relation; +import static org.elasticsearch.xpack.esql.core.expression.Literal.FALSE; +import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL; +import static org.elasticsearch.xpack.esql.core.expression.Literal.TRUE; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.CombineDisjunctionsToIn; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.PropagateNullable; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.PushDownAndCombineFilters; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.ReplaceRegexMatch; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.hamcrest.Matchers.contains; + +public class OptimizerRulesTests extends ESTestCase { + + private static final Expression DUMMY_EXPRESSION = new DummyBooleanExpression(EMPTY, 0); + + private static final Literal ONE = L(1); + private static final Literal TWO = L(2); + private static final Literal THREE = L(3); + private static final Literal FOUR = L(4); + private static final Literal FIVE = L(5); + private static final Literal SIX = L(6); + + public static class DummyBooleanExpression extends Expression { + + private final int id; + + public DummyBooleanExpression(Source source, int id) { + super(source, Collections.emptyList()); + this.id = id; + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, DummyBooleanExpression::new, id); + } + + @Override + public Expression replaceChildren(List newChildren) { + throw new UnsupportedOperationException("this type of node doesn't have any children"); + } + + @Override + public Nullability nullable() { + return Nullability.FALSE; + } + + @Override + public DataType dataType() { + return BOOLEAN; + } + + @Override + public int hashCode() { + int h = getClass().hashCode(); + h = 31 * h + id; + return h; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return id == ((DummyBooleanExpression) obj).id; + } + } + + private static Literal L(Object value) { + return of(value); + } + + private static FieldAttribute getFieldAttribute() { + return TestUtils.getFieldAttribute("a"); + } + + // + // Constant folding + // + + public void testConstantFolding() { + Expression exp = new Add(EMPTY, TWO, THREE); + + assertTrue(exp.foldable()); + Expression result = new ConstantFolding().rule(exp); + assertTrue(result instanceof Literal); + assertEquals(5, ((Literal) result).value()); + + // check now with an alias + result = new ConstantFolding().rule(new Alias(EMPTY, "a", exp)); + assertEquals("a", Expressions.name(result)); + assertEquals(Alias.class, result.getClass()); + } + + public void testConstantFoldingBinaryComparison() { + assertEquals(FALSE, new ConstantFolding().rule(greaterThanOf(TWO, THREE)).canonical()); + assertEquals(FALSE, new ConstantFolding().rule(greaterThanOrEqualOf(TWO, THREE)).canonical()); + assertEquals(FALSE, new ConstantFolding().rule(equalsOf(TWO, THREE)).canonical()); + assertEquals(FALSE, new ConstantFolding().rule(nullEqualsOf(TWO, THREE)).canonical()); + assertEquals(FALSE, new ConstantFolding().rule(nullEqualsOf(TWO, NULL)).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(notEqualsOf(TWO, THREE)).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(lessThanOrEqualOf(TWO, THREE)).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(lessThanOf(TWO, THREE)).canonical()); + } + + public void testConstantFoldingBinaryLogic() { + assertEquals(FALSE, new ConstantFolding().rule(new And(EMPTY, greaterThanOf(TWO, THREE), TRUE)).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(new Or(EMPTY, greaterThanOrEqualOf(TWO, THREE), TRUE)).canonical()); + } + + public void testConstantFoldingBinaryLogic_WithNullHandling() { + assertEquals(Nullability.TRUE, new ConstantFolding().rule(new And(EMPTY, NULL, TRUE)).canonical().nullable()); + assertEquals(Nullability.TRUE, new ConstantFolding().rule(new And(EMPTY, TRUE, NULL)).canonical().nullable()); + assertEquals(FALSE, new ConstantFolding().rule(new And(EMPTY, NULL, FALSE)).canonical()); + assertEquals(FALSE, new ConstantFolding().rule(new And(EMPTY, FALSE, NULL)).canonical()); + assertEquals(Nullability.TRUE, new ConstantFolding().rule(new And(EMPTY, NULL, NULL)).canonical().nullable()); + + assertEquals(TRUE, new ConstantFolding().rule(new Or(EMPTY, NULL, TRUE)).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(new Or(EMPTY, TRUE, NULL)).canonical()); + assertEquals(Nullability.TRUE, new ConstantFolding().rule(new Or(EMPTY, NULL, FALSE)).canonical().nullable()); + assertEquals(Nullability.TRUE, new ConstantFolding().rule(new Or(EMPTY, FALSE, NULL)).canonical().nullable()); + assertEquals(Nullability.TRUE, new ConstantFolding().rule(new Or(EMPTY, NULL, NULL)).canonical().nullable()); + } + + public void testConstantFoldingRange() { + assertEquals(true, new ConstantFolding().rule(rangeOf(FIVE, FIVE, true, L(10), false)).fold()); + assertEquals(false, new ConstantFolding().rule(rangeOf(FIVE, FIVE, false, L(10), false)).fold()); + } + + public void testConstantNot() { + assertEquals(FALSE, new ConstantFolding().rule(new Not(EMPTY, TRUE))); + assertEquals(TRUE, new ConstantFolding().rule(new Not(EMPTY, FALSE))); + } + + public void testConstantFoldingLikes() { + assertEquals(TRUE, new ConstantFolding().rule(new Like(EMPTY, of("test_emp"), new LikePattern("test%", (char) 0))).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(new WildcardLike(EMPTY, of("test_emp"), new WildcardPattern("test*"))).canonical()); + assertEquals(TRUE, new ConstantFolding().rule(new RLike(EMPTY, of("test_emp"), new RLikePattern("test.emp"))).canonical()); + } + + public void testArithmeticFolding() { + assertEquals(10, foldOperator(new Add(EMPTY, L(7), THREE))); + assertEquals(4, foldOperator(new Sub(EMPTY, L(7), THREE))); + assertEquals(21, foldOperator(new Mul(EMPTY, L(7), THREE))); + assertEquals(2, foldOperator(new Div(EMPTY, L(7), THREE))); + assertEquals(1, foldOperator(new Mod(EMPTY, L(7), THREE))); + } + + private static Object foldOperator(BinaryOperator b) { + return ((Literal) new ConstantFolding().rule(b)).value(); + } + + // + // Logical simplifications + // + + public void testLiteralsOnTheRight() { + Alias a = new Alias(EMPTY, "a", L(10)); + Expression result = new LiteralsOnTheRight().rule(equalsOf(FIVE, a)); + assertTrue(result instanceof Equals); + Equals eq = (Equals) result; + assertEquals(a, eq.left()); + assertEquals(FIVE, eq.right()); + + a = new Alias(EMPTY, "a", L(10)); + result = new LiteralsOnTheRight().rule(nullEqualsOf(FIVE, a)); + assertTrue(result instanceof NullEquals); + NullEquals nullEquals = (NullEquals) result; + assertEquals(a, nullEquals.left()); + assertEquals(FIVE, nullEquals.right()); + } + + public void testBoolSimplifyOr() { + BooleanSimplification simplification = new BooleanSimplification(); + + assertEquals(TRUE, simplification.rule(new Or(EMPTY, TRUE, TRUE))); + assertEquals(TRUE, simplification.rule(new Or(EMPTY, TRUE, DUMMY_EXPRESSION))); + assertEquals(TRUE, simplification.rule(new Or(EMPTY, DUMMY_EXPRESSION, TRUE))); + + assertEquals(FALSE, simplification.rule(new Or(EMPTY, FALSE, FALSE))); + assertEquals(DUMMY_EXPRESSION, simplification.rule(new Or(EMPTY, FALSE, DUMMY_EXPRESSION))); + assertEquals(DUMMY_EXPRESSION, simplification.rule(new Or(EMPTY, DUMMY_EXPRESSION, FALSE))); + } + + public void testBoolSimplifyAnd() { + BooleanSimplification simplification = new BooleanSimplification(); + + assertEquals(TRUE, simplification.rule(new And(EMPTY, TRUE, TRUE))); + assertEquals(DUMMY_EXPRESSION, simplification.rule(new And(EMPTY, TRUE, DUMMY_EXPRESSION))); + assertEquals(DUMMY_EXPRESSION, simplification.rule(new And(EMPTY, DUMMY_EXPRESSION, TRUE))); + + assertEquals(FALSE, simplification.rule(new And(EMPTY, FALSE, FALSE))); + assertEquals(FALSE, simplification.rule(new And(EMPTY, FALSE, DUMMY_EXPRESSION))); + assertEquals(FALSE, simplification.rule(new And(EMPTY, DUMMY_EXPRESSION, FALSE))); + } + + public void testBoolCommonFactorExtraction() { + BooleanSimplification simplification = new BooleanSimplification(); + + Expression a1 = new DummyBooleanExpression(EMPTY, 1); + Expression a2 = new DummyBooleanExpression(EMPTY, 1); + Expression b = new DummyBooleanExpression(EMPTY, 2); + Expression c = new DummyBooleanExpression(EMPTY, 3); + + Or actual = new Or(EMPTY, new And(EMPTY, a1, b), new And(EMPTY, a2, c)); + And expected = new And(EMPTY, a1, new Or(EMPTY, b, c)); + + assertEquals(expected, simplification.rule(actual)); + } + + public void testBinaryComparisonSimplification() { + assertEquals(TRUE, new BinaryComparisonSimplification().rule(equalsOf(FIVE, FIVE))); + assertEquals(TRUE, new BinaryComparisonSimplification().rule(nullEqualsOf(FIVE, FIVE))); + assertEquals(TRUE, new BinaryComparisonSimplification().rule(nullEqualsOf(NULL, NULL))); + assertEquals(FALSE, new BinaryComparisonSimplification().rule(notEqualsOf(FIVE, FIVE))); + assertEquals(TRUE, new BinaryComparisonSimplification().rule(greaterThanOrEqualOf(FIVE, FIVE))); + assertEquals(TRUE, new BinaryComparisonSimplification().rule(lessThanOrEqualOf(FIVE, FIVE))); + + assertEquals(FALSE, new BinaryComparisonSimplification().rule(greaterThanOf(FIVE, FIVE))); + assertEquals(FALSE, new BinaryComparisonSimplification().rule(lessThanOf(FIVE, FIVE))); + } + + public void testNullEqualsWithNullLiteralBecomesIsNull() { + LiteralsOnTheRight swapLiteralsToRight = new LiteralsOnTheRight(); + BinaryComparisonSimplification bcSimpl = new BinaryComparisonSimplification(); + FieldAttribute fa = getFieldAttribute(); + Source source = new Source(1, 10, "IS_NULL(a)"); + + Expression e = bcSimpl.rule((BinaryComparison) swapLiteralsToRight.rule(new NullEquals(source, fa, NULL, randomZone()))); + assertEquals(IsNull.class, e.getClass()); + IsNull isNull = (IsNull) e; + assertEquals(source, isNull.source()); + + e = bcSimpl.rule((BinaryComparison) swapLiteralsToRight.rule(new NullEquals(source, NULL, fa, randomZone()))); + assertEquals(IsNull.class, e.getClass()); + isNull = (IsNull) e; + assertEquals(source, isNull.source()); + } + + public void testBoolEqualsSimplificationOnExpressions() { + BooleanFunctionEqualsElimination s = new BooleanFunctionEqualsElimination(); + Expression exp = new GreaterThan(EMPTY, getFieldAttribute(), L(0), null); + + assertEquals(exp, s.rule(new Equals(EMPTY, exp, TRUE))); + assertEquals(new Not(EMPTY, exp), s.rule(new Equals(EMPTY, exp, FALSE))); + } + + public void testBoolEqualsSimplificationOnFields() { + BooleanFunctionEqualsElimination s = new BooleanFunctionEqualsElimination(); + + FieldAttribute field = getFieldAttribute(); + + List comparisons = asList( + new Equals(EMPTY, field, TRUE), + new Equals(EMPTY, field, FALSE), + notEqualsOf(field, TRUE), + notEqualsOf(field, FALSE), + new Equals(EMPTY, NULL, TRUE), + new Equals(EMPTY, NULL, FALSE), + notEqualsOf(NULL, TRUE), + notEqualsOf(NULL, FALSE) + ); + + for (BinaryComparison comparison : comparisons) { + assertEquals(comparison, s.rule(comparison)); + } + } + + // + // Range optimization + // + + // 6 < a <= 5 -> FALSE + public void testFoldExcludingRangeToFalse() { + FieldAttribute fa = getFieldAttribute(); + + Range r = rangeOf(fa, SIX, false, FIVE, true); + assertTrue(r.foldable()); + assertEquals(Boolean.FALSE, r.fold()); + } + + // 6 < a <= 5.5 -> FALSE + public void testFoldExcludingRangeWithDifferentTypesToFalse() { + FieldAttribute fa = getFieldAttribute(); + + Range r = rangeOf(fa, SIX, false, L(5.5d), true); + assertTrue(r.foldable()); + assertEquals(Boolean.FALSE, r.fold()); + } + + // Conjunction + + public void testCombineBinaryComparisonsNotComparable() { + FieldAttribute fa = getFieldAttribute(); + LessThanOrEqual lte = lessThanOrEqualOf(fa, SIX); + LessThan lt = lessThanOf(fa, FALSE); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + And and = new And(EMPTY, lte, lt); + Expression exp = rule.rule(and); + assertEquals(exp, and); + } + + // a <= 6 AND a < 5 -> a < 5 + public void testCombineBinaryComparisonsUpper() { + FieldAttribute fa = getFieldAttribute(); + LessThanOrEqual lte = lessThanOrEqualOf(fa, SIX); + LessThan lt = lessThanOf(fa, FIVE); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + + Expression exp = rule.rule(new And(EMPTY, lte, lt)); + assertEquals(LessThan.class, exp.getClass()); + LessThan r = (LessThan) exp; + assertEquals(FIVE, r.right()); + } + + // 6 <= a AND 5 < a -> 6 <= a + public void testCombineBinaryComparisonsLower() { + FieldAttribute fa = getFieldAttribute(); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, SIX); + GreaterThan gt = greaterThanOf(fa, FIVE); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + + Expression exp = rule.rule(new And(EMPTY, gte, gt)); + assertEquals(GreaterThanOrEqual.class, exp.getClass()); + GreaterThanOrEqual r = (GreaterThanOrEqual) exp; + assertEquals(SIX, r.right()); + } + + // 5 <= a AND 5 < a -> 5 < a + public void testCombineBinaryComparisonsInclude() { + FieldAttribute fa = getFieldAttribute(); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, FIVE); + GreaterThan gt = greaterThanOf(fa, FIVE); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + + Expression exp = rule.rule(new And(EMPTY, gte, gt)); + assertEquals(GreaterThan.class, exp.getClass()); + GreaterThan r = (GreaterThan) exp; + assertEquals(FIVE, r.right()); + } + + // 2 < a AND (2 <= a < 3) -> 2 < a < 3 + public void testCombineBinaryComparisonsAndRangeLower() { + FieldAttribute fa = getFieldAttribute(); + + GreaterThan gt = greaterThanOf(fa, TWO); + Range range = rangeOf(fa, TWO, true, THREE, false); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(new And(EMPTY, gt, range)); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertFalse(r.includeLower()); + assertEquals(THREE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a < 4 AND (1 < a < 3) -> 1 < a < 3 + public void testCombineBinaryComparisonsAndRangeUpper() { + FieldAttribute fa = getFieldAttribute(); + + LessThan lt = lessThanOf(fa, FOUR); + Range range = rangeOf(fa, ONE, false, THREE, false); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(new And(EMPTY, range, lt)); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(ONE, r.lower()); + assertFalse(r.includeLower()); + assertEquals(THREE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a <= 2 AND (1 < a < 3) -> 1 < a <= 2 + public void testCombineBinaryComparisonsAndRangeUpperEqual() { + FieldAttribute fa = getFieldAttribute(); + + LessThanOrEqual lte = lessThanOrEqualOf(fa, TWO); + Range range = rangeOf(fa, ONE, false, THREE, false); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(new And(EMPTY, lte, range)); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(ONE, r.lower()); + assertFalse(r.includeLower()); + assertEquals(TWO, r.upper()); + assertTrue(r.includeUpper()); + } + + // 3 <= a AND 4 < a AND a <= 7 AND a < 6 -> 4 < a < 6 + public void testCombineMultipleBinaryComparisons() { + FieldAttribute fa = getFieldAttribute(); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, THREE); + GreaterThan gt = greaterThanOf(fa, FOUR); + LessThanOrEqual lte = lessThanOrEqualOf(fa, L(7)); + LessThan lt = lessThanOf(fa, SIX); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + + Expression exp = rule.rule(new And(EMPTY, gte, new And(EMPTY, gt, new And(EMPTY, lt, lte)))); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(FOUR, r.lower()); + assertFalse(r.includeLower()); + assertEquals(SIX, r.upper()); + assertFalse(r.includeUpper()); + } + + // 3 <= a AND TRUE AND 4 < a AND a != 5 AND a <= 7 -> 4 < a <= 7 AND a != 5 AND TRUE + public void testCombineMixedMultipleBinaryComparisons() { + FieldAttribute fa = getFieldAttribute(); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, THREE); + GreaterThan gt = greaterThanOf(fa, FOUR); + LessThanOrEqual lte = lessThanOrEqualOf(fa, L(7)); + Expression ne = new Not(EMPTY, equalsOf(fa, FIVE)); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + + // TRUE AND a != 5 AND 4 < a <= 7 + Expression exp = rule.rule(new And(EMPTY, gte, new And(EMPTY, TRUE, new And(EMPTY, gt, new And(EMPTY, ne, lte))))); + assertEquals(And.class, exp.getClass()); + And and = ((And) exp); + assertEquals(Range.class, and.right().getClass()); + Range r = (Range) and.right(); + assertEquals(FOUR, r.lower()); + assertFalse(r.includeLower()); + assertEquals(L(7), r.upper()); + assertTrue(r.includeUpper()); + } + + // 1 <= a AND a < 5 -> 1 <= a < 5 + public void testCombineComparisonsIntoRange() { + FieldAttribute fa = getFieldAttribute(); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, ONE); + LessThan lt = lessThanOf(fa, FIVE); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(new And(EMPTY, gte, lt)); + assertEquals(Range.class, exp.getClass()); + + Range r = (Range) exp; + assertEquals(ONE, r.lower()); + assertTrue(r.includeLower()); + assertEquals(FIVE, r.upper()); + assertFalse(r.includeUpper()); + } + + // 1 < a AND a < 3 AND 2 < b AND b < 4 AND c < 4 -> (1 < a < 3) AND (2 < b < 4) AND c < 4 + public void testCombineMultipleComparisonsIntoRange() { + FieldAttribute fa = TestUtils.getFieldAttribute("a"); + FieldAttribute fb = TestUtils.getFieldAttribute("b"); + FieldAttribute fc = TestUtils.getFieldAttribute("c"); + + ZoneId zoneId = randomZone(); + GreaterThan agt1 = new GreaterThan(EMPTY, fa, ONE, zoneId); + LessThan alt3 = new LessThan(EMPTY, fa, THREE, zoneId); + GreaterThan bgt2 = new GreaterThan(EMPTY, fb, TWO, zoneId); + LessThan blt4 = new LessThan(EMPTY, fb, FOUR, zoneId); + LessThan clt4 = new LessThan(EMPTY, fc, FOUR, zoneId); + + Expression inputAnd = Predicates.combineAnd(asList(agt1, alt3, bgt2, blt4, clt4)); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression outputAnd = rule.rule((And) inputAnd); + + Range agt1lt3 = new Range(EMPTY, fa, ONE, false, THREE, false, zoneId); + Range bgt2lt4 = new Range(EMPTY, fb, TWO, false, FOUR, false, zoneId); + + // The actual outcome is (c < 4) AND (1 < a < 3) AND (2 < b < 4), due to the way the Expression types are combined in the Optimizer + Expression expectedAnd = Predicates.combineAnd(asList(clt4, agt1lt3, bgt2lt4)); + + assertTrue(outputAnd.semanticEquals(expectedAnd)); + } + + // (2 < a < 3) AND (1 < a < 4) -> (2 < a < 3) + public void testCombineBinaryComparisonsConjunctionOfIncludedRange() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, ONE, false, FOUR, false); + + And and = new And(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(r1, exp); + } + + // (2 < a < 3) AND a < 2 -> 2 < a < 2 + public void testCombineBinaryComparisonsConjunctionOfNonOverlappingBoundaries() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, ONE, false, TWO, false); + + And and = new And(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertFalse(r.includeLower()); + assertEquals(TWO, r.upper()); + assertFalse(r.includeUpper()); + assertEquals(Boolean.FALSE, r.fold()); + } + + // (2 < a < 3) AND (2 < a <= 3) -> 2 < a < 3 + public void testCombineBinaryComparisonsConjunctionOfUpperEqualsOverlappingBoundaries() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, TWO, false, THREE, true); + + And and = new And(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(r1, exp); + } + + // (2 < a < 3) AND (1 < a < 3) -> 2 < a < 3 + public void testCombineBinaryComparisonsConjunctionOverlappingUpperBoundary() { + FieldAttribute fa = getFieldAttribute(); + + Range r2 = rangeOf(fa, TWO, false, THREE, false); + Range r1 = rangeOf(fa, ONE, false, THREE, false); + + And and = new And(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(r2, exp); + } + + // (2 < a <= 3) AND (1 < a < 3) -> 2 < a < 3 + public void testCombineBinaryComparisonsConjunctionWithDifferentUpperLimitInclusion() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, ONE, false, THREE, false); + Range r2 = rangeOf(fa, TWO, false, THREE, true); + + And and = new And(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertFalse(r.includeLower()); + assertEquals(THREE, r.upper()); + assertFalse(r.includeUpper()); + } + + // (0 < a <= 1) AND (0 <= a < 2) -> 0 < a <= 1 + public void testRangesOverlappingConjunctionNoLowerBoundary() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, L(0), false, ONE, true); + Range r2 = rangeOf(fa, L(0), true, TWO, false); + + And and = new And(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(r1, exp); + } + + // a != 2 AND 3 < a < 5 -> 3 < a < 5 + public void testCombineBinaryComparisonsConjunction_Neq2AndRangeGt3Lt5() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + Range range = rangeOf(fa, THREE, false, FIVE, false); + And and = new And(EMPTY, range, neq); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(THREE, r.lower()); + assertFalse(r.includeLower()); + assertEquals(FIVE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a != 2 AND 0 < a < 1 -> 0 < a < 1 + public void testCombineBinaryComparisonsConjunction_Neq2AndRangeGt0Lt1() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + Range range = rangeOf(fa, L(0), false, ONE, false); + And and = new And(EMPTY, neq, range); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(L(0), r.lower()); + assertFalse(r.includeLower()); + assertEquals(ONE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a != 2 AND 2 <= a < 3 -> 2 < a < 3 + public void testCombineBinaryComparisonsConjunction_Neq2AndRangeGte2Lt3() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + Range range = rangeOf(fa, TWO, true, THREE, false); + And and = new And(EMPTY, neq, range); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertFalse(r.includeLower()); + assertEquals(THREE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a != 3 AND 2 < a <= 3 -> 2 < a < 3 + public void testCombineBinaryComparisonsConjunction_Neq3AndRangeGt2Lte3() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, THREE); + Range range = rangeOf(fa, TWO, false, THREE, true); + And and = new And(EMPTY, neq, range); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertFalse(r.includeLower()); + assertEquals(THREE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a != 2 AND 1 < a < 3 + public void testCombineBinaryComparisonsConjunction_Neq2AndRangeGt1Lt3() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + Range range = rangeOf(fa, ONE, false, THREE, false); + And and = new And(EMPTY, neq, range); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(And.class, exp.getClass()); // can't optimize + } + + // a != 2 AND a > 3 -> a > 3 + public void testCombineBinaryComparisonsConjunction_Neq2AndGt3() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + GreaterThan gt = greaterThanOf(fa, THREE); + And and = new And(EMPTY, neq, gt); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(gt, exp); + } + + // a != 2 AND a >= 2 -> a > 2 + public void testCombineBinaryComparisonsConjunction_Neq2AndGte2() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, TWO); + And and = new And(EMPTY, neq, gte); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(GreaterThan.class, exp.getClass()); + GreaterThan gt = (GreaterThan) exp; + assertEquals(TWO, gt.right()); + } + + // a != 2 AND a >= 1 -> nop + public void testCombineBinaryComparisonsConjunction_Neq2AndGte1() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, ONE); + And and = new And(EMPTY, neq, gte); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(And.class, exp.getClass()); // can't optimize + } + + // a != 2 AND a <= 3 -> nop + public void testCombineBinaryComparisonsConjunction_Neq2AndLte3() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + LessThanOrEqual lte = lessThanOrEqualOf(fa, THREE); + And and = new And(EMPTY, neq, lte); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(and, exp); // can't optimize + } + + // a != 2 AND a <= 2 -> a < 2 + public void testCombineBinaryComparisonsConjunction_Neq2AndLte2() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + LessThanOrEqual lte = lessThanOrEqualOf(fa, TWO); + And and = new And(EMPTY, neq, lte); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(LessThan.class, exp.getClass()); + LessThan lt = (LessThan) exp; + assertEquals(TWO, lt.right()); + } + + // a != 2 AND a <= 1 -> a <= 1 + public void testCombineBinaryComparisonsConjunction_Neq2AndLte1() { + FieldAttribute fa = getFieldAttribute(); + + NotEquals neq = notEqualsOf(fa, TWO); + LessThanOrEqual lte = lessThanOrEqualOf(fa, ONE); + And and = new And(EMPTY, neq, lte); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals(lte, exp); + } + + // Disjunction + + public void testCombineBinaryComparisonsDisjunctionNotComparable() { + FieldAttribute fa = getFieldAttribute(); + + GreaterThan gt1 = greaterThanOf(fa, ONE); + GreaterThan gt2 = greaterThanOf(fa, FALSE); + + Or or = new Or(EMPTY, gt1, gt2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(exp, or); + } + + // 2 < a OR 1 < a OR 3 < a -> 1 < a + public void testCombineBinaryComparisonsDisjunctionLowerBound() { + FieldAttribute fa = getFieldAttribute(); + + GreaterThan gt1 = greaterThanOf(fa, ONE); + GreaterThan gt2 = greaterThanOf(fa, TWO); + GreaterThan gt3 = greaterThanOf(fa, THREE); + + Or or = new Or(EMPTY, gt1, new Or(EMPTY, gt2, gt3)); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(GreaterThan.class, exp.getClass()); + + GreaterThan gt = (GreaterThan) exp; + assertEquals(ONE, gt.right()); + } + + // 2 < a OR 1 < a OR 3 <= a -> 1 < a + public void testCombineBinaryComparisonsDisjunctionIncludeLowerBounds() { + FieldAttribute fa = getFieldAttribute(); + + GreaterThan gt1 = greaterThanOf(fa, ONE); + GreaterThan gt2 = greaterThanOf(fa, TWO); + GreaterThanOrEqual gte3 = greaterThanOrEqualOf(fa, THREE); + + Or or = new Or(EMPTY, new Or(EMPTY, gt1, gt2), gte3); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(GreaterThan.class, exp.getClass()); + + GreaterThan gt = (GreaterThan) exp; + assertEquals(ONE, gt.right()); + } + + // a < 1 OR a < 2 OR a < 3 -> a < 3 + public void testCombineBinaryComparisonsDisjunctionUpperBound() { + FieldAttribute fa = getFieldAttribute(); + + LessThan lt1 = lessThanOf(fa, ONE); + LessThan lt2 = lessThanOf(fa, TWO); + LessThan lt3 = lessThanOf(fa, THREE); + + Or or = new Or(EMPTY, new Or(EMPTY, lt1, lt2), lt3); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(LessThan.class, exp.getClass()); + + LessThan lt = (LessThan) exp; + assertEquals(THREE, lt.right()); + } + + // a < 2 OR a <= 2 OR a < 1 -> a <= 2 + public void testCombineBinaryComparisonsDisjunctionIncludeUpperBounds() { + FieldAttribute fa = getFieldAttribute(); + + LessThan lt1 = lessThanOf(fa, ONE); + LessThan lt2 = lessThanOf(fa, TWO); + LessThanOrEqual lte2 = lessThanOrEqualOf(fa, TWO); + + Or or = new Or(EMPTY, lt2, new Or(EMPTY, lte2, lt1)); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(LessThanOrEqual.class, exp.getClass()); + + LessThanOrEqual lte = (LessThanOrEqual) exp; + assertEquals(TWO, lte.right()); + } + + // a < 2 OR 3 < a OR a < 1 OR 4 < a -> a < 2 OR 3 < a + public void testCombineBinaryComparisonsDisjunctionOfLowerAndUpperBounds() { + FieldAttribute fa = getFieldAttribute(); + + LessThan lt1 = lessThanOf(fa, ONE); + LessThan lt2 = lessThanOf(fa, TWO); + + GreaterThan gt3 = greaterThanOf(fa, THREE); + GreaterThan gt4 = greaterThanOf(fa, FOUR); + + Or or = new Or(EMPTY, new Or(EMPTY, lt2, gt3), new Or(EMPTY, lt1, gt4)); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(Or.class, exp.getClass()); + + Or ro = (Or) exp; + + assertEquals(LessThan.class, ro.left().getClass()); + LessThan lt = (LessThan) ro.left(); + assertEquals(TWO, lt.right()); + assertEquals(GreaterThan.class, ro.right().getClass()); + GreaterThan gt = (GreaterThan) ro.right(); + assertEquals(THREE, gt.right()); + } + + // (2 < a < 3) OR (1 < a < 4) -> (1 < a < 4) + public void testCombineBinaryComparisonsDisjunctionOfIncludedRangeNotComparable() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, ONE, false, FALSE, false); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(or, exp); + } + + // (2 < a < 3) OR (1 < a < 4) -> (1 < a < 4) + public void testCombineBinaryComparisonsDisjunctionOfIncludedRange() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, ONE, false, FOUR, false); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(Range.class, exp.getClass()); + + Range r = (Range) exp; + assertEquals(ONE, r.lower()); + assertFalse(r.includeLower()); + assertEquals(FOUR, r.upper()); + assertFalse(r.includeUpper()); + } + + // (2 < a < 3) OR (1 < a < 2) -> same + public void testCombineBinaryComparisonsDisjunctionOfNonOverlappingBoundaries() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, ONE, false, TWO, false); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(or, exp); + } + + // (2 < a < 3) OR (2 < a <= 3) -> 2 < a <= 3 + public void testCombineBinaryComparisonsDisjunctionOfUpperEqualsOverlappingBoundaries() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, TWO, false, THREE, false); + Range r2 = rangeOf(fa, TWO, false, THREE, true); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(r2, exp); + } + + // (2 < a < 3) OR (1 < a < 3) -> 1 < a < 3 + public void testCombineBinaryComparisonsOverlappingUpperBoundary() { + FieldAttribute fa = getFieldAttribute(); + + Range r2 = rangeOf(fa, TWO, false, THREE, false); + Range r1 = rangeOf(fa, ONE, false, THREE, false); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(r1, exp); + } + + // (2 < a <= 3) OR (1 < a < 3) -> same (the <= prevents the ranges from being combined) + public void testCombineBinaryComparisonsWithDifferentUpperLimitInclusion() { + FieldAttribute fa = getFieldAttribute(); + + Range r1 = rangeOf(fa, ONE, false, THREE, false); + Range r2 = rangeOf(fa, TWO, false, THREE, true); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(or, exp); + } + + // (a = 1 AND b = 3 AND c = 4) OR (a = 2 AND b = 3 AND c = 4) -> (b = 3 AND c = 4) AND (a = 1 OR a = 2) + public void testBooleanSimplificationCommonExpressionSubstraction() { + FieldAttribute fa = TestUtils.getFieldAttribute("a"); + FieldAttribute fb = TestUtils.getFieldAttribute("b"); + FieldAttribute fc = TestUtils.getFieldAttribute("c"); + + Expression a1 = equalsOf(fa, ONE); + Expression a2 = equalsOf(fa, TWO); + And common = new And(EMPTY, equalsOf(fb, THREE), equalsOf(fc, FOUR)); + And left = new And(EMPTY, a1, common); + And right = new And(EMPTY, a2, common); + Or or = new Or(EMPTY, left, right); + + Expression exp = new BooleanSimplification().rule(or); + assertEquals(new And(EMPTY, common, new Or(EMPTY, a1, a2)), exp); + } + + // (0 < a <= 1) OR (0 < a < 2) -> 0 < a < 2 + public void testRangesOverlappingNoLowerBoundary() { + FieldAttribute fa = getFieldAttribute(); + + Range r2 = rangeOf(fa, L(0), false, TWO, false); + Range r1 = rangeOf(fa, L(0), false, ONE, true); + + Or or = new Or(EMPTY, r1, r2); + + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(or); + assertEquals(r2, exp); + } + + public void testBinaryComparisonAndOutOfRangeNotEqualsDifferentFields() { + FieldAttribute doubleOne = fieldAttribute("double", DOUBLE); + FieldAttribute doubleTwo = fieldAttribute("double2", DOUBLE); + FieldAttribute intOne = fieldAttribute("int", INTEGER); + FieldAttribute datetimeOne = fieldAttribute("datetime", INTEGER); + FieldAttribute keywordOne = fieldAttribute("keyword", KEYWORD); + FieldAttribute keywordTwo = fieldAttribute("keyword2", KEYWORD); + + List testCases = asList( + // double > 10 AND integer != -10 + new And(EMPTY, greaterThanOf(doubleOne, L(10)), notEqualsOf(intOne, L(-10))), + // keyword > '5' AND keyword2 != '48' + new And(EMPTY, greaterThanOf(keywordOne, L("5")), notEqualsOf(keywordTwo, L("48"))), + // keyword != '2021' AND datetime <= '2020-12-04T17:48:22.954240Z' + new And(EMPTY, notEqualsOf(keywordOne, L("2021")), lessThanOrEqualOf(datetimeOne, L("2020-12-04T17:48:22.954240Z"))), + // double > 10.1 AND double2 != -10.1 + new And(EMPTY, greaterThanOf(doubleOne, L(10.1d)), notEqualsOf(doubleTwo, L(-10.1d))) + ); + + for (And and : testCases) { + CombineBinaryComparisons rule = new CombineBinaryComparisons(); + Expression exp = rule.rule(and); + assertEquals("Rule should not have transformed [" + and.nodeString() + "]", and, exp); + } + } + + // Equals & NullEquals + + // 1 <= a < 10 AND a == 1 -> a == 1 + public void testEliminateRangeByEqualsInInterval() { + FieldAttribute fa = getFieldAttribute(); + Equals eq1 = equalsOf(fa, ONE); + Range r = rangeOf(fa, ONE, true, L(10), false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq1, r)); + assertEquals(eq1, exp); + } + + // 1 <= a < 10 AND a <=> 1 -> a <=> 1 + public void testEliminateRangeByNullEqualsInInterval() { + FieldAttribute fa = getFieldAttribute(); + NullEquals eq1 = nullEqualsOf(fa, ONE); + Range r = rangeOf(fa, ONE, true, L(10), false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq1, r)); + assertEquals(eq1, exp); + } + + // The following tests should work only to simplify filters and + // not if the expressions are part of a projection + // See: https://github.com/elastic/elasticsearch/issues/35859 + + // a == 1 AND a == 2 -> FALSE + public void testDualEqualsConjunction() { + FieldAttribute fa = getFieldAttribute(); + Equals eq1 = equalsOf(fa, ONE); + Equals eq2 = equalsOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq1, eq2)); + assertEquals(FALSE, exp); + } + + // a <=> 1 AND a <=> 2 -> FALSE + public void testDualNullEqualsConjunction() { + FieldAttribute fa = getFieldAttribute(); + NullEquals eq1 = nullEqualsOf(fa, ONE); + NullEquals eq2 = nullEqualsOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq1, eq2)); + assertEquals(FALSE, exp); + } + + // 1 < a < 10 AND a == 10 -> FALSE + public void testEliminateRangeByEqualsOutsideInterval() { + FieldAttribute fa = getFieldAttribute(); + Equals eq1 = equalsOf(fa, L(10)); + Range r = rangeOf(fa, ONE, false, L(10), false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq1, r)); + assertEquals(FALSE, exp); + } + + // 1 < a < 10 AND a <=> 10 -> FALSE + public void testEliminateRangeByNullEqualsOutsideInterval() { + FieldAttribute fa = getFieldAttribute(); + NullEquals eq1 = nullEqualsOf(fa, L(10)); + Range r = rangeOf(fa, ONE, false, L(10), false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq1, r)); + assertEquals(FALSE, exp); + } + + // a != 3 AND a = 3 -> FALSE + public void testPropagateEquals_VarNeq3AndVarEq3() { + FieldAttribute fa = getFieldAttribute(); + NotEquals neq = notEqualsOf(fa, THREE); + Equals eq = equalsOf(fa, THREE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, neq, eq)); + assertEquals(FALSE, exp); + } + + // a != 4 AND a = 3 -> a = 3 + public void testPropagateEquals_VarNeq4AndVarEq3() { + FieldAttribute fa = getFieldAttribute(); + NotEquals neq = notEqualsOf(fa, FOUR); + Equals eq = equalsOf(fa, THREE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, neq, eq)); + assertEquals(Equals.class, exp.getClass()); + assertEquals(eq, exp); + } + + // a = 2 AND a < 2 -> FALSE + public void testPropagateEquals_VarEq2AndVarLt2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + LessThan lt = lessThanOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq, lt)); + assertEquals(FALSE, exp); + } + + // a = 2 AND a <= 2 -> a = 2 + public void testPropagateEquals_VarEq2AndVarLte2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + LessThanOrEqual lt = lessThanOrEqualOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq, lt)); + assertEquals(eq, exp); + } + + // a = 2 AND a <= 1 -> FALSE + public void testPropagateEquals_VarEq2AndVarLte1() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + LessThanOrEqual lt = lessThanOrEqualOf(fa, ONE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq, lt)); + assertEquals(FALSE, exp); + } + + // a = 2 AND a > 2 -> FALSE + public void testPropagateEquals_VarEq2AndVarGt2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + GreaterThan gt = greaterThanOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq, gt)); + assertEquals(FALSE, exp); + } + + // a = 2 AND a >= 2 -> a = 2 + public void testPropagateEquals_VarEq2AndVarGte2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + GreaterThanOrEqual gte = greaterThanOrEqualOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq, gte)); + assertEquals(eq, exp); + } + + // a = 2 AND a > 3 -> FALSE + public void testPropagateEquals_VarEq2AndVarLt3() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + GreaterThan gt = greaterThanOf(fa, THREE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new And(EMPTY, eq, gt)); + assertEquals(FALSE, exp); + } + + // a = 2 AND a < 3 AND a > 1 AND a != 4 -> a = 2 + public void testPropagateEquals_VarEq2AndVarLt3AndVarGt1AndVarNeq4() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + LessThan lt = lessThanOf(fa, THREE); + GreaterThan gt = greaterThanOf(fa, ONE); + NotEquals neq = notEqualsOf(fa, FOUR); + + PropagateEquals rule = new PropagateEquals(); + Expression and = Predicates.combineAnd(asList(eq, lt, gt, neq)); + Expression exp = rule.rule((And) and); + assertEquals(eq, exp); + } + + // a = 2 AND 1 < a < 3 AND a > 0 AND a != 4 -> a = 2 + public void testPropagateEquals_VarEq2AndVarRangeGt1Lt3AndVarGt0AndVarNeq4() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + Range range = rangeOf(fa, ONE, false, THREE, false); + GreaterThan gt = greaterThanOf(fa, L(0)); + NotEquals neq = notEqualsOf(fa, FOUR); + + PropagateEquals rule = new PropagateEquals(); + Expression and = Predicates.combineAnd(asList(eq, range, gt, neq)); + Expression exp = rule.rule((And) and); + assertEquals(eq, exp); + } + + // a = 2 OR a > 1 -> a > 1 + public void testPropagateEquals_VarEq2OrVarGt1() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + GreaterThan gt = greaterThanOf(fa, ONE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, gt)); + assertEquals(gt, exp); + } + + // a = 2 OR a > 2 -> a >= 2 + public void testPropagateEquals_VarEq2OrVarGte2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + GreaterThan gt = greaterThanOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, gt)); + assertEquals(GreaterThanOrEqual.class, exp.getClass()); + GreaterThanOrEqual gte = (GreaterThanOrEqual) exp; + assertEquals(TWO, gte.right()); + } + + // a = 2 OR a < 3 -> a < 3 + public void testPropagateEquals_VarEq2OrVarLt3() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + LessThan lt = lessThanOf(fa, THREE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, lt)); + assertEquals(lt, exp); + } + + // a = 3 OR a < 3 -> a <= 3 + public void testPropagateEquals_VarEq3OrVarLt3() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, THREE); + LessThan lt = lessThanOf(fa, THREE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, lt)); + assertEquals(LessThanOrEqual.class, exp.getClass()); + LessThanOrEqual lte = (LessThanOrEqual) exp; + assertEquals(THREE, lte.right()); + } + + // a = 2 OR 1 < a < 3 -> 1 < a < 3 + public void testPropagateEquals_VarEq2OrVarRangeGt1Lt3() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + Range range = rangeOf(fa, ONE, false, THREE, false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, range)); + assertEquals(range, exp); + } + + // a = 2 OR 2 < a < 3 -> 2 <= a < 3 + public void testPropagateEquals_VarEq2OrVarRangeGt2Lt3() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + Range range = rangeOf(fa, TWO, false, THREE, false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, range)); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertTrue(r.includeLower()); + assertEquals(THREE, r.upper()); + assertFalse(r.includeUpper()); + } + + // a = 3 OR 2 < a < 3 -> 2 < a <= 3 + public void testPropagateEquals_VarEq3OrVarRangeGt2Lt3() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, THREE); + Range range = rangeOf(fa, TWO, false, THREE, false); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, range)); + assertEquals(Range.class, exp.getClass()); + Range r = (Range) exp; + assertEquals(TWO, r.lower()); + assertFalse(r.includeLower()); + assertEquals(THREE, r.upper()); + assertTrue(r.includeUpper()); + } + + // a = 2 OR a != 2 -> TRUE + public void testPropagateEquals_VarEq2OrVarNeq2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + NotEquals neq = notEqualsOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, neq)); + assertEquals(TRUE, exp); + } + + // a = 2 OR a != 5 -> a != 5 + public void testPropagateEquals_VarEq2OrVarNeq5() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + NotEquals neq = notEqualsOf(fa, FIVE); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(new Or(EMPTY, eq, neq)); + assertEquals(NotEquals.class, exp.getClass()); + NotEquals ne = (NotEquals) exp; + assertEquals(FIVE, ne.right()); + } + + // a = 2 OR 3 < a < 4 OR a > 2 OR a!= 2 -> TRUE + public void testPropagateEquals_VarEq2OrVarRangeGt3Lt4OrVarGt2OrVarNe2() { + FieldAttribute fa = getFieldAttribute(); + Equals eq = equalsOf(fa, TWO); + Range range = rangeOf(fa, THREE, false, FOUR, false); + GreaterThan gt = greaterThanOf(fa, TWO); + NotEquals neq = notEqualsOf(fa, TWO); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule((Or) Predicates.combineOr(asList(eq, range, neq, gt))); + assertEquals(TRUE, exp); + } + + // a == 1 AND a == 2 -> nop for date/time fields + public void testPropagateEquals_ignoreDateTimeFields() { + FieldAttribute fa = TestUtils.getFieldAttribute("a", DataTypes.DATETIME); + Equals eq1 = equalsOf(fa, ONE); + Equals eq2 = equalsOf(fa, TWO); + And and = new And(EMPTY, eq1, eq2); + + PropagateEquals rule = new PropagateEquals(); + Expression exp = rule.rule(and); + assertEquals(and, exp); + } + + // + // Like / Regex + // + public void testMatchAllLikeToExist() throws Exception { + for (String s : asList("%", "%%", "%%%")) { + LikePattern pattern = new LikePattern(s, (char) 0); + FieldAttribute fa = getFieldAttribute(); + Like l = new Like(EMPTY, fa, pattern); + Expression e = new ReplaceRegexMatch().rule(l); + assertEquals(IsNotNull.class, e.getClass()); + IsNotNull inn = (IsNotNull) e; + assertEquals(fa, inn.field()); + } + } + + public void testMatchAllWildcardLikeToExist() throws Exception { + for (String s : asList("*", "**", "***")) { + WildcardPattern pattern = new WildcardPattern(s); + FieldAttribute fa = getFieldAttribute(); + WildcardLike l = new WildcardLike(EMPTY, fa, pattern); + Expression e = new ReplaceRegexMatch().rule(l); + assertEquals(IsNotNull.class, e.getClass()); + IsNotNull inn = (IsNotNull) e; + assertEquals(fa, inn.field()); + } + } + + public void testMatchAllRLikeToExist() throws Exception { + RLikePattern pattern = new RLikePattern(".*"); + FieldAttribute fa = getFieldAttribute(); + RLike l = new RLike(EMPTY, fa, pattern); + Expression e = new ReplaceRegexMatch().rule(l); + assertEquals(IsNotNull.class, e.getClass()); + IsNotNull inn = (IsNotNull) e; + assertEquals(fa, inn.field()); + } + + public void testExactMatchLike() throws Exception { + for (String s : asList("ab", "ab0%", "ab0_c")) { + LikePattern pattern = new LikePattern(s, '0'); + FieldAttribute fa = getFieldAttribute(); + Like l = new Like(EMPTY, fa, pattern); + Expression e = new ReplaceRegexMatch().rule(l); + assertEquals(Equals.class, e.getClass()); + Equals eq = (Equals) e; + assertEquals(fa, eq.left()); + assertEquals(s.replace("0", StringUtils.EMPTY), eq.right().fold()); + } + } + + public void testExactMatchWildcardLike() throws Exception { + String s = "ab"; + WildcardPattern pattern = new WildcardPattern(s); + FieldAttribute fa = getFieldAttribute(); + WildcardLike l = new WildcardLike(EMPTY, fa, pattern); + Expression e = new ReplaceRegexMatch().rule(l); + assertEquals(Equals.class, e.getClass()); + Equals eq = (Equals) e; + assertEquals(fa, eq.left()); + assertEquals(s, eq.right().fold()); + } + + public void testExactMatchRLike() throws Exception { + RLikePattern pattern = new RLikePattern("abc"); + FieldAttribute fa = getFieldAttribute(); + RLike l = new RLike(EMPTY, fa, pattern); + Expression e = new ReplaceRegexMatch().rule(l); + assertEquals(Equals.class, e.getClass()); + Equals eq = (Equals) e; + assertEquals(fa, eq.left()); + assertEquals("abc", eq.right().fold()); + } + + // + // CombineDisjunction in Equals + // + public void testTwoEqualsWithOr() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or or = new Or(EMPTY, equalsOf(fa, ONE), equalsOf(fa, TWO)); + Expression e = new CombineDisjunctionsToIn().rule(or); + assertEquals(In.class, e.getClass()); + In in = (In) e; + assertEquals(fa, in.value()); + assertThat(in.list(), contains(ONE, TWO)); + } + + public void testTwoEqualsWithSameValue() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or or = new Or(EMPTY, equalsOf(fa, ONE), equalsOf(fa, ONE)); + Expression e = new CombineDisjunctionsToIn().rule(or); + assertEquals(Equals.class, e.getClass()); + Equals eq = (Equals) e; + assertEquals(fa, eq.left()); + assertEquals(ONE, eq.right()); + } + + public void testOneEqualsOneIn() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or or = new Or(EMPTY, equalsOf(fa, ONE), new In(EMPTY, fa, singletonList(TWO))); + Expression e = new CombineDisjunctionsToIn().rule(or); + assertEquals(In.class, e.getClass()); + In in = (In) e; + assertEquals(fa, in.value()); + assertThat(in.list(), contains(ONE, TWO)); + } + + public void testOneEqualsOneInWithSameValue() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or or = new Or(EMPTY, equalsOf(fa, ONE), new In(EMPTY, fa, asList(ONE, TWO))); + Expression e = new CombineDisjunctionsToIn().rule(or); + assertEquals(In.class, e.getClass()); + In in = (In) e; + assertEquals(fa, in.value()); + assertThat(in.list(), contains(ONE, TWO)); + } + + public void testSingleValueInToEquals() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Equals equals = equalsOf(fa, ONE); + Or or = new Or(EMPTY, equals, new In(EMPTY, fa, singletonList(ONE))); + Expression e = new CombineDisjunctionsToIn().rule(or); + assertEquals(equals, e); + } + + public void testEqualsBehindAnd() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + And and = new And(EMPTY, equalsOf(fa, ONE), equalsOf(fa, TWO)); + Filter dummy = new Filter(EMPTY, relation(), and); + LogicalPlan transformed = new CombineDisjunctionsToIn().apply(dummy); + assertSame(dummy, transformed); + assertEquals(and, ((Filter) transformed).condition()); + } + + public void testTwoEqualsDifferentFields() throws Exception { + FieldAttribute fieldOne = TestUtils.getFieldAttribute("ONE"); + FieldAttribute fieldTwo = TestUtils.getFieldAttribute("TWO"); + + Or or = new Or(EMPTY, equalsOf(fieldOne, ONE), equalsOf(fieldTwo, TWO)); + Expression e = new CombineDisjunctionsToIn().rule(or); + assertEquals(or, e); + } + + public void testMultipleIn() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or firstOr = new Or(EMPTY, new In(EMPTY, fa, singletonList(ONE)), new In(EMPTY, fa, singletonList(TWO))); + Or secondOr = new Or(EMPTY, firstOr, new In(EMPTY, fa, singletonList(THREE))); + Expression e = new CombineDisjunctionsToIn().rule(secondOr); + assertEquals(In.class, e.getClass()); + In in = (In) e; + assertEquals(fa, in.value()); + assertThat(in.list(), contains(ONE, TWO, THREE)); + } + + public void testOrWithNonCombinableExpressions() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or firstOr = new Or(EMPTY, new In(EMPTY, fa, singletonList(ONE)), lessThanOf(fa, TWO)); + Or secondOr = new Or(EMPTY, firstOr, new In(EMPTY, fa, singletonList(THREE))); + Expression e = new CombineDisjunctionsToIn().rule(secondOr); + assertEquals(Or.class, e.getClass()); + Or or = (Or) e; + assertEquals(or.left(), firstOr.right()); + assertEquals(In.class, or.right().getClass()); + In in = (In) or.right(); + assertEquals(fa, in.value()); + assertThat(in.list(), contains(ONE, THREE)); + } + + // Null folding + + public void testNullFoldingIsNull() { + FoldNull foldNull = new FoldNull(); + assertEquals(true, foldNull.rule(new IsNull(EMPTY, NULL)).fold()); + assertEquals(false, foldNull.rule(new IsNull(EMPTY, TRUE)).fold()); + } + + public void testGenericNullableExpression() { + FoldNull rule = new FoldNull(); + // arithmetic + assertNullLiteral(rule.rule(new Add(EMPTY, getFieldAttribute(), NULL))); + // comparison + assertNullLiteral(rule.rule(greaterThanOf(getFieldAttribute(), NULL))); + // regex + assertNullLiteral(rule.rule(new RLike(EMPTY, NULL, new RLikePattern("123")))); + } + + public void testNullFoldingDoesNotApplyOnLogicalExpressions() { + FoldNull rule = new FoldNull(); + + Or or = new Or(EMPTY, NULL, TRUE); + assertEquals(or, rule.rule(or)); + or = new Or(EMPTY, NULL, NULL); + assertEquals(or, rule.rule(or)); + + And and = new And(EMPTY, NULL, TRUE); + assertEquals(and, rule.rule(and)); + and = new And(EMPTY, NULL, NULL); + assertEquals(and, rule.rule(and)); + } + + // + // Propagate nullability (IS NULL / IS NOT NULL) + // + + // a IS NULL AND a IS NOT NULL => false + public void testIsNullAndNotNull() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + And and = new And(EMPTY, new IsNull(EMPTY, fa), new IsNotNull(EMPTY, fa)); + assertEquals(FALSE, new PropagateNullable().rule(and)); + } + + // a IS NULL AND b IS NOT NULL AND c IS NULL AND d IS NOT NULL AND e IS NULL AND a IS NOT NULL => false + public void testIsNullAndNotNullMultiField() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + And andOne = new And(EMPTY, new IsNull(EMPTY, fa), new IsNotNull(EMPTY, getFieldAttribute())); + And andTwo = new And(EMPTY, new IsNull(EMPTY, getFieldAttribute()), new IsNotNull(EMPTY, getFieldAttribute())); + And andThree = new And(EMPTY, new IsNull(EMPTY, getFieldAttribute()), new IsNotNull(EMPTY, fa)); + + And and = new And(EMPTY, andOne, new And(EMPTY, andThree, andTwo)); + + assertEquals(FALSE, new PropagateNullable().rule(and)); + } + + // a IS NULL AND a > 1 => a IS NULL AND false + public void testIsNullAndComparison() throws Exception { + FieldAttribute fa = getFieldAttribute(); + IsNull isNull = new IsNull(EMPTY, fa); + + And and = new And(EMPTY, isNull, greaterThanOf(fa, ONE)); + assertEquals(new And(EMPTY, isNull, nullOf(BOOLEAN)), new PropagateNullable().rule(and)); + } + + // a IS NULL AND b < 1 AND c < 1 AND a < 1 => a IS NULL AND b < 1 AND c < 1 => a IS NULL AND b < 1 AND c < 1 + public void testIsNullAndMultipleComparison() throws Exception { + FieldAttribute fa = getFieldAttribute(); + IsNull isNull = new IsNull(EMPTY, fa); + + And nestedAnd = new And( + EMPTY, + lessThanOf(TestUtils.getFieldAttribute("b"), ONE), + lessThanOf(TestUtils.getFieldAttribute("c"), ONE) + ); + And and = new And(EMPTY, isNull, nestedAnd); + And top = new And(EMPTY, and, lessThanOf(fa, ONE)); + + Expression optimized = new PropagateNullable().rule(top); + Expression expected = new And(EMPTY, and, nullOf(BOOLEAN)); + assertEquals(Predicates.splitAnd(expected), Predicates.splitAnd(optimized)); + } + + // ((a+1)/2) > 1 AND a + 2 AND a IS NULL AND b < 3 => NULL AND NULL AND a IS NULL AND b < 3 + public void testIsNullAndDeeplyNestedExpression() throws Exception { + FieldAttribute fa = getFieldAttribute(); + IsNull isNull = new IsNull(EMPTY, fa); + + Expression nullified = new And( + EMPTY, + greaterThanOf(new Div(EMPTY, new Add(EMPTY, fa, ONE), TWO), ONE), + greaterThanOf(new Add(EMPTY, fa, TWO), ONE) + ); + Expression kept = new And(EMPTY, isNull, lessThanOf(TestUtils.getFieldAttribute("b"), THREE)); + And and = new And(EMPTY, nullified, kept); + + Expression optimized = new PropagateNullable().rule(and); + Expression expected = new And(EMPTY, new And(EMPTY, nullOf(BOOLEAN), nullOf(BOOLEAN)), kept); + + assertEquals(Predicates.splitAnd(expected), Predicates.splitAnd(optimized)); + } + + // a IS NULL OR a IS NOT NULL => no change + // a IS NULL OR a > 1 => no change + public void testIsNullInDisjunction() throws Exception { + FieldAttribute fa = getFieldAttribute(); + + Or or = new Or(EMPTY, new IsNull(EMPTY, fa), new IsNotNull(EMPTY, fa)); + Filter dummy = new Filter(EMPTY, relation(), or); + LogicalPlan transformed = new PropagateNullable().apply(dummy); + assertSame(dummy, transformed); + assertEquals(or, ((Filter) transformed).condition()); + + or = new Or(EMPTY, new IsNull(EMPTY, fa), greaterThanOf(fa, ONE)); + dummy = new Filter(EMPTY, relation(), or); + transformed = new PropagateNullable().apply(dummy); + assertSame(dummy, transformed); + assertEquals(or, ((Filter) transformed).condition()); + } + + // a + 1 AND (a IS NULL OR a > 3) => no change + public void testIsNullDisjunction() throws Exception { + FieldAttribute fa = getFieldAttribute(); + IsNull isNull = new IsNull(EMPTY, fa); + + Or or = new Or(EMPTY, isNull, greaterThanOf(fa, THREE)); + And and = new And(EMPTY, new Add(EMPTY, fa, ONE), or); + + assertEquals(and, new PropagateNullable().rule(and)); + } + + public void testCombineFilters() throws Exception { + EsRelation relation = relation(); + GreaterThan conditionA = greaterThanOf(TestUtils.getFieldAttribute("a"), ONE); + LessThan conditionB = lessThanOf(TestUtils.getFieldAttribute("b"), TWO); + + Filter fa = new Filter(EMPTY, relation, conditionA); + Filter fb = new Filter(EMPTY, fa, conditionB); + + assertEquals(new Filter(EMPTY, relation, new And(EMPTY, conditionA, conditionB)), new PushDownAndCombineFilters().apply(fb)); + } + + public void testPushDownFilter() throws Exception { + EsRelation relation = relation(); + GreaterThan conditionA = greaterThanOf(TestUtils.getFieldAttribute("a"), ONE); + LessThan conditionB = lessThanOf(TestUtils.getFieldAttribute("b"), TWO); + + Filter fa = new Filter(EMPTY, relation, conditionA); + List projections = singletonList(TestUtils.getFieldAttribute("b")); + Project project = new Project(EMPTY, fa, projections); + Filter fb = new Filter(EMPTY, project, conditionB); + + Filter combinedFilter = new Filter(EMPTY, relation, new And(EMPTY, conditionA, conditionB)); + assertEquals(new Project(EMPTY, combinedFilter, projections), new PushDownAndCombineFilters().apply(fb)); + } + + public void testPushDownFilterThroughAgg() throws Exception { + EsRelation relation = relation(); + GreaterThan conditionA = greaterThanOf(TestUtils.getFieldAttribute("a"), ONE); + LessThan conditionB = lessThanOf(TestUtils.getFieldAttribute("b"), TWO); + GreaterThanOrEqual aggregateCondition = greaterThanOrEqualOf(new Count(EMPTY, ONE, false), THREE); + + Filter fa = new Filter(EMPTY, relation, conditionA); + List projections = singletonList(TestUtils.getFieldAttribute("b")); + // invalid aggregate but that's fine cause its properties are not used by this rule + Aggregate aggregate = new Aggregate(EMPTY, fa, emptyList(), emptyList()); + Filter fb = new Filter(EMPTY, aggregate, new And(EMPTY, aggregateCondition, conditionB)); + + Filter combinedFilter = new Filter(EMPTY, relation, new And(EMPTY, conditionA, conditionB)); + + // expected + Filter expected = new Filter(EMPTY, new Aggregate(EMPTY, combinedFilter, emptyList(), emptyList()), aggregateCondition); + assertEquals(expected, new PushDownAndCombineFilters().apply(fb)); + } + + public void testIsNotNullOnIsNullField() { + EsRelation relation = relation(); + var fieldA = TestUtils.getFieldAttribute("a"); + Expression inn = isNotNull(fieldA); + Filter f = new Filter(EMPTY, relation, inn); + + assertEquals(f, new OptimizerRules.InferIsNotNull().apply(f)); + } + + public void testIsNotNullOnOperatorWithOneField() { + EsRelation relation = relation(); + var fieldA = TestUtils.getFieldAttribute("a"); + Expression inn = isNotNull(new Add(EMPTY, fieldA, ONE)); + Filter f = new Filter(EMPTY, relation, inn); + Filter expected = new Filter(EMPTY, relation, new And(EMPTY, isNotNull(fieldA), inn)); + + assertEquals(expected, new OptimizerRules.InferIsNotNull().apply(f)); + } + + public void testIsNotNullOnOperatorWithTwoFields() { + EsRelation relation = relation(); + var fieldA = TestUtils.getFieldAttribute("a"); + var fieldB = TestUtils.getFieldAttribute("b"); + Expression inn = isNotNull(new Add(EMPTY, fieldA, fieldB)); + Filter f = new Filter(EMPTY, relation, inn); + Filter expected = new Filter(EMPTY, relation, new And(EMPTY, new And(EMPTY, isNotNull(fieldA), isNotNull(fieldB)), inn)); + + assertEquals(expected, new OptimizerRules.InferIsNotNull().apply(f)); + } + + public void testIsNotNullOnFunctionWithOneField() { + EsRelation relation = relation(); + var fieldA = TestUtils.getFieldAttribute("a"); + var pattern = L("abc"); + Expression inn = isNotNull( + new And(EMPTY, new TestStartsWith(EMPTY, fieldA, pattern, false), greaterThanOf(new Add(EMPTY, ONE, TWO), THREE)) + ); + + Filter f = new Filter(EMPTY, relation, inn); + Filter expected = new Filter(EMPTY, relation, new And(EMPTY, isNotNull(fieldA), inn)); + + assertEquals(expected, new OptimizerRules.InferIsNotNull().apply(f)); + } + + public void testIsNotNullOnFunctionWithTwoFields() { + EsRelation relation = relation(); + var fieldA = TestUtils.getFieldAttribute("a"); + var fieldB = TestUtils.getFieldAttribute("b"); + var pattern = L("abc"); + Expression inn = isNotNull(new TestStartsWith(EMPTY, fieldA, fieldB, false)); + + Filter f = new Filter(EMPTY, relation, inn); + Filter expected = new Filter(EMPTY, relation, new And(EMPTY, new And(EMPTY, isNotNull(fieldA), isNotNull(fieldB)), inn)); + + assertEquals(expected, new OptimizerRules.InferIsNotNull().apply(f)); + } + + public static class TestStartsWith extends StartsWith { + + public TestStartsWith(Source source, Expression input, Expression pattern, boolean caseInsensitive) { + super(source, input, pattern, caseInsensitive); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new TestStartsWith(source(), newChildren.get(0), newChildren.get(1), isCaseInsensitive()); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, TestStartsWith::new, input(), pattern(), isCaseInsensitive()); + } + } + + public void testIsNotNullOnFunctionWithTwoField() {} + + private IsNotNull isNotNull(Expression field) { + return new IsNotNull(EMPTY, field); + } + + private IsNull isNull(Expression field) { + return new IsNull(EMPTY, field); + } + + private Literal nullOf(DataType dataType) { + return new Literal(Source.EMPTY, null, dataType); + } + + private void assertNullLiteral(Expression expression) { + assertEquals(Literal.class, expression.getClass()); + assertNull(expression.fold()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/plan/QueryPlanTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/plan/QueryPlanTests.java new file mode 100644 index 000000000000..747823795d40 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/plan/QueryPlanTests.java @@ -0,0 +1,157 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.plan; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Add; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.plan.logical.Project; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.TestUtils.equalsOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.fieldAttribute; +import static org.elasticsearch.xpack.esql.core.TestUtils.of; +import static org.elasticsearch.xpack.esql.core.TestUtils.relation; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.hamcrest.Matchers.contains; + +public class QueryPlanTests extends ESTestCase { + + public void testTransformWithExpressionTopLevel() throws Exception { + Limit limit = new Limit(EMPTY, of(42), relation()); + LogicalPlan transformed = limit.transformExpressionsOnly(Literal.class, l -> of(24)); + + assertEquals(Limit.class, transformed.getClass()); + Limit l = (Limit) transformed; + assertEquals(24, l.limit().fold()); + } + + public void testTransformWithExpressionTree() throws Exception { + Limit limit = new Limit(EMPTY, of(42), relation()); + OrderBy o = new OrderBy(EMPTY, limit, emptyList()); + LogicalPlan transformed = o.transformExpressionsDown(Literal.class, l -> of(24)); + + assertEquals(OrderBy.class, transformed.getClass()); + OrderBy order = (OrderBy) transformed; + assertEquals(Limit.class, order.child().getClass()); + assertEquals(24, ((Limit) order.child()).limit().fold()); + } + + public void testTransformWithExpressionTopLevelInCollection() throws Exception { + FieldAttribute one = fieldAttribute("one", INTEGER); + FieldAttribute two = fieldAttribute("two", INTEGER); + + Project project = new Project(EMPTY, relation(), asList(one, two)); + LogicalPlan transformed = project.transformExpressionsOnly( + NamedExpression.class, + n -> n.name().equals("one") ? new FieldAttribute(EMPTY, "changed", one.field()) : n + ); + + assertEquals(Project.class, transformed.getClass()); + Project p = (Project) transformed; + assertEquals(2, p.projections().size()); + assertSame(two, p.projections().get(1)); + + NamedExpression o = p.projections().get(0); + assertEquals("changed", o.name()); + } + + public void testForEachWithExpressionTopLevel() throws Exception { + Alias one = new Alias(EMPTY, "one", of(42)); + FieldAttribute two = fieldAttribute(); + + Project project = new Project(EMPTY, relation(), asList(one, two)); + + List list = new ArrayList<>(); + project.forEachExpression(Literal.class, l -> { + if (l.fold().equals(42)) { + list.add(l.fold()); + } + }); + + assertEquals(singletonList(one.child().fold()), list); + } + + public void testForEachWithExpressionTree() throws Exception { + Limit limit = new Limit(EMPTY, of(42), relation()); + OrderBy o = new OrderBy(EMPTY, limit, emptyList()); + + List list = new ArrayList<>(); + o.forEachExpressionDown(Literal.class, l -> { + if (l.fold().equals(42)) { + list.add(l.fold()); + } + }); + + assertEquals(singletonList(limit.limit().fold()), list); + } + + public void testForEachWithExpressionTopLevelInCollection() throws Exception { + FieldAttribute one = fieldAttribute("one", INTEGER); + FieldAttribute two = fieldAttribute("two", INTEGER); + + Project project = new Project(EMPTY, relation(), asList(one, two)); + + List list = new ArrayList<>(); + project.forEachExpression(NamedExpression.class, n -> { + if (n.name().equals("one")) { + list.add(n); + } + }); + + assertEquals(singletonList(one), list); + } + + public void testForEachWithExpressionTreeInCollection() throws Exception { + Alias one = new Alias(EMPTY, "one", of(42)); + FieldAttribute two = fieldAttribute(); + + Project project = new Project(EMPTY, relation(), asList(one, two)); + + List list = new ArrayList<>(); + project.forEachExpression(Literal.class, l -> { + if (l.fold().equals(42)) { + list.add(l.fold()); + } + }); + + assertEquals(singletonList(one.child().fold()), list); + } + + public void testPlanExpressions() { + Alias one = new Alias(EMPTY, "one", of(42)); + FieldAttribute two = fieldAttribute(); + Project project = new Project(EMPTY, relation(), asList(one, two)); + + assertThat(Expressions.names(project.expressions()), contains("one", two.name())); + } + + public void testPlanReferences() { + var one = fieldAttribute("one", INTEGER); + var two = fieldAttribute("two", INTEGER); + var add = new Add(EMPTY, one, two); + var field = fieldAttribute("field", INTEGER); + + var filter = new Filter(EMPTY, relation(), equalsOf(field, add)); + assertThat(Expressions.names(filter.references()), contains("field", "one", "two")); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java new file mode 100644 index 000000000000..c2f517aba4e1 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/BoolQueryTests.java @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import static java.util.Collections.singletonMap; +import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.hasSize; + +public class BoolQueryTests extends ESTestCase { + static BoolQuery randomBoolQuery(int depth) { + return new BoolQuery( + SourceTests.randomSource(), + randomBoolean(), + NestedQueryTests.randomQuery(depth), + NestedQueryTests.randomQuery(depth) + ); + } + + public void testEqualsAndHashCode() { + checkEqualsAndHashCode(randomBoolQuery(5), BoolQueryTests::copy, BoolQueryTests::mutate); + } + + private static BoolQuery copy(BoolQuery query) { + return new BoolQuery(query.source(), query.isAnd(), query.queries()); + } + + private static BoolQuery mutate(BoolQuery query) { + List> options = Arrays.asList( + q -> new BoolQuery(SourceTests.mutate(q.source()), q.isAnd(), left(q), right(q)), + q -> new BoolQuery(q.source(), false == q.isAnd(), left(q), right(q)), + q -> new BoolQuery(q.source(), q.isAnd(), randomValueOtherThan(left(q), () -> NestedQueryTests.randomQuery(5)), right(q)), + q -> new BoolQuery(q.source(), q.isAnd(), left(q), randomValueOtherThan(right(q), () -> NestedQueryTests.randomQuery(5))) + ); + return randomFrom(options).apply(query); + } + + public void testContainsNestedField() { + assertFalse(boolQueryWithoutNestedChildren().containsNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5))); + + String path = randomAlphaOfLength(5); + String field = randomAlphaOfLength(5); + assertTrue(boolQueryWithNestedChildren(path, field).containsNestedField(path, field)); + } + + public void testAddNestedField() { + Query q = boolQueryWithoutNestedChildren(); + assertSame(q, q.addNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5), null, randomBoolean())); + + String path = randomAlphaOfLength(5); + String field = randomAlphaOfLength(5); + q = boolQueryWithNestedChildren(path, field); + String newField = randomAlphaOfLength(5); + boolean hasDocValues = randomBoolean(); + Query rewritten = q.addNestedField(path, newField, null, hasDocValues); + assertNotSame(q, rewritten); + assertTrue(rewritten.containsNestedField(path, newField)); + } + + public void testEnrichNestedSort() { + Query q = boolQueryWithoutNestedChildren(); + NestedSortBuilder sort = new NestedSortBuilder(randomAlphaOfLength(5)); + q.enrichNestedSort(sort); + assertNull(sort.getFilter()); + + String path = randomAlphaOfLength(5); + String field = randomAlphaOfLength(5); + q = boolQueryWithNestedChildren(path, field); + sort = new NestedSortBuilder(path); + q.enrichNestedSort(sort); + assertNotNull(sort.getFilter()); + } + + private Query boolQueryWithoutNestedChildren() { + return new BoolQuery( + SourceTests.randomSource(), + randomBoolean(), + new MatchAll(SourceTests.randomSource()), + new MatchAll(SourceTests.randomSource()) + ); + } + + private Query boolQueryWithNestedChildren(String path, String field) { + NestedQuery match = new NestedQuery( + SourceTests.randomSource(), + path, + singletonMap(field, new SimpleImmutableEntry<>(randomBoolean(), null)), + new MatchAll(SourceTests.randomSource()) + ); + Query matchAll = new MatchAll(SourceTests.randomSource()); + Query left; + Query right; + if (randomBoolean()) { + left = match; + right = matchAll; + } else { + left = matchAll; + right = match; + } + return new BoolQuery(SourceTests.randomSource(), randomBoolean(), left, right); + } + + public void testToString() { + assertEquals( + "BoolQuery@1:2[ExistsQuery@1:2[f1] AND ExistsQuery@1:8[f2]]", + new BoolQuery( + new Source(1, 1, StringUtils.EMPTY), + true, + new ExistsQuery(new Source(1, 1, StringUtils.EMPTY), "f1"), + new ExistsQuery(new Source(1, 7, StringUtils.EMPTY), "f2") + ).toString() + ); + } + + public void testNotAllNegated() { + var q = new BoolQuery(Source.EMPTY, true, new ExistsQuery(Source.EMPTY, "f1"), new ExistsQuery(Source.EMPTY, "f2")); + assertThat(q.negate(Source.EMPTY), equalTo(new NotQuery(Source.EMPTY, q))); + } + + public void testNotSomeNegated() { + var q = new BoolQuery( + Source.EMPTY, + true, + new ExistsQuery(Source.EMPTY, "f1"), + new NotQuery(Source.EMPTY, new ExistsQuery(Source.EMPTY, "f2")) + ); + assertThat( + q.negate(Source.EMPTY), + equalTo( + new BoolQuery( + Source.EMPTY, + false, + new NotQuery(Source.EMPTY, new ExistsQuery(Source.EMPTY, "f1")), + new ExistsQuery(Source.EMPTY, "f2") + ) + ) + ); + } + + public static Query left(BoolQuery bool) { + return indexOf(bool, 0); + } + + public static Query right(BoolQuery bool) { + return indexOf(bool, 1); + } + + private static Query indexOf(BoolQuery bool, int index) { + List queries = bool.queries(); + assertThat(queries, hasSize(greaterThanOrEqualTo(2))); + return queries.get(index); + } + +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java new file mode 100644 index 000000000000..1ac96b6d30e8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/LeafQueryTests.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; +import static org.hamcrest.Matchers.equalTo; + +public class LeafQueryTests extends ESTestCase { + private static class DummyLeafQuery extends LeafQuery { + private DummyLeafQuery(Source source) { + super(source); + } + + @Override + public QueryBuilder asBuilder() { + return null; + } + + @Override + protected String innerToString() { + return ""; + } + } + + public void testEqualsAndHashCode() { + DummyLeafQuery query = new DummyLeafQuery(SourceTests.randomSource()); + checkEqualsAndHashCode(query, LeafQueryTests::copy, LeafQueryTests::mutate); + } + + private static DummyLeafQuery copy(DummyLeafQuery query) { + return new DummyLeafQuery(query.source()); + } + + private static DummyLeafQuery mutate(DummyLeafQuery query) { + return new DummyLeafQuery(SourceTests.mutate(query.source())); + } + + public void testContainsNestedField() { + Query query = new DummyLeafQuery(SourceTests.randomSource()); + // Leaf queries don't contain nested fields. + assertFalse(query.containsNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5))); + } + + public void testAddNestedField() { + Query query = new DummyLeafQuery(SourceTests.randomSource()); + // Leaf queries don't contain nested fields. + assertSame(query, query.addNestedField(randomAlphaOfLength(5), randomAlphaOfLength(5), null, randomBoolean())); + } + + public void testEnrichNestedSort() { + Query query = new DummyLeafQuery(SourceTests.randomSource()); + // Leaf queries don't contain nested fields. + NestedSortBuilder sort = new NestedSortBuilder(randomAlphaOfLength(5)); + query.enrichNestedSort(sort); + assertNull(sort.getFilter()); + } + + public void testNot() { + var q = new LeafQueryTests.DummyLeafQuery(new Source(Location.EMPTY, "test")); + assertThat(q.negate(new Source(Location.EMPTY, "not")), equalTo(new NotQuery(new Source(Location.EMPTY, "not"), q))); + } + + public void testNotNot() { + var q = new LeafQueryTests.DummyLeafQuery(new Source(Location.EMPTY, "test")); + assertThat(q.negate(Source.EMPTY).negate(Source.EMPTY), equalTo(q)); + } + + public void testToString() { + assertEquals("DummyLeafQuery@1:2[]", new DummyLeafQuery(new Source(1, 1, StringUtils.EMPTY)).toString()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQueryTests.java new file mode 100644 index 000000000000..47fa87bf188a --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/MatchQueryTests.java @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.index.query.MatchQueryBuilder; +import org.elasticsearch.index.query.Operator; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.MatchQueryPredicate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import static java.util.Collections.emptyMap; +import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.hamcrest.Matchers.equalTo; + +public class MatchQueryTests extends ESTestCase { + static MatchQuery randomMatchQuery() { + return new MatchQuery(SourceTests.randomSource(), randomAlphaOfLength(5), randomAlphaOfLength(5)); + // TODO add the predicate + } + + public void testEqualsAndHashCode() { + checkEqualsAndHashCode(randomMatchQuery(), MatchQueryTests::copy, MatchQueryTests::mutate); + } + + private static MatchQuery copy(MatchQuery query) { + return new MatchQuery(query.source(), query.name(), query.text(), query.predicate()); + } + + private static MatchQuery mutate(MatchQuery query) { + List> options = Arrays.asList( + q -> new MatchQuery(SourceTests.mutate(q.source()), q.name(), q.text(), q.predicate()), + q -> new MatchQuery(q.source(), randomValueOtherThan(q.name(), () -> randomAlphaOfLength(5)), q.text(), q.predicate()), + q -> new MatchQuery(q.source(), q.name(), randomValueOtherThan(q.text(), () -> randomAlphaOfLength(5)), q.predicate()) + ); + // TODO mutate the predicate + return randomFrom(options).apply(query); + } + + public void testQueryBuilding() { + MatchQueryBuilder qb = getBuilder("lenient=true"); + assertThat(qb.lenient(), equalTo(true)); + + qb = getBuilder("lenient=true;operator=AND"); + assertThat(qb.lenient(), equalTo(true)); + assertThat(qb.operator(), equalTo(Operator.AND)); + + Exception e = expectThrows(IllegalArgumentException.class, () -> getBuilder("pizza=yummy")); + assertThat(e.getMessage(), equalTo("illegal match option [pizza]")); + + e = expectThrows(IllegalArgumentException.class, () -> getBuilder("operator=aoeu")); + assertThat(e.getMessage(), equalTo("No enum constant org.elasticsearch.index.query.Operator.AOEU")); + } + + private static MatchQueryBuilder getBuilder(String options) { + final Source source = new Source(1, 1, StringUtils.EMPTY); + FieldAttribute fa = new FieldAttribute(EMPTY, "a", new EsField("af", KEYWORD, emptyMap(), true)); + final MatchQueryPredicate mmqp = new MatchQueryPredicate(source, fa, "eggplant", options); + final MatchQuery mmq = new MatchQuery(source, "eggplant", "foo", mmqp); + return (MatchQueryBuilder) mmq.asBuilder(); + } + + public void testToString() { + final Source source = new Source(1, 1, StringUtils.EMPTY); + FieldAttribute fa = new FieldAttribute(EMPTY, "a", new EsField("af", KEYWORD, emptyMap(), true)); + final MatchQueryPredicate mmqp = new MatchQueryPredicate(source, fa, "eggplant", ""); + final MatchQuery mmq = new MatchQuery(source, "eggplant", "foo", mmqp); + assertEquals("MatchQuery@1:2[eggplant:foo]", mmq.toString()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQueryTests.java new file mode 100644 index 000000000000..9ca9765ed054 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/MultiMatchQueryTests.java @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.index.query.MultiMatchQueryBuilder; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.MultiMatchQueryPredicate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import static org.hamcrest.Matchers.equalTo; + +public class MultiMatchQueryTests extends ESTestCase { + + public void testQueryBuilding() { + MultiMatchQueryBuilder qb = getBuilder("lenient=true"); + assertThat(qb.lenient(), equalTo(true)); + + qb = getBuilder("type=best_fields"); + assertThat(qb.getType(), equalTo(MultiMatchQueryBuilder.Type.BEST_FIELDS)); + + Exception e = expectThrows(IllegalArgumentException.class, () -> getBuilder("pizza=yummy")); + assertThat(e.getMessage(), equalTo("illegal multi_match option [pizza]")); + + e = expectThrows(ElasticsearchParseException.class, () -> getBuilder("type=aoeu")); + assertThat(e.getMessage(), equalTo("failed to parse [multi_match] query type [aoeu]. unknown type.")); + } + + private static MultiMatchQueryBuilder getBuilder(String options) { + final Source source = new Source(1, 1, StringUtils.EMPTY); + final MultiMatchQueryPredicate mmqp = new MultiMatchQueryPredicate(source, "foo,bar", "eggplant", options); + final Map fields = new HashMap<>(); + fields.put("foo", 1.0f); + fields.put("bar", 1.0f); + final MultiMatchQuery mmq = new MultiMatchQuery(source, "eggplant", fields, mmqp); + return (MultiMatchQueryBuilder) mmq.asBuilder(); + } + + public void testToString() { + final Source source = new Source(1, 1, StringUtils.EMPTY); + final MultiMatchQueryPredicate mmqp = new MultiMatchQueryPredicate(source, "foo,bar", "eggplant", ""); + // Use a TreeMap so we get the fields in a predictable order. + final Map fields = new TreeMap<>(); + fields.put("foo", 1.0f); + fields.put("bar", 1.0f); + final MultiMatchQuery mmq = new MultiMatchQuery(source, "eggplant", fields, mmqp); + assertEquals("MultiMatchQuery@1:2[{bar=1.0, foo=1.0}:eggplant]", mmq.toString()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java new file mode 100644 index 000000000000..1a36531efec5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/NestedQueryTests.java @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.common.util.Maps; +import org.elasticsearch.search.sort.NestedSortBuilder; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.util.Collections.singletonMap; +import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; +import static org.hamcrest.Matchers.hasEntry; + +public class NestedQueryTests extends ESTestCase { + static Query randomQuery(int depth) { + List> options = new ArrayList<>(); + options.add(MatchQueryTests::randomMatchQuery); + if (depth > 0) { + options.add(() -> randomNestedQuery(depth - 1)); + options.add(() -> BoolQueryTests.randomBoolQuery(depth - 1)); + } + return randomFrom(options).get(); + } + + static NestedQuery randomNestedQuery(int depth) { + return new NestedQuery(SourceTests.randomSource(), randomAlphaOfLength(5), randomFields(), randomQuery(depth)); + } + + private static Map> randomFields() { + int size = between(0, 5); + Map> fields = Maps.newMapWithExpectedSize(size); + while (fields.size() < size) { + fields.put(randomAlphaOfLength(5), new SimpleImmutableEntry<>(randomBoolean(), null)); + } + return fields; + } + + public void testEqualsAndHashCode() { + checkEqualsAndHashCode(randomNestedQuery(5), NestedQueryTests::copy, NestedQueryTests::mutate); + } + + private static NestedQuery copy(NestedQuery query) { + return new NestedQuery(query.source(), query.path(), query.fields(), query.child()); + } + + private static NestedQuery mutate(NestedQuery query) { + List> options = Arrays.asList( + q -> new NestedQuery(SourceTests.mutate(q.source()), q.path(), q.fields(), q.child()), + q -> new NestedQuery(q.source(), randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5)), q.fields(), q.child()), + q -> new NestedQuery(q.source(), q.path(), randomValueOtherThan(q.fields(), NestedQueryTests::randomFields), q.child()), + q -> new NestedQuery(q.source(), q.path(), q.fields(), randomValueOtherThan(q.child(), () -> randomQuery(5))) + ); + return randomFrom(options).apply(query); + } + + public void testContainsNestedField() { + NestedQuery q = randomNestedQuery(0); + for (String field : q.fields().keySet()) { + assertTrue(q.containsNestedField(q.path(), field)); + assertFalse(q.containsNestedField(randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5)), field)); + } + assertFalse(q.containsNestedField(q.path(), randomValueOtherThanMany(q.fields()::containsKey, () -> randomAlphaOfLength(5)))); + } + + public void testAddNestedField() { + NestedQuery q = randomNestedQuery(0); + for (String field : q.fields().keySet()) { + // add does nothing if the field is already there + assertSame(q, q.addNestedField(q.path(), field, null, randomBoolean())); + String otherPath = randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5)); + // add does nothing if the path doesn't match + assertSame(q, q.addNestedField(otherPath, randomAlphaOfLength(5), null, randomBoolean())); + } + + // if the field isn't in the list then add rewrites to a query with all the old fields and the new one + String newField = randomValueOtherThanMany(q.fields()::containsKey, () -> randomAlphaOfLength(5)); + boolean hasDocValues = randomBoolean(); + NestedQuery added = (NestedQuery) q.addNestedField(q.path(), newField, null, hasDocValues); + assertNotSame(q, added); + assertThat(added.fields(), hasEntry(newField, new SimpleImmutableEntry<>(hasDocValues, null))); + assertTrue(added.containsNestedField(q.path(), newField)); + for (Map.Entry> field : q.fields().entrySet()) { + assertThat(added.fields(), hasEntry(field.getKey(), field.getValue())); + assertTrue(added.containsNestedField(q.path(), field.getKey())); + } + } + + public void testEnrichNestedSort() { + NestedQuery q = randomNestedQuery(0); + + // enrich adds the filter if the path matches + { + NestedSortBuilder sort = new NestedSortBuilder(q.path()); + q.enrichNestedSort(sort); + assertEquals(q.child().asBuilder(), sort.getFilter()); + } + + // but doesn't if it doesn't match + { + NestedSortBuilder sort = new NestedSortBuilder(randomValueOtherThan(q.path(), () -> randomAlphaOfLength(5))); + q.enrichNestedSort(sort); + assertNull(sort.getFilter()); + } + + // enriching with the same query twice is fine + { + NestedSortBuilder sort = new NestedSortBuilder(q.path()); + q.enrichNestedSort(sort); + assertEquals(q.child().asBuilder(), sort.getFilter()); + q.enrichNestedSort(sort); + + // But enriching using another query will keep only the first query + Query originalChildQuery = randomValueOtherThan(q.child(), () -> randomQuery(0)); + NestedQuery other = new NestedQuery(SourceTests.randomSource(), q.path(), q.fields(), originalChildQuery); + other.enrichNestedSort(sort); + assertEquals(other.child().asBuilder(), originalChildQuery.asBuilder()); + } + } + + public void testToString() { + NestedQuery q = new NestedQuery( + new Source(1, 1, StringUtils.EMPTY), + "a.b", + singletonMap("f", new SimpleImmutableEntry<>(true, null)), + new MatchAll(new Source(1, 1, StringUtils.EMPTY)) + ); + assertEquals("NestedQuery@1:2[a.b.{f=true=null}[MatchAll@1:2[]]]", q.toString()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQueryTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQueryTests.java new file mode 100644 index 000000000000..0f8001196109 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/querydsl/query/QueryStringQueryTests.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.querydsl.query; + +import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.index.query.Operator; +import org.elasticsearch.index.query.QueryStringQueryBuilder; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.StringQueryPredicate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.StringUtils; + +import java.util.Collections; + +import static org.hamcrest.Matchers.equalTo; + +public class QueryStringQueryTests extends ESTestCase { + + public void testQueryBuilding() { + QueryStringQueryBuilder qb = getBuilder("lenient=true"); + assertThat(qb.lenient(), equalTo(true)); + + qb = getBuilder("lenient=true;default_operator=AND"); + assertThat(qb.lenient(), equalTo(true)); + assertThat(qb.defaultOperator(), equalTo(Operator.AND)); + + Exception e = expectThrows(IllegalArgumentException.class, () -> getBuilder("pizza=yummy")); + assertThat(e.getMessage(), equalTo("illegal query_string option [pizza]")); + + e = expectThrows(ElasticsearchParseException.class, () -> getBuilder("type=aoeu")); + assertThat(e.getMessage(), equalTo("failed to parse [multi_match] query type [aoeu]. unknown type.")); + } + + private static QueryStringQueryBuilder getBuilder(String options) { + final Source source = new Source(1, 1, StringUtils.EMPTY); + final StringQueryPredicate mmqp = new StringQueryPredicate(source, "eggplant", options); + final QueryStringQuery mmq = new QueryStringQuery(source, "eggplant", Collections.singletonMap("foo", 1.0f), mmqp); + return (QueryStringQueryBuilder) mmq.asBuilder(); + } + + public void testToString() { + final Source source = new Source(1, 1, StringUtils.EMPTY); + final StringQueryPredicate mmqp = new StringQueryPredicate(source, "eggplant", ""); + final QueryStringQuery mmq = new QueryStringQuery(source, "eggplant", Collections.singletonMap("foo", 1.0f), mmqp); + assertEquals("QueryStringQuery@1:2[{foo=1.0}:eggplant]", mmq.toString()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/AbstractNodeTestCase.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/AbstractNodeTestCase.java new file mode 100644 index 000000000000..dfb7073ab003 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/AbstractNodeTestCase.java @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.EqualsHashCodeTestUtils; + +import java.util.List; + +/** + * Superclass for tests of subclasses of {@link Node}. + */ +public abstract class AbstractNodeTestCase> extends ESTestCase { + /** + * Make a new random instance. + */ + protected abstract T randomInstance(); + + /** + * Mutate an instance into some other similar instance that + * shouldn't be {@link #equals} to the original. + */ + protected abstract T mutate(T instance); + + /** + * Copy and instance so it isn't {@code ==} but should still + * be {@link #equals}. + */ + protected abstract T copy(T instance); + + /** + * Test this subclass's implementation of {@link Node#transformNodeProps}. + */ + public abstract void testTransform(); + + /** + * Test this subclass's implementation of {@link Node#replaceChildren(List)}. + */ + public abstract void testReplaceChildren(); + + public final void testHashCodeAndEquals() { + EqualsHashCodeTestUtils.checkEqualsAndHashCode(randomInstance(), this::copy, this::mutate); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/NodeSubclassTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/NodeSubclassTests.java new file mode 100644 index 000000000000..d17a191961d8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/NodeSubclassTests.java @@ -0,0 +1,769 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.core.PathUtils; +import org.elasticsearch.core.SuppressForbidden; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.core.enrich.EnrichPolicy; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttributeTests; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.CompoundAggregate; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.InnerAggregate; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.AggExtractorInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.BinaryPipesTests; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.ConstantProcessor; +import org.elasticsearch.xpack.esql.core.expression.gen.processor.Processor; +import org.elasticsearch.xpack.esql.core.expression.predicate.fulltext.FullTextPredicate; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.In; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.InPipe; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.Like; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.LikePattern; +import org.elasticsearch.xpack.esql.core.tree.NodeTests.ChildrenAreAProperty; +import org.elasticsearch.xpack.esql.core.tree.NodeTests.Dummy; +import org.elasticsearch.xpack.esql.core.tree.NodeTests.NoChildren; +import org.mockito.exceptions.base.MockitoException; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.mockito.Mockito.mock; + +/** + * Looks for all subclasses of {@link Node} and verifies that they + * implement {@link Node#info()} and + * {@link Node#replaceChildren(List)} sanely. It'd be better if + * each subclass had its own test case that verified those methods + * and any other interesting things that that they do but we're a + * long way from that and this gets the job done for now. + *

+ * This test attempts to use reflection to create believeable nodes + * and manipulate them in believeable ways with as little knowledge + * of the actual subclasses as possible. This is problematic because + * it is possible, for example, for nodes to stackoverflow because + * they can contain themselves. So this class + * does have some {@link Node}-subclass-specific + * knowledge. As little as I could get away with though. + *

+ * When there are actual tests for a subclass of {@linkplain Node} + * then this class will do two things: + *

    + *
  • Skip running any tests for that subclass entirely. + *
  • Delegate to that test to build nodes of that type when a + * node of that type is called for. + *
+ */ +public class NodeSubclassTests> extends ESTestCase { + + private static final List> CLASSES_WITH_MIN_TWO_CHILDREN = asList(In.class, InPipe.class); + + private final Class subclass; + + public NodeSubclassTests(Class subclass) { + this.subclass = subclass; + } + + public void testInfoParameters() throws Exception { + Constructor ctor = longestCtor(subclass); + Object[] nodeCtorArgs = ctorArgs(ctor); + T node = ctor.newInstance(nodeCtorArgs); + /* + * The count should be the same size as the longest constructor + * by convention. If it isn't then we're missing something. + */ + int expectedCount = ctor.getParameterCount(); + /* + * Except the first `Location` argument of the ctor is implicit + * in the parameters and not included. + */ + expectedCount -= 1; + assertEquals(expectedCount, node.info().properties().size()); + } + + /** + * Test {@link Node#transformPropertiesOnly(Class, java.util.function.Function)} + * implementation on {@link #subclass} which tests the implementation of + * {@link Node#info()}. And tests the actual {@link NodeInfo} subclass + * implementations in the process. + */ + public void testTransform() throws Exception { + Constructor ctor = longestCtor(subclass); + Object[] nodeCtorArgs = ctorArgs(ctor); + T node = ctor.newInstance(nodeCtorArgs); + + Type[] argTypes = ctor.getGenericParameterTypes(); + // start at 1 because we can't change Location. + for (int changedArgOffset = 1; changedArgOffset < ctor.getParameterCount(); changedArgOffset++) { + Object originalArgValue = nodeCtorArgs[changedArgOffset]; + + Type changedArgType = argTypes[changedArgOffset]; + Object changedArgValue = randomValueOtherThan(nodeCtorArgs[changedArgOffset], () -> makeArg(changedArgType)); + + B transformed = node.transformNodeProps(Object.class, prop -> Objects.equals(prop, originalArgValue) ? changedArgValue : prop); + + if (node.children().contains(originalArgValue) || node.children().equals(originalArgValue)) { + if (node.children().equals(emptyList()) && originalArgValue.equals(emptyList())) { + /* + * If the children are an empty list and the value + * we want to change is an empty list they'll be + * equal to one another so they'll come on this branch. + * This case is rare and hard to reason about so we're + * just going to assert nothing here and hope to catch + * it when we write non-reflection hack tests. + */ + continue; + } + // Transformation shouldn't apply to children. + assertSame(node, transformed); + } else { + assertTransformedOrReplacedChildren(node, transformed, ctor, nodeCtorArgs, changedArgOffset, changedArgValue); + } + } + } + + /** + * Test {@link Node#replaceChildren(List)} implementation on {@link #subclass}. + */ + public void testReplaceChildren() throws Exception { + Constructor ctor = longestCtor(subclass); + Object[] nodeCtorArgs = ctorArgs(ctor); + T node = ctor.newInstance(nodeCtorArgs); + + Type[] argTypes = ctor.getGenericParameterTypes(); + // start at 1 because we can't change Location. + for (int changedArgOffset = 1; changedArgOffset < ctor.getParameterCount(); changedArgOffset++) { + Object originalArgValue = nodeCtorArgs[changedArgOffset]; + Type changedArgType = argTypes[changedArgOffset]; + + if (originalArgValue instanceof Collection col) { + + if (col.isEmpty() || col instanceof EnumSet) { + /* + * We skip empty lists here because they'll spuriously + * pass the conditions below if statements even if they don't + * have anything to do with children. This might cause us to + * ignore the case where a parameter gets copied into the + * children and just happens to be empty but I don't really + * know another way. + */ + + continue; + } + + if (col instanceof List originalList && node.children().equals(originalList)) { + // The arg we're looking at *is* the children + @SuppressWarnings("unchecked") // we pass a reasonable type so get reasonable results + List newChildren = (List) makeListOfSameSizeOtherThan(changedArgType, originalList); + B transformed = node.replaceChildren(newChildren); + assertTransformedOrReplacedChildren(node, transformed, ctor, nodeCtorArgs, changedArgOffset, newChildren); + } else if (false == col.isEmpty() && node.children().containsAll(col)) { + // The arg we're looking at is a collection contained within the children + List originalList = (List) originalArgValue; + + // First make the new children + @SuppressWarnings("unchecked") // we pass a reasonable type so get reasonable results + List newCollection = (List) makeListOfSameSizeOtherThan(changedArgType, originalList); + + // Now merge that list of children into the original list of children + List originalChildren = node.children(); + List newChildren = new ArrayList<>(originalChildren.size()); + int originalOffset = 0; + for (int i = 0; i < originalChildren.size(); i++) { + if (originalOffset < originalList.size() && originalChildren.get(i).equals(originalList.get(originalOffset))) { + newChildren.add(newCollection.get(originalOffset)); + originalOffset++; + } else { + newChildren.add(originalChildren.get(i)); + } + } + + // Finally! We can assert..... + B transformed = node.replaceChildren(newChildren); + assertTransformedOrReplacedChildren(node, transformed, ctor, nodeCtorArgs, changedArgOffset, newCollection); + } else { + // The arg we're looking at has nothing to do with the children + } + } else { + if (node.children().contains(originalArgValue)) { + // The arg we're looking at is one of the children + List newChildren = new ArrayList<>(node.children()); + @SuppressWarnings("unchecked") // makeArg produced reasonable values + B newChild = (B) randomValueOtherThan(nodeCtorArgs[changedArgOffset], () -> makeArg(changedArgType)); + newChildren.replaceAll(e -> Objects.equals(originalArgValue, e) ? newChild : e); + B transformed = node.replaceChildren(newChildren); + assertTransformedOrReplacedChildren(node, transformed, ctor, nodeCtorArgs, changedArgOffset, newChild); + } else { + // The arg we're looking at has nothing to do with the children + } + } + } + } + + private void assertTransformedOrReplacedChildren( + T node, + B transformed, + Constructor ctor, + Object[] nodeCtorArgs, + int changedArgOffset, + Object changedArgValue + ) throws Exception { + if (node instanceof Function) { + /* + * Functions have a weaker definition of transform then other + * things: + * + * Transforming using the way we did above should only change + * the one property of the node that we intended to transform. + */ + assertEquals(node.source(), transformed.source()); + List op = node.nodeProperties(); + List tp = transformed.nodeProperties(); + for (int p = 0; p < op.size(); p++) { + if (p == changedArgOffset - 1) { // -1 because location isn't in the list + assertEquals(changedArgValue, tp.get(p)); + } else { + assertEquals(op.get(p), tp.get(p)); + } + } + } else { + /* + * The stronger assertion for all non-Functions: transforming + * a node changes *only* the transformed value such that you + * can rebuild a copy of the node using its constructor changing + * only one argument and it'll be *equal* to the result of the + * transformation. + */ + Type[] argTypes = ctor.getGenericParameterTypes(); + Object[] args = new Object[argTypes.length]; + for (int i = 0; i < argTypes.length; i++) { + args[i] = nodeCtorArgs[i] == nodeCtorArgs[changedArgOffset] ? changedArgValue : nodeCtorArgs[i]; + } + T reflectionTransformed = ctor.newInstance(args); + assertEquals(reflectionTransformed, transformed); + } + } + + /** + * Find the longest constructor of the given class. + * By convention, for all subclasses of {@link Node}, + * this constructor should have "all" of the state of + * the node. All other constructors should all delegate + * to this constructor. + */ + static Constructor longestCtor(Class clazz) { + Constructor longest = null; + for (Constructor ctor : clazz.getConstructors()) { + if (longest == null || longest.getParameterCount() < ctor.getParameterCount()) { + @SuppressWarnings("unchecked") // Safe because the ctor has to be a ctor for T + Constructor castCtor = (Constructor) ctor; + longest = castCtor; + } + } + if (longest == null) { + throw new IllegalArgumentException("Couldn't find any constructors for [" + clazz.getName() + "]"); + } + return longest; + } + + /** + * Scans the {@code .class} files to identify all classes and + * checks if they are subclasses of {@link Node}. + */ + @ParametersFactory + @SuppressWarnings("rawtypes") + public static List nodeSubclasses() throws IOException { + return subclassesOf(Node.class, CLASSNAME_FILTER).stream() + .filter(c -> testClassFor(c) == null) + .map(c -> new Object[] { c }) + .toList(); + } + + /** + * Build a list of arguments to use when calling + * {@code ctor} that make sense when {@code ctor} + * builds subclasses of {@link Node}. + */ + private Object[] ctorArgs(Constructor> ctor) throws Exception { + Type[] argTypes = ctor.getGenericParameterTypes(); + Object[] args = new Object[argTypes.length]; + for (int i = 0; i < argTypes.length; i++) { + final int currentArgIndex = i; + args[i] = randomValueOtherThanMany(candidate -> { + for (int a = 0; a < currentArgIndex; a++) { + if (Objects.equals(args[a], candidate)) { + return true; + } + } + return false; + }, () -> { + try { + return makeArg(ctor.getDeclaringClass(), argTypes[currentArgIndex]); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + return args; + } + + /** + * Make an argument to feed the {@link #subclass}'s ctor. + */ + protected Object makeArg(Type argType) { + try { + return makeArg(subclass, argType); + } catch (Exception e) { + // Wrap to make `randomValueOtherThan` happy. + throw new RuntimeException(e); + } + } + + /** + * Make an argument to feed to the constructor for {@code toBuildClass}. + */ + @SuppressWarnings("unchecked") + private Object makeArg(Class> toBuildClass, Type argType) throws Exception { + + if (argType instanceof ParameterizedType pt) { + if (pt.getRawType() == Map.class) { + return makeMap(toBuildClass, pt); + } + if (pt.getRawType() == List.class) { + return makeList(toBuildClass, pt); + } + if (pt.getRawType() == Set.class) { + return makeSet(toBuildClass, pt); + } + if (pt.getRawType() == EnumSet.class) { + @SuppressWarnings("rawtypes") + Enum enm = (Enum) makeArg(toBuildClass, pt.getActualTypeArguments()[0]); + return EnumSet.of(enm); + } + if (pt.getRawType() == Supplier.class) { + if (toBuildClass == AggExtractorInput.class) { + // AggValueInput just needs a valid java type in a supplier + Object o = randomBoolean() ? null : randomAlphaOfLength(5); + // But the supplier has to implement equals for randomValueOtherThan + return new Supplier<>() { + @Override + public Object get() { + return o; + } + + @Override + public int hashCode() { + return Objects.hash(o); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + Supplier other = (Supplier) obj; + return Objects.equals(o, other.get()); + } + }; + } + } + Object obj = pluggableMakeParameterizedArg(toBuildClass, pt); + if (obj != null) { + return obj; + } + throw new IllegalArgumentException("Unsupported parameterized type [" + pt + "], for " + toBuildClass.getSimpleName()); + } + if (argType instanceof WildcardType wt) { + if (wt.getLowerBounds().length > 0 || wt.getUpperBounds().length > 1) { + throw new IllegalArgumentException("Unsupported wildcard type [" + wt + "]"); + } + return makeArg(toBuildClass, wt.getUpperBounds()[0]); + } + Class argClass = (Class) argType; + + /* + * Sometimes all of the required type information isn't in the ctor + * so we have to hard code it here. + */ + if (toBuildClass == InnerAggregate.class) { + // InnerAggregate's AggregateFunction must be an EnclosedAgg. + if (argClass == AggregateFunction.class) { + return makeEnclosedAgg(); + } else if (argClass == CompoundAggregate.class) { + return makeCompoundAgg(); + } + } else if (toBuildClass == FieldAttribute.class) { + // `parent` is nullable. + if (argClass == FieldAttribute.class && randomBoolean()) { + return null; + } + } else if (toBuildClass == ChildrenAreAProperty.class) { + /* + * While any subclass of DummyFunction will do here we want to prevent + * stack overflow so we use the one without children. + */ + if (argClass == Dummy.class) { + return makeNode(NoChildren.class); + } + } else if (FullTextPredicate.class.isAssignableFrom(toBuildClass)) { + /* + * FullTextPredicate analyzes its string arguments on + * construction so they have to be valid. + */ + if (argClass == String.class) { + int size = between(0, 5); + StringBuilder b = new StringBuilder(); + for (int i = 0; i < size; i++) { + if (i != 0) { + b.append(';'); + } + b.append(randomAlphaOfLength(5)).append('=').append(randomAlphaOfLength(5)); + } + return b.toString(); + } + } else if (toBuildClass == Like.class) { + + if (argClass == LikePattern.class) { + return new LikePattern(randomAlphaOfLength(16), randomFrom('\\', '|', '/', '`')); + } + + } else { + Object postProcess = pluggableMakeArg(toBuildClass, argClass); + if (postProcess != null) { + return postProcess; + } + } + if (Expression.class == argClass) { + /* + * Rather than use any old subclass of expression lets + * use a simple one. Without this we're very prone to + * stackoverflow errors while building the tree. + */ + return UnresolvedAttributeTests.randomUnresolvedAttribute(); + } + if (EnrichPolicy.class == argClass) { + List enrichFields = randomSubsetOf(List.of("e1", "e2", "e3")); + return new EnrichPolicy(randomFrom("match", "range"), null, List.of(), randomFrom("m1", "m2"), enrichFields); + } + + if (Pipe.class == argClass) { + /* + * Similar to expressions, mock pipes to avoid + * stackoverflow errors while building the tree. + */ + return BinaryPipesTests.randomUnaryPipe(); + } + + if (Processor.class == argClass) { + /* + * Similar to expressions, mock pipes to avoid + * stackoverflow errors while building the tree. + */ + return new ConstantProcessor(randomAlphaOfLength(16)); + } + + if (Node.class.isAssignableFrom(argClass)) { + /* + * Rather than attempting to mock subclasses of node + * and emulate them we just try and instantiate an + * appropriate subclass + */ + @SuppressWarnings("unchecked") // safe because this is the lowest possible bounds for Node + Class> asNodeSubclass = (Class>) argType; + return makeNode(asNodeSubclass); + } + + if (argClass.isEnum()) { + // Can't mock enums but luckily we can just pick one + return randomFrom(argClass.getEnumConstants()); + } + if (argClass == boolean.class) { + // Can't mock primitives.... + return randomBoolean(); + } + if (argClass == int.class) { + return randomInt(); + } + if (argClass == String.class) { + // Nor strings + return randomAlphaOfLength(5); + } + if (argClass == Source.class) { + // Location is final and can't be mocked but we have a handy method to generate ones. + return SourceTests.randomSource(); + } + if (argClass == ZoneId.class) { + // ZoneId is a sealed class (cannot be mocked) starting with Java 19 + return randomZone(); + } + try { + return mock(argClass); + } catch (MockitoException e) { + throw new RuntimeException("failed to mock [" + argClass.getName() + "] for [" + toBuildClass.getName() + "]", e); + } + } + + protected Object makeCompoundAgg() throws Exception { + return makeArg(TestCompoundAggregate.class); + } + + protected Object makeEnclosedAgg() throws Exception { + return makeArg(TestEnclosedAgg.class); + } + + protected Object pluggableMakeArg(Class> toBuildClass, Class argClass) throws Exception { + return null; + } + + protected Object pluggableMakeParameterizedArg(Class> toBuildClass, ParameterizedType pt) { + return null; + } + + private List makeList(Class> toBuildClass, ParameterizedType listType) throws Exception { + return makeList(toBuildClass, listType, randomSizeForCollection(toBuildClass)); + } + + private List makeList(Class> toBuildClass, ParameterizedType listType, int size) throws Exception { + List list = new ArrayList<>(); + for (int i = 0; i < size; i++) { + list.add(makeArg(toBuildClass, listType.getActualTypeArguments()[0])); + } + return list; + } + + private Set makeSet(Class> toBuildClass, ParameterizedType listType) throws Exception { + return makeSet(toBuildClass, listType, randomSizeForCollection(toBuildClass)); + } + + private Set makeSet(Class> toBuildClass, ParameterizedType listType, int size) throws Exception { + Set list = new HashSet<>(); + for (int i = 0; i < size; i++) { + list.add(makeArg(toBuildClass, listType.getActualTypeArguments()[0])); + } + return list; + } + + private Object makeMap(Class> toBuildClass, ParameterizedType pt) throws Exception { + Map map = new HashMap<>(); + int size = randomSizeForCollection(toBuildClass); + while (map.size() < size) { + Object key = makeArg(toBuildClass, pt.getActualTypeArguments()[0]); + Object value = makeArg(toBuildClass, pt.getActualTypeArguments()[1]); + map.put(key, value); + } + return map; + } + + private int randomSizeForCollection(Class> toBuildClass) { + int minCollectionLength = 0; + int maxCollectionLength = 10; + + if (hasAtLeastTwoChildren(toBuildClass)) { + minCollectionLength = 2; + } + return between(minCollectionLength, maxCollectionLength); + } + + protected boolean hasAtLeastTwoChildren(Class> toBuildClass) { + return CLASSES_WITH_MIN_TWO_CHILDREN.stream().anyMatch(toBuildClass::equals); + } + + private List makeListOfSameSizeOtherThan(Type listType, List original) throws Exception { + if (original.isEmpty()) { + throw new IllegalArgumentException("Can't make a different empty list"); + } + return randomValueOtherThan(original, () -> { + try { + return makeList(subclass, (ParameterizedType) listType, original.size()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + } + + public > T makeNode(Class nodeClass) throws Exception { + if (Modifier.isAbstract(nodeClass.getModifiers())) { + nodeClass = randomFrom(innerSubclassesOf(nodeClass)); + } + Class testSubclassFor = testClassFor(nodeClass); + if (testSubclassFor != null) { + // Delegate to the test class for a node if there is one + Method m = testSubclassFor.getMethod("random" + Strings.capitalize(nodeClass.getSimpleName())); + assert Modifier.isStatic(m.getModifiers()) : "Expected static method, got:" + m; + return nodeClass.cast(m.invoke(null)); + } + Constructor ctor = longestCtor(nodeClass); + Object[] nodeCtorArgs = ctorArgs(ctor); + return ctor.newInstance(nodeCtorArgs); + } + + /** + * Cache of subclasses. We use a cache because it significantly speeds up + * the test. + */ + private static final Map, Set> subclassCache = new HashMap<>(); + + private static final Predicate CLASSNAME_FILTER = className -> { + // filter the class that are not interested + // (and IDE folders like eclipse) + if (className.startsWith("org.elasticsearch.xpack.esql.core") == false + && className.startsWith("org.elasticsearch.xpack.sql") == false + && className.startsWith("org.elasticsearch.xpack.eql") == false) { + return false; + } + return true; + }; + + protected Predicate pluggableClassNameFilter() { + return CLASSNAME_FILTER; + } + + private Set> innerSubclassesOf(Class clazz) throws IOException { + return subclassesOf(clazz, pluggableClassNameFilter()); + } + + public static Set> subclassesOf(Class clazz) throws IOException { + return subclassesOf(clazz, CLASSNAME_FILTER); + } + + /** + * Find all subclasses of a particular class. + */ + public static Set> subclassesOf(Class clazz, Predicate classNameFilter) throws IOException { + @SuppressWarnings("unchecked") // The map is built this way + Set> lookup = (Set>) subclassCache.get(clazz); + if (lookup != null) { + return lookup; + } + Set> results = new LinkedHashSet<>(); + String[] paths = System.getProperty("java.class.path").split(System.getProperty("path.separator")); + for (String path : paths) { + Path root = PathUtils.get(path); + int rootLength = root.toString().length() + 1; + + // load classes from jar files + // NIO FileSystem API is not used since it trips the SecurityManager + // https://bugs.openjdk.java.net/browse/JDK-8160798 + // so iterate the jar "by hand" + if (path.endsWith(".jar") && path.contains("x-pack-ql")) { + try (JarInputStream jar = jarStream(root)) { + JarEntry je = null; + while ((je = jar.getNextJarEntry()) != null) { + String name = je.getName(); + if (name.endsWith(".class")) { + String className = name.substring(0, name.length() - ".class".length()).replace("/", "."); + maybeLoadClass(clazz, className, root + "!/" + name, classNameFilter, results); + } + } + } + } + // for folders, just use the FileSystems API + else { + Files.walkFileTree(root, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (Files.isRegularFile(file) && file.getFileName().toString().endsWith(".class")) { + String fileName = file.toString(); + // Chop off the root and file extension + String className = fileName.substring(rootLength, fileName.length() - ".class".length()); + // Go from "path" style to class style + className = className.replace(PathUtils.getDefaultFileSystem().getSeparator(), "."); + maybeLoadClass(clazz, className, fileName, classNameFilter, results); + } + return FileVisitResult.CONTINUE; + } + }); + } + } + subclassCache.put(clazz, results); + return results; + } + + @SuppressForbidden(reason = "test reads from jar") + private static JarInputStream jarStream(Path path) throws IOException { + return new JarInputStream(path.toUri().toURL().openStream()); + } + + /** + * Load classes from predefined packages (hack to limit the scope) and if they match the hierarchy, add them to the cache + */ + private static void maybeLoadClass( + Class clazz, + String className, + String location, + Predicate classNameFilter, + Set> results + ) throws IOException { + if (classNameFilter.test(className) == false) { + return; + } + + Class c; + try { + c = Class.forName(className); + } catch (ClassNotFoundException e) { + throw new IOException("Couldn't load " + location, e); + } + + if (false == Modifier.isAbstract(c.getModifiers()) && false == c.isAnonymousClass() && clazz.isAssignableFrom(c)) { + Class s = c.asSubclass(clazz); + results.add(s); + } + } + + /** + * The test class for some subclass of node or {@code null} + * if there isn't such a class or it doesn't extend + * {@link AbstractNodeTestCase}. + */ + protected static Class testClassFor(Class nodeSubclass) { + String testClassName = nodeSubclass.getName() + "Tests"; + try { + Class c = Class.forName(testClassName); + if (AbstractNodeTestCase.class.isAssignableFrom(c)) { + return c; + } + return null; + } catch (ClassNotFoundException e) { + return null; + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/NodeTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/NodeTests.java new file mode 100644 index 000000000000..61ff9cdc809c --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/NodeTests.java @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.tree.SourceTests.randomSource; + +public class NodeTests extends ESTestCase { + public void testToString() { + assertEquals("NoChildren[thing]", new NoChildren(randomSource(), "thing").toString()); + { + ChildrenAreAProperty empty = new ChildrenAreAProperty(randomSource(), emptyList(), "thing"); + assertEquals("ChildrenAreAProperty[thing]", empty.toString()); + assertEquals( + "ChildrenAreAProperty[single]\n\\_ChildrenAreAProperty[thing]", + new ChildrenAreAProperty(randomSource(), singletonList(empty), "single").toString() + ); + assertEquals( + """ + ChildrenAreAProperty[many] + |_ChildrenAreAProperty[thing] + \\_ChildrenAreAProperty[thing]""", + new ChildrenAreAProperty(randomSource(), Arrays.asList(empty, empty), "many").toString() + ); + } + { + NoChildren empty = new NoChildren(randomSource(), "thing"); + assertEquals( + "AChildIsAProperty[single]\n" + "\\_NoChildren[thing]", + new AChildIsAProperty(randomSource(), empty, "single").toString() + ); + } + } + + public void testWithNullChild() { + List listWithNull = new ArrayList<>(); + listWithNull.add(null); + var e = expectThrows(QlIllegalArgumentException.class, () -> new ChildrenAreAProperty(randomSource(), listWithNull, "single")); + assertEquals("Null children are not allowed", e.getMessage()); + } + + public void testWithImmutableChildList() { + // It's good enough that the node can be created without throwing a NPE + var node = new ChildrenAreAProperty(randomSource(), List.of(), "single"); + assertEquals(node.children().size(), 0); + } + + public abstract static class Dummy extends Node { + private final String thing; + + public Dummy(Source source, List children, String thing) { + super(source, children); + this.thing = thing; + } + + public String thing() { + return thing; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != getClass()) { + return false; + } + Dummy other = (Dummy) obj; + return thing.equals(other.thing) && children().equals(other.children()); + } + + @Override + public int hashCode() { + return Objects.hash(thing, children()); + } + } + + public static class ChildrenAreAProperty extends Dummy { + public ChildrenAreAProperty(Source source, List children, String thing) { + super(source, children, thing); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, ChildrenAreAProperty::new, children(), thing()); + } + + @Override + public ChildrenAreAProperty replaceChildren(List newChildren) { + return new ChildrenAreAProperty(source(), newChildren, thing()); + } + } + + public static class AChildIsAProperty extends Dummy { + public AChildIsAProperty(Source source, Dummy child, String thing) { + super(source, singletonList(child), thing); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, AChildIsAProperty::new, child(), thing()); + } + + @Override + public AChildIsAProperty replaceChildren(List newChildren) { + return new AChildIsAProperty(source(), newChildren.get(0), thing()); + } + + public Dummy child() { + return children().get(0); + } + } + + public static class NoChildren extends Dummy { + public NoChildren(Source source, String thing) { + super(source, emptyList(), thing); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, NoChildren::new, thing()); + } + + @Override + public Dummy replaceChildren(List newChildren) { + throw new UnsupportedOperationException("no children to replace"); + } + } + + // Returns an empty list. The returned list may be backed various implementations, some + // allowing null some not - disallowing null disallows (throws NPE for) contains(null). + private static List emptyList() { + return randomFrom(List.of(), Collections.emptyList(), new ArrayList<>(), new LinkedList<>()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/SourceTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/SourceTests.java new file mode 100644 index 000000000000..b53d04bbb1e7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/SourceTests.java @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.tree; + +import org.elasticsearch.test.ESTestCase; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; + +public class SourceTests extends ESTestCase { + public static Source randomSource() { + return new Source(between(1, Integer.MAX_VALUE), between(1, Integer.MAX_VALUE), randomAlphaOfLength(25)); + } + + public static Source mutate(Source source) { + List> options = Arrays.asList( + l -> new Source( + randomValueOtherThan(l.source().getLineNumber(), () -> between(1, Integer.MAX_VALUE)), + l.source().getColumnNumber() - 1, + l.text() + ), + l -> new Source( + l.source().getLineNumber(), + randomValueOtherThan(l.source().getColumnNumber() - 1, () -> between(1, Integer.MAX_VALUE)), + l.text() + ) + ); + return randomFrom(options).apply(source); + } + + public void testEqualsAndHashCode() { + checkEqualsAndHashCode( + randomSource(), + l -> new Source(l.source().getLineNumber(), l.source().getColumnNumber() - 1, l.text()), + SourceTests::mutate + ); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/TestCompoundAggregate.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/TestCompoundAggregate.java new file mode 100644 index 000000000000..38eab9b8f335 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/TestCompoundAggregate.java @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.tree; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.CompoundAggregate; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.List; + +public class TestCompoundAggregate extends AggregateFunction implements CompoundAggregate { + + public TestCompoundAggregate(Source source, Expression field) { + super(source, field); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, TestCompoundAggregate::new, field()); + } + + @Override + public TestCompoundAggregate replaceChildren(List newChildren) { + return new TestCompoundAggregate(source(), newChildren.get(0)); + } + + @Override + public DataType dataType() { + return DataTypes.DOUBLE; + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/TestEnclosedAgg.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/TestEnclosedAgg.java new file mode 100644 index 000000000000..5d9e40df37e5 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/tree/TestEnclosedAgg.java @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.tree; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.AggregateFunction; +import org.elasticsearch.xpack.esql.core.expression.function.aggregate.EnclosedAgg; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; + +import java.util.List; + +public class TestEnclosedAgg extends AggregateFunction implements EnclosedAgg { + + public TestEnclosedAgg(Source source, Expression field) { + super(source, field); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, TestEnclosedAgg::new, field()); + } + + @Override + public TestEnclosedAgg replaceChildren(List newChildren) { + return new TestEnclosedAgg(source(), newChildren.get(0)); + } + + @Override + public String innerName() { + return "testEnclosed"; + } + + @Override + public DataType dataType() { + return DataTypes.DOUBLE; + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/type/DataTypeConversionTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/type/DataTypeConversionTests.java new file mode 100644 index 000000000000..80754857d7f2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/type/DataTypeConversionTests.java @@ -0,0 +1,588 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.versionfield.Version; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.ZonedDateTime; + +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.commonType; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.converterFor; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BYTE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SHORT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSUPPORTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asDateTime; + +public class DataTypeConversionTests extends ESTestCase { + + public void testConversionToString() { + DataType to = KEYWORD; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals("10.0", conversion.convert(10.0)); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + BigInteger bi = randomBigInteger(); + assertEquals(bi.toString(), conversion.convert(bi)); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals("1973-11-29T21:33:09.101Z", conversion.convert(asDateTime(123456789101L))); + assertEquals("1966-02-02T02:26:50.899Z", conversion.convert(asDateTime(-123456789101L))); + assertEquals("2020-05-01T10:20:30.123456789Z", conversion.convert(DateUtils.asDateTime("2020-05-01T10:20:30.123456789Z"))); + } + } + + /** + * Test conversion to long. + */ + public void testConversionToLong() { + DataType to = LONG; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals(10L, conversion.convert(10.0)); + assertEquals(10L, conversion.convert(10.1)); + assertEquals(11L, conversion.convert(10.6)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(Double.MAX_VALUE)); + assertEquals("[" + Double.MAX_VALUE + "] out of [long] range", e.getMessage()); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + BigInteger bi = BigInteger.valueOf(randomNonNegativeLong()); + assertEquals(bi.longValue(), conversion.convert(bi)); + + BigInteger longPlus = bi.add(BigInteger.valueOf(Long.MAX_VALUE)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(longPlus)); + assertEquals("[" + longPlus + "] out of [long] range", e.getMessage()); + } + { + Converter conversion = converterFor(INTEGER, to); + assertNull(conversion.convert(null)); + assertEquals(10L, conversion.convert(10)); + assertEquals(-134L, conversion.convert(-134)); + } + { + Converter conversion = converterFor(BOOLEAN, to); + assertNull(conversion.convert(null)); + assertEquals(1L, conversion.convert(true)); + assertEquals(0L, conversion.convert(false)); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals(123456789101L, conversion.convert(asDateTime(123456789101L))); + assertEquals(-123456789101L, conversion.convert(asDateTime(-123456789101L))); + // Nanos are ignored, only millis are used + assertEquals(1588328430123L, conversion.convert(DateUtils.asDateTime("2020-05-01T10:20:30.123456789Z"))); + } + { + Converter conversion = converterFor(KEYWORD, to); + assertNull(conversion.convert(null)); + assertEquals(1L, conversion.convert("1")); + assertEquals(0L, conversion.convert("-0")); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("0xff")); + assertEquals("cannot cast [0xff] to [long]", e.getMessage()); + } + } + + public void testConversionToDateTime() { + DataType to = DATETIME; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals(asDateTime(10L), conversion.convert(10.0)); + assertEquals(asDateTime(10L), conversion.convert(10.1)); + assertEquals(asDateTime(11L), conversion.convert(10.6)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(Double.MAX_VALUE)); + assertEquals("[" + Double.MAX_VALUE + "] out of [long] range", e.getMessage()); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + BigInteger bi = BigInteger.valueOf(randomNonNegativeLong()); + assertEquals(asDateTime(bi.longValue()), conversion.convert(bi)); + + BigInteger longPlus = bi.add(BigInteger.valueOf(Long.MAX_VALUE)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(longPlus)); + assertEquals("[" + longPlus + "] out of [long] range", e.getMessage()); + } + { + Converter conversion = converterFor(INTEGER, to); + assertNull(conversion.convert(null)); + assertEquals(asDateTime(10L), conversion.convert(10)); + assertEquals(asDateTime(-134L), conversion.convert(-134)); + } + { + Converter conversion = converterFor(BOOLEAN, to); + assertNull(conversion.convert(null)); + assertEquals(asDateTime(1), conversion.convert(true)); + assertEquals(asDateTime(0), conversion.convert(false)); + } + { + Converter conversion = converterFor(KEYWORD, to); + assertNull(conversion.convert(null)); + + assertEquals(asDateTime(0L), conversion.convert("1970-01-01")); + assertEquals(asDateTime(1000L), conversion.convert("1970-01-01T00:00:01Z")); + + assertEquals(asDateTime(1483228800000L), conversion.convert("2017-01-01T00:00:00Z")); + assertEquals(asDateTime(1483228800000L), conversion.convert("2017-01-01 00:00:00Z")); + + assertEquals(asDateTime(1483228800123L), conversion.convert("2017-01-01T00:00:00.123Z")); + assertEquals(asDateTime(1483228800123L), conversion.convert("2017-01-01 00:00:00.123Z")); + + assertEquals(asDateTime(18000321L), conversion.convert("1970-01-01T00:00:00.321-05:00")); + assertEquals(asDateTime(18000321L), conversion.convert("1970-01-01 00:00:00.321-05:00")); + + assertEquals(asDateTime(3849948162000321L), conversion.convert("+123970-01-01T00:00:00.321-05:00")); + assertEquals(asDateTime(3849948162000321L), conversion.convert("+123970-01-01 00:00:00.321-05:00")); + + assertEquals(asDateTime(-818587277999679L), conversion.convert("-23970-01-01T00:00:00.321-05:00")); + assertEquals(asDateTime(-818587277999679L), conversion.convert("-23970-01-01 00:00:00.321-05:00")); + + // double check back and forth conversion + ZonedDateTime dt = org.elasticsearch.common.time.DateUtils.nowWithMillisResolution(); + Converter forward = converterFor(DATETIME, KEYWORD); + Converter back = converterFor(KEYWORD, DATETIME); + assertEquals(dt, back.convert(forward.convert(dt))); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("0xff")); + assertEquals("cannot cast [0xff] to [datetime]: Text '0xff' could not be parsed at index 0", e.getMessage()); + } + } + + public void testConversionToFloat() { + DataType to = FLOAT; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals(10.0f, (float) conversion.convert(10.0d), 0.00001); + assertEquals(10.1f, (float) conversion.convert(10.1d), 0.00001); + assertEquals(10.6f, (float) conversion.convert(10.6d), 0.00001); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + + BigInteger bi = randomBigInteger(); + assertEquals(bi.floatValue(), (float) conversion.convert(bi), 0); + } + { + Converter conversion = converterFor(INTEGER, to); + assertNull(conversion.convert(null)); + assertEquals(10.0f, (float) conversion.convert(10), 0.00001); + assertEquals(-134.0f, (float) conversion.convert(-134), 0.00001); + } + { + Converter conversion = converterFor(BOOLEAN, to); + assertNull(conversion.convert(null)); + assertEquals(1.0f, (float) conversion.convert(true), 0); + assertEquals(0.0f, (float) conversion.convert(false), 0); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals(1.23456789101E11f, (float) conversion.convert(asDateTime(123456789101L)), 0); + assertEquals(-1.23456789101E11f, (float) conversion.convert(asDateTime(-123456789101L)), 0); + // Nanos are ignored, only millis are used + assertEquals(1.5883284E12f, conversion.convert(DateUtils.asDateTime("2020-05-01T10:20:30.123456789Z"))); + } + { + Converter conversion = converterFor(KEYWORD, to); + assertNull(conversion.convert(null)); + assertEquals(1.0f, (float) conversion.convert("1"), 0); + assertEquals(0.0f, (float) conversion.convert("-0"), 0); + assertEquals(12.776f, (float) conversion.convert("12.776"), 0.00001); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("0xff")); + assertEquals("cannot cast [0xff] to [float]", e.getMessage()); + } + } + + public void testConversionToDouble() { + DataType to = DOUBLE; + { + Converter conversion = converterFor(FLOAT, to); + assertNull(conversion.convert(null)); + assertEquals(10.0, (double) conversion.convert(10.0f), 0.00001); + assertEquals(10.1, (double) conversion.convert(10.1f), 0.00001); + assertEquals(10.6, (double) conversion.convert(10.6f), 0.00001); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + + BigInteger bi = randomBigInteger(); + assertEquals(bi.doubleValue(), (double) conversion.convert(bi), 0); + } + { + Converter conversion = converterFor(INTEGER, to); + assertNull(conversion.convert(null)); + assertEquals(10.0, (double) conversion.convert(10), 0.00001); + assertEquals(-134.0, (double) conversion.convert(-134), 0.00001); + } + { + Converter conversion = converterFor(BOOLEAN, to); + assertNull(conversion.convert(null)); + assertEquals(1.0, (double) conversion.convert(true), 0); + assertEquals(0.0, (double) conversion.convert(false), 0); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals(1.23456789101E11, (double) conversion.convert(asDateTime(123456789101L)), 0); + assertEquals(-1.23456789101E11, (double) conversion.convert(asDateTime(-123456789101L)), 0); + // Nanos are ignored, only millis are used + assertEquals(1.588328430123E12, conversion.convert(DateUtils.asDateTime("2020-05-01T10:20:30.123456789Z"))); + } + { + Converter conversion = converterFor(KEYWORD, to); + assertNull(conversion.convert(null)); + assertEquals(1.0, (double) conversion.convert("1"), 0); + assertEquals(0.0, (double) conversion.convert("-0"), 0); + assertEquals(12.776, (double) conversion.convert("12.776"), 0.00001); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("0xff")); + assertEquals("cannot cast [0xff] to [double]", e.getMessage()); + } + } + + public void testConversionToBoolean() { + DataType to = BOOLEAN; + { + Converter conversion = converterFor(FLOAT, to); + assertNull(conversion.convert(null)); + assertEquals(true, conversion.convert(10.0f)); + assertEquals(true, conversion.convert(-10.0f)); + assertEquals(false, conversion.convert(0.0f)); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + assertEquals(true, conversion.convert(BigInteger.valueOf(randomNonNegativeLong()))); + assertEquals(false, conversion.convert(BigInteger.ZERO)); + } + { + Converter conversion = converterFor(INTEGER, to); + assertNull(conversion.convert(null)); + assertEquals(true, conversion.convert(10)); + assertEquals(true, conversion.convert(-10)); + assertEquals(false, conversion.convert(0)); + } + { + Converter conversion = converterFor(LONG, to); + assertNull(conversion.convert(null)); + assertEquals(true, conversion.convert(10L)); + assertEquals(true, conversion.convert(-10L)); + assertEquals(false, conversion.convert(0L)); + } + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals(true, conversion.convert(10.0d)); + assertEquals(true, conversion.convert(-10.0d)); + assertEquals(false, conversion.convert(0.0d)); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals(true, conversion.convert(asDateTime(123456789101L))); + assertEquals(true, conversion.convert(asDateTime(-123456789101L))); + assertEquals(false, conversion.convert(asDateTime(0L))); + } + { + Converter conversion = converterFor(KEYWORD, to); + assertNull(conversion.convert(null)); + // We only handled upper and lower case true and false + assertEquals(true, conversion.convert("true")); + assertEquals(false, conversion.convert("false")); + assertEquals(true, conversion.convert("True")); + assertEquals(false, conversion.convert("fAlSe")); + // Everything else should fail + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("10")); + assertEquals("cannot cast [10] to [boolean]", e.getMessage()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("-1")); + assertEquals("cannot cast [-1] to [boolean]", e.getMessage()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("0")); + assertEquals("cannot cast [0] to [boolean]", e.getMessage()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("blah")); + assertEquals("cannot cast [blah] to [boolean]", e.getMessage()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("Yes")); + assertEquals("cannot cast [Yes] to [boolean]", e.getMessage()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("nO")); + assertEquals("cannot cast [nO] to [boolean]", e.getMessage()); + } + } + + public void testConversionToUnsignedLong() { + DataType to = UNSIGNED_LONG; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + double d = Math.abs(randomDouble()); + assertEquals(BigDecimal.valueOf(d).toBigInteger(), conversion.convert(d)); + + Double ulmAsDouble = UNSIGNED_LONG_MAX.doubleValue(); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(ulmAsDouble)); + assertEquals("[" + ulmAsDouble + "] out of [unsigned_long] range", e.getMessage()); + + Double nd = -Math.abs(randomDouble()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(nd)); + assertEquals("[" + nd + "] out of [unsigned_long] range", e.getMessage()); + } + { + Converter conversion = converterFor(LONG, to); + assertNull(conversion.convert(null)); + + BigInteger bi = BigInteger.valueOf(randomNonNegativeLong()); + assertEquals(bi, conversion.convert(bi.longValue())); + + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(bi.negate())); + assertEquals("[" + bi.negate() + "] out of [unsigned_long] range", e.getMessage()); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + + long l = randomNonNegativeLong(); + assertEquals(BigInteger.valueOf(l), conversion.convert(asDateTime(l))); + + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(asDateTime(-l))); + assertEquals("[" + -l + "] out of [unsigned_long] range", e.getMessage()); + } + { + Converter conversion = converterFor(BOOLEAN, to); + assertNull(conversion.convert(null)); + + assertEquals(BigInteger.ONE, conversion.convert(true)); + assertEquals(BigInteger.ZERO, conversion.convert(false)); + } + { + Converter conversion = converterFor(KEYWORD, to); + assertNull(conversion.convert(null)); + BigInteger bi = randomBigInteger(); + assertEquals(bi, conversion.convert(bi.toString())); + + assertEquals(UNSIGNED_LONG_MAX, conversion.convert(UNSIGNED_LONG_MAX.toString())); + assertEquals(UNSIGNED_LONG_MAX, conversion.convert(UNSIGNED_LONG_MAX.toString() + ".0")); + + assertEquals(bi, conversion.convert(bi.toString() + "." + randomNonNegativeLong())); + + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(BigInteger.ONE.negate().toString())); + assertEquals("[-1] out of [unsigned_long] range", e.getMessage()); + e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(UNSIGNED_LONG_MAX.add(BigInteger.ONE).toString())); + assertEquals("[" + UNSIGNED_LONG_MAX.add(BigInteger.ONE).toString() + "] out of [unsigned_long] range", e.getMessage()); + } + } + + public void testConversionToInt() { + DataType to = INTEGER; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals(10, conversion.convert(10.0)); + assertEquals(10, conversion.convert(10.1)); + assertEquals(11, conversion.convert(10.6)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(Long.MAX_VALUE)); + assertEquals("[" + Long.MAX_VALUE + "] out of [integer] range", e.getMessage()); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + BigInteger bi = BigInteger.valueOf(randomIntBetween(0, Integer.MAX_VALUE)); + assertEquals(bi.intValueExact(), conversion.convert(bi)); + + BigInteger bip = BigInteger.valueOf(randomLongBetween(Integer.MAX_VALUE, Long.MAX_VALUE)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(bip)); + assertEquals("[" + bip + "] out of [integer] range", e.getMessage()); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals(12345678, conversion.convert(asDateTime(12345678L))); + assertEquals(223456789, conversion.convert(asDateTime(223456789L))); + assertEquals(-123456789, conversion.convert(asDateTime(-123456789L))); + // Nanos are ignored, only millis are used + assertEquals(62123, conversion.convert(DateUtils.asDateTime("1970-01-01T00:01:02.123456789Z"))); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(asDateTime(Long.MAX_VALUE))); + assertEquals("[" + Long.MAX_VALUE + "] out of [integer] range", e.getMessage()); + } + } + + public void testConversionToShort() { + DataType to = SHORT; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals((short) 10, conversion.convert(10.0)); + assertEquals((short) 10, conversion.convert(10.1)); + assertEquals((short) 11, conversion.convert(10.6)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(Integer.MAX_VALUE)); + assertEquals("[" + Integer.MAX_VALUE + "] out of [short] range", e.getMessage()); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + BigInteger bi = BigInteger.valueOf(randomIntBetween(0, Short.MAX_VALUE)); + assertEquals(bi.shortValueExact(), conversion.convert(bi)); + + BigInteger bip = BigInteger.valueOf(randomLongBetween(Short.MAX_VALUE, Long.MAX_VALUE)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(bip)); + assertEquals("[" + bip + "] out of [short] range", e.getMessage()); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals((short) 12345, conversion.convert(asDateTime(12345L))); + assertEquals((short) -12345, conversion.convert(asDateTime(-12345L))); + // Nanos are ignored, only millis are used + assertEquals((short) 1123, conversion.convert(DateUtils.asDateTime("1970-01-01T00:00:01.123456789Z"))); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(asDateTime(Integer.MAX_VALUE))); + assertEquals("[" + Integer.MAX_VALUE + "] out of [short] range", e.getMessage()); + } + } + + public void testConversionToByte() { + DataType to = BYTE; + { + Converter conversion = converterFor(DOUBLE, to); + assertNull(conversion.convert(null)); + assertEquals((byte) 10, conversion.convert(10.0)); + assertEquals((byte) 10, conversion.convert(10.1)); + assertEquals((byte) 11, conversion.convert(10.6)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(Short.MAX_VALUE)); + assertEquals("[" + Short.MAX_VALUE + "] out of [byte] range", e.getMessage()); + } + { + Converter conversion = converterFor(UNSIGNED_LONG, to); + assertNull(conversion.convert(null)); + BigInteger bi = BigInteger.valueOf(randomIntBetween(0, Byte.MAX_VALUE)); + assertEquals(bi.byteValueExact(), conversion.convert(bi)); + + BigInteger bip = BigInteger.valueOf(randomLongBetween(Byte.MAX_VALUE, Long.MAX_VALUE)); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(bip)); + assertEquals("[" + bip + "] out of [byte] range", e.getMessage()); + } + { + Converter conversion = converterFor(DATETIME, to); + assertNull(conversion.convert(null)); + assertEquals((byte) 123, conversion.convert(asDateTime(123L))); + assertEquals((byte) -123, conversion.convert(asDateTime(-123L))); + // Nanos are ignored, only millis are used + assertEquals((byte) 123, conversion.convert(DateUtils.asDateTime("1970-01-01T00:00:00.123456789Z"))); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert(asDateTime(Integer.MAX_VALUE))); + assertEquals("[" + Integer.MAX_VALUE + "] out of [byte] range", e.getMessage()); + } + } + + public void testConversionToNull() { + Converter conversion = converterFor(DOUBLE, NULL); + assertNull(conversion.convert(null)); + assertNull(conversion.convert(10.0)); + } + + public void testConversionFromNull() { + Converter conversion = converterFor(NULL, INTEGER); + assertNull(conversion.convert(null)); + assertNull(conversion.convert(10)); + } + + public void testConversionToIdentity() { + Converter conversion = converterFor(INTEGER, INTEGER); + assertNull(conversion.convert(null)); + assertEquals(10, conversion.convert(10)); + } + + public void testCommonType() { + assertEquals(BOOLEAN, commonType(BOOLEAN, NULL)); + assertEquals(BOOLEAN, commonType(NULL, BOOLEAN)); + assertEquals(BOOLEAN, commonType(BOOLEAN, BOOLEAN)); + assertEquals(NULL, commonType(NULL, NULL)); + assertEquals(INTEGER, commonType(INTEGER, KEYWORD)); + assertEquals(LONG, commonType(TEXT, LONG)); + assertEquals(SHORT, commonType(SHORT, BYTE)); + assertEquals(FLOAT, commonType(BYTE, FLOAT)); + assertEquals(FLOAT, commonType(FLOAT, INTEGER)); + assertEquals(UNSIGNED_LONG, commonType(UNSIGNED_LONG, LONG)); + assertEquals(DOUBLE, commonType(DOUBLE, FLOAT)); + assertEquals(FLOAT, commonType(FLOAT, UNSIGNED_LONG)); + + // strings + assertEquals(TEXT, commonType(TEXT, KEYWORD)); + assertEquals(TEXT, commonType(KEYWORD, TEXT)); + } + + public void testEsDataTypes() { + for (DataType type : DataTypes.types()) { + assertEquals(type, DataTypes.fromTypeName(type.typeName())); + } + } + + public void testConversionToUnsupported() { + Exception e = expectThrows(InvalidArgumentException.class, () -> DataTypeConverter.convert(Integer.valueOf(1), UNSUPPORTED)); + assertEquals("cannot convert from [1], type [integer] to [unsupported]", e.getMessage()); + } + + public void testStringToIp() { + Converter conversion = converterFor(KEYWORD, IP); + assertNull(conversion.convert(null)); + assertEquals("192.168.1.1", conversion.convert("192.168.1.1")); + Exception e = expectThrows(InvalidArgumentException.class, () -> conversion.convert("10.1.1.300")); + assertEquals("[10.1.1.300] is not a valid IPv4 or IPv6 address", e.getMessage()); + } + + public void testIpToString() { + Source s = new Source(Location.EMPTY, "10.0.0.1"); + Converter ipToString = converterFor(IP, KEYWORD); + assertEquals("10.0.0.1", ipToString.convert(new Literal(s, "10.0.0.1", IP))); + Converter stringToIp = converterFor(KEYWORD, IP); + assertEquals("10.0.0.1", ipToString.convert(stringToIp.convert(new Literal(s, "10.0.0.1", KEYWORD)))); + } + + public void testStringToVersion() { + Converter conversion = converterFor(randomFrom(TEXT, KEYWORD), VERSION); + assertNull(conversion.convert(null)); + assertEquals(new Version("2.1.4").toString(), conversion.convert("2.1.4").toString()); + assertEquals(new Version("2.1.4").toBytesRef(), ((Version) conversion.convert("2.1.4")).toBytesRef()); + assertEquals(new Version("2.1.4-SNAPSHOT").toString(), conversion.convert("2.1.4-SNAPSHOT").toString()); + assertEquals(new Version("2.1.4-SNAPSHOT").toBytesRef(), ((Version) conversion.convert("2.1.4-SNAPSHOT")).toBytesRef()); + } + + public void testVersionToString() { + Source s = new Source(Location.EMPTY, "2.1.4"); + Source s2 = new Source(Location.EMPTY, "2.1.4-SNAPSHOT"); + DataType stringType = randomFrom(TEXT, KEYWORD); + Converter versionToString = converterFor(VERSION, stringType); + assertEquals("2.1.4", versionToString.convert(new Literal(s, "2.1.4", VERSION))); + assertEquals("2.1.4-SNAPSHOT", versionToString.convert(new Literal(s2, "2.1.4-SNAPSHOT", VERSION))); + Converter stringToVersion = converterFor(stringType, VERSION); + assertEquals("2.1.4", versionToString.convert(stringToVersion.convert(new Literal(s, "2.1.4", stringType)))); + assertEquals("2.1.4-SNAPSHOT", versionToString.convert(stringToVersion.convert(new Literal(s2, "2.1.4-SNAPSHOT", stringType)))); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/type/TypesTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/type/TypesTests.java new file mode 100644 index 000000000000..b3be18156ab8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/type/TypesTests.java @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +package org.elasticsearch.xpack.esql.core.type; + +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xcontent.json.JsonXContent; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import static java.util.Collections.emptyMap; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NESTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.OBJECT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; + +public class TypesTests extends ESTestCase { + + public void testNullMap() { + Map fromEs = Types.fromEs(DefaultDataTypeRegistry.INSTANCE, null); + assertThat(fromEs.isEmpty(), is(true)); + } + + public void testEmptyMap() { + Map fromEs = Types.fromEs(DefaultDataTypeRegistry.INSTANCE, emptyMap()); + assertThat(fromEs.isEmpty(), is(true)); + } + + public void testBasicMapping() { + Map mapping = loadMapping("mapping-basic.json"); + assertThat(mapping.size(), is(7)); + assertThat(mapping.get("emp_no").getDataType(), is(INTEGER)); + assertThat(mapping.get("first_name"), instanceOf(TextEsField.class)); + assertThat(mapping.get("last_name").getDataType(), is(TEXT)); + assertThat(mapping.get("gender").getDataType(), is(KEYWORD)); + assertThat(mapping.get("salary").getDataType(), is(INTEGER)); + assertThat(mapping.get("_meta_field").getDataType(), is(KEYWORD)); + } + + public void testDefaultStringMapping() { + Map mapping = loadMapping("mapping-default-string.json"); + + assertThat(mapping.size(), is(1)); + assertThat(mapping.get("dep_no").getDataType(), is(TEXT)); + } + + public void testTextField() { + Map mapping = loadMapping("mapping-text.json"); + + assertThat(mapping.size(), is(1)); + EsField type = mapping.get("full_name"); + assertThat(type, instanceOf(TextEsField.class)); + assertThat(type.isAggregatable(), is(false)); + TextEsField ttype = (TextEsField) type; + assertThat(ttype.isAggregatable(), is(false)); + } + + public void testKeywordField() { + Map mapping = loadMapping("mapping-keyword.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("full_name"); + assertThat(field, instanceOf(KeywordEsField.class)); + assertThat(field.isAggregatable(), is(true)); + } + + public void testDateField() { + Map mapping = loadMapping("mapping-date.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("date"); + assertThat(field.getDataType(), is(DATETIME)); + assertThat(field.isAggregatable(), is(true)); + } + + public void testDateNoFormat() { + Map mapping = loadMapping("mapping-date-no-format.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("date"); + assertThat(field.getDataType(), is(DATETIME)); + assertThat(field.isAggregatable(), is(true)); + assertThat(field, is(instanceOf(DateEsField.class))); + } + + public void testDateMulti() { + Map mapping = loadMapping("mapping-date-multi.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("date"); + assertThat(field.getDataType(), is(DATETIME)); + assertThat(field.isAggregatable(), is(true)); + assertThat(field, is(instanceOf(DateEsField.class))); + } + + public void testDateNanosField() { + Map mapping = loadMapping("mapping-date_nanos.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("date_nanos"); + assertThat(field.getDataType(), is(DATETIME)); + assertThat(field.isAggregatable(), is(true)); + assertThat(field, is(instanceOf(DateEsField.class))); + } + + public void testDocValueField() { + Map mapping = loadMapping("mapping-docvalues.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("session_id"); + assertThat(field, instanceOf(KeywordEsField.class)); + // assertThat(field.getPrecision(), is(15)); + assertThat(field.isAggregatable(), is(false)); + } + + public void testDottedField() { + Map mapping = loadMapping("mapping-object.json"); + + assertThat(mapping.size(), is(2)); + EsField field = mapping.get("manager"); + assertThat(DataTypes.isPrimitive(field.getDataType()), is(false)); + assertThat(field.getDataType(), is(OBJECT)); + Map children = field.getProperties(); + assertThat(children.size(), is(2)); + EsField names = children.get("name"); + children = names.getProperties(); + assertThat(children.size(), is(2)); + assertThat(children.get("first").getDataType(), is(TEXT)); + } + + public void testMultiField() { + Map mapping = loadMapping("mapping-multi-field.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("text"); + assertThat(DataTypes.isPrimitive(field.getDataType()), is(true)); + assertThat(field.getDataType(), is(TEXT)); + Map fields = field.getProperties(); + assertThat(fields.size(), is(4)); + assertThat(fields.get("raw").getDataType(), is(KEYWORD)); + assertThat(fields.get("english").getDataType(), is(TEXT)); + assertThat(fields.get("wildcard").getDataType(), is(KEYWORD)); + } + + public void testMultiFieldTooManyOptions() { + Map mapping = loadMapping("mapping-multi-field.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("text"); + assertThat(DataTypes.isPrimitive(field.getDataType()), is(true)); + assertThat(field, instanceOf(TextEsField.class)); + Map fields = field.getProperties(); + assertThat(fields.size(), is(4)); + assertThat(fields.get("raw").getDataType(), is(KEYWORD)); + assertThat(fields.get("english").getDataType(), is(TEXT)); + assertThat(fields.get("wildcard").getDataType(), is(KEYWORD)); + } + + public void testNestedDoc() { + Map mapping = loadMapping("mapping-nested.json"); + + assertThat(mapping.size(), is(1)); + EsField field = mapping.get("dep"); + assertThat(DataTypes.isPrimitive(field.getDataType()), is(false)); + assertThat(field.getDataType(), is(NESTED)); + Map children = field.getProperties(); + assertThat(children.size(), is(4)); + assertThat(children.get("dep_name").getDataType(), is(TEXT)); + assertThat(children.get("start_date").getDataType(), is(DATETIME)); + } + + public void testIpField() { + Map mapping = loadMapping("mapping-ip.json"); + assertThat(mapping.size(), is(1)); + EsField dt = mapping.get("ip_addr"); + assertThat(dt.getDataType().typeName(), is("ip")); + } + + public void testVersionField() { + Map mapping = loadMapping("mapping-version.json"); + assertThat(mapping.size(), is(1)); + EsField dt = mapping.get("version_number"); + assertThat(dt.getDataType().typeName(), is("version")); + } + + public void testConstantKeywordField() { + Map mapping = loadMapping("mapping-constant-keyword.json"); + assertThat(mapping.size(), is(1)); + EsField dt = mapping.get("full_name"); + assertThat(dt.getDataType().typeName(), is("keyword")); + } + + public void testWildcardField() { + Map mapping = loadMapping("mapping-wildcard.json"); + assertThat(mapping.size(), is(1)); + EsField dt = mapping.get("full_name"); + assertThat(dt.getDataType().typeName(), is("keyword")); + } + + public void testUnsupportedTypes() { + Map mapping = loadMapping("mapping-unsupported.json"); + EsField dt = mapping.get("range"); + assertThat(dt.getDataType().typeName(), is("unsupported")); + dt = mapping.get("time_frame"); + assertThat(dt.getDataType().typeName(), is("unsupported")); + dt = mapping.get("flat"); + assertThat(dt.getDataType().typeName(), is("unsupported")); + } + + public static Map loadMapping(String name) { + return loadMapping(DefaultDataTypeRegistry.INSTANCE, name, null); + } + + public static Map loadMapping(String name, boolean ordered) { + return loadMapping(DefaultDataTypeRegistry.INSTANCE, name, ordered); + } + + public static Map loadMapping(DataTypeRegistry registry, String name) { + return loadMapping(registry, name, null); + } + + public static Map loadMapping(DataTypeRegistry registry, String name, Boolean ordered) { + InputStream stream = TypesTests.class.getResourceAsStream("/" + name); + assertNotNull("Could not find mapping resource:" + name, stream); + return loadMapping(registry, stream, ordered); + } + + private static Map loadMapping(DataTypeRegistry registry, InputStream stream, Boolean ordered) { + boolean order = ordered != null ? ordered.booleanValue() : randomBoolean(); + try (InputStream in = stream) { + Map map = XContentHelper.convertToMap(JsonXContent.jsonXContent, in, order); + return Types.fromEs(registry, map); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/NumericUtilsTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/NumericUtilsTests.java new file mode 100644 index 000000000000..148c9a841a73 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/NumericUtilsTests.java @@ -0,0 +1,147 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.test.ESTestCase; + +import java.math.BigInteger; +import java.util.function.BiFunction; + +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsBigInteger; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.parseIntegral; +import static org.hamcrest.Matchers.equalTo; + +public class NumericUtilsTests extends ESTestCase { + + public void testUnsignedLongAddExact() { + assertThat(addExact("9223372036854775808", "0"), equalTo("9223372036854775808")); + assertThat(addExact("9223372036854775807", "0"), equalTo("9223372036854775807")); + assertThat(addExact("9223372036854775808", "1"), equalTo("9223372036854775809")); + assertThat(addExact("9223372036854775807", "1"), equalTo("9223372036854775808")); + + assertThat(addExact("0", "0"), equalTo("0")); + assertThat(addExact("1", "1"), equalTo("2")); + + assertThat(addExact("9223372036854775808", "9223372036854775807"), equalTo("18446744073709551615")); + assertThat(addExact("9223372036854775807", "9223372036854775807"), equalTo("18446744073709551614")); + assertThat(addExact("9223372036854775806", "9223372036854775807"), equalTo("18446744073709551613")); + assertThat(addExact("9223372036854775805", "9223372036854775807"), equalTo("18446744073709551612")); + + assertThat(addExact("18446744073709551612", "3"), equalTo("18446744073709551615")); + assertThat(addExact("18446744073709551613", "2"), equalTo("18446744073709551615")); + assertThat(addExact("18446744073709551614", "1"), equalTo("18446744073709551615")); + assertThat(addExact("18446744073709551615", "0"), equalTo("18446744073709551615")); + + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "1")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "2")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "3")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551614", "2")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "18446744073709551615")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "18446744073709551614")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "9223372036854775808")); + expectThrows(ArithmeticException.class, () -> addExact("18446744073709551615", "9223372036854775807")); + expectThrows(ArithmeticException.class, () -> addExact("9223372036854775808", "9223372036854775808")); + expectThrows(ArithmeticException.class, () -> addExact("9223372036854775807", "9223372036854775809")); + } + + public void testUnsignedLongSubtractExact() { + assertThat(subExact("18446744073709551615", "0"), equalTo("18446744073709551615")); + assertThat(subExact("18446744073709551615", "18446744073709551615"), equalTo("0")); + + assertThat(subExact("18446744073709551615", "9223372036854775808"), equalTo("9223372036854775807")); + assertThat(subExact("18446744073709551615", "9223372036854775807"), equalTo("9223372036854775808")); + assertThat(subExact("18446744073709551615", "9223372036854775806"), equalTo("9223372036854775809")); + assertThat(subExact("18446744073709551614", "9223372036854775808"), equalTo("9223372036854775806")); + assertThat(subExact("18446744073709551614", "9223372036854775807"), equalTo("9223372036854775807")); + + assertThat(subExact("9223372036854775809", "9223372036854775809"), equalTo("0")); + assertThat(subExact("9223372036854775808", "9223372036854775808"), equalTo("0")); + + assertThat(subExact("9223372036854775808", "1"), equalTo("9223372036854775807")); + assertThat(subExact("9223372036854775807", "1"), equalTo("9223372036854775806")); + assertThat(subExact("9223372036854775808", "0"), equalTo("9223372036854775808")); + assertThat(subExact("9223372036854775807", "0"), equalTo("9223372036854775807")); + + assertThat(subExact("0", "0"), equalTo("0")); + assertThat(subExact("1", "1"), equalTo("0")); + + expectThrows(ArithmeticException.class, () -> subExact("9223372036854775807", "9223372036854775808")); + expectThrows(ArithmeticException.class, () -> subExact("9223372036854775805", "9223372036854775808")); + expectThrows(ArithmeticException.class, () -> subExact("9223372036854775805", "9223372036854775806")); + expectThrows(ArithmeticException.class, () -> subExact("0", "9223372036854775808")); + expectThrows(ArithmeticException.class, () -> subExact("0", "9223372036854775807")); + expectThrows(ArithmeticException.class, () -> subExact("0", "9223372036854775805")); + } + + // 18446744073709551615 = 3 * 5 * 17 * 257 * 641 * 65537 * 6700417 + public void testUnsignedLongMultiplyExact() { + assertThat(mulExact("6148914691236517205", "3"), equalTo("18446744073709551615")); + expectThrows(ArithmeticException.class, () -> mulExact("6148914691236517205", "4")); + expectThrows(ArithmeticException.class, () -> mulExact("6148914691236517206", "3")); + + assertThat(mulExact("3689348814741910323", "5"), equalTo("18446744073709551615")); + expectThrows(ArithmeticException.class, () -> mulExact("3689348814741910324", "5")); + expectThrows(ArithmeticException.class, () -> mulExact("3689348814741910323", "6")); + + assertThat(mulExact("6700417", "2753074036095"), equalTo("18446744073709551615")); + expectThrows(ArithmeticException.class, () -> mulExact("6700418", "2753074036095")); + expectThrows(ArithmeticException.class, () -> mulExact("6700417", "2753074036096")); + + assertThat(mulExact("1844674407370955161", "0"), equalTo("0")); + assertThat(mulExact("1844674407370955161", "9"), equalTo("16602069666338596449")); + assertThat(mulExact("1844674407370955161", "10"), equalTo("18446744073709551610")); + expectThrows(ArithmeticException.class, () -> mulExact("1844674407370955161", "11")); + + assertThat(mulExact("18446744073709551615", "1"), equalTo("18446744073709551615")); + expectThrows(ArithmeticException.class, () -> mulExact("18446744073709551615", "2")); + expectThrows(ArithmeticException.class, () -> mulExact("18446744073709551615", "10")); + expectThrows(ArithmeticException.class, () -> mulExact("18446744073709551615", "18446744073709551615")); + + assertThat(mulExact("9223372036854775807", "2"), equalTo("18446744073709551614")); + expectThrows(ArithmeticException.class, () -> mulExact("9223372036854775808", "2")); + expectThrows(ArithmeticException.class, () -> mulExact("9223372036854775807", "3")); + expectThrows(ArithmeticException.class, () -> mulExact("9223372036854775808", "9223372036854775808")); + expectThrows(ArithmeticException.class, () -> mulExact("9223372036854775807", "9223372036854775807")); + expectThrows(ArithmeticException.class, () -> mulExact("9223372036854775807", "9223372036854775808")); + + assertThat(mulExact("1", "1"), equalTo("1")); + assertThat(mulExact("0", "1"), equalTo("0")); + assertThat(mulExact("0", "0"), equalTo("0")); + } + + public void testRoundTripConversion() { + BigInteger b = randomUnsignedLongBetween(BigInteger.ZERO, UNSIGNED_LONG_MAX); + assertThat(b, equalTo(unsignedLongAsBigInteger(asLongUnsigned(b)))); + } + + private static String addExact(String x, String y) { + return exactOperation(x, y, NumericUtils::unsignedLongAddExact); + } + + private static String subExact(String x, String y) { + return exactOperation(x, y, NumericUtils::unsignedLongSubtractExact); + } + + private static String mulExact(String x, String y) { + return exactOperation(x, y, NumericUtils::unsignedLongMultiplyExact); + } + + private static String exactOperation(String x, String y, BiFunction operation) { + long xl = parseUnsignedLong(x); + long yl = parseUnsignedLong(y); + long rl = operation.apply(xl, yl); + return unsignedLongAsNumber(rl).toString(); + } + + private static long parseUnsignedLong(String number) { + Number n = parseIntegral(number); + return n instanceof BigInteger bi ? asLongUnsigned(bi) : asLongUnsigned(n.longValue()); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/QueriesTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/QueriesTests.java new file mode 100644 index 000000000000..c5f4eb2ba828 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/QueriesTests.java @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.test.ESTestCase; + +import static java.util.Arrays.asList; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.in; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.sameInstance; + +public class QueriesTests extends ESTestCase { + + private static QueryBuilder randomNonBoolQuery() { + return randomFrom( + random(), + QueryBuilders::matchAllQuery, + QueryBuilders::idsQuery, + () -> QueryBuilders.rangeQuery(randomRealisticUnicodeOfLength(5)), + () -> QueryBuilders.termQuery(randomAlphaOfLength(5), randomAlphaOfLength(5)), + () -> QueryBuilders.existsQuery(randomAlphaOfLength(5)), + () -> QueryBuilders.geoBoundingBoxQuery(randomAlphaOfLength(5)) + ); + } + + private static BoolQueryBuilder randomBoolQuery() { + var bool = QueryBuilders.boolQuery(); + if (randomBoolean()) { + bool.filter(randomNonBoolQuery()); + } + if (randomBoolean()) { + bool.must(randomNonBoolQuery()); + } + if (randomBoolean()) { + bool.mustNot(randomNonBoolQuery()); + } + if (randomBoolean()) { + bool.should(randomNonBoolQuery()); + } + return bool; + } + + public void testCombineNotCreatingBool() { + var clause = randomFrom(Queries.Clause.values()); + var nonBool = randomNonBoolQuery(); + assertThat(nonBool, sameInstance(Queries.combine(clause, asList(null, null, nonBool, null)))); + } + + public void testCombineNonBoolQueries() { + var queries = randomArray(2, 10, QueryBuilder[]::new, QueriesTests::randomNonBoolQuery); + + var clause = randomFrom(Queries.Clause.values()); + var list = asList(queries); + var combination = Queries.combine(clause, list); + + assertThat(combination, instanceOf(BoolQueryBuilder.class)); + var bool = (BoolQueryBuilder) combination; + var clauseList = clause.innerQueries.apply(bool); + assertThat(list, everyItem(in(clauseList))); + } + + public void testCombineBoolQueries() { + var queries = randomArray(2, 10, QueryBuilder[]::new, () -> { + var bool = QueryBuilders.boolQuery(); + if (randomBoolean()) { + bool.filter(randomNonBoolQuery()); + } + if (randomBoolean()) { + bool.must(randomNonBoolQuery()); + } + if (randomBoolean()) { + bool.mustNot(randomNonBoolQuery()); + } + if (randomBoolean()) { + bool.should(randomNonBoolQuery()); + } + return bool; + }); + + var clause = randomFrom(Queries.Clause.values()); + var list = asList(queries); + var combination = Queries.combine(clause, list); + + assertThat(combination, instanceOf(BoolQueryBuilder.class)); + var bool = (BoolQueryBuilder) combination; + + var clauseList = clause.innerQueries.apply(bool); + + for (QueryBuilder query : queries) { + if (query != bool) { + assertThat(query, in(clauseList)); + } + } + } + + public void testCombineMixedBoolAndNonBoolQueries() { + var queries = randomArray(2, 10, QueryBuilder[]::new, () -> { + if (randomBoolean()) { + return QueriesTests.randomBoolQuery(); + } else { + return QueriesTests.randomNonBoolQuery(); + } + }); + + var clause = randomFrom(Queries.Clause.values()); + var list = asList(queries); + var combination = Queries.combine(clause, list); + + assertThat(combination, instanceOf(BoolQueryBuilder.class)); + var bool = (BoolQueryBuilder) combination; + + var clauseList = clause.innerQueries.apply(bool); + + for (QueryBuilder query : queries) { + if (query != bool) { + assertThat(query, in(clauseList)); + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/RemoteClusterUtilsTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/RemoteClusterUtilsTests.java new file mode 100644 index 000000000000..999adba1370e --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/RemoteClusterUtilsTests.java @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.core.Tuple; +import org.elasticsearch.test.ESTestCase; + +import static org.elasticsearch.xpack.esql.core.util.StringUtils.isQualified; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.qualifyAndJoinIndices; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.splitQualifiedIndex; + +public class RemoteClusterUtilsTests extends ESTestCase { + public void testSplitQualifiedIndex() { + String cluster = randomAlphaOfLength(20); + String index = randomAlphaOfLength(30); + assertEquals(Tuple.tuple(cluster, index), splitQualifiedIndex(cluster + ":" + index)); + } + + public void testQualifyAndJoinIndices() { + String[] indices = { "foo", "bar", "bar*", "*foo" }; + assertEquals("cluster:foo,cluster:bar,cluster:bar*,cluster:*foo", qualifyAndJoinIndices("cluster", indices)); + } + + public void testIsQualified() { + assertTrue(isQualified("foo:bar")); + assertFalse(isQualified("foobar")); + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/SpatialCoordinateTypesTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/SpatialCoordinateTypesTests.java new file mode 100644 index 000000000000..83ee745876dc --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/SpatialCoordinateTypesTests.java @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.geo.GeometryTestUtils; +import org.elasticsearch.geo.ShapeTestUtils; +import org.elasticsearch.geometry.Point; +import org.elasticsearch.test.ESTestCase; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.closeTo; + +public class SpatialCoordinateTypesTests extends ESTestCase { + + private static final Map types = new LinkedHashMap<>(); + static { + types.put(SpatialCoordinateTypes.GEO, new TestTypeFunctions(GeometryTestUtils::randomPoint, v -> 1e-5)); + types.put( + SpatialCoordinateTypes.CARTESIAN, + new TestTypeFunctions(ShapeTestUtils::randomPoint, SpatialCoordinateTypesTests::cartesianError) + ); + } + + private static double cartesianError(double v) { + double abs = Math.abs(v); + return (abs < 1) ? 1e-5 : abs / 1e7; + } + + record TestTypeFunctions(Supplier randomPoint, Function error) {} + + public void testEncoding() { + for (var type : types.entrySet()) { + for (int i = 0; i < 10; i++) { + SpatialCoordinateTypes coordType = type.getKey(); + Point original = type.getValue().randomPoint().get(); + var error = type.getValue().error; + Point point = coordType.longAsPoint(coordType.pointAsLong(original.getX(), original.getY())); + assertThat(coordType + ": Y[" + i + "]", point.getY(), closeTo(original.getY(), error.apply(original.getY()))); + assertThat(coordType + ": X[" + i + "]", point.getX(), closeTo(original.getX(), error.apply(original.getX()))); + } + } + } + + public void testParsing() { + for (var type : types.entrySet()) { + for (int i = 0; i < 10; i++) { + SpatialCoordinateTypes coordType = type.getKey(); + Point point = type.getValue().randomPoint.get(); + assertEquals(coordType.wkbToWkt(coordType.asWkb(point)), coordType.asWkt(point)); + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/StringUtilsTests.java b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/StringUtilsTests.java new file mode 100644 index 000000000000..e584357b25b0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/java/org/elasticsearch/xpack/esql/core/util/StringUtilsTests.java @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core.util; + +import org.elasticsearch.test.ESTestCase; + +import static org.elasticsearch.xpack.esql.core.util.StringUtils.wildcardToJavaPattern; + +public class StringUtilsTests extends ESTestCase { + + public void testNoWildcard() { + assertEquals("^fooBar$", wildcardToJavaPattern("fooBar", '\\')); + } + + public void testSimpleWildcard() { + assertEquals("^foo.bar$", wildcardToJavaPattern("foo?bar", '\\')); + assertEquals("^foo.*bar$", wildcardToJavaPattern("foo*bar", '\\')); + } + + public void testMultipleWildcards() { + assertEquals("^.*foo.*bar.$", wildcardToJavaPattern("*foo*bar?", '\\')); + assertEquals("^foo.*bar.$", wildcardToJavaPattern("foo*bar?", '\\')); + assertEquals("^foo.*bar...$", wildcardToJavaPattern("foo*bar???", '\\')); + assertEquals("^foo.*bar..*.$", wildcardToJavaPattern("foo*bar?*?", '\\')); + } + + public void testDot() { + assertEquals("^foo\\.$", wildcardToJavaPattern("foo.", '\\')); + assertEquals("^\\..*foobar$", wildcardToJavaPattern(".*foobar", '\\')); + assertEquals("^foo\\..*bar$", wildcardToJavaPattern("foo.*bar", '\\')); + assertEquals("^foobar\\..*$", wildcardToJavaPattern("foobar.*", '\\')); + } + + public void testEscapedJavaRegex() { + assertEquals("^\\[a-zA-Z\\]$", wildcardToJavaPattern("[a-zA-Z]", '\\')); + } + + public void testWildcard() { + assertEquals("^foo\\?$", wildcardToJavaPattern("foo\\?", '\\')); + assertEquals("^foo\\?bar$", wildcardToJavaPattern("foo\\?bar", '\\')); + assertEquals("^foo\\?.$", wildcardToJavaPattern("foo\\??", '\\')); + assertEquals("^foo\\*$", wildcardToJavaPattern("foo\\*", '\\')); + assertEquals("^foo\\*bar$", wildcardToJavaPattern("foo\\*bar", '\\')); + assertEquals("^foo\\*.*$", wildcardToJavaPattern("foo\\**", '\\')); + + assertEquals("^foo\\?$", wildcardToJavaPattern("foox?", 'x')); + assertEquals("^foo\\*$", wildcardToJavaPattern("foox*", 'x')); + } + + public void testEscapedEscape() { + assertEquals("^\\\\\\\\$", wildcardToJavaPattern("\\\\\\\\", '\\')); + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/fc-incompatible-object-compatible-subfields.json b/x-pack/plugin/esql-core/src/test/resources/fc-incompatible-object-compatible-subfields.json new file mode 100644 index 000000000000..df9bd4d3ab42 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/fc-incompatible-object-compatible-subfields.json @@ -0,0 +1,48 @@ +{ + "indices": [ + "index-1", + "index-2" + ], + "fields": { + "file": { + "keyword": { + "type": "keyword", + "metadata_field": false, + "searchable": true, + "aggregatable": true, + "indices": [ + "index-2" + ] + }, + "object": { + "type": "object", + "metadata_field": false, + "searchable": false, + "aggregatable": false, + "indices": [ + "index-1" + ] + } + }, + "file.name": { + "keyword": { + "type": "keyword", + "metadata_field": false, + "searchable": true, + "aggregatable": true, + "indices": [ + "index-1" + ] + }, + "unmapped": { + "type": "unmapped", + "metadata_field": false, + "searchable": false, + "aggregatable": false, + "indices": [ + "index-2" + ] + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/fc-unsupported-object-compatible-subfields.json b/x-pack/plugin/esql-core/src/test/resources/fc-unsupported-object-compatible-subfields.json new file mode 100644 index 000000000000..60001c79b5d0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/fc-unsupported-object-compatible-subfields.json @@ -0,0 +1,48 @@ +{ + "indices": [ + "index-1", + "index-2" + ], + "fields": { + "file": { + "unknown": { + "type": "unknown", + "metadata_field": false, + "searchable": false, + "aggregatable": false, + "indices": [ + "index-2" + ] + }, + "object": { + "type": "object", + "metadata_field": false, + "searchable": false, + "aggregatable": false, + "indices": [ + "index-1" + ] + } + }, + "file.name": { + "keyword": { + "type": "keyword", + "metadata_field": false, + "searchable": true, + "aggregatable": true, + "indices": [ + "index-1" + ] + }, + "unmapped": { + "type": "unmapped", + "metadata_field": false, + "searchable": false, + "aggregatable": false, + "indices": [ + "index-2" + ] + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-basic-incompatible.json b/x-pack/plugin/esql-core/src/test/resources/mapping-basic-incompatible.json new file mode 100644 index 000000000000..9042415a5159 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-basic-incompatible.json @@ -0,0 +1,22 @@ +{ + "properties" : { + "emp_no" : { + "type" : "long" + }, + "first_name" : { + "type" : "text" + }, + "gender" : { + "type" : "text" + }, + "languages" : { + "type" : "byte" + }, + "last_name" : { + "type" : "text" + }, + "salary" : { + "type" : "integer" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-basic-nodocvalues.json b/x-pack/plugin/esql-core/src/test/resources/mapping-basic-nodocvalues.json new file mode 100644 index 000000000000..bb9cd60dc02e --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-basic-nodocvalues.json @@ -0,0 +1,23 @@ +{ + "properties" : { + "emp_no" : { + "type" : "integer", + "doc_values" : false + }, + "first_name" : { + "type" : "text" + }, + "gender" : { + "type" : "keyword" + }, + "languages" : { + "type" : "byte" + }, + "last_name" : { + "type" : "text" + }, + "salary" : { + "type" : "integer" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-basic.json b/x-pack/plugin/esql-core/src/test/resources/mapping-basic.json new file mode 100644 index 000000000000..142b347fbe31 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-basic.json @@ -0,0 +1,25 @@ +{ + "properties" : { + "emp_no" : { + "type" : "integer" + }, + "first_name" : { + "type" : "text" + }, + "gender" : { + "type" : "keyword" + }, + "languages" : { + "type" : "byte" + }, + "last_name" : { + "type" : "text" + }, + "salary" : { + "type" : "integer" + }, + "_meta_field": { + "type" : "keyword" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-constant-keyword.json b/x-pack/plugin/esql-core/src/test/resources/mapping-constant-keyword.json new file mode 100644 index 000000000000..7f248dc26fba --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-constant-keyword.json @@ -0,0 +1,8 @@ +{ + "properties" : { + "full_name" : { + "type" : "constant_keyword", + "value" : "foo" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-date-multi.json b/x-pack/plugin/esql-core/src/test/resources/mapping-date-multi.json new file mode 100644 index 000000000000..e6cd9091f841 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-date-multi.json @@ -0,0 +1,9 @@ +{ + "properties": { + "date": { + "type": "date", + "format": "yyyy-MM-dd" + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-date-no-format.json b/x-pack/plugin/esql-core/src/test/resources/mapping-date-no-format.json new file mode 100644 index 000000000000..e0e5fa852f52 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-date-no-format.json @@ -0,0 +1,8 @@ +{ + "properties": { + "date": { + "type": "date" + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-date.json b/x-pack/plugin/esql-core/src/test/resources/mapping-date.json new file mode 100644 index 000000000000..0422d7e1026b --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-date.json @@ -0,0 +1,9 @@ +{ + "properties": { + "date": { + "type": "date", + "format": "yyyy-MM-dd || basic_time || year" + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-date_nanos.json b/x-pack/plugin/esql-core/src/test/resources/mapping-date_nanos.json new file mode 100644 index 000000000000..8a06d01d0b01 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-date_nanos.json @@ -0,0 +1,7 @@ +{ + "properties": { + "date_nanos": { + "type": "date_nanos" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-default-string.json b/x-pack/plugin/esql-core/src/test/resources/mapping-default-string.json new file mode 100644 index 000000000000..e8777a9cd68b --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-default-string.json @@ -0,0 +1,13 @@ +{ + "properties" : { + "dep_no" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-docvalues.json b/x-pack/plugin/esql-core/src/test/resources/mapping-docvalues.json new file mode 100644 index 000000000000..5cd0ed200ce9 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-docvalues.json @@ -0,0 +1,9 @@ +{ + "properties" : { + "session_id" : { + "type" : "keyword", + "ignore_above" : 15, + "doc_values" : false + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-dotted-field.json b/x-pack/plugin/esql-core/src/test/resources/mapping-dotted-field.json new file mode 100644 index 000000000000..c48cd5c77065 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-dotted-field.json @@ -0,0 +1,32 @@ +{ + "properties" : { + "test" : { + "properties" : { + "test" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword" + } + } + }, + "bar" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword" + } + } + } + } + }, + "bar" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword" + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-geo.json b/x-pack/plugin/esql-core/src/test/resources/mapping-geo.json new file mode 100644 index 000000000000..e6e499ef82e8 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-geo.json @@ -0,0 +1,10 @@ +{ + "properties" : { + "location" : { + "type" : "geo_point" + }, + "site": { + "type" : "geo_shape" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-ip.json b/x-pack/plugin/esql-core/src/test/resources/mapping-ip.json new file mode 100644 index 000000000000..19211b82b0a7 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-ip.json @@ -0,0 +1,7 @@ +{ + "properties" : { + "ip_addr" : { + "type" : "ip" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-keyword.json b/x-pack/plugin/esql-core/src/test/resources/mapping-keyword.json new file mode 100644 index 000000000000..aa47e9e42ad0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-keyword.json @@ -0,0 +1,8 @@ +{ + "properties" : { + "full_name" : { + "type" : "keyword", + "ignore_above" : 256 + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-options.json b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-options.json new file mode 100644 index 000000000000..f2389aed3d78 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-options.json @@ -0,0 +1,15 @@ +{ + "properties" : { + "text" : { + "type" : "text", + "fields" : { + "raw" : { + "type" : "keyword" + }, + "key" : { + "type" : "keyword" + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-variation.json b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-variation.json new file mode 100644 index 000000000000..b5b3d4281650 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-variation.json @@ -0,0 +1,61 @@ +{ + "properties" : { + "bool" : { "type" : "boolean" }, + "int" : { "type" : "integer" }, + "unsigned_long" : { "type" : "unsigned_long" }, + "float" : { "type" : "float" }, + "text" : { "type" : "text" }, + "keyword" : { "type" : "keyword" }, + "date" : { "type" : "date" }, + "date_nanos": { "type" : "date_nanos" }, + "unsupported" : { "type" : "ip_range" }, + "some" : { + "properties" : { + "dotted" : { + "properties" : { + "field" : { + "type" : "keyword" + } + } + }, + "string" : { + "type" : "text", + "fields" : { + "normalized" : { + "type" : "keyword", + "normalizer" : "some_normalizer" + }, + "typical" : { + "type" : "keyword" + } + } + }, + "ambiguous" : { + "type" : "text", + "fields" : { + "one" : { + "type" : "keyword" + }, + "two" : { + "type" : "keyword" + }, + "normalized" : { + "type" : "keyword", + "normalizer" : "some_normalizer" + } + } + } + } + }, + "foo_type" : { "type" : "foo" }, + "point": {"type" : "geo_point"}, + "shape": {"type" : "geo_shape"}, + "nested": { + "type": "nested", + "properties": { + "point": {"type" : "geo_point"} + } + }, + "version": {"type" : "version"} + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-with-nested.json b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-with-nested.json new file mode 100644 index 000000000000..cf864fc56a0e --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field-with-nested.json @@ -0,0 +1,100 @@ +{ + "properties" : { + "bool" : { "type" : "boolean" }, + "int" : { "type" : "integer" }, + "unsigned_long" : { "type" : "unsigned_long" }, + "text" : { "type" : "text" }, + "keyword" : { "type" : "keyword" }, + "unsupported" : { "type" : "ip_range" }, + "date" : { "type" : "date" }, + "date_nanos" : { "type" : "date_nanos" }, + "shape": { "type" : "shape" }, + "geo_shape": { "type" : "geo_shape" }, + "binary": {"type" : "binary", "doc_values": false }, + "binary_stored": {"type" : "binary", "doc_values": true }, + "x" : { + "type" : "text", + "fields" : { + "y" : { + "type" : "foobar", + "fields" : { + "z" : { + "properties" : { + "v" : { + "type" : "keyword" + }, + "w" : { + "type" : "foo" + } + } + } + } + } + } + }, + "some" : { + "properties" : { + "dotted" : { + "properties" : { + "field" : { + "type" : "keyword" + } + } + }, + "string" : { + "type" : "text", + "fields" : { + "normalized" : { + "type" : "keyword", + "normalizer" : "some_normalizer" + }, + "typical" : { + "type" : "keyword" + } + } + }, + "ambiguous" : { + "type" : "text", + "fields" : { + "one" : { + "type" : "keyword" + }, + "two" : { + "type" : "keyword" + }, + "normalized" : { + "type" : "keyword", + "normalizer" : "some_normalizer" + } + } + } + } + }, + "dep" : { + "type" : "nested", + "properties" : { + "dep_name" : { + "type" : "text" + }, + "dep_id" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "end_date" : { + "type" : "date" + }, + "start_date" : { + "type" : "date" + }, + "location" : { + "type" : "geo_point" + } + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field.json b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field.json new file mode 100644 index 000000000000..490f1306250d --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-multi-field.json @@ -0,0 +1,23 @@ +{ + "properties" : { + "text" : { + "type" : "text", + "fields" : { + "raw" : { + "type" : "keyword" + }, + "english" : { + "type" : "text", + "analyzer" : "english" + }, + "constant" : { + "type" : "constant_keyword", + "value" : "some constant value" + }, + "wildcard" : { + "type" : "wildcard" + } + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-nested.json b/x-pack/plugin/esql-core/src/test/resources/mapping-nested.json new file mode 100644 index 000000000000..1251d17525a0 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-nested.json @@ -0,0 +1,26 @@ +{ + "properties" : { + "dep" : { + "type" : "nested", + "properties" : { + "dep_name" : { + "type" : "text" + }, + "dep_no" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword" + } + } + }, + "end_date" : { + "type" : "date" + }, + "start_date" : { + "type" : "date" + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-numeric.json b/x-pack/plugin/esql-core/src/test/resources/mapping-numeric.json new file mode 100644 index 000000000000..119be02a4f09 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-numeric.json @@ -0,0 +1,27 @@ +{ + "properties" : { + "byte" : { + "type" : "byte" + }, + "short" : { + "type" : "short" + }, + "integer" : { + "type" : "integer" + }, + "long" : { + "type" : "long" + }, + "unsigned_long" : { + "type" : "unsigned_long" + }, + "meta_subfield" : { + "type" : "text", + "fields" : { + "_meta" : { + "type" : "keyword" + } + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-object.json b/x-pack/plugin/esql-core/src/test/resources/mapping-object.json new file mode 100644 index 000000000000..65fd391f901d --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-object.json @@ -0,0 +1,24 @@ +{ + "properties" : { + "region" : { + "type" : "keyword" + }, + "manager" : { + "properties" : { + "age" : { + "type" : "integer" + }, + "name" : { + "properties" : { + "first" : { + "type" : "text" + }, + "last" : { + "type" : "text" + } + } + } + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-one-field.json b/x-pack/plugin/esql-core/src/test/resources/mapping-one-field.json new file mode 100644 index 000000000000..ae6e1aed0767 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-one-field.json @@ -0,0 +1,7 @@ +{ + "properties" : { + "emp_no" : { + "type" : "integer" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-parent-child.json b/x-pack/plugin/esql-core/src/test/resources/mapping-parent-child.json new file mode 100644 index 000000000000..b62e19625e26 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-parent-child.json @@ -0,0 +1,10 @@ +{ + "properties" : { + "parent_child" : { + "type" : "join", + "relations" : { + "question" : "answer" + } + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-sample_data.json b/x-pack/plugin/esql-core/src/test/resources/mapping-sample_data.json new file mode 100644 index 000000000000..838a8ba09b45 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-sample_data.json @@ -0,0 +1,16 @@ +{ + "properties": { + "@timestamp": { + "type": "date" + }, + "client_ip": { + "type": "ip" + }, + "event_duration": { + "type": "long" + }, + "message": { + "type": "keyword" + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-text.json b/x-pack/plugin/esql-core/src/test/resources/mapping-text.json new file mode 100644 index 000000000000..ecf2f09c98a2 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-text.json @@ -0,0 +1,8 @@ +{ + "properties" : { + "full_name" : { + "type" : "text", + "fielddata" : false + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-unsupported.json b/x-pack/plugin/esql-core/src/test/resources/mapping-unsupported.json new file mode 100644 index 000000000000..d3afa7fa5240 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-unsupported.json @@ -0,0 +1,14 @@ +{ + "properties" : { + "range" : { + "type" : "integer_range" + }, + "time_frame" : { + "type" : "date_range", + "format" : "yyyy-MM-dd" + }, + "flat" : { + "type" : "flattened" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-version.json b/x-pack/plugin/esql-core/src/test/resources/mapping-version.json new file mode 100644 index 000000000000..d25880444584 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-version.json @@ -0,0 +1,7 @@ +{ + "properties" : { + "version_number" : { + "type" : "version" + } + } +} diff --git a/x-pack/plugin/esql-core/src/test/resources/mapping-wildcard.json b/x-pack/plugin/esql-core/src/test/resources/mapping-wildcard.json new file mode 100644 index 000000000000..f24a4ec31a10 --- /dev/null +++ b/x-pack/plugin/esql-core/src/test/resources/mapping-wildcard.json @@ -0,0 +1,8 @@ +{ + "properties" : { + "full_name" : { + "type" : "wildcard", + "ignore_above" : 256 + } + } +} diff --git a/x-pack/plugin/esql-core/test-fixtures/build.gradle b/x-pack/plugin/esql-core/test-fixtures/build.gradle new file mode 100644 index 000000000000..e76d3c3e2625 --- /dev/null +++ b/x-pack/plugin/esql-core/test-fixtures/build.gradle @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +apply plugin: 'elasticsearch.java' + +dependencies { + api project(xpackModule('esql-core')) + api project(':test:framework') +} + +tasks.named("test").configure { enabled = false } diff --git a/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/CsvSpecReader.java b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/CsvSpecReader.java new file mode 100644 index 000000000000..a1f524e525ee --- /dev/null +++ b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/CsvSpecReader.java @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.Function; +import java.util.regex.Pattern; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public final class CsvSpecReader { + + private CsvSpecReader() {} + + public static SpecReader.Parser specParser() { + return new CsvSpecParser(); + } + + public static class CsvSpecParser implements SpecReader.Parser { + private static final String SCHEMA_PREFIX = "schema::"; + + private final StringBuilder earlySchema = new StringBuilder(); + private final StringBuilder query = new StringBuilder(); + private final StringBuilder data = new StringBuilder(); + private final List requiredCapabilities = new ArrayList<>(); + private CsvTestCase testCase; + + private CsvSpecParser() {} + + @Override + public Object parse(String line) { + // read the query + if (testCase == null) { + if (line.startsWith(SCHEMA_PREFIX)) { + assertThat("Early schema already declared " + earlySchema, earlySchema.length(), is(0)); + earlySchema.append(line.substring(SCHEMA_PREFIX.length()).trim()); + } else if (line.toLowerCase(Locale.ROOT).startsWith("required_capability:")) { + requiredCapabilities.add(line.substring("required_capability:".length()).trim()); + } else { + if (line.endsWith(";")) { + // pick up the query + testCase = new CsvTestCase(); + query.append(line.substring(0, line.length() - 1).trim()); + testCase.query = query.toString(); + testCase.earlySchema = earlySchema.toString(); + testCase.requiredCapabilities = List.copyOf(requiredCapabilities); + requiredCapabilities.clear(); + earlySchema.setLength(0); + query.setLength(0); + } + // keep reading the query + else { + query.append(line); + query.append("\r\n"); + } + } + } + // read the results + else { + // read data + String lower = line.toLowerCase(Locale.ROOT); + if (lower.startsWith("warning:")) { + if (testCase.expectedWarningsRegex.isEmpty() == false) { + throw new IllegalArgumentException("Cannot mix warnings and regex warnings in CSV SPEC files: [" + line + "]"); + } + testCase.expectedWarnings.add(line.substring("warning:".length()).trim()); + } else if (lower.startsWith("warningregex:")) { + if (testCase.expectedWarnings.isEmpty() == false) { + throw new IllegalArgumentException("Cannot mix warnings and regex warnings in CSV SPEC files: [" + line + "]"); + } + String regex = line.substring("warningregex:".length()).trim(); + testCase.expectedWarningsRegexString.add(regex); + testCase.expectedWarningsRegex.add(warningRegexToPattern(regex)); + } else if (lower.startsWith("ignoreorder:")) { + testCase.ignoreOrder = Boolean.parseBoolean(line.substring("ignoreOrder:".length()).trim()); + } else if (line.startsWith(";")) { + testCase.expectedResults = data.toString(); + // clean-up and emit + CsvTestCase result = testCase; + testCase = null; + data.setLength(0); + return result; + } else { + data.append(line); + data.append("\r\n"); + } + } + + return null; + } + } + + private static Pattern warningRegexToPattern(String regex) { + return Pattern.compile(".*" + regex + ".*"); + } + + public static class CsvTestCase { + public String query; + public String earlySchema; + public String expectedResults; + private final List expectedWarnings = new ArrayList<>(); + private final List expectedWarningsRegexString = new ArrayList<>(); + private final List expectedWarningsRegex = new ArrayList<>(); + public boolean ignoreOrder; + public List requiredCapabilities = List.of(); + + // The emulated-specific warnings must always trail the non-emulated ones, if these are present. Otherwise, the closing bracket + // would need to be changed to a less common sequence (like `]#` maybe). + private static final String EMULATED_PREFIX = "#[emulated:"; + + /** + * Returns the warning headers expected to be added by the test. To declare such a header, use the `warning:definition` format + * in the CSV test declaration. The `definition` can use the `EMULATED_PREFIX` string to specify the format of the warning run on + * emulated physical operators, if this differs from the format returned by SingleValueQuery. + * @param forEmulated if true, the tests are run on emulated physical operators; if false, the test case is for queries executed + * on a "full stack" ESQL, having data loaded from Lucene. + * @return the list of headers that are expected to be returned part of the response. + */ + public List expectedWarnings(boolean forEmulated) { + List warnings = new ArrayList<>(expectedWarnings.size()); + for (String warning : expectedWarnings) { + int idx = warning.toLowerCase(Locale.ROOT).indexOf(EMULATED_PREFIX); + if (idx >= 0) { + assertTrue("Invalid warning spec: closing delimiter (]) missing: `" + warning + "`", warning.endsWith("]")); + if (forEmulated) { + if (idx + EMULATED_PREFIX.length() < warning.length() - 1) { + warnings.add(warning.substring(idx + EMULATED_PREFIX.length(), warning.length() - 1)); + } + } else if (idx > 0) { + warnings.add(warning.substring(0, idx)); + } // else: no warnings expected for non-emulated + } else { + warnings.add(warning); + } + } + return warnings; + } + + /** + * Modifies the expected warnings. + * In some cases, we modify the query to run against multiple clusters. As a result, the line/column positions + * of the expected warnings no longer match the actual warnings. To enable reusing of spec tests, this method + * allows adjusting the expected warnings. + */ + public void adjustExpectedWarnings(Function updater) { + expectedWarnings.replaceAll(updater::apply); + expectedWarningsRegexString.replaceAll(updater::apply); + expectedWarningsRegex.clear(); + expectedWarningsRegex.addAll(expectedWarningsRegexString.stream().map(CsvSpecReader::warningRegexToPattern).toList()); + } + + public List expectedWarningsRegex() { + return expectedWarningsRegex; + } + } + +} diff --git a/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/SpecReader.java b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/SpecReader.java new file mode 100644 index 000000000000..422a5b744eed --- /dev/null +++ b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/SpecReader.java @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core; + +import org.elasticsearch.common.Strings; + +import java.io.BufferedReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static java.util.Collections.emptyList; +import static org.elasticsearch.xpack.esql.core.TestUtils.pathAndName; +import static org.junit.Assert.assertNull; + +public final class SpecReader { + + private SpecReader() {} + + public static List readScriptSpec(URL source, String url, Parser parser) throws Exception { + Objects.requireNonNull(source, "Cannot find resource " + url); + return readURLSpec(source, parser); + } + + public static List readScriptSpec(List urls, Parser parser) throws Exception { + List results = emptyList(); + for (URL url : urls) { + List specs = readURLSpec(url, parser); + if (results.isEmpty()) { + results = specs; + } else { + results.addAll(specs); + } + } + + return results; + } + + public static List readURLSpec(URL source, Parser parser) throws Exception { + String fileName = pathAndName(source.getFile()).v2(); + String groupName = fileName.substring(0, fileName.lastIndexOf('.')); + + Map testNames = new LinkedHashMap<>(); + List testCases = new ArrayList<>(); + + String testName = null; + try (BufferedReader reader = TestUtils.reader(source)) { + String line; + int lineNumber = 1; + while ((line = reader.readLine()) != null) { + line = line.trim(); + // ignore comments + if (shouldSkipLine(line) == false) { + // parse test name + if (testName == null) { + if (testNames.keySet().contains(line)) { + throw new IllegalStateException( + "Duplicate test name '" + + line + + "' at line " + + lineNumber + + " (previously seen at line " + + testNames.get(line) + + ")" + ); + } else { + testName = Strings.capitalize(line); + testNames.put(testName, Integer.valueOf(lineNumber)); + } + } else { + Object result = parser.parse(line); + // only if the parser is ready, add the object - otherwise keep on serving it lines + if (result != null) { + testCases.add(new Object[] { fileName, groupName, testName, Integer.valueOf(lineNumber), result }); + testName = null; + } + } + } + lineNumber++; + } + if (testName != null) { + throw new IllegalStateException("Read a test without a body at the end of [" + fileName + "]."); + } + } + assertNull("Cannot find spec for test " + testName, testName); + + return testCases; + } + + public interface Parser { + Object parse(String line); + } + + public static boolean shouldSkipLine(String line) { + return line.isEmpty() || line.startsWith("//") || line.startsWith("#"); + } +} diff --git a/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestNode.java b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestNode.java new file mode 100644 index 000000000000..6571c5e60497 --- /dev/null +++ b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestNode.java @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core; + +import org.apache.http.HttpHost; +import org.elasticsearch.TransportVersion; +import org.elasticsearch.core.Nullable; + +public record TestNode(String id, String version, @Nullable TransportVersion transportVersion, HttpHost publishAddress) { + @Override + public String toString() { + return "Node{" + "id='" + id + '\'' + ", version=" + version + '}'; + } +} diff --git a/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestNodes.java b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestNodes.java new file mode 100644 index 000000000000..9201860ee038 --- /dev/null +++ b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestNodes.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core; + +import org.elasticsearch.TransportVersion; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public final class TestNodes extends HashMap { + + private final String bwcNodesVersion; + + TestNodes(String bwcNodesVersion) { + this.bwcNodesVersion = bwcNodesVersion; + } + + public void add(TestNode node) { + put(node.id(), node); + } + + public List getNewNodes() { + return values().stream().filter(n -> n.version().equals(bwcNodesVersion) == false).collect(Collectors.toList()); + } + + public List getBWCNodes() { + return values().stream().filter(n -> n.version().equals(bwcNodesVersion)).collect(Collectors.toList()); + } + + public TransportVersion getBWCTransportVersion() { + if (isEmpty()) { + throw new IllegalStateException("no nodes available"); + } + // there will be either at least one node with version <8.8.0, and so a mapped TransportVersion will be set, + // or all >=8.8.0,so TransportVersion will always be there + return values().stream().map(TestNode::transportVersion).filter(Objects::nonNull).min(Comparator.naturalOrder()).get(); + } + + @Override + public String toString() { + return "Nodes{" + values().stream().map(TestNode::toString).collect(Collectors.joining("\n")) + '}'; + } +} diff --git a/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestUtils.java b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestUtils.java new file mode 100644 index 000000000000..27da0f56deb2 --- /dev/null +++ b/x-pack/plugin/esql-core/test-fixtures/src/main/java/org/elasticsearch/xpack/esql/core/TestUtils.java @@ -0,0 +1,486 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.core; + +import org.apache.http.HttpHost; +import org.elasticsearch.TransportVersion; +import org.elasticsearch.Version; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.common.regex.Regex; +import org.elasticsearch.common.util.Maps; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.core.PathUtils; +import org.elasticsearch.core.SuppressForbidden; +import org.elasticsearch.core.Tuple; +import org.elasticsearch.test.rest.ObjectPath; +import org.elasticsearch.xcontent.json.JsonXContent; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.Range; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThan; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NotEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.NullEquals; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.plan.logical.EsRelation; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.StringUtils; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.jar.JarInputStream; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; + +import static java.util.Collections.emptyMap; +import static org.elasticsearch.cluster.ClusterState.VERSION_INTRODUCING_TRANSPORT_VERSIONS; +import static org.elasticsearch.test.ESTestCase.between; +import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength; +import static org.elasticsearch.test.ESTestCase.randomBoolean; +import static org.elasticsearch.test.ESTestCase.randomFrom; +import static org.elasticsearch.test.ESTestCase.randomZone; +import static org.elasticsearch.xpack.esql.core.TestUtils.StringContainsRegex.containsRegex; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; + +public final class TestUtils { + + public static final ZoneId UTC = ZoneId.of("Z"); + public static final Configuration TEST_CFG = new Configuration(UTC, null, null); + + private static final String MATCHER_TYPE_CONTAINS = "CONTAINS"; + private static final String MATCHER_TYPE_REGEX = "REGEX"; + + private TestUtils() {} + + public static Configuration randomConfiguration() { + return new Configuration(randomZone(), randomAlphaOfLength(10), randomAlphaOfLength(10)); + } + + public static Configuration randomConfiguration(ZoneId zoneId) { + return new Configuration(zoneId, randomAlphaOfLength(10), randomAlphaOfLength(10)); + } + + public static Literal of(Object value) { + return of(Source.EMPTY, value); + } + + /** + * Utility method for creating 'in-line' Literals (out of values instead of expressions). + */ + public static Literal of(Source source, Object value) { + if (value instanceof Literal) { + return (Literal) value; + } + return new Literal(source, value, DataTypes.fromJava(value)); + } + + public static Equals equalsOf(Expression left, Expression right) { + return new Equals(EMPTY, left, right, randomZone()); + } + + public static NotEquals notEqualsOf(Expression left, Expression right) { + return new NotEquals(EMPTY, left, right, randomZone()); + } + + public static NullEquals nullEqualsOf(Expression left, Expression right) { + return new NullEquals(EMPTY, left, right, randomZone()); + } + + public static LessThan lessThanOf(Expression left, Expression right) { + return new LessThan(EMPTY, left, right, randomZone()); + } + + public static LessThanOrEqual lessThanOrEqualOf(Expression left, Expression right) { + return new LessThanOrEqual(EMPTY, left, right, randomZone()); + } + + public static GreaterThan greaterThanOf(Expression left, Expression right) { + return new GreaterThan(EMPTY, left, right, randomZone()); + } + + public static GreaterThanOrEqual greaterThanOrEqualOf(Expression left, Expression right) { + return new GreaterThanOrEqual(EMPTY, left, right, randomZone()); + } + + public static Range rangeOf(Expression value, Expression lower, boolean includeLower, Expression upper, boolean includeUpper) { + return new Range(EMPTY, value, lower, includeLower, upper, includeUpper, randomZone()); + } + + public static WildcardLike wildcardLike(Expression left, String exp) { + return new WildcardLike(EMPTY, left, new WildcardPattern(exp)); + } + + public static RLike rlike(Expression left, String exp) { + return new RLike(EMPTY, left, new RLikePattern(exp)); + } + + public static FieldAttribute fieldAttribute() { + return fieldAttribute(randomAlphaOfLength(10), randomFrom(DataTypes.types())); + } + + public static FieldAttribute fieldAttribute(String name, DataType type) { + return new FieldAttribute(EMPTY, name, new EsField(name, type, emptyMap(), randomBoolean())); + } + + public static EsRelation relation() { + return new EsRelation(EMPTY, new EsIndex(randomAlphaOfLength(8), emptyMap()), randomBoolean()); + } + + // + // Common methods / assertions + // + + public static void assertNoSearchContexts(RestClient client) throws IOException { + Map stats = searchStats(client); + @SuppressWarnings("unchecked") + Map indicesStats = (Map) stats.get("indices"); + for (String index : indicesStats.keySet()) { + if (index.startsWith(".") == false) { // We are not interested in internal indices + assertEquals(index + " should have no search contexts", 0, getOpenContexts(stats, index)); + } + } + } + + public static int getNumberOfSearchContexts(RestClient client, String index) throws IOException { + return getOpenContexts(searchStats(client), index); + } + + private static Map searchStats(RestClient client) throws IOException { + Response response = client.performRequest(new Request("GET", "/_stats/search")); + try (InputStream content = response.getEntity().getContent()) { + return XContentHelper.convertToMap(JsonXContent.jsonXContent, content, false); + } + } + + @SuppressWarnings("unchecked") + private static int getOpenContexts(Map stats, String index) { + stats = (Map) stats.get("indices"); + stats = (Map) stats.get(index); + stats = (Map) stats.get("total"); + stats = (Map) stats.get("search"); + return (Integer) stats.get("open_contexts"); + } + + // + // Classpath + // + /** + * Returns the classpath resources matching a simple pattern ("*.csv"). + * It supports folders separated by "/" (e.g. "/some/folder/*.txt"). + * + * Currently able to resolve resources inside the classpath either from: + * folders in the file-system (typically IDEs) or + * inside jars (gradle). + */ + @SuppressForbidden(reason = "classpath discovery") + public static List classpathResources(String pattern) throws IOException { + while (pattern.startsWith("/")) { + pattern = pattern.substring(1); + } + + Tuple split = pathAndName(pattern); + + // the root folder searched inside the classpath - default is the root classpath + // default file match + final String root = split.v1(); + final String filePattern = split.v2(); + + String[] resources = System.getProperty("java.class.path").split(System.getProperty("path.separator")); + + List matches = new ArrayList<>(); + + for (String resource : resources) { + Path path = PathUtils.get(resource); + + // check whether we're dealing with a jar + // Java 7 java.nio.fileFileSystem can be used on top of ZIPs/JARs but consumes more memory + // hence the use of the JAR API + if (path.toString().endsWith(".jar")) { + try (JarInputStream jar = jarInputStream(path.toUri().toURL())) { + ZipEntry entry = null; + while ((entry = jar.getNextEntry()) != null) { + String name = entry.getName(); + Tuple entrySplit = pathAndName(name); + if (root.equals(entrySplit.v1()) && Regex.simpleMatch(filePattern, entrySplit.v2())) { + matches.add(new URL("jar:" + path.toUri() + "!/" + name)); + } + } + } + } + // normal file access + else if (Files.isDirectory(path)) { + Files.walkFileTree(path, EnumSet.allOf(FileVisitOption.class), 1, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (Regex.simpleMatch(filePattern, file.toString())) { + matches.add(file.toUri().toURL()); + } + return FileVisitResult.CONTINUE; + } + }); + } + } + return matches; + } + + @SuppressForbidden(reason = "need to open stream") + public static InputStream inputStream(URL resource) throws IOException { + URLConnection con = resource.openConnection(); + // do not to cache files (to avoid keeping file handles around) + con.setUseCaches(false); + return con.getInputStream(); + } + + @SuppressForbidden(reason = "need to open jar") + public static JarInputStream jarInputStream(URL resource) throws IOException { + return new JarInputStream(inputStream(resource)); + } + + public static BufferedReader reader(URL resource) throws IOException { + return new BufferedReader(new InputStreamReader(inputStream(resource), StandardCharsets.UTF_8)); + } + + public static Tuple pathAndName(String string) { + String folder = StringUtils.EMPTY; + String file = string; + int lastIndexOf = string.lastIndexOf('/'); + if (lastIndexOf > 0) { + folder = string.substring(0, lastIndexOf - 1); + if (lastIndexOf + 1 < string.length()) { + file = string.substring(lastIndexOf + 1); + } + } + return new Tuple<>(folder, file); + } + + public static TestNodes buildNodeAndVersions(RestClient client, String bwcNodesVersion) throws IOException { + Response response = client.performRequest(new Request("GET", "_nodes")); + ObjectPath objectPath = ObjectPath.createFromResponse(response); + Map nodesAsMap = objectPath.evaluate("nodes"); + TestNodes nodes = new TestNodes(bwcNodesVersion); + for (String id : nodesAsMap.keySet()) { + String nodeVersion = objectPath.evaluate("nodes." + id + ".version"); + + Object tvField; + TransportVersion transportVersion = null; + if ((tvField = objectPath.evaluate("nodes." + id + ".transport_version")) != null) { + // this json might be from a node <8.8.0, but about a node >=8.8.0 + // in which case the transport_version field won't exist. Just ignore it for now. + transportVersion = TransportVersion.fromString(tvField.toString()); + } else { // no transport_version field + // this json might be from a node <8.8.0, but about a node >=8.8.0 + // In that case the transport_version field won't exist. Just ignore it for now. + Version version = Version.fromString(nodeVersion); + if (version.before(VERSION_INTRODUCING_TRANSPORT_VERSIONS)) { + transportVersion = TransportVersion.fromId(version.id); + } + } + + nodes.add( + new TestNode( + id, + nodeVersion, + transportVersion, + HttpHost.create(objectPath.evaluate("nodes." + id + ".http.publish_address")) + ) + ); + } + return nodes; + } + + public static String readResource(InputStream input) throws IOException { + StringBuilder builder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) { + String line = reader.readLine(); + while (line != null) { + if (line.trim().startsWith("//") == false) { + builder.append(line); + builder.append('\n'); + } + line = reader.readLine(); + } + return builder.toString(); + } + } + + public static Map randomRuntimeMappings() { + int count = between(1, 100); + Map runtimeFields = Maps.newMapWithExpectedSize(count); + while (runtimeFields.size() < count) { + int size = between(1, 10); + Map config = Maps.newMapWithExpectedSize(size); + while (config.size() < size) { + config.put(randomAlphaOfLength(5), randomAlphaOfLength(5)); + } + runtimeFields.put(randomAlphaOfLength(5), config); + } + return runtimeFields; + } + + public static Collection readSpec(Class clazz, String testFileName) throws Exception { + ArrayList arr = new ArrayList<>(); + Map testNames = new LinkedHashMap<>(); + + try ( + InputStream is = clazz.getResourceAsStream(testFileName); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)) + ) { + int lineNumber = 0; + String line; + boolean done = false; + String name = null; + String query = null; + ArrayList> matchers = new ArrayList<>(8); + + StringBuilder sb = new StringBuilder(); + + while ((line = reader.readLine()) != null) { + lineNumber++; + line = line.trim(); + + if (line.isEmpty() || line.startsWith("//")) { + continue; + } + + if (name == null) { + name = line; + Integer previousName = testNames.put(name, lineNumber); + if (previousName != null) { + throw new IllegalArgumentException( + "Duplicate test name '" + line + "' at line " + lineNumber + " (previously seen at line " + previousName + ")" + ); + } + } + + else if (query == null) { + sb.append(line).append(' '); + if (line.endsWith(";")) { + sb.setLength(sb.length() - 2); + query = sb.toString(); + sb.setLength(0); + } + } + + else { + if (line.endsWith(";")) { + line = line.substring(0, line.length() - 1); + done = true; + } + + if (line.isEmpty() == false) { + String[] matcherAndExpectation = line.split("[ \\t]+", 2); + if (matcherAndExpectation.length == 1) { + matchers.add(containsString(matcherAndExpectation[0])); + } else if (matcherAndExpectation.length == 2) { + String matcherType = matcherAndExpectation[0]; + String expectation = matcherAndExpectation[1]; + switch (matcherType.toUpperCase(Locale.ROOT)) { + case MATCHER_TYPE_CONTAINS -> matchers.add(containsString(expectation)); + case MATCHER_TYPE_REGEX -> matchers.add(containsRegex(expectation)); + default -> throw new IllegalArgumentException( + "unsupported matcher on line " + testFileName + ":" + lineNumber + ": " + matcherType + ); + } + } + } + + if (done) { + // Add and zero out for the next spec + arr.add(new Object[] { testFileName, name, query, matchers }); + name = null; + query = null; + matchers = new ArrayList<>(8); + done = false; + } + } + } + + if (name != null) { + throw new IllegalStateException("Read a test [" + name + "] without a body at the end of [" + testFileName + "]"); + } + } + return arr; + } + + public static FieldAttribute getFieldAttribute(String name) { + return getFieldAttribute(name, INTEGER); + } + + public static FieldAttribute getFieldAttribute(String name, DataType dataType) { + return new FieldAttribute(EMPTY, name, new EsField(name + "f", dataType, emptyMap(), true)); + } + + // Matcher which extends the functionality of org.hamcrest.Matchers.matchesPattern(String)} + // by allowing to match detected regex groups later on in the pattern, e.g.: + // "(?.+?)"....... \k....."} + public static class StringContainsRegex extends TypeSafeDiagnosingMatcher { + + private final Pattern pattern; + + protected StringContainsRegex(Pattern pattern) { + this.pattern = pattern; + } + + @Override + public void describeTo(Description description) { + description.appendText("a string containing the pattern ").appendValue(pattern); + } + + @Override + protected boolean matchesSafely(String actual, Description mismatchDescription) { + if (pattern.matcher(actual).find() == false) { + mismatchDescription.appendText("the string was ").appendValue(actual); + return false; + } + return true; + } + + public static Matcher containsRegex(String regex) { + return new StringContainsRegex(Pattern.compile(regex)); + } + } +} diff --git a/x-pack/plugin/esql/build.gradle b/x-pack/plugin/esql/build.gradle index 102319d74d3d..669f38bd44ec 100644 --- a/x-pack/plugin/esql/build.gradle +++ b/x-pack/plugin/esql/build.gradle @@ -8,7 +8,7 @@ esplugin { name 'x-pack-esql' description 'The plugin that powers ESQL for Elasticsearch' classname 'org.elasticsearch.xpack.esql.plugin.EsqlPlugin' - extendedPlugins = ['x-pack-ql', 'lang-painless'] + extendedPlugins = ['x-pack-esql-core', 'lang-painless'] } base { @@ -18,7 +18,7 @@ base { dependencies { compileOnly project(path: xpackModule('core')) compileOnly project(':modules:lang-painless:spi') - compileOnly project(xpackModule('ql')) + compileOnly project(xpackModule('esql-core')) implementation project('compute') implementation project('compute:ann') implementation project(':libs:elasticsearch-dissect') diff --git a/x-pack/plugin/esql/compute/build.gradle b/x-pack/plugin/esql/compute/build.gradle index b4fb7637bc67..fce051ed6003 100644 --- a/x-pack/plugin/esql/compute/build.gradle +++ b/x-pack/plugin/esql/compute/build.gradle @@ -7,7 +7,7 @@ dependencies { annotationProcessor project('gen') testImplementation project(':test:framework') - testImplementation(project(xpackModule('ql'))) + testImplementation(project(xpackModule('esql-core'))) } tasks.named("compileJava").configure { diff --git a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java index e0533c68afd1..6618d9e4f41b 100644 --- a/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java +++ b/x-pack/plugin/esql/compute/gen/src/main/java/org/elasticsearch/compute/gen/Types.java @@ -120,7 +120,7 @@ public class Types { static final ClassName WARNINGS = ClassName.get("org.elasticsearch.xpack.esql.expression.function", "Warnings"); - static final ClassName SOURCE = ClassName.get("org.elasticsearch.xpack.ql.tree", "Source"); + static final ClassName SOURCE = ClassName.get("org.elasticsearch.xpack.esql.core.tree", "Source"); static final ClassName BYTES_REF = ClassName.get("org.apache.lucene.util", "BytesRef"); diff --git a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BasicBlockTests.java b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BasicBlockTests.java index 017d4c7065be..1d58d49c9282 100644 --- a/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BasicBlockTests.java +++ b/x-pack/plugin/esql/compute/src/test/java/org/elasticsearch/compute/data/BasicBlockTests.java @@ -41,8 +41,8 @@ import java.util.stream.IntStream; import java.util.stream.LongStream; import static java.util.Collections.singletonList; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; diff --git a/x-pack/plugin/esql/qa/action/build.gradle b/x-pack/plugin/esql/qa/action/build.gradle index 171f0c39df21..433fd667e97f 100644 --- a/x-pack/plugin/esql/qa/action/build.gradle +++ b/x-pack/plugin/esql/qa/action/build.gradle @@ -11,6 +11,6 @@ dependencies { testImplementation(testArtifact(project(xpackModule('core')))) // runtime only - since the test source should not explicitly depend // upon any types from ES|QL (only xpack core) - testImplementation project(':x-pack:plugin:ql') + testImplementation project(':x-pack:plugin:esql-core') testImplementation project(':x-pack:plugin:esql') } diff --git a/x-pack/plugin/esql/qa/server/build.gradle b/x-pack/plugin/esql/qa/server/build.gradle index fe5e08cda32f..a023772dc592 100644 --- a/x-pack/plugin/esql/qa/server/build.gradle +++ b/x-pack/plugin/esql/qa/server/build.gradle @@ -6,7 +6,7 @@ dependencies { api project(":test:framework") // Common utilities from QL - api project(xpackModule('ql:test-fixtures')) + api project(xpackModule('esql-core:test-fixtures')) // Requirement for some ESQL-specific utilities implementation project(':x-pack:plugin:esql') api project(xpackModule('esql:qa:testFixtures')) diff --git a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java index 5153d7a2a6d9..cbfa043b9dc5 100644 --- a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/MixedClusterEsqlSpecIT.java @@ -11,8 +11,8 @@ import org.elasticsearch.Version; import org.elasticsearch.features.NodeFeature; import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.test.rest.TestFeatureService; +import org.elasticsearch.xpack.esql.core.CsvSpecReader.CsvTestCase; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.ql.CsvSpecReader.CsvTestCase; import org.junit.AfterClass; import org.junit.Before; import org.junit.ClassRule; diff --git a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java index fb6a59bf4190..39373c6a53c0 100644 --- a/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClusterSpecIT.java @@ -21,10 +21,10 @@ import org.elasticsearch.test.TestClustersThreadFilter; import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.TestFeatureService; +import org.elasticsearch.xpack.esql.core.CsvSpecReader; +import org.elasticsearch.xpack.esql.core.CsvSpecReader.CsvTestCase; +import org.elasticsearch.xpack.esql.core.SpecReader; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.ql.CsvSpecReader; -import org.elasticsearch.xpack.ql.CsvSpecReader.CsvTestCase; -import org.elasticsearch.xpack.ql.SpecReader; import org.junit.AfterClass; import org.junit.ClassRule; import org.junit.rules.RuleChain; @@ -44,9 +44,9 @@ import java.util.stream.Collectors; import static org.elasticsearch.xpack.esql.CsvTestUtils.isEnabled; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.ENRICH_SOURCE_INDICES; +import static org.elasticsearch.xpack.esql.core.CsvSpecReader.specParser; +import static org.elasticsearch.xpack.esql.core.TestUtils.classpathResources; import static org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase.Mode.SYNC; -import static org.elasticsearch.xpack.ql.CsvSpecReader.specParser; -import static org.elasticsearch.xpack.ql.TestUtils.classpathResources; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; diff --git a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java index 67b916a81581..aeb8fa96d0db 100644 --- a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/EsqlSpecIT.java @@ -8,8 +8,8 @@ package org.elasticsearch.xpack.esql.qa.multi_node; import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.xpack.esql.core.CsvSpecReader.CsvTestCase; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.ql.CsvSpecReader.CsvTestCase; import org.junit.ClassRule; public class EsqlSpecIT extends EsqlSpecTestCase { diff --git a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java index db737e367875..a3af3cbc8458 100644 --- a/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java +++ b/x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/EsqlSpecIT.java @@ -11,8 +11,8 @@ import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters; import org.elasticsearch.test.TestClustersThreadFilter; import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.xpack.esql.core.CsvSpecReader.CsvTestCase; import org.elasticsearch.xpack.esql.qa.rest.EsqlSpecTestCase; -import org.elasticsearch.xpack.ql.CsvSpecReader.CsvTestCase; import org.junit.ClassRule; @ThreadLeakFilters(filters = TestClustersThreadFilter.class) diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java index f44e82a3002f..3847ec7b74ca 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/EsqlSpecTestCase.java @@ -28,11 +28,11 @@ import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.TestFeatureService; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.esql.CsvTestUtils; +import org.elasticsearch.xpack.esql.core.CsvSpecReader.CsvTestCase; +import org.elasticsearch.xpack.esql.core.SpecReader; import org.elasticsearch.xpack.esql.plugin.EsqlFeatures; import org.elasticsearch.xpack.esql.qa.rest.RestEsqlTestCase.RequestObjectBuilder; import org.elasticsearch.xpack.esql.version.EsqlVersion; -import org.elasticsearch.xpack.ql.CsvSpecReader.CsvTestCase; -import org.elasticsearch.xpack.ql.SpecReader; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -61,8 +61,8 @@ import static org.elasticsearch.xpack.esql.CsvTestUtils.isEnabled; import static org.elasticsearch.xpack.esql.CsvTestUtils.loadCsvSpecValues; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.CSV_DATASET_MAP; import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.loadDataSetIntoEs; -import static org.elasticsearch.xpack.ql.CsvSpecReader.specParser; -import static org.elasticsearch.xpack.ql.TestUtils.classpathResources; +import static org.elasticsearch.xpack.esql.core.CsvSpecReader.specParser; +import static org.elasticsearch.xpack.esql.core.TestUtils.classpathResources; // This test can run very long in serverless configurations @TimeoutSuite(millis = 30 * TimeUnits.MINUTE) diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java index 0163530777fe..40c549f336ef 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java @@ -426,7 +426,7 @@ public abstract class RestEsqlTestCase extends ESRestTestCase { for (int i = 1; i < warnings.size(); i++) { assertThat( warnings.get(i), - containsString("org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [keyword") + containsString("org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [keyword") ); } } diff --git a/x-pack/plugin/esql/qa/testFixtures/build.gradle b/x-pack/plugin/esql/qa/testFixtures/build.gradle index 52a0df539e93..520873a6cb03 100644 --- a/x-pack/plugin/esql/qa/testFixtures/build.gradle +++ b/x-pack/plugin/esql/qa/testFixtures/build.gradle @@ -9,7 +9,7 @@ dependencies { implementation project(':client:rest') implementation project(':libs:elasticsearch-logging') implementation project(':test:framework') - api(testArtifact(project(xpackModule('ql')))) + api(testArtifact(project(xpackModule('esql-core')))) implementation project(':server') api "net.sf.supercsv:super-csv:${versions.supercsv}" } diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java index dcbcaea3ce50..af3af033efd4 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java @@ -34,10 +34,10 @@ import static org.elasticsearch.xpack.esql.CsvTestUtils.ExpectedResults; import static org.elasticsearch.xpack.esql.CsvTestUtils.Type; import static org.elasticsearch.xpack.esql.CsvTestUtils.Type.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.CsvTestUtils.logMetaData; -import static org.elasticsearch.xpack.ql.util.DateUtils.UTC_DATE_TIME_FORMATTER; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.DateUtils.UTC_DATE_TIME_FORMATTER; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java index ef9d7bcc8961..9c1b4de803bc 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java @@ -28,7 +28,7 @@ import org.elasticsearch.core.Tuple; import org.elasticsearch.logging.Logger; import org.elasticsearch.test.VersionUtils; import org.elasticsearch.xpack.esql.action.ResponseValueUtils; -import org.elasticsearch.xpack.ql.util.StringUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.supercsv.io.CsvListReader; import org.supercsv.prefs.CsvPreference; @@ -51,12 +51,12 @@ import java.util.regex.Pattern; import static org.elasticsearch.common.Strings.delimitedListToStringArray; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; -import static org.elasticsearch.xpack.ql.SpecReader.shouldSkipLine; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToUnsignedLong; -import static org.elasticsearch.xpack.ql.util.DateUtils.UTC_DATE_TIME_FORMATTER; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.SpecReader.shouldSkipLine; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToUnsignedLong; +import static org.elasticsearch.xpack.esql.core.util.DateUtils.UTC_DATE_TIME_FORMATTER; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; public final class CsvTestUtils { private static final int MAX_WIDTH = 20; @@ -148,7 +148,7 @@ public final class CsvTestUtils { CsvColumn[] columns = null; var blockFactory = BlockFactory.getInstance(new NoopCircuitBreaker("test-noop"), BigArrays.NON_RECYCLING_INSTANCE); - try (BufferedReader reader = org.elasticsearch.xpack.ql.TestUtils.reader(source)) { + try (BufferedReader reader = org.elasticsearch.xpack.esql.core.TestUtils.reader(source)) { String line; int lineNumber = 1; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java index 04c059d8ef95..e9d6b1f5c6b8 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java @@ -31,7 +31,7 @@ import org.elasticsearch.xcontent.XContent; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.ql.TestUtils; +import org.elasticsearch.xpack.esql.core.TestUtils; import java.io.BufferedReader; import java.io.IOException; @@ -314,7 +314,7 @@ public class CsvTestsDataLoader { ) throws IOException { ArrayList failures = new ArrayList<>(); StringBuilder builder = new StringBuilder(); - try (BufferedReader reader = org.elasticsearch.xpack.ql.TestUtils.reader(resource)) { + try (BufferedReader reader = org.elasticsearch.xpack.esql.core.TestUtils.reader(resource)) { String line; int lineNumber = 1; String[] columns = null; // list of column names. If one column name contains dot, it is a subfield and its value will be null diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java index 3d5468cd2bfc..be93ac0ed301 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java @@ -21,6 +21,16 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DateUtils; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.TypesTests; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; @@ -31,16 +41,6 @@ import org.elasticsearch.xpack.esql.stats.Metrics; import org.elasticsearch.xpack.esql.stats.SearchStats; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; import org.elasticsearch.xpack.esql.version.EsqlVersion; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.DateUtils; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.type.TypesTests; -import org.elasticsearch.xpack.ql.util.StringUtils; import org.junit.Assert; import java.io.IOException; @@ -60,7 +60,7 @@ import static java.util.Collections.unmodifiableMap; import static org.elasticsearch.test.ESTestCase.randomBoolean; import static org.elasticsearch.test.ListMatcher.matchesList; import static org.elasticsearch.test.MapMatcher.assertMap; -import static org.elasticsearch.xpack.ql.TestUtils.of; +import static org.elasticsearch.xpack.esql.core.TestUtils.of; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertTrue; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec index 94dfd9f3267f..3ef1a322eb94 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/convert.csv-spec @@ -40,8 +40,8 @@ convertToLongWithWarning required_capability: casting_operator ROW long="1.1.1.1"::long ; -warning:Line 1:10: evaluation of [\"1.1.1.1\"::long] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:10: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [1.1.1.1] +warningRegex:Line 1:10: evaluation of \[\\\"1.1.1.1\\\"::long\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:10: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[1.1.1.1\] long:long null diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec index 22e9231939d0..0c808afc9d12 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec @@ -219,8 +219,8 @@ convertFromUnsignedLong required_capability: convert_warn row ul = [9223372036854775808, 520128000000] | eval dt = to_datetime(ul); -warning:Line 1:58: evaluation of [to_datetime(ul)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:58: org.elasticsearch.xpack.ql.InvalidArgumentException: [9223372036854775808] out of [long] range +warningRegex:Line 1:58: evaluation of \[to_datetime\(ul\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:58: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: \[9223372036854775808\] out of \[long\] range ul:ul | dt:date [9223372036854775808, 520128000000]|1986-06-26T00:00:00.000Z @@ -336,8 +336,8 @@ ROW date1=to_datetime("2023-12-02T11:00:00.000Z"), date2=to_datetime("2023-12-23 | EVAL dd_oo=date_diff("nanoseconds", date1, date2) | keep dd_oo ; -warning: Line 2:14: evaluation of [date_diff(\"nanoseconds\", date1, date2)] failed, treating result as null. Only first 20 failures recorded. -warning: Line 2:14: org.elasticsearch.xpack.ql.InvalidArgumentException: [1814400000000000] out of [integer] range +warningRegex: Line 2:14: evaluation of \[date_diff\(\\\"nanoseconds\\\", date1, date2\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex: Line 2:14: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: \[1814400000000000\] out of \[integer\] range dd_oo:integer null diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/floats.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/floats.csv-spec index 1f2bcb6b5120..bbe0df9a8cda 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/floats.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/floats.csv-spec @@ -61,8 +61,8 @@ ROW str1 = "5.20128E11", str2 = "foo" | EVAL dbl = TO_DOUBLE("520128000000"), dbl1 = TO_DOUBLE(str1), dbl2 = TO_DOUBLE(str2) // end::to_double-str[] ; -warning:Line 2:72: evaluation of [TO_DOUBLE(str2)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 2:72: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [foo] +warningRegex:Line 2:72: evaluation of \[TO_DOUBLE\(str2\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 2:72: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[foo\] // tag::to_double-str-result[] str1:keyword |str2:keyword |dbl:double |dbl1:double |dbl2:double diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ints.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ints.csv-spec index e247d6c3a04e..2e45febe0de1 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ints.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/ints.csv-spec @@ -72,7 +72,7 @@ required_capability: convert_warn row d = 123.4 | eval ul = to_ul(d), overflow = to_ul(1e20); warningRegex:Line 1:48: evaluation of \[to_ul\(1e20\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:48: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[1.0E20\] out of \[unsigned_long\] range +warningRegex:Line 1:48: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[1.0E20\] out of \[unsigned_long\] range d:double |ul:ul |overflow:ul 123.4 |123 |null @@ -131,7 +131,7 @@ required_capability: convert_warn row ul = [9223372036854775807, 9223372036854775808] | eval long = to_long(ul); warningRegex:Line 1:67: evaluation of \[to_long\(ul\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:67: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[9223372036854775808\] out of \[long\] range +warningRegex:Line 1:67: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[9223372036854775808\] out of \[long\] range ul:ul | long:long [9223372036854775807, 9223372036854775808]|9223372036854775807 @@ -159,8 +159,8 @@ ROW str1 = "2147483648", str2 = "2147483648.2", str3 = "foo" | EVAL long1 = TO_LONG(str1), long2 = TO_LONG(str2), long3 = TO_LONG(str3) // end::to_long-str[] ; -warning:Line 2:62: evaluation of [TO_LONG(str3)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 2:62: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [foo] +warningRegex:Line 2:62: evaluation of \[TO_LONG\(str3\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 2:62: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[foo\] // tag::to_long-str-result[] @@ -174,7 +174,7 @@ required_capability: convert_warn row d = 123.4 | eval d2l = to_long(d), overflow = to_long(1e19); warningRegex:Line 1:51: evaluation of \[to_long\(1e19\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:51: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[1.0E19\] out of \[long\] range +warningRegex:Line 1:51: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[1.0E19\] out of \[long\] range d:double |d2l:long |overflow:long 123.4 |123 |null @@ -198,7 +198,7 @@ ROW long = [5013792, 2147483647, 501379200000] // end::to_int-long[] ; warningRegex:Line 2:14: evaluation of \[TO_INTEGER\(long\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 2:14: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[501379200000\] out of \[integer\] range +warningRegex:Line 2:14: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[501379200000\] out of \[integer\] range // tag::to_int-long-result[] long:long |int:integer @@ -211,7 +211,7 @@ required_capability: convert_warn row ul = [2147483647, 9223372036854775808] | eval int = to_int(ul); warningRegex:Line 1:57: evaluation of \[to_int\(ul\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:57: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[9223372036854775808\] out of \[integer\] range +warningRegex:Line 1:57: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[9223372036854775808\] out of \[integer\] range ul:ul |int:integer [2147483647, 9223372036854775808]|2147483647 @@ -242,12 +242,12 @@ convertStringToIntFail#[skip:-8.13.99, reason:warning changed in 8.14] required_capability: mv_warn row str1 = "2147483647.2", str2 = "2147483648", non = "no number" | eval i1 = to_integer(str1), i2 = to_integer(str2), noi = to_integer(non); -warning:Line 1:79: evaluation of [to_integer(str1)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:79: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [2147483647.2] -warning:Line 1:102: evaluation of [to_integer(str2)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:102: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [2147483648] -warning:Line 1:126: evaluation of [to_integer(non)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:126: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [no number] +warningRegex:Line 1:79: evaluation of \[to_integer\(str1\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:79: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[2147483647.2\] +warningRegex:Line 1:102: evaluation of \[to_integer\(str2\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:102: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[2147483648\] +warningRegex:Line 1:126: evaluation of \[to_integer\(non\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:126: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[no number\] str1:keyword |str2:keyword |non:keyword |i1:integer |i2:integer |noi:integer 2147483647.2 |2147483648 |no number |null |null |null @@ -258,7 +258,7 @@ required_capability: convert_warn row d = 123.4 | eval d2i = to_integer(d), overflow = to_integer(1e19); warningRegex:Line 1:54: evaluation of \[to_integer\(1e19\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:54: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[1.0E19\] out of \[integer\] range +warningRegex:Line 1:54: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[1.0E19\] out of \[integer\] range d:double |d2i:integer |overflow:integer 123.4 |123 |null @@ -734,7 +734,7 @@ ROW deg = [90, 180, 270] warningWithFromSource from employees | sort emp_no | limit 1 | eval x = to_long(emp_no) * 10000000 | eval y = to_int(x) > 1 | keep y; warningRegex:Line 1:89: evaluation of \[to_int\(x\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:89: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[10\d+0000000\] out of \[integer\] range +warningRegex:Line 1:89: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[10\d+0000000\] out of \[integer\] range y:boolean null @@ -744,7 +744,7 @@ null multipleWarnings from employees | sort emp_no | eval x = to_long(emp_no) * 10000000 | where to_int(x) > 1 | keep x | limit 1; warningRegex:Line 1:76: evaluation of \[to_int\(x\)\] failed, treating result as null. Only first 20 failures recorded. -warningRegex:Line 1:76: org.elasticsearch.xpack.ql.(Invalid|QlIllegal)ArgumentException: \[10\d+0000000\] out of \[integer\] range +warningRegex:Line 1:76: org.elasticsearch.xpack.(esql.core|ql).(Invalid|QlIllegal)ArgumentException: \[10\d+0000000\] out of \[integer\] range x:long ; diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/row.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/row.csv-spec index 3f441c94967d..bb1cf7358ca7 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/row.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/row.csv-spec @@ -291,8 +291,8 @@ a:integer |b:integer |c:integer convertMvToMvDifferentCardinality#[skip:-8.13.99, reason:warning changed in 8.14] row strings = ["1", "2", "three"] | eval ints = to_int(strings); -warning:Line 1:49: evaluation of [to_int(strings)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:49: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [three] +warningRegex:Line 1:49: evaluation of \[to_int\(strings\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:49: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[three\] strings:keyword |ints:integer [1, 2, three] |[1, 2] @@ -301,8 +301,8 @@ strings:keyword |ints:integer convertMvToSv#[skip:-8.13.99, reason:warning changed in 8.14] row strings = ["1", "two"] | eval ints = to_int(strings); -warning:Line 1:42: evaluation of [to_int(strings)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:42: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [two] +warningRegex:Line 1:42: evaluation of \[to_int\(strings\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:42: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[two\] strings:keyword |ints:integer [1, two] |1 @@ -310,9 +310,9 @@ strings:keyword |ints:integer convertMvToNull#[skip:-8.13.99, reason:warning changed in 8.14] row strings = ["one", "two"] | eval ints = to_int(strings); -warning:Line 1:44: evaluation of [to_int(strings)] failed, treating result as null. Only first 20 failures recorded. -warning:Line 1:44: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [one] -warning:Line 1:44: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [two] +warningRegex:Line 1:44: evaluation of \[to_int\(strings\)\] failed, treating result as null. Only first 20 failures recorded. +warningRegex:Line 1:44: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[one\] +warningRegex:Line 1:44: org.elasticsearch.xpack.(esql.core|ql).InvalidArgumentException: Cannot parse number \[two\] strings:keyword |ints:integer [one, two] |null diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/evaluator/predicate/operator/logical/NotEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/evaluator/predicate/operator/logical/NotEvaluator.java index 822d380386ee..8479e2c073d8 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/evaluator/predicate/operator/logical/NotEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/evaluator/predicate/operator/logical/NotEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Not}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBooleanEvaluator.java index 75558171ab58..e136926ea1f5 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBooleanEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Greatest}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBytesRefEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBytesRefEvaluator.java index e70d147ec19b..bff5eb17aa98 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBytesRefEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestBytesRefEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Greatest}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestDoubleEvaluator.java index 4a5d49cb5853..c82e076e6d80 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestDoubleEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Greatest}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestIntEvaluator.java index 6c675c316852..28dbdd4218c1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestIntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Greatest}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestLongEvaluator.java index 3f4f0c748db3..8e907c20742e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Greatest}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBooleanEvaluator.java index 70d4345fe197..f99f385ba616 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBooleanEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Least}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBytesRefEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBytesRefEvaluator.java index 642ca36574cb..23d03102eed5 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBytesRefEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastBytesRefEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Least}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastDoubleEvaluator.java index 41b0ad4d4d08..4dae6fe78041 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastDoubleEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Least}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastIntEvaluator.java index c2c80db6ca0b..a6a1cac60146 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastIntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Least}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastLongEvaluator.java index cd8ab3a0cd06..e8416095d46b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Least}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Evaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Evaluator.java index 5eb0071b2264..fff0acc5009f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Evaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Evaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link FromBase64}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Evaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Evaluator.java index 785a935e73f3..2bf0df5caeec 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Evaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Evaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToBase64}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromDoubleEvaluator.java index c64568251fee..c4264fb78be9 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromDoubleEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.DoubleVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToBoolean}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromIntEvaluator.java index daac34639c66..43ac58d1f0fc 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromIntEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.IntVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToBoolean}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromLongEvaluator.java index 1e6b2aefce9f..c8b2814a3f6d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromLongEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToBoolean}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromStringEvaluator.java index ce573a3b8d2d..8859bfce25ba 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromStringEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToBoolean}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromUnsignedLongEvaluator.java index 5ec75f10c2ec..2f4037ff3b11 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanFromUnsignedLongEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToBoolean}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointFromStringEvaluator.java index ee5159be521d..7c47e39dfba1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointFromStringEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToCartesianPoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeFromStringEvaluator.java index 5ec9dcb94f67..6ae079e153e0 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeFromStringEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToCartesianShape}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeFromStringEvaluator.java index b868fe9b950c..3e074dba3d45 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeFromStringEvaluator.java @@ -15,7 +15,7 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDatetime}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesEvaluator.java index 8b581cbac598..11bf9ffed0fb 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.DoubleVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDegrees}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromBooleanEvaluator.java index c831e1b0a314..60433ea5efae 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromBooleanEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.DoubleBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDouble}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromIntEvaluator.java index ef1081f4ebd6..1e3c48f472ad 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromIntEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.IntVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDouble}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromLongEvaluator.java index fc78d9cfebc0..6e959a28459a 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromLongEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDouble}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromStringEvaluator.java index 209b15ef21a2..6613fc1dd6b9 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromStringEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.DoubleBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDouble}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromUnsignedLongEvaluator.java index b2e4e5137543..9badb00fc472 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleFromUnsignedLongEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToDouble}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointFromStringEvaluator.java index 7ef047655b49..ad33737f3da1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointFromStringEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToGeoPoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeFromStringEvaluator.java index 68a6087d8695..db59fd3a16da 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeFromStringEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToGeoShape}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPFromStringEvaluator.java index bd6e883a6e89..7a2b2a016d60 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPFromStringEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToIP}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromBooleanEvaluator.java index f778deb32865..9bd1304024ad 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromBooleanEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToInteger}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromDoubleEvaluator.java index 329269bafd9b..5057037993f6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromDoubleEvaluator.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToInteger}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromLongEvaluator.java index f9b3cb60dad2..b2e891a6e65d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromLongEvaluator.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToInteger}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromStringEvaluator.java index ef91bf890cd2..d50c18501e37 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromStringEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToInteger}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromUnsignedLongEvaluator.java index 34128e44f150..31fadc9f2884 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerFromUnsignedLongEvaluator.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToInteger}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromBooleanEvaluator.java index 7d6c145405e5..668bedfa4440 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromBooleanEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromDoubleEvaluator.java index 03daa257e5af..cb1c10558f10 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromDoubleEvaluator.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromIntEvaluator.java index dc3a9578ffd9..74be177061f7 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromIntEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromStringEvaluator.java index 0d7a2cb9d745..1d58a05c7d97 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromStringEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromUnsignedLongEvaluator.java index b5999d1a4e1a..af911e5b787a 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongFromUnsignedLongEvaluator.java @@ -12,8 +12,8 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansEvaluator.java index 3bd997d0b1d3..6aed22da1b01 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansEvaluator.java @@ -12,7 +12,7 @@ import org.elasticsearch.compute.data.DoubleVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToRadians}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromBooleanEvaluator.java index a68cd61a8c47..47af1b25c88e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromBooleanEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.BytesRefBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianPointEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianPointEvaluator.java index b15f77608598..d42c945c0cee 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianPointEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianPointEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianShapeEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianShapeEvaluator.java index 5e466ddfbfdd..93901e1c4486 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianShapeEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromCartesianShapeEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDatetimeEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDatetimeEvaluator.java index 569881ad30b6..e179f92665a7 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDatetimeEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDatetimeEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDoubleEvaluator.java index 69c33e07c165..7815b3384539 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromDoubleEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.DoubleVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoPointEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoPointEvaluator.java index 32fe16075e04..42b3c37fed89 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoPointEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoPointEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoShapeEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoShapeEvaluator.java index df8e86e58fa6..a8c1b8e241ba 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoShapeEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromGeoShapeEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIPEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIPEvaluator.java index 00fb269699fe..d51ae78956c2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIPEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIPEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIntEvaluator.java index 6e371c90adb2..cfff78cf3b55 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromIntEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.IntVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromLongEvaluator.java index 3dc8f738d7b1..f4e0046f93f4 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromLongEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromUnsignedLongEvaluator.java index 4bce2c1fec40..57275460a181 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromUnsignedLongEvaluator.java @@ -14,7 +14,7 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromVersionEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromVersionEvaluator.java index a37696e149d4..816963dd7353 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromVersionEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringFromVersionEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToString}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromBooleanEvaluator.java index 619a4ec09d60..3b7dd65b68f2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromBooleanEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToUnsignedLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromDoubleEvaluator.java index 6a45dcf90788..1a6b9ee26557 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromDoubleEvaluator.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToUnsignedLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromIntEvaluator.java index 703f0729654a..56c3c0cecc22 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromIntEvaluator.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToUnsignedLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromLongEvaluator.java index b43b961f5d34..323661261ce5 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromLongEvaluator.java @@ -12,8 +12,8 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToUnsignedLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromStringEvaluator.java index 5b46fe2bfc9b..0f3096c4824d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongFromStringEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToUnsignedLong}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionFromStringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionFromStringEvaluator.java index 5945129a8ae0..fecd2b62e53a 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionFromStringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionFromStringEvaluator.java @@ -13,7 +13,7 @@ import org.elasticsearch.compute.data.BytesRefVector; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToVersion}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffConstantEvaluator.java index 3cb41d0028d5..6543e1e9bcb2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffConstantEvaluator.java @@ -15,9 +15,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateDiff}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffEvaluator.java index 952a819a014a..7d7874c1beb9 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffEvaluator.java @@ -18,9 +18,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateDiff}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractConstantEvaluator.java index 8b1804cacfc2..4f63a5579474 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateExtract}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractEvaluator.java index 65af16e2a9f5..dafe99859f77 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateExtract}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatConstantEvaluator.java index 38cc3e2809f0..55170fc19d05 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatConstantEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateFormat}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatEvaluator.java index d517c16cb407..9b2df06b61ce 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateFormat}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseConstantEvaluator.java index 3a6b44d82a01..28ef039cf72c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseConstantEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateParse}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseEvaluator.java index 2da9310b0f53..4f1018b44658 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateParse}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncEvaluator.java index 27a15ca19bec..5630f963eac2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link DateTrunc}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/NowEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/NowEvaluator.java index 45465468f7c9..51e00309f445 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/NowEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/NowEvaluator.java @@ -11,8 +11,8 @@ import org.elasticsearch.compute.data.LongVector; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Now}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchEvaluator.java index 4ac2fa7d2738..0f91568f3643 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link CIDRMatch}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsDoubleEvaluator.java index d7c793b99e57..917f2efac561 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsDoubleEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Abs}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsIntEvaluator.java index 9964a95fafe0..fa8a17266cbc 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsIntEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Abs}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsLongEvaluator.java index 9457112aa9d8..0a8f122176f0 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsLongEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Abs}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosEvaluator.java index 1c86fe46e9b9..1d7d18ff1e43 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Acos}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinEvaluator.java index fc73f4c47567..c5d116c3bce8 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Asin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Evaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Evaluator.java index b6d0a628c329..c71612a98d7e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Evaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Evaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Atan2}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanEvaluator.java index b40a6cde6550..fd6bbfd2b8a3 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Atan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToDoubleEvaluator.java index a13d11199c0f..ccd453db17df 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToDoubleEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cast}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToLongEvaluator.java index cf91f080537e..b2f965d9862e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cast}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToUnsignedLongEvaluator.java index 15b18a91ee24..723acd381886 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastIntToUnsignedLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cast}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToDoubleEvaluator.java index 1bb63cb66eec..3a18e2f3d6c7 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToDoubleEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cast}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToUnsignedLongEvaluator.java index 3ed067671183..4b4b30ff5452 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastLongToUnsignedLongEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cast}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastUnsignedLongToDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastUnsignedLongToDoubleEvaluator.java index 5135aab0dcc5..f5cf77cde426 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastUnsignedLongToDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CastUnsignedLongToDoubleEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cast}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtDoubleEvaluator.java index 67549b6c8daa..adb850f6dc57 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtDoubleEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cbrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtIntEvaluator.java index 4b582cf5e165..8d1fb71f79a0 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtIntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cbrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtLongEvaluator.java index b23f2a6935dd..766fe75bf828 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cbrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtUnsignedLongEvaluator.java index 61b5808b4cb8..b3b0567a058e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtUnsignedLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cbrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilDoubleEvaluator.java index 500f108afbe3..30882e1c0777 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilDoubleEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Ceil}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosEvaluator.java index dd3961845c24..d92c19a9637f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cos}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshEvaluator.java index 2f0bbaaacb40..1c113bd9655a 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Cosh}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorDoubleEvaluator.java index f8a10822a3c4..867c43951818 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorDoubleEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Floor}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10DoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10DoubleEvaluator.java index d402cf7a79e6..8fa1e7218ac6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10DoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10DoubleEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Log10}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10IntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10IntEvaluator.java index a1aa03af7d7f..417074d0a47b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10IntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10IntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Log10}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10LongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10LongEvaluator.java index 848baaea72b6..1134de7f76b0 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10LongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10LongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Log10}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10UnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10UnsignedLongEvaluator.java index 01812d8b1d2c..6f5f036e29a6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10UnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10UnsignedLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Log10}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogConstantEvaluator.java index ff814b530b10..82d34296a64d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogConstantEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Log}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogEvaluator.java index 7fcfb37483bb..9ef5cf8d9580 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Log}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowEvaluator.java index 33bf2b4bd0c2..2721150e4900 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Pow}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleEvaluator.java index 3b85a32fc308..07d165f9b102 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Round}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleNoDecimalsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleNoDecimalsEvaluator.java index c36a1fe25b61..cf7300ce8aea 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleNoDecimalsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundDoubleNoDecimalsEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Round}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundIntEvaluator.java index f96f92e5d0b3..0ea8111d392c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundIntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Round}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundLongEvaluator.java index c8a2fdd384f4..9f862a4e7289 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundLongEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Round}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundUnsignedLongEvaluator.java index 5c94e386d497..3d07675692f8 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundUnsignedLongEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Round}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumDoubleEvaluator.java index c7d21a7b9c5a..4fbac4ce9639 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumDoubleEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Signum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumIntEvaluator.java index 939807d8deff..122779e1d5e6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumIntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Signum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumLongEvaluator.java index 0c4af4671672..aaae4eb6ba1c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Signum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumUnsignedLongEvaluator.java index d3b20c98139c..4070836e89c1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumUnsignedLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Signum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinEvaluator.java index a3c9e1481c19..7e7484b3f47c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhEvaluator.java index c6020d6bd86e..6850b2e15195 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sinh}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtDoubleEvaluator.java index 516d6639fb11..60d735cdf6a2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtDoubleEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sqrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtIntEvaluator.java index 3719bc6bd732..0e13726e3a4b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtIntEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sqrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtLongEvaluator.java index a9620291ddd8..5695b23eba72 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sqrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtUnsignedLongEvaluator.java index 6478f0639bb9..fd60cbb41941 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtUnsignedLongEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sqrt}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanEvaluator.java index ed410d20d122..78214b1c0d32 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Tan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhEvaluator.java index 94fa4fad18fd..1acd2b47174c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Tanh}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBooleanEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBooleanEvaluator.java index 6c4174bd9cca..d63da310b7ac 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBooleanEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBooleanEvaluator.java @@ -14,9 +14,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSlice}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBytesRefEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBytesRefEvaluator.java index 4a4a169e45ae..f9ad5518e579 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBytesRefEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceBytesRefEvaluator.java @@ -14,9 +14,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSlice}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceDoubleEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceDoubleEvaluator.java index 3e4a83cec68b..13eed4711c8f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceDoubleEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceDoubleEvaluator.java @@ -14,9 +14,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSlice}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceIntEvaluator.java index fc54dfb1f833..114677f07026 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceIntEvaluator.java @@ -13,9 +13,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSlice}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceLongEvaluator.java index d6a1e7e45cab..207d342a1b72 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceLongEvaluator.java @@ -14,9 +14,9 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSlice}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumIntEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumIntEvaluator.java index 20ae9a404738..dea92249e7e0 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumIntEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumIntEvaluator.java @@ -11,8 +11,8 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumLongEvaluator.java index bff596a76d69..dda5638fbeef 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumLongEvaluator.java @@ -11,8 +11,8 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumUnsignedLongEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumUnsignedLongEvaluator.java index 28ae5e5a2da3..83ca390fdd90 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumUnsignedLongEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumUnsignedLongEvaluator.java @@ -11,8 +11,8 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvSum}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipEvaluator.java index b53a1c8f9b3c..37f880408293 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MvZip}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java index 982bbd3b518d..32bc1acf0dcd 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java index 5b536707e8a0..832e8f990720 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianPointDocValuesAndSourceEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java index a9c3a4f887a7..a1c8d482ddca 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java index d2456597b576..38c1087cc760 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsCartesianSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java index de4537e6e0a1..49c7d1433dae 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java index 348c343f0b00..b1fee22fcb20 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoPointDocValuesAndSourceEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java index a84c661df18d..377ead4fb938 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java index 6bff91629f74..f906969a0357 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsGeoSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialContains}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java index 62b5761cfd65..1265e3eb7f49 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java index 4f11da3c474a..6a6f1a292a59 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianPointDocValuesAndSourceEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java index adb5a33b83f3..46dded83d3af 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java index 186a1299a4a9..a7cea9330aa0 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointCartesianSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java index 675b6cc58197..e52c04c4d72b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java index 1b22e67d11b2..3e8df2f0b785 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoPointDocValuesAndSourceEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java index 1df80cf90bd1..c061ecf09ced 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java index 9bdc60813ad6..9d617a39973f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointGeoSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialDisjoint}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java index e32357c42bf7..775680d2cde4 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java index 7bf47b766bd9..4b6d8168000a 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianPointDocValuesAndSourceEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java index 979869dc86c5..d7e6507bec3e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java index 6c47745d6af3..f1581fefbf0f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsCartesianSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java index 8d87884d0407..c1618b407b0e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java index 45e9daf5bc45..89ba6c79c06d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoPointDocValuesAndSourceEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java index f043ff4104bb..8fa0f02b783b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java index 9f5f1c7cc967..a6dc48b76198 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsGeoSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialIntersects}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java index 6deb7133fcf1..f17a5183e9a3 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java index d2470583c3a7..702f59970069 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianPointDocValuesAndSourceEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java index 45c8f60d12b0..2e16e18b5677 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java index 958ac825eeb0..1714ff54543e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinCartesianSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java index 680cf7b38445..2df0772da62b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndConstantEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java index 624b9243a62c..458532018ffd 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoPointDocValuesAndSourceEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java index 3647594337c5..f284cc124260 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java index 8794c3d0488b..2f18cb11d06e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinGeoSourceAndSourceEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link SpatialWithin}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXFromWKBEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXFromWKBEvaluator.java index 937eedc1d8fe..d396529f532e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXFromWKBEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXFromWKBEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.DoubleBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StX}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYFromWKBEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYFromWKBEvaluator.java index 33405f6db599..4e6e3a2ccd75 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYFromWKBEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYFromWKBEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.DoubleBlock; import org.elasticsearch.compute.data.Vector; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StY}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatchEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatchEvaluator.java index fb95bbc1acef..223f607a8b23 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatchEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatchEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link AutomataMatch}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatEvaluator.java index 99e87ce490eb..0b539a5fdaf7 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Concat}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithEvaluator.java index 8d1d197aae9a..7c00bd2e27cc 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link EndsWith}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimEvaluator.java index 0f68955507d5..f04e56d0b87f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LTrim}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftEvaluator.java index 13e7cbe9ece9..6c0e392cf612 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Left}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthEvaluator.java index 890b56e78ca1..25877cfc3d5b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Length}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateEvaluator.java index 24055ad44f62..e62d32dca1ef 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Locate}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateNoStartEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateNoStartEvaluator.java index 947b1ecb49d0..4fcffcb88412 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateNoStartEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateNoStartEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Locate}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimEvaluator.java index fdd1c2a23357..8cbd454895a6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link RTrim}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceConstantEvaluator.java index 71f8724d17a8..09a5429f351b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceConstantEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Replace}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceEvaluator.java index 8d4deb878f11..782a0323bc82 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Replace}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightEvaluator.java index 96473a2deefd..f8d3a8dae348 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightEvaluator.java @@ -19,8 +19,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Right}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitSingleByteEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitSingleByteEvaluator.java index 7081f2260611..89138d2f54f6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitSingleByteEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitSingleByteEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Split}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitVariableEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitVariableEvaluator.java index 82feca1b7905..be072452f9e8 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitVariableEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitVariableEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Split}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithEvaluator.java index 9eb1c488f52d..83527c4b1aa2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link StartsWith}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringEvaluator.java index 9da104137ba9..98fc2510a1f8 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Substring}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringNoLengthEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringNoLengthEvaluator.java index 08d12ac04983..442ffd517d43 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringNoLengthEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringNoLengthEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Substring}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerEvaluator.java index 23f28385916c..ac032e60a6b4 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToLower}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperEvaluator.java index 5c3e86184d46..e79aa71a0e9d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link ToUpper}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimEvaluator.java index 1ecb6b3bd578..fd357506c91a 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Trim}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDatetimesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDatetimesEvaluator.java index 04b433ecde34..a48c658ee825 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDatetimesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDatetimesEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Add}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDoublesEvaluator.java index 071369c29f33..a9b2ebef3012 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddDoublesEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Add}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddIntsEvaluator.java index bf9157540ea5..aeba6794fe9d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddIntsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Add}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddLongsEvaluator.java index 51199df88fb9..8f5b399e39b7 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Add}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddUnsignedLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddUnsignedLongsEvaluator.java index 10b21fb5898e..36096e878ea8 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddUnsignedLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddUnsignedLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Add}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivDoublesEvaluator.java index 88bf948749ff..f158cd20fc87 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivDoublesEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Div}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivIntsEvaluator.java index de3fb03fe440..db4c22491be3 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivIntsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Div}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivLongsEvaluator.java index 9eb02cbd4761..359f549d137e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Div}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivUnsignedLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivUnsignedLongsEvaluator.java index 50e3c933fec4..bf3d579788dc 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivUnsignedLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivUnsignedLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Div}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModDoublesEvaluator.java index 3afcac77973f..659e3b2c3c89 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModDoublesEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mod}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModIntsEvaluator.java index c2c44dba5207..97916c7c0b1f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModIntsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mod}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModLongsEvaluator.java index 58b3f055db6b..89d598b5b74c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mod}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModUnsignedLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModUnsignedLongsEvaluator.java index 5b79aa865392..11764071bb03 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModUnsignedLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModUnsignedLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mod}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulDoublesEvaluator.java index 1b9d10bff58e..6a035b343d12 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulDoublesEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mul}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulIntsEvaluator.java index 7501d0fc505a..5c8b11fdd24b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulIntsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mul}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulLongsEvaluator.java index 383e55755917..87d547fc0e59 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mul}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulUnsignedLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulUnsignedLongsEvaluator.java index 95ecaee6b34a..8b85459fe49c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulUnsignedLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulUnsignedLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Mul}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegDoublesEvaluator.java index 5915d4d476f1..2b996c7174ce 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegDoublesEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Neg}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegIntsEvaluator.java index 1821406f061b..e3b8552b81ee 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegIntsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Neg}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegLongsEvaluator.java index 49a009666511..b269d4c8c3fd 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Neg}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDatetimesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDatetimesEvaluator.java index 88d94573b756..ab162ea12000 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDatetimesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDatetimesEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sub}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDoublesEvaluator.java index d479d0fe751c..ff1e3d584772 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubDoublesEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sub}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubIntsEvaluator.java index 72bd7e4b6848..cc47c615e186 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubIntsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sub}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubLongsEvaluator.java index 88cb6bf287d8..de3e0dd0dcba 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sub}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubUnsignedLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubUnsignedLongsEvaluator.java index 1ef9034d76f6..7ab72956562d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubUnsignedLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubUnsignedLongsEvaluator.java @@ -15,8 +15,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Sub}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsBoolsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsBoolsEvaluator.java index 9344c46ac1bf..185e225fadb9 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsBoolsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsBoolsEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Equals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsDoublesEvaluator.java index 3281809a723f..9e0c62d118ec 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsDoublesEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Equals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsGeometriesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsGeometriesEvaluator.java index 2d5f9daa78f2..192a5272789b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsGeometriesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsGeometriesEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Equals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsIntsEvaluator.java index 0bd61aa34639..5728b9be40b4 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsIntsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Equals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsKeywordsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsKeywordsEvaluator.java index 8ddbc4296d97..2d3b679960d1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsKeywordsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsKeywordsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Equals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsLongsEvaluator.java index fcd98f27ea3e..fa4da286cde2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsLongsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link Equals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanDoublesEvaluator.java index 3f01ea2d3465..e40ce0df22a1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanDoublesEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanIntsEvaluator.java index 83f63a3b3ae5..e89243079134 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanIntsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanKeywordsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanKeywordsEvaluator.java index 79e2516701ba..82f8f6209754 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanKeywordsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanKeywordsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanLongsEvaluator.java index 8dbf8c18a504..0db53292de9b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanLongsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualDoublesEvaluator.java index b188682facb3..2dabfdb8c0e4 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualDoublesEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualIntsEvaluator.java index 10141ec62d3b..12674aee9d46 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualIntsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualKeywordsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualKeywordsEvaluator.java index 977f9b0b955f..433a88cd5f5b 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualKeywordsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualKeywordsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualLongsEvaluator.java index b80872fb6d72..f7b040cbcde5 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualLongsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link GreaterThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsConstantEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsConstantEvaluator.java index dffbdb24efe1..e8f02f232bbf 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsConstantEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsConstantEvaluator.java @@ -18,8 +18,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link InsensitiveEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsEvaluator.java index bbb8cae36f9d..a3b5a743daab 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link InsensitiveEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanDoublesEvaluator.java index ef3c955bb94f..4ad14555619f 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanDoublesEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanIntsEvaluator.java index 994723001823..f54a4dea0a1d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanIntsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanKeywordsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanKeywordsEvaluator.java index 8e8360ad0677..0085bd7f37ed 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanKeywordsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanKeywordsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanLongsEvaluator.java index 5adf118e8c6e..bf0241d05c50 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanLongsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThan}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualDoublesEvaluator.java index e296c5f6a5f1..4ff3a3fb65b1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualDoublesEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualIntsEvaluator.java index 088a8629d681..00afea476db1 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualIntsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualKeywordsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualKeywordsEvaluator.java index fb388275db52..460b0ed07d6d 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualKeywordsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualKeywordsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualLongsEvaluator.java index 64f3587d411b..5a293be95484 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualLongsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link LessThanOrEqual}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsBoolsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsBoolsEvaluator.java index 27cba7df1907..29af62dbbc8c 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsBoolsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsBoolsEvaluator.java @@ -14,8 +14,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link NotEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsDoublesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsDoublesEvaluator.java index a0f68648e03d..d24ff131d21e 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsDoublesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsDoublesEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link NotEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsGeometriesEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsGeometriesEvaluator.java index cf714564dbb9..abc0323722e2 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsGeometriesEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsGeometriesEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link NotEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsIntsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsIntsEvaluator.java index ead28b80c3ae..23b49df95aa6 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsIntsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsIntsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link NotEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsKeywordsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsKeywordsEvaluator.java index aab45501e2c5..e4980ffeac82 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsKeywordsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsKeywordsEvaluator.java @@ -17,8 +17,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link NotEquals}. diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsLongsEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsLongsEvaluator.java index 4aab9a6ad9ec..e6dc060bf837 100644 --- a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsLongsEvaluator.java +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsLongsEvaluator.java @@ -16,8 +16,8 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.tree.Source; /** * {@link EvalOperator.ExpressionEvaluator} implementation for {@link NotEquals}. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/Column.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/Column.java index b3d22da643ef..1495c90dc67b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/Column.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/Column.java @@ -13,8 +13,8 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BlockStreamInput; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.type.DataType; import java.io.IOException; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlClientException.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlClientException.java index ba539777b36c..e05449a3493d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlClientException.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlClientException.java @@ -6,7 +6,7 @@ */ package org.elasticsearch.xpack.esql; -import org.elasticsearch.xpack.ql.QlClientException; +import org.elasticsearch.xpack.esql.core.QlClientException; public class EsqlClientException extends QlClientException { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlIllegalArgumentException.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlIllegalArgumentException.java index 0fd79559c6be..d9a0694e98d2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlIllegalArgumentException.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/EsqlIllegalArgumentException.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.type.DataType; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.type.DataType; public class EsqlIllegalArgumentException extends QlIllegalArgumentException { public EsqlIllegalArgumentException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/ExceptionUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/ExceptionUtils.java index cb9f86d20915..16b386542dd4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/ExceptionUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/ExceptionUtils.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; public class ExceptionUtils { /** diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/VerificationException.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/VerificationException.java index 67e13bc954d8..99e4a57757e3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/VerificationException.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/VerificationException.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.common.Failures; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.common.Failures; import java.util.Collection; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlResponseListener.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlResponseListener.java index 3b6f612c658e..34f2906d003a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlResponseListener.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlResponseListener.java @@ -26,9 +26,9 @@ import java.io.IOException; import java.util.Locale; import java.util.concurrent.TimeUnit; +import static org.elasticsearch.xpack.esql.core.util.LoggingUtils.logOnFailure; import static org.elasticsearch.xpack.esql.formatter.TextFormat.CSV; import static org.elasticsearch.xpack.esql.formatter.TextFormat.URL_PARAM_DELIMITER; -import static org.elasticsearch.xpack.ql.util.LoggingUtils.logOnFailure; /** * Listens for a single {@link EsqlQueryResponse}, builds a corresponding {@link RestResponse} and sends it. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ParseTables.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ParseTables.java index 771adb6f9ce5..1c607e6446f4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ParseTables.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ParseTables.java @@ -20,8 +20,8 @@ import org.elasticsearch.core.Releasables; import org.elasticsearch.xcontent.XContentParseException; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xpack.esql.Column; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import java.io.IOException; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/PositionToXContent.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/PositionToXContent.java index 7e54bf94ac26..1d07ccc27694 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/PositionToXContent.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/PositionToXContent.java @@ -26,11 +26,11 @@ import org.elasticsearch.xpack.core.esql.action.ColumnInfo; import java.io.IOException; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.ipToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.spatialToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.versionToString; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; abstract class PositionToXContent { protected final Block block; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ResponseValueUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ResponseValueUtils.java index ba9aafe03143..98f2bbf95d3d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ResponseValueUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/ResponseValueUtils.java @@ -37,6 +37,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.ipToString; @@ -46,7 +47,6 @@ import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToIP import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToSpatial; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToVersion; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.versionToString; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; /** * Collection of static utility methods for helping transform response data between pages and values. 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 106a92d48a18..0f54fb3817a2 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 @@ -12,6 +12,47 @@ import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.analyzer.AnalyzerRules; +import org.elasticsearch.xpack.esql.core.analyzer.AnalyzerRules.BaseAnalyzerRule; +import org.elasticsearch.xpack.esql.core.analyzer.AnalyzerRules.ParameterizedAnalyzerRule; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedStar; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRule; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRuleExecutor; +import org.elasticsearch.xpack.esql.core.rule.RuleExecutor; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.util.Holder; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.NamedExpressions; import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; @@ -34,47 +75,6 @@ import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.stats.FeatureMetric; import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.analyzer.AnalyzerRules; -import org.elasticsearch.xpack.ql.analyzer.AnalyzerRules.BaseAnalyzerRule; -import org.elasticsearch.xpack.ql.analyzer.AnalyzerRules.ParameterizedAnalyzerRule; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeMap; -import org.elasticsearch.xpack.ql.expression.EmptyAttribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedStar; -import org.elasticsearch.xpack.ql.expression.function.FunctionDefinition; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; -import org.elasticsearch.xpack.ql.expression.predicate.BinaryOperator; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.rule.ParameterizedRule; -import org.elasticsearch.xpack.ql.rule.ParameterizedRuleExecutor; -import org.elasticsearch.xpack.ql.rule.RuleExecutor; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.type.InvalidMappedField; -import org.elasticsearch.xpack.ql.type.UnsupportedEsField; -import org.elasticsearch.xpack.ql.util.CollectionUtils; -import org.elasticsearch.xpack.ql.util.Holder; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.util.ArrayList; import java.util.Arrays; @@ -94,20 +94,20 @@ import java.util.stream.Collectors; 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.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NESTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; import static org.elasticsearch.xpack.esql.stats.FeatureMetric.LIMIT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.NESTED; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; public class Analyzer extends ParameterizedRuleExecutor { // marker list of attributes for plans that do not have any concrete fields to return, but have other computed columns to return @@ -740,12 +740,12 @@ public class Analyzer extends ParameterizedRuleExecutor { public final Class typeToken; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java index a07c963dc084..7af2668e9d74 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java @@ -11,6 +11,8 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.xpack.esql.action.EsqlQueryRequest; import org.elasticsearch.xpack.esql.analysis.PreAnalyzer; import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.index.IndexResolver; import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolver; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.optimizer.LogicalOptimizerContext; @@ -22,8 +24,6 @@ import org.elasticsearch.xpack.esql.session.EsqlIndexResolver; import org.elasticsearch.xpack.esql.session.EsqlSession; import org.elasticsearch.xpack.esql.stats.Metrics; import org.elasticsearch.xpack.esql.stats.QueryMetric; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.index.IndexResolver; import static org.elasticsearch.action.ActionListener.wrap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java index 85d5357d7c1e..415a46d1a609 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java @@ -7,23 +7,23 @@ package org.elasticsearch.xpack.esql.expression; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; import java.util.Locale; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_SHAPE; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; public class EsqlTypeResolutions { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/NamedExpressions.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/NamedExpressions.java index 895a471033b2..cb6aaf879f3c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/NamedExpressions.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/NamedExpressions.java @@ -8,9 +8,9 @@ package org.elasticsearch.xpack.esql.expression; import org.elasticsearch.common.util.Maps; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Order.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Order.java index 95852a00ce2b..fa66f299b227 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Order.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Order.java @@ -7,14 +7,14 @@ package org.elasticsearch.xpack.esql.expression; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import java.util.List; -public class Order extends org.elasticsearch.xpack.ql.expression.Order { +public class Order extends org.elasticsearch.xpack.esql.core.expression.Order { public Order(Source source, Expression child, OrderDirection direction, NullsPosition nulls) { super(source, child, direction, nulls); } @@ -33,7 +33,7 @@ public class Order extends org.elasticsearch.xpack.ql.expression.Order { } @Override - protected NodeInfo info() { + protected NodeInfo info() { return NodeInfo.create(this, Order::new, child(), direction(), nullsPosition()); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/SurrogateExpression.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/SurrogateExpression.java index bf48d1d806e1..590b68a6892e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/SurrogateExpression.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/SurrogateExpression.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.expression; -import org.elasticsearch.xpack.ql.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expression; /** * Interface signaling to the planner that the declaring expression diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/UnresolvedNamePattern.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/UnresolvedNamePattern.java index bea368028438..7df28f064831 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/UnresolvedNamePattern.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/UnresolvedNamePattern.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.expression; import org.apache.lucene.util.automaton.CharacterRunAutomaton; -import org.elasticsearch.xpack.ql.capabilities.UnresolvedException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.UnresolvedNamedExpression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedNamedExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Validations.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Validations.java index 37f262a84d2c..dffa723a1f3d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Validations.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/Validations.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.expression; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expression.TypeResolution; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expression.TypeResolution; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; public final class Validations { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java index 4dfdf547f940..90f28b263f07 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java @@ -7,6 +7,12 @@ package org.elasticsearch.xpack.esql.expression.function; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.aggregate.Avg; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.expression.function.aggregate.CountDistinct; @@ -105,12 +111,6 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.string.ToLower; import org.elasticsearch.xpack.esql.expression.function.scalar.string.ToUpper; import org.elasticsearch.xpack.esql.expression.function.scalar.string.Trim; import org.elasticsearch.xpack.esql.plan.logical.meta.MetaFunctions; -import org.elasticsearch.xpack.ql.expression.function.Function; -import org.elasticsearch.xpack.ql.expression.function.FunctionDefinition; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.lang.reflect.Constructor; import java.util.ArrayList; @@ -122,21 +122,21 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSUPPORTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_SHAPE; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; public final class EsqlFunctionRegistry extends FunctionRegistry { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Functions.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Functions.java index 5d132298de03..21af7db0cede 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Functions.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Functions.java @@ -6,9 +6,9 @@ */ package org.elasticsearch.xpack.esql.expression.function; +import org.elasticsearch.xpack.esql.core.expression.Expression; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.grouping.GroupingFunction; -import org.elasticsearch.xpack.ql.expression.Expression; public abstract class Functions { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/UnsupportedAttribute.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/UnsupportedAttribute.java index e5ac3e395f6a..9c37dab90db5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/UnsupportedAttribute.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/UnsupportedAttribute.java @@ -7,15 +7,15 @@ package org.elasticsearch.xpack.esql.expression.function; -import org.elasticsearch.xpack.ql.capabilities.Unresolvable; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.UnsupportedEsField; +import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Warnings.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Warnings.java index b7b77e70d755..ae1072a0a5bf 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Warnings.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/Warnings.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.expression.function; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; import static org.elasticsearch.common.logging.HeaderWarning.addWarning; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AggregateFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AggregateFunction.java index 7ffaffe0855b..01ef4aedb85c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AggregateFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/AggregateFunction.java @@ -6,22 +6,22 @@ */ package org.elasticsearch.xpack.esql.expression.function.aggregate; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.Function; -import org.elasticsearch.xpack.ql.expression.gen.pipeline.AggNameInput; -import org.elasticsearch.xpack.ql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.AggNameInput; +import org.elasticsearch.xpack.esql.core.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; import java.util.List; import java.util.Objects; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; /** * A type of {@code Function} that takes multiple values and extracts a single value out of them. For example, {@code AVG()}. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java index bd2c3ad9f76d..39d73dd82e39 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Avg.java @@ -7,21 +7,21 @@ package org.elasticsearch.xpack.esql.expression.function.aggregate; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvAvg; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public class Avg extends AggregateFunction implements SurrogateExpression { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java index 54d7b33f4b09..73bbfba544bd 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Count.java @@ -9,6 +9,14 @@ package org.elasticsearch.xpack.esql.expression.function.aggregate; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.CountAggregatorFunction; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; @@ -17,19 +25,11 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Mul; import org.elasticsearch.xpack.esql.planner.ToAggregator; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public class Count extends AggregateFunction implements EnclosedAgg, ToAggregator, SurrogateExpression { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java index a462db2b575b..481f02539984 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java @@ -14,6 +14,13 @@ import org.elasticsearch.compute.aggregation.CountDistinctDoubleAggregatorFuncti import org.elasticsearch.compute.aggregation.CountDistinctIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.CountDistinctLongAggregatorFunctionSupplier; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; @@ -23,21 +30,14 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvCoun import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvDedupe; import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; import org.elasticsearch.xpack.esql.planner.ToAggregator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isFoldable; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isInteger; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isFoldable; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isInteger; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public class CountDistinct extends AggregateFunction implements OptionalArgument, ToAggregator, SurrogateExpression { private static final int DEFAULT_PRECISION = 3000; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java index 3e8030322caa..3f6632f66bce 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Max.java @@ -11,14 +11,14 @@ import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MaxDoubleAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MaxIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MaxLongAggregatorFunctionSupplier; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMax; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java index 2804f7f5d2b0..7c48a58ddb64 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Median.java @@ -8,22 +8,22 @@ package org.elasticsearch.xpack.esql.expression.function.aggregate; import org.elasticsearch.compute.aggregation.QuantileStates; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMedian; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public class Median extends AggregateFunction implements SurrogateExpression { // TODO: Add the compression parameter diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java index db7979ef0359..db25ad6c8c41 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/MedianAbsoluteDeviation.java @@ -11,11 +11,11 @@ import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MedianAbsoluteDeviationDoubleAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MedianAbsoluteDeviationIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MedianAbsoluteDeviationLongAggregatorFunctionSupplier; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java index c69d2f4a1fc2..16821752bc7b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Min.java @@ -11,14 +11,14 @@ import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MinDoubleAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MinIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.MinLongAggregatorFunctionSupplier; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMin; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java index d23531e07449..7f77f9cbb8cc 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/NumericAggregate.java @@ -8,17 +8,17 @@ package org.elasticsearch.xpack.esql.expression.function.aggregate; import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.planner.ToAggregator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public abstract class NumericAggregate extends AggregateFunction implements ToAggregator { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java index 22592f067ba9..b06053199c5a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java @@ -11,20 +11,20 @@ import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.PercentileDoubleAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.PercentileIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.PercentileLongAggregatorFunctionSupplier; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isFoldable; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isFoldable; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public class Percentile extends NumericAggregate { private final Expression percentile; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregateFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregateFunction.java index 3bdc67465295..66a7e0ca436d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregateFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialAggregateFunction.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql.expression.function.aggregate; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java index 88302bde4752..f8e038b70c88 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/SpatialCentroid.java @@ -12,19 +12,19 @@ import org.elasticsearch.compute.aggregation.spatial.SpatialCentroidCartesianPoi import org.elasticsearch.compute.aggregation.spatial.SpatialCentroidGeoPointDocValuesAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.spatial.SpatialCentroidGeoPointSourceValuesAggregatorFunctionSupplier; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.ToAggregator; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isSpatialPoint; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; /** * Calculate spatial centroid of all geo_point or cartesian point values of a field in matching documents. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java index 805724bfcd16..78ad04414cd5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sum.java @@ -10,24 +10,24 @@ import org.elasticsearch.compute.aggregation.AggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.SumDoubleAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.SumIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.SumLongAggregatorFunctionSupplier; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvSum; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Mul; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.util.List; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; /** * Sum all values of a field in matching documents. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java index 86090ffff93d..1723027a8e8e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Values.java @@ -14,19 +14,19 @@ import org.elasticsearch.compute.aggregation.ValuesDoubleAggregatorFunctionSuppl import org.elasticsearch.compute.aggregation.ValuesIntAggregatorFunctionSupplier; import org.elasticsearch.compute.aggregation.ValuesLongAggregatorFunctionSupplier; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.ToAggregator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; public class Values extends AggregateFunction implements ToAggregator { @FunctionInfo( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java index 32073d830841..6e8341614a97 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/Bucket.java @@ -13,6 +13,16 @@ import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.core.TimeValue; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.capabilities.Validatable; +import org.elasticsearch.xpack.esql.core.common.Failures; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Foldables; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.TwoOptionalArguments; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; @@ -21,16 +31,6 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.math.Floor; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Mul; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.common.Failures; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Foldables; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.TwoOptionalArguments; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.time.ZoneOffset; @@ -38,14 +38,14 @@ import java.util.List; import java.util.function.Function; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FOURTH; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.expression.Validations.isFoldable; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToLong; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FOURTH; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; /** * Splits dates and numbers into a given number of buckets. There are two ways to invoke diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/GroupingFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/GroupingFunction.java index 61b04c5e51ac..c4ab71894639 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/GroupingFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/grouping/GroupingFunction.java @@ -7,11 +7,11 @@ package org.elasticsearch.xpack.esql.expression.function.grouping; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.Function; -import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlConfigurationFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlConfigurationFunction.java index f6dae5bd0117..3b092ddc29de 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlConfigurationFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlConfigurationFunction.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlScalarFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlScalarFunction.java index 4a54e6c4f5aa..43becfd9302c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlScalarFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/EsqlScalarFunction.java @@ -7,11 +7,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; -import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/UnaryScalarFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/UnaryScalarFunction.java index 0a9b4a7b7d0f..2e29162aebb4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/UnaryScalarFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/UnaryScalarFunction.java @@ -7,14 +7,14 @@ package org.elasticsearch.xpack.esql.expression.function.scalar; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import java.util.Arrays; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; public abstract class UnaryScalarFunction extends EsqlScalarFunction { protected final Expression field; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Case.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Case.java index 1018a03762cc..f67940e95ec0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Case.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Case.java @@ -16,18 +16,18 @@ import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; @@ -36,7 +36,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; -import static org.elasticsearch.xpack.ql.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; public final class Case extends EsqlScalarFunction { record Condition(Expression condition, Expression value) {} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Greatest.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Greatest.java index b1c761a50d8b..3491cd00f9ae 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Greatest.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Greatest.java @@ -11,25 +11,25 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMax; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; -import static org.elasticsearch.xpack.ql.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; /** * Returns the maximum value of multiple columns. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Least.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Least.java index 8b68196af68a..1238418264fb 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Least.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Least.java @@ -11,25 +11,25 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.MvMin; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; -import static org.elasticsearch.xpack.ql.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; /** * Returns the minimum value of multiple columns. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/AbstractConvertFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/AbstractConvertFunction.java index 5ccc1405cf13..f04f41813d57 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/AbstractConvertFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/AbstractConvertFunction.java @@ -19,13 +19,13 @@ import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.core.Releasables; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Warnings; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.HashSet; @@ -35,7 +35,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; /** * Base class for functions that converts a field into a function-specific type. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64.java index 68856d455663..6cbcd853be3c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64.java @@ -13,23 +13,23 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.Base64; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; public class FromBase64 extends UnaryScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64.java index df21620df7e7..b2b15a3b824b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64.java @@ -13,23 +13,23 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.Base64; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; public class ToBase64 extends UnaryScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBoolean.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBoolean.java index ff91638565e1..127ad0d8c471 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBoolean.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBoolean.java @@ -9,26 +9,26 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToBoolean; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToBoolean; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; public class ToBoolean extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPoint.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPoint.java index ee5b10e9b2be..e54c438296f6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPoint.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPoint.java @@ -9,21 +9,21 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToSpatial; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; public class ToCartesianPoint extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShape.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShape.java index 9bce6fd7c111..e648ea0c8a81 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShape.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShape.java @@ -9,22 +9,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToSpatial; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_SHAPE; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; public class ToCartesianShape extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetime.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetime.java index a41a8041b851..ed14c2209287 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetime.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetime.java @@ -9,25 +9,25 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToLong; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; public class ToDatetime extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegrees.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegrees.java index c11e0131d731..590ab9de11d4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegrees.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegrees.java @@ -8,23 +8,23 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.util.List; import java.util.Map; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; /** * Converts from radians diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDouble.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDouble.java index 20cb46def4d8..b39abb51c458 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDouble.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDouble.java @@ -9,29 +9,29 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToDouble; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToDouble; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; public class ToDouble extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPoint.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPoint.java index ce217298d8e1..d64ddbd8e6f0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPoint.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPoint.java @@ -9,21 +9,21 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToSpatial; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; public class ToGeoPoint extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShape.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShape.java index 23263669839b..67ec2e47008c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShape.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShape.java @@ -9,22 +9,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToSpatial; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; public class ToGeoShape extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIP.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIP.java index 1f1fdd9711b7..b7340f1853d3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIP.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIP.java @@ -9,21 +9,21 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToIP; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; public class ToIP extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToInteger.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToInteger.java index 32e3b8a77695..3ff1a2031823 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToInteger.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToInteger.java @@ -9,30 +9,30 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToInt; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToInt; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToInt; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToInt; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; public class ToInteger extends AbstractConvertFunction { @@ -64,7 +64,7 @@ public class ToInteger extends AbstractConvertFunction { A following header will contain the failure reason and the offending value: - `"org.elasticsearch.xpack.ql.InvalidArgumentException: [501379200000] out of [integer] range"`""") + `"org.elasticsearch.xpack.esql.core.InvalidArgumentException: [501379200000] out of [integer] range"`""") ) public ToInteger( Source source, diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLong.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLong.java index c7b77a3c7f2c..f86bf19bdc18 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLong.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLong.java @@ -9,30 +9,30 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeDoubleToLong; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToLong; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeDoubleToLong; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; public class ToLong extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadians.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadians.java index b66a4823b5d9..830463eca38e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadians.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadians.java @@ -8,22 +8,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; /** * Converts from degrees diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToString.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToString.java index 70eb9f0a9f3b..ec5542d40c5b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToString.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToString.java @@ -9,18 +9,28 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.ipToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.numericBooleanToString; @@ -31,16 +41,6 @@ import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_SHAPE; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; public class ToString extends AbstractConvertFunction implements EvaluatorMapper { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLong.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLong.java index dc6e842f3b09..b9206c592010 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLong.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLong.java @@ -9,31 +9,31 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.booleanToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.doubleToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.intToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.longToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToUnsignedLong; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; public class ToUnsignedLong extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersion.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersion.java index 44636b196019..94c48bace1f3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersion.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersion.java @@ -9,21 +9,21 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Map; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToVersion; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; public class ToVersion extends AbstractConvertFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/BinaryDateTimeFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/BinaryDateTimeFunction.java index c7c923e8e912..f5860bbf65c8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/BinaryDateTimeFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/BinaryDateTimeFunction.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.date; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.scalar.BinaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.BinaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import java.time.ZoneId; import java.time.ZoneOffset; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiff.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiff.java index c0691dd0b046..33db8430f20b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiff.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiff.java @@ -11,16 +11,16 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Instant; import java.time.ZoneId; @@ -35,12 +35,12 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isDate; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToInt; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isDate; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToInt; /** * Subtract the second argument from the third argument and return their difference diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java index 9b685bd1f2ec..11759cdab158 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java @@ -11,29 +11,29 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.time.temporal.ChronoField; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isDate; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.EsqlConverter.STRING_TO_CHRONO_FIELD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.chronoToLong; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isDate; public class DateExtract extends EsqlConfigurationFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java index eea8551335d5..6690d495b0ec 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java @@ -12,30 +12,30 @@ import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.Locale; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isDate; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.DEFAULT_DATE_TIME_FORMATTER; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isDate; public class DateFormat extends EsqlConfigurationFunction implements OptionalArgument { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java index 6f10e48fcf27..3852d57772e7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java @@ -12,31 +12,31 @@ import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.List; import java.util.function.Function; import static org.elasticsearch.common.time.DateFormatter.forPattern; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.util.DateUtils.UTC; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.DEFAULT_DATE_TIME_FORMATTER; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToLong; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.util.DateUtils.UTC; public class DateParse extends EsqlScalarFunction implements OptionalArgument { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTimeField.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTimeField.java index 85651af67e8e..45cc79076037 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTimeField.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTimeField.java @@ -6,7 +6,7 @@ */ package org.elasticsearch.xpack.esql.expression.function.scalar.date; -import org.elasticsearch.xpack.ql.util.StringUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import java.util.Arrays; import java.util.Collections; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTrunc.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTrunc.java index e2b55fe8a677..49f55e42931a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTrunc.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTrunc.java @@ -12,16 +12,16 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.core.TimeValue; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Duration; import java.time.Period; @@ -31,10 +31,10 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isDate; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isDate; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; public class DateTrunc extends EsqlScalarFunction { private final Expression interval; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/Now.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/Now.java index 21fcd6fe7ab2..88e9d2b60b5b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/Now.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/Now.java @@ -10,15 +10,15 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.date; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java index e047906d10ed..12d2692460cb 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatch.java @@ -12,27 +12,27 @@ import org.elasticsearch.common.network.CIDRUtils; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.CollectionUtils; import java.util.Arrays; import java.util.List; import java.util.function.Function; import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.fromIndex; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isIPAndExact; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.fromIndex; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isIPAndExact; /** * This function takes a first parameter of type IP, followed by one or more parameters evaluated to a CIDR specification: diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Abs.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Abs.java index 3b66543f4bfd..3898b342f007 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Abs.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Abs.java @@ -10,14 +10,14 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbstractTrigonometricFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbstractTrigonometricFunction.java index f027f01a4a39..7ec618b621c5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbstractTrigonometricFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbstractTrigonometricFunction.java @@ -9,16 +9,16 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; /** * Common base for trigonometric functions. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Acos.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Acos.java index e4982fa69826..e3c83f2f4abc 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Acos.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Acos.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Asin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Asin.java index c1c1e72633d6..bc2de0a5b511 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Asin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Asin.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan.java index 6cd3d4b9ffb6..d840faf6d970 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2.java index 47a17a90d2d7..50b1e6fc0b17 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2.java @@ -9,22 +9,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; /** * Inverse cosine trigonometric function. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cast.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cast.java index 60bb904ab484..5ffac6fb2b01 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cast.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cast.java @@ -11,9 +11,9 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.intToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.longToUnsignedLong; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cbrt.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cbrt.java index 455e460b25e8..8eec5ff9b7aa 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cbrt.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cbrt.java @@ -10,22 +10,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToDouble; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; public class Cbrt extends UnaryScalarFunction { @FunctionInfo(returnType = "double", description = """ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Ceil.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Ceil.java index 3ab9b1fc2cb1..06f092a00e94 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Ceil.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Ceil.java @@ -9,19 +9,19 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; /** * Round a number up to the nearest integer. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cos.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cos.java index d32795672084..29387606a497 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cos.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cos.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cosh.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cosh.java index 93170ec4d754..5e0a8c9b970f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cosh.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Cosh.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/DoubleConstantFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/DoubleConstantFunction.java index ca33ec335d6c..cb21c2b6cf3d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/DoubleConstantFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/DoubleConstantFunction.java @@ -7,13 +7,13 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; -import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; /** * Function that emits constants, like Euler's number. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/E.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/E.java index f68283d356e8..9bcd8a2467b1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/E.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/E.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Floor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Floor.java index 224d037816ee..173a8ef15230 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Floor.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Floor.java @@ -9,19 +9,19 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; /** * Round a number down to the nearest integer. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log.java index ffe92c8c19b3..f60b0341dbb1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log.java @@ -9,24 +9,24 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; public class Log extends EsqlScalarFunction implements OptionalArgument { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10.java index ab109c8c95bd..ad08b34e3c53 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10.java @@ -10,23 +10,23 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToDouble; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; public class Log10 extends UnaryScalarFunction { @FunctionInfo( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pi.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pi.java index e7ba8def13f8..a87849c5684a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pi.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pi.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pow.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pow.java index ad1c513e3a15..dab7de2b455c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pow.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Pow.java @@ -9,25 +9,25 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; public class Pow extends EsqlScalarFunction implements OptionalArgument { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Round.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Round.java index 1bcf288cb5c8..d1f6eba4081b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Round.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Round.java @@ -11,17 +11,17 @@ import org.elasticsearch.common.TriFunction; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.math.Maths; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.expression.predicate.operator.math.Maths; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.Arrays; @@ -29,13 +29,13 @@ import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isInteger; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.bigIntegerToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.longToUnsignedLong; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isInteger; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; public class Round extends EsqlScalarFunction implements OptionalArgument { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Signum.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Signum.java index ede41c10f3ac..84126e0d1079 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Signum.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Signum.java @@ -10,16 +10,16 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.util.List; import java.util.function.Function; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sin.java index 11cc7bccc228..2dd9520ab066 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sin.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sinh.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sinh.java index 142f15c8bfbe..274fb938f68d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sinh.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sinh.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sqrt.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sqrt.java index c0bd74ea90e7..65e24bb5de13 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sqrt.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Sqrt.java @@ -10,22 +10,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToDouble; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric; public class Sqrt extends UnaryScalarFunction { @FunctionInfo(returnType = "double", description = """ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tan.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tan.java index 3752f986894e..e0ae6ff5234e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tan.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tan.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tanh.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tanh.java index 726a269ebedc..5d423eaf2dd3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tanh.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tanh.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tau.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tau.java index 79f6914b7f49..7a2eb801be84 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tau.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Tau.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunction.java index 81de1792bdcc..2ceedd14d6fd 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunction.java @@ -13,9 +13,9 @@ import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; /** * Base class for functions that reduce multivalued fields into single valued fields. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvg.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvg.java index b0e5dc028248..ba217c6fa039 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvg.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvg.java @@ -12,21 +12,21 @@ import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.search.aggregations.metrics.CompensatedSum; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToDouble; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isRepresentable; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the average value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcat.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcat.java index 5f5f03a4fbbd..dd4b552999a0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcat.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcat.java @@ -14,21 +14,21 @@ import org.elasticsearch.compute.data.BytesRefBlock; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.BinaryScalarFunction; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.scalar.BinaryScalarFunction; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; /** * Reduce a multivalued string field to a single valued field by concatenating all values. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCount.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCount.java index 2007f8d5290b..26c3345240cd 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCount.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCount.java @@ -11,19 +11,19 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the count of values. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupe.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupe.java index f7df1384cefa..543e37f43f67 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupe.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupe.java @@ -9,18 +9,18 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.compute.operator.mvdedupe.MultivalueDedupe; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; /** * Removes duplicate values from a multivalued field. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirst.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirst.java index a917d64a198e..a985c10824ae 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirst.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirst.java @@ -17,18 +17,18 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the minimum value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLast.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLast.java index d9117b90fbfe..8dcc4c8b1222 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLast.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLast.java @@ -17,18 +17,18 @@ import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the minimum value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMax.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMax.java index 220daa444224..7cfc4a94b35d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMax.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMax.java @@ -12,19 +12,19 @@ import org.elasticsearch.compute.ann.MvEvaluator; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isRepresentable; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isSpatial; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the maximum value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedian.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedian.java index b54c404c252c..f936cd6fdfd1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedian.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedian.java @@ -14,23 +14,23 @@ import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.Arrays; import java.util.List; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.bigIntegerToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.unsignedLongToBigInteger; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isRepresentable; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the average value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMin.java index b4eaf91ce4e6..e52e72c766a3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMin.java @@ -12,19 +12,19 @@ import org.elasticsearch.compute.ann.MvEvaluator; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isRepresentable; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isSpatial; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; /** * Reduce a multivalued field to a single valued field containing the minimum value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSlice.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSlice.java index c4c8f54e2a10..d066745cc65b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSlice.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSlice.java @@ -16,6 +16,13 @@ import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; @@ -23,24 +30,17 @@ import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.Arrays; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToInt; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; /** * Returns a subset of the multivalued field using the start and end index values. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSort.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSort.java index 2da362e56db3..3e1d7aabe7d3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSort.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSort.java @@ -26,30 +26,30 @@ import org.elasticsearch.compute.operator.mvdedupe.MultivalueDedupeDouble; import org.elasticsearch.compute.operator.mvdedupe.MultivalueDedupeInt; import org.elasticsearch.compute.operator.mvdedupe.MultivalueDedupeLong; import org.elasticsearch.xpack.esql.capabilities.Validatable; +import org.elasticsearch.xpack.esql.core.common.Failures; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.common.Failures; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.expression.Validations.isFoldable; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; /** * Sorts a multivalued field in lexicographical order. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSum.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSum.java index 21a40c7e0600..c3cee1a22732 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSum.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSum.java @@ -12,20 +12,20 @@ import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.search.aggregations.metrics.CompensatedSum; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAddExact; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isRepresentable; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAddExact; /** * Reduce a multivalued field to a single valued field containing the sum of all values. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZip.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZip.java index a0db5d8394c8..8ca09569015a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZip.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZip.java @@ -12,27 +12,27 @@ import org.apache.lucene.util.BytesRefBuilder; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.data.BytesRefBlock; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; /** * Combines the values from two multivalued fields with a delimiter that joins them together. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/Coalesce.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/Coalesce.java index 8c39a29f67f9..97d558ce53b6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/Coalesce.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/Coalesce.java @@ -15,26 +15,26 @@ import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.core.Releasable; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; -import static org.elasticsearch.xpack.ql.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; /** * Function returning the first non-null value. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/package-info.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/package-info.java index a8d4139ed2cf..3f6ad8ca3ab0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/package-info.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/package-info.java @@ -7,7 +7,7 @@ /** * Functions that take a row of data and produce a row of data without holding - * any state between rows. This includes both the {@link org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction} + * any state between rows. This includes both the {@link org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction} * subclass to link into the QL infrastucture and the {@link org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator} * implementation to run the actual function. * diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java index 31e0a86a1e3e..161d11478fd2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContains.java @@ -20,16 +20,16 @@ import org.elasticsearch.index.mapper.ShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; import org.elasticsearch.lucene.spatial.GeometryDocValueReader; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import java.io.IOException; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java index 7b85ebfea5ee..07fe0a3776fe 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjoint.java @@ -18,16 +18,16 @@ import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; import org.elasticsearch.lucene.spatial.GeometryDocValueReader; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import java.io.IOException; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialEvaluatorFactory.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialEvaluatorFactory.java index e3bb3e8c8a3c..14e743c5be46 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialEvaluatorFactory.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialEvaluatorFactory.java @@ -10,9 +10,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import org.apache.lucene.geo.Component2D; import org.elasticsearch.common.TriFunction; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import java.util.Map; import java.util.function.Function; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java index 462f3bce1aee..6ac7a2f659ea 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersects.java @@ -18,16 +18,16 @@ import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; import org.elasticsearch.lucene.spatial.GeometryDocValueReader; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import java.io.IOException; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java index 51109aee2948..69f10cebb636 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunction.java @@ -17,16 +17,16 @@ import org.elasticsearch.index.mapper.ShapeIndexer; import org.elasticsearch.lucene.spatial.Component2DVisitor; import org.elasticsearch.lucene.spatial.CoordinateEncoder; import org.elasticsearch.lucene.spatial.GeometryDocValueReader; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.BinaryScalarFunction; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.scalar.BinaryScalarFunction; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import java.io.IOException; import java.util.Map; @@ -37,15 +37,15 @@ import java.util.function.Predicate; import static org.apache.lucene.document.ShapeField.QueryRelation.CONTAINS; import static org.apache.lucene.document.ShapeField.QueryRelation.DISJOINT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isNull; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isSpatial; import static org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesUtils.asGeometryDocValueReader; import static org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesUtils.asLuceneComponent2D; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; -import static org.elasticsearch.xpack.ql.type.DataTypes.isNull; public abstract class SpatialRelatesFunction extends BinaryScalarFunction implements diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java index db45a791a122..3278eaac43d0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesUtils.java @@ -23,12 +23,12 @@ import org.elasticsearch.lucene.spatial.CentroidCalculator; import org.elasticsearch.lucene.spatial.CoordinateEncoder; import org.elasticsearch.lucene.spatial.GeometryDocValueReader; import org.elasticsearch.lucene.spatial.GeometryDocValueWriter; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import java.io.IOException; -import static org.elasticsearch.xpack.ql.planner.ExpressionTranslators.valueOf; +import static org.elasticsearch.xpack.esql.core.planner.ExpressionTranslators.valueOf; public class SpatialRelatesUtils { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java index 1eaf1e31e543..6c10907ada50 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithin.java @@ -18,17 +18,17 @@ import org.elasticsearch.index.mapper.GeoShapeIndexer; import org.elasticsearch.lucene.spatial.CartesianShapeIndexer; import org.elasticsearch.lucene.spatial.CoordinateEncoder; import org.elasticsearch.lucene.spatial.GeometryDocValueReader; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import java.io.IOException; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StX.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StX.java index f5ff933babc9..b2ece9388e35 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StX.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StX.java @@ -10,22 +10,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.UNSPECIFIED; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isSpatialPoint; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.UNSPECIFIED; /** * Extracts the x-coordinate from a point geometry. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StY.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StY.java index 48de97da4bef..b52d6929ec3a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StY.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StY.java @@ -10,22 +10,22 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.ConvertEvaluator; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.UNSPECIFIED; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isSpatialPoint; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.UNSPECIFIED; /** * Extracts the y-coordinate from a point geometry. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatch.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatch.java index 7dac02e50ddb..09166f0cff7a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatch.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AutomataMatch.java @@ -17,7 +17,7 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.data.BooleanBlock; import org.elasticsearch.compute.operator.EvalOperator; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; /** * Matches {@link BytesRef}s against {@link Automaton automata}. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Concat.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Concat.java index 5fe369e1ee28..670c96d880f2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Concat.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Concat.java @@ -13,24 +13,24 @@ import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.BreakingBytesRefBuilder; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlClientException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; import static org.elasticsearch.common.unit.ByteSizeUnit.MB; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; /** * Join strings. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java index 109beebaaf81..11a33d9a038e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWith.java @@ -10,23 +10,23 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; public class EndsWith extends EsqlScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrim.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrim.java index 4c290c0f9d73..e7e0b69d5149 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrim.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrim.java @@ -11,19 +11,19 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; /** * Removes leading whitespaces from a string. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Left.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Left.java index 004cedafb386..422ae9532aab 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Left.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Left.java @@ -12,25 +12,25 @@ import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; /** * {code left(foo, len)} is an alias to {code substring(foo, 0, len)} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Length.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Length.java index 39213a6f09f4..cad8bf277052 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Length.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Length.java @@ -11,21 +11,21 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; public class Length extends UnaryScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Locate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Locate.java index 1c2d828fe533..067a16cc3fc6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Locate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Locate.java @@ -11,26 +11,26 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; /** * Locate function, given a string 'a' and a substring 'b', it returns the index of the first occurrence of the substring 'b' in 'a'. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLike.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLike.java index 3fe4b92ca8f2..16a4730a2007 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLike.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLike.java @@ -8,18 +8,18 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RLikePattern; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; -public class RLike extends org.elasticsearch.xpack.ql.expression.predicate.regex.RLike implements EvaluatorMapper { +public class RLike extends org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike implements EvaluatorMapper { public RLike(Source source, Expression value, RLikePattern pattern) { super(source, value, pattern); } @@ -29,7 +29,7 @@ public class RLike extends org.elasticsearch.xpack.ql.expression.predicate.regex } @Override - protected NodeInfo info() { + protected NodeInfo info() { return NodeInfo.create(this, RLike::new, field(), pattern(), caseInsensitive()); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrim.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrim.java index 2dd0fe5a8fdf..9edac22ca643 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrim.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrim.java @@ -11,19 +11,19 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; /** * Removes trailing whitespaces from a string. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Replace.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Replace.java index f628bffc10a9..c0871974bcc1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Replace.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Replace.java @@ -11,15 +11,15 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; @@ -27,10 +27,10 @@ import java.util.function.Function; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; public class Replace extends EsqlScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Right.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Right.java index 07810a7f9baf..cc051d93b6cb 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Right.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Right.java @@ -12,25 +12,25 @@ import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; /** * {code right(foo, len)} is an alias to {code substring(foo, foo.length-len, len)} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java index 4b53393deb88..edb052821bef 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java @@ -12,23 +12,23 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.data.BytesRefBlock; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.BinaryScalarFunction; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.scalar.BinaryScalarFunction; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; /** * Splits a string on some delimiter into a multivalued string field. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java index d4f9bd0dfe2b..13a9fb42d2db 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWith.java @@ -10,23 +10,23 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; public class StartsWith extends EsqlScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Substring.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Substring.java index a8b62ae1109c..5c84d5bcee85 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Substring.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Substring.java @@ -11,27 +11,27 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.OptionalArgument; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.OptionalArgument; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Arrays; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.THIRD; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.THIRD; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; public class Substring extends EsqlScalarFunction implements OptionalArgument { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java index 014328a2db76..f14df4f56929 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLower.java @@ -12,23 +12,23 @@ import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Locale; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; public class ToLower extends EsqlConfigurationFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java index 69180c6cf811..6c903b4bfdde 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpper.java @@ -12,23 +12,23 @@ import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.session.Configuration; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.session.Configuration; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; import java.util.Locale; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; public class ToUpper extends EsqlConfigurationFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Trim.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Trim.java index 4615106790ca..d7d9019a7fba 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Trim.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Trim.java @@ -11,19 +11,19 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; /** * Removes leading and trailing whitespaces from a string. diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java index bf709b022279..3a98f45a25af 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLike.java @@ -9,21 +9,21 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import org.apache.lucene.util.automaton.Automata; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.expression.function.Param; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString; -public class WildcardLike extends org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardLike implements EvaluatorMapper { +public class WildcardLike extends org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike implements EvaluatorMapper { @FunctionInfo(returnType = "boolean", description = """ Use `LIKE` to filter data based on string patterns using wildcards. `LIKE` usually acts on a field placed on the left-hand side of the operator, but it can @@ -43,7 +43,7 @@ public class WildcardLike extends org.elasticsearch.xpack.ql.expression.predicat } @Override - protected NodeInfo info() { + protected NodeInfo info() { return NodeInfo.create(this, WildcardLike::new, field(), pattern()); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Add.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Add.java index 4439c4ebc754..b84082d410af 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Add.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Add.java @@ -9,20 +9,20 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryComparisonInversible; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryComparisonInversible; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.time.DateTimeException; import java.time.Duration; import java.time.Period; import java.time.temporal.TemporalAmount; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asDateTime; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asMillis; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAddExact; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation.OperationSymbol.ADD; -import static org.elasticsearch.xpack.ql.type.DateUtils.asDateTime; -import static org.elasticsearch.xpack.ql.type.DateUtils.asMillis; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAddExact; public class Add extends DateTimeArithmeticOperation implements BinaryComparisonInversible { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java index a45707a0197d..0782d298cc80 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DateTimeArithmeticOperation.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.ExceptionUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Duration; import java.time.Period; @@ -22,13 +22,13 @@ import java.time.temporal.TemporalAmount; import java.util.Collection; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isDateTime; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isNull; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.DATE_PERIOD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.TIME_DURATION; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isDateTimeOrTemporal; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isTemporalAmount; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.isDateTime; -import static org.elasticsearch.xpack.ql.type.DataTypes.isNull; abstract class DateTimeArithmeticOperation extends EsqlArithmeticOperation { /** Arithmetic (quad) function. */ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Div.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Div.java index 73863d308f6e..375a105f1952 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Div.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Div.java @@ -8,12 +8,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.compute.ann.Evaluator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryComparisonInversible; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.NumericUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryComparisonInversible; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation.OperationSymbol.DIV; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.longToUnsignedLong; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/EsqlArithmeticOperation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/EsqlArithmeticOperation.java index ba283bc4d877..f43b217d7ebe 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/EsqlArithmeticOperation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/EsqlArithmeticOperation.java @@ -10,24 +10,24 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.ArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryArithmeticOperation; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cast; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.ArithmeticOperation; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryArithmeticOperation; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.io.IOException; import java.util.function.Function; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; public abstract class EsqlArithmeticOperation extends ArithmeticOperation implements EvaluatorMapper { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mod.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mod.java index df3b8f27c488..bfa10eef9a1c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mod.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mod.java @@ -8,10 +8,10 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.compute.ann.Evaluator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.NumericUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation.OperationSymbol.MOD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.longToUnsignedLong; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mul.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mul.java index 5210fcb10ad8..efb0b7dbfdc4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mul.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Mul.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.compute.ann.Evaluator; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryComparisonInversible; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryComparisonInversible; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongMultiplyExact; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation.OperationSymbol.MUL; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongMultiplyExact; public class Mul extends EsqlArithmeticOperation implements BinaryComparisonInversible { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Neg.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Neg.java index 1adfc05b813e..c8a10668691a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Neg.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Neg.java @@ -11,24 +11,24 @@ import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.ExceptionUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.Warnings; import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Duration; import java.time.Period; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.DATE_PERIOD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.TIME_DURATION; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isTemporalAmount; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isType; public class Neg extends UnaryScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Sub.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Sub.java index dd05faa401fe..7c1ece4efaa1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Sub.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/Sub.java @@ -9,12 +9,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.BinaryComparisonInversible; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryComparisonInversible; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.DateTimeException; import java.time.Duration; @@ -22,10 +22,10 @@ import java.time.Period; import java.time.temporal.TemporalAmount; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asDateTime; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asMillis; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongSubtractExact; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation.OperationSymbol.SUB; -import static org.elasticsearch.xpack.ql.type.DateUtils.asDateTime; -import static org.elasticsearch.xpack.ql.type.DateUtils.asMillis; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongSubtractExact; public class Sub extends DateTimeArithmeticOperation implements BinaryComparisonInversible { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/Equals.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/Equals.java index c3eb0c064c5f..c57c9c300665 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/Equals.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/Equals.java @@ -8,14 +8,14 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.Negatable; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparison.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparison.java index a8a8166f7c06..a1a1bf6b2c19 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparison.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparison.java @@ -12,17 +12,17 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cast; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparisonProcessor; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.io.IOException; import java.time.ZoneId; @@ -30,7 +30,7 @@ import java.util.Map; import java.util.function.Function; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; public abstract class EsqlBinaryComparison extends BinaryComparison implements EvaluatorMapper { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThan.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThan.java index 4b3565005790..655641be88f8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThan.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThan.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.Negatable; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqual.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqual.java index 2878fb7d2210..48ed5f513bbd 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqual.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqual.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.Negatable; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/In.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/In.java index 077ca5a978a7..c46b3588df3d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/In.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/In.java @@ -7,25 +7,25 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.InProcessor; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions; import org.elasticsearch.xpack.esql.expression.function.Example; import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.InProcessor; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; -import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.DEFAULT; -import static org.elasticsearch.xpack.ql.util.StringUtils.ordinal; +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.ordinal; -public class In extends org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.In { +public class In extends org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.In { @FunctionInfo( returnType = "boolean", description = "The `IN` operator allows testing whether a field or expression equals an element in a list of literals, " @@ -37,7 +37,7 @@ public class In extends org.elasticsearch.xpack.ql.expression.predicate.operator } @Override - protected NodeInfo info() { + protected NodeInfo info() { return NodeInfo.create(this, In::new, value(), list()); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveBinaryComparison.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveBinaryComparison.java index 69ef6b4648c7..6275db7d7852 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveBinaryComparison.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveBinaryComparison.java @@ -6,11 +6,11 @@ */ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.scalar.BinaryScalarFunction; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.BinaryScalarFunction; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; public abstract class InsensitiveBinaryComparison extends BinaryScalarFunction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEquals.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEquals.java index 98cab93f1055..5711495dc29e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEquals.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEquals.java @@ -13,10 +13,10 @@ import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.lucene.search.AutomatonQueries; import org.elasticsearch.compute.ann.Evaluator; import org.elasticsearch.compute.ann.Fixed; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; public class InsensitiveEquals extends InsensitiveBinaryComparison { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsMapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsMapper.java index b773473d4c06..f73960fc73e8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsMapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsMapper.java @@ -14,13 +14,13 @@ import org.elasticsearch.common.TriFunction; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.evaluator.mapper.ExpressionMapper; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cast; import org.elasticsearch.xpack.esql.planner.Layout; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import static org.elasticsearch.xpack.esql.evaluator.EvalMapper.toEvaluator; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThan.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThan.java index 88cef9acff6c..c1e8d167c9d2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThan.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThan.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.Negatable; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqual.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqual.java index da15e6b78655..a2daa8b48ea6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqual.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqual.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.Negatable; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEquals.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEquals.java index daedafee02c6..2d7828db899f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEquals.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEquals.java @@ -8,14 +8,14 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Negatable; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.Negatable; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZoneId; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/formatter/TextFormat.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/formatter/TextFormat.java index df2536379f3b..5c0d6b138b32 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/formatter/TextFormat.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/formatter/TextFormat.java @@ -13,7 +13,7 @@ import org.elasticsearch.rest.RestRequest; import org.elasticsearch.xcontent.MediaType; import org.elasticsearch.xpack.core.esql.action.ColumnInfo; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; -import org.elasticsearch.xpack.ql.util.StringUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import java.io.IOException; import java.io.Writer; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java index 385058c52039..7a00b7ef467d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypes.java @@ -20,6 +20,40 @@ import org.elasticsearch.dissect.DissectParser; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.transport.RemoteClusterAware; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogic; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.ArithmeticOperation; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexMatch; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DateEsField; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.type.KeywordEsField; +import org.elasticsearch.xpack.esql.core.type.TextEsField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.aggregate.Avg; @@ -172,40 +206,6 @@ import org.elasticsearch.xpack.esql.plan.physical.ProjectExec; import org.elasticsearch.xpack.esql.plan.physical.RowExec; import org.elasticsearch.xpack.esql.plan.physical.ShowExec; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.BinaryLogic; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.ArithmeticOperation; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RLikePattern; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RegexMatch; -import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DateEsField; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.type.InvalidMappedField; -import org.elasticsearch.xpack.ql.type.KeywordEsField; -import org.elasticsearch.xpack.ql.type.TextEsField; -import org.elasticsearch.xpack.ql.type.UnsupportedEsField; import java.io.IOException; import java.util.List; @@ -215,14 +215,14 @@ import java.util.function.BiFunction; import java.util.function.Function; import static java.util.Map.entry; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.Entry.of; import static org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanReader.readerFromPlanReader; import static org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanWriter.writerFromPlanWriter; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; /** * A utility class that consists solely of static methods that describe how to serialize and @@ -249,8 +249,8 @@ public final class PlanNamedTypes { return cls.getSimpleName(); } - static final Class QL_UNARY_SCLR_CLS = - org.elasticsearch.xpack.ql.expression.function.scalar.UnaryScalarFunction.class; + static final Class QL_UNARY_SCLR_CLS = + org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction.class; static final Class ESQL_UNARY_SCLR_CLS = UnaryScalarFunction.class; @@ -1385,15 +1385,19 @@ public final class PlanNamedTypes { static final Map< String, - BiFunction> QL_UNARY_SCALAR_CTRS = - Map.ofEntries( + BiFunction< + Source, + Expression, + org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction>> QL_UNARY_SCALAR_CTRS = Map.ofEntries( entry(name(IsNotNull.class), IsNotNull::new), entry(name(IsNull.class), IsNull::new), entry(name(Not.class), Not::new) ); - static org.elasticsearch.xpack.ql.expression.function.scalar.UnaryScalarFunction readQLUnaryScalar(PlanStreamInput in, String name) - throws IOException { + static org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction readQLUnaryScalar( + PlanStreamInput in, + String name + ) throws IOException { var ctr = QL_UNARY_SCALAR_CTRS.get(name); if (ctr == null) { throw new IOException("Constructor for QLUnaryScalar not found for name:" + name); @@ -1401,8 +1405,10 @@ public final class PlanNamedTypes { return ctr.apply(in.readSource(), in.readExpression()); } - static void writeQLUnaryScalar(PlanStreamOutput out, org.elasticsearch.xpack.ql.expression.function.scalar.UnaryScalarFunction function) - throws IOException { + static void writeQLUnaryScalar( + PlanStreamOutput out, + org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction function + ) throws IOException { out.writeSource(function.source()); out.writeExpression(function.field()); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java index 93bd2518ae38..3faf85b989c0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInput.java @@ -24,21 +24,21 @@ import org.elasticsearch.compute.data.IntBigArrayBlock; import org.elasticsearch.compute.data.LongBigArrayBlock; import org.elasticsearch.core.Releasables; import org.elasticsearch.xpack.esql.Column; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanNamedReader; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanReader; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeSet; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.EsField; import java.io.IOException; import java.util.Collection; @@ -48,7 +48,7 @@ import java.util.Map; import java.util.function.LongFunction; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SourceUtils.readSourceWithText; +import static org.elasticsearch.xpack.esql.core.util.SourceUtils.readSourceWithText; /** * A customized stream input used to deserialize ESQL physical plan fragments. Complements stream diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java index d78e004aade3..6cf64de33938 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutput.java @@ -19,21 +19,21 @@ import org.elasticsearch.compute.data.IntBigArrayBlock; import org.elasticsearch.compute.data.LongBigArrayBlock; import org.elasticsearch.core.Nullable; import org.elasticsearch.xpack.esql.Column; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry.PlanWriter; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Source; import java.io.IOException; import java.util.IdentityHashMap; import java.util.Map; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.util.SourceUtils.writeSourceNoText; +import static org.elasticsearch.xpack.esql.core.util.SourceUtils.writeSourceNoText; /** * A customized stream output used to serialize ESQL physical plan fragments. Complements stream diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java index ba64c708dc68..ffed3bf8e9c3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizer.java @@ -12,6 +12,26 @@ import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.data.BlockUtils; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRule; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRuleExecutor; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; @@ -25,26 +45,6 @@ import org.elasticsearch.xpack.esql.planner.AbstractPhysicalOperationProviders; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.stats.SearchStats; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeMap; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.predicate.Predicates; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.rule.ParameterizedRule; -import org.elasticsearch.xpack.ql.rule.ParameterizedRuleExecutor; -import org.elasticsearch.xpack.ql.rule.Rule; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.CollectionUtils; import java.util.ArrayList; import java.util.LinkedHashSet; @@ -54,9 +54,9 @@ import java.util.Set; import static java.util.Arrays.asList; import static java.util.Collections.emptySet; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection.UP; import static org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer.cleanup; import static org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer.operators; -import static org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection.UP; public class LocalLogicalPlanOptimizer extends ParameterizedRuleExecutor { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizer.java index 40e2d0a1370f..022af58624c4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizer.java @@ -11,6 +11,33 @@ import org.elasticsearch.core.Tuple; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.TypedAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.BinaryLogic; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexMatch; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardLike; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRuleExecutor; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.Queries; +import org.elasticsearch.xpack.esql.core.util.Queries.Clause; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.expression.function.aggregate.SpatialAggregateFunction; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; @@ -37,33 +64,6 @@ import org.elasticsearch.xpack.esql.plan.physical.UnaryExec; import org.elasticsearch.xpack.esql.planner.AbstractPhysicalOperationProviders; import org.elasticsearch.xpack.esql.planner.EsqlTranslatorHandler; import org.elasticsearch.xpack.esql.stats.SearchStats; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeMap; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.TypedAttribute; -import org.elasticsearch.xpack.ql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.ql.expression.predicate.Predicates; -import org.elasticsearch.xpack.ql.expression.predicate.logical.BinaryLogic; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RegexMatch; -import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardLike; -import org.elasticsearch.xpack.ql.querydsl.query.Query; -import org.elasticsearch.xpack.ql.rule.ParameterizedRuleExecutor; -import org.elasticsearch.xpack.ql.rule.Rule; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.Queries; -import org.elasticsearch.xpack.ql.util.Queries.Clause; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.util.ArrayList; import java.util.Collection; @@ -77,9 +77,9 @@ import java.util.function.Predicate; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.expression.predicate.Predicates.splitAnd; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection.UP; import static org.elasticsearch.xpack.esql.plan.physical.EsStatsQueryExec.StatsType.COUNT; -import static org.elasticsearch.xpack.ql.expression.predicate.Predicates.splitAnd; -import static org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection.UP; public class LocalPhysicalPlanOptimizer extends ParameterizedRuleExecutor { public static final EsqlTranslatorHandler TRANSLATOR_HANDLER = new EsqlTranslatorHandler(); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java index ccdcdaa2128c..d97d54eb884f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java @@ -15,6 +15,43 @@ import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.data.BlockUtils; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.analyzer.AnalyzerRules; +import org.elasticsearch.xpack.esql.core.common.Failures; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.ExpressionSet; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexMatch; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.ConstantFolding; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.LiteralsOnTheRight; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.PruneLiteralsInOrderBy; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.SetAsOptimized; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.SimplifyComparisonsArithmetics; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRule; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRuleExecutor; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.CollectionUtils; +import org.elasticsearch.xpack.esql.core.util.Holder; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.SurrogateExpression; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; @@ -37,43 +74,6 @@ import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.analyzer.AnalyzerRules; -import org.elasticsearch.xpack.ql.common.Failures; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeMap; -import org.elasticsearch.xpack.ql.expression.AttributeSet; -import org.elasticsearch.xpack.ql.expression.EmptyAttribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.ExpressionSet; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.predicate.Predicates; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RegexMatch; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.ConstantFolding; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.LiteralsOnTheRight; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.PruneLiteralsInOrderBy; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.SetAsOptimized; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.SimplifyComparisonsArithmetics; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.rule.ParameterizedRule; -import org.elasticsearch.xpack.ql.rule.ParameterizedRuleExecutor; -import org.elasticsearch.xpack.ql.rule.Rule; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.CollectionUtils; -import org.elasticsearch.xpack.ql.util.Holder; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.util.ArrayList; import java.util.Collections; @@ -86,11 +86,11 @@ import java.util.function.Predicate; import static java.util.Arrays.asList; import static java.util.Collections.singleton; +import static org.elasticsearch.xpack.esql.core.expression.Expressions.asAttributes; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection; +import static org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection.DOWN; import static org.elasticsearch.xpack.esql.expression.NamedExpressions.mergeOutputExpressions; import static org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer.SubstituteSurrogates.rawTemporaryName; -import static org.elasticsearch.xpack.ql.expression.Expressions.asAttributes; -import static org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection; -import static org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection.DOWN; public class LogicalPlanOptimizer extends ParameterizedRuleExecutor { @@ -800,7 +800,7 @@ public class LogicalPlanOptimizer extends ParameterizedRuleExecutor { + public static class CombineDisjunctionsToIn extends org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.OptimizerExpressionRule< + Or> { CombineDisjunctionsToIn() { - super(org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection.UP); + super(org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection.UP); } protected In createIn(Expression key, List values, ZoneId zoneId) { @@ -260,14 +261,14 @@ class OptimizerRules { } /** - * This rule must always be placed after {@link org.elasticsearch.xpack.ql.optimizer.OptimizerRules.LiteralsOnTheRight}, since it looks - * at TRUE/FALSE literals' existence on the right hand-side of the {@link Equals}/{@link NotEquals} expressions. + * This rule must always be placed after {@link org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.LiteralsOnTheRight} + * since it looks at TRUE/FALSE literals' existence on the right hand-side of the {@link Equals}/{@link NotEquals} expressions. */ public static final class BooleanFunctionEqualsElimination extends - org.elasticsearch.xpack.ql.optimizer.OptimizerRules.OptimizerExpressionRule { + org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.OptimizerExpressionRule { BooleanFunctionEqualsElimination() { - super(org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection.UP); + super(org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection.UP); } @Override @@ -294,17 +295,17 @@ class OptimizerRules { * When encountering a containing {@link Range}, {@link BinaryComparison} or {@link NotEquals}, these get eliminated by the equality. * * Since this rule can eliminate Ranges and BinaryComparisons, it should be applied before - * {@link org.elasticsearch.xpack.ql.optimizer.OptimizerRules.CombineBinaryComparisons}. + * {@link org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.CombineBinaryComparisons}. * * This rule doesn't perform any promotion of {@link BinaryComparison}s, that is handled by - * {@link org.elasticsearch.xpack.ql.optimizer.OptimizerRules.CombineBinaryComparisons} on purpose as the resulting Range might be - * foldable (which is picked by the folding rule on the next run). + * {@link org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.CombineBinaryComparisons} on purpose as the resulting Range might + * be foldable (which is picked by the folding rule on the next run). */ - public static final class PropagateEquals extends org.elasticsearch.xpack.ql.optimizer.OptimizerRules.OptimizerExpressionRule< + public static final class PropagateEquals extends org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.OptimizerExpressionRule< BinaryLogic> { PropagateEquals() { - super(org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection.DOWN); + super(org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection.DOWN); } public Expression rule(BinaryLogic e) { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalOptimizerRules.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalOptimizerRules.java index af72c8e8b164..1def5a4133a3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalOptimizerRules.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalOptimizerRules.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.optimizer; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules.TransformDirection; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRule; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.util.ReflectionUtils; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules.TransformDirection; -import org.elasticsearch.xpack.ql.rule.ParameterizedRule; -import org.elasticsearch.xpack.ql.rule.Rule; -import org.elasticsearch.xpack.ql.util.ReflectionUtils; public class PhysicalOptimizerRules { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java index 96e593d5aa0f..17ded5cf44c0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizer.java @@ -8,6 +8,19 @@ package org.elasticsearch.xpack.esql.optimizer; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.rule.ParameterizedRuleExecutor; +import org.elasticsearch.xpack.esql.core.rule.Rule; +import org.elasticsearch.xpack.esql.core.rule.RuleExecutor; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.plan.logical.Project; @@ -20,19 +33,6 @@ import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.plan.physical.ProjectExec; import org.elasticsearch.xpack.esql.plan.physical.RegexExtractExec; import org.elasticsearch.xpack.esql.plan.physical.UnaryExec; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.AttributeMap; -import org.elasticsearch.xpack.ql.expression.AttributeSet; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.rule.ParameterizedRuleExecutor; -import org.elasticsearch.xpack.ql.rule.Rule; -import org.elasticsearch.xpack.ql.rule.RuleExecutor; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.Holder; import java.util.ArrayList; import java.util.Collection; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalVerifier.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalVerifier.java index ce174142fc4a..77c8e7da5d89 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalVerifier.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/PhysicalVerifier.java @@ -7,18 +7,18 @@ package org.elasticsearch.xpack.esql.optimizer; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; import org.elasticsearch.xpack.esql.optimizer.OptimizerRules.PhysicalPlanDependencyCheck; import org.elasticsearch.xpack.esql.plan.physical.FieldExtractExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; -import static org.elasticsearch.xpack.ql.common.Failure.fail; +import static org.elasticsearch.xpack.esql.core.common.Failure.fail; /** Physical plan verifier. */ public final class PhysicalVerifier { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/AbstractBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/AbstractBuilder.java index aff66b6485db..0ec1d0b74272 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/AbstractBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/AbstractBuilder.java @@ -9,8 +9,8 @@ package org.elasticsearch.xpack.esql.parser; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; -import org.elasticsearch.xpack.ql.parser.ParserUtils; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.parser.ParserUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; abstract class AbstractBuilder extends EsqlBaseParserBaseVisitor { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java index 8baee4be1491..147d946dcef0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlParser.java @@ -19,8 +19,8 @@ import org.antlr.v4.runtime.TokenSource; import org.antlr.v4.runtime.atn.PredictionMode; import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; -import org.elasticsearch.xpack.ql.parser.CaseChangingCharStream; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.parser.CaseChangingCharStream; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; import java.util.HashMap; import java.util.List; @@ -28,7 +28,7 @@ import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.source; public class EsqlParser { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java index 7ab3dfefc325..fa4afd9e1e52 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ExpressionBuilder.java @@ -17,6 +17,30 @@ import org.apache.lucene.util.automaton.CharacterRunAutomaton; import org.apache.lucene.util.automaton.Operations; import org.elasticsearch.common.Strings; import org.elasticsearch.common.regex.Regex; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedStar; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionResolutionStrategy; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RegexMatch; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DateUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.Order; import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; @@ -37,30 +61,6 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Les import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThanOrEqual; import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedStar; -import org.elasticsearch.xpack.ql.expression.function.FunctionResolutionStrategy; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RLikePattern; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RegexMatch; -import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.DateUtils; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.math.BigInteger; import java.time.Duration; @@ -73,17 +73,17 @@ import java.util.Map; import java.util.function.BiFunction; import static java.util.Collections.singletonList; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.source; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.typedParsing; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.visitList; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.WILDCARD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.bigIntegerToUnsignedLong; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.parseTemporalAmout; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToIntegral; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.DATE_PERIOD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.TIME_DURATION; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.typedParsing; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; -import static org.elasticsearch.xpack.ql.util.StringUtils.WILDCARD; public abstract class ExpressionBuilder extends IdentifierBuilder { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java index b5e348589fa7..e626f502f541 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/IdentifierBuilder.java @@ -14,7 +14,7 @@ import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.IndexIdentifierContext import java.util.List; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.visitList; abstract class IdentifierBuilder extends AbstractBuilder { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java index 1365f1698176..596d3849fb08 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java @@ -15,6 +15,28 @@ import org.elasticsearch.core.Tuple; import org.elasticsearch.dissect.DissectException; import org.elasticsearch.dissect.DissectParser; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedStar; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.parser.ParserUtils; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.MetadataOptionContext; import org.elasticsearch.xpack.esql.parser.EsqlBaseParser.QualifiedNamePatternContext; @@ -33,28 +55,6 @@ import org.elasticsearch.xpack.esql.plan.logical.Rename; import org.elasticsearch.xpack.esql.plan.logical.Row; import org.elasticsearch.xpack.esql.plan.logical.meta.MetaFunctions; import org.elasticsearch.xpack.esql.plan.logical.show.ShowInfo; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.EmptyAttribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedStar; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.parser.ParserUtils; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.Arrays; @@ -68,11 +68,11 @@ import java.util.Set; import java.util.function.Function; import static org.elasticsearch.common.logging.HeaderWarning.addWarning; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.source; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.typedParsing; +import static org.elasticsearch.xpack.esql.core.parser.ParserUtils.visitList; import static org.elasticsearch.xpack.esql.plan.logical.Enrich.Mode; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.stringToInt; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.source; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.typedParsing; -import static org.elasticsearch.xpack.ql.parser.ParserUtils.visitList; public class LogicalPlanBuilder extends ExpressionBuilder { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ParsingException.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ParsingException.java index 6779e25b8851..0705ae7f778c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ParsingException.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/ParsingException.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.parser; import org.elasticsearch.xpack.esql.EsqlClientException; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; import static org.elasticsearch.common.logging.LoggerMessageFormat.format; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java index 926475fa57b7..8827e843939b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Aggregate.java @@ -6,15 +6,15 @@ */ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Dissect.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Dissect.java index 49c87f2b4cc7..1307d1870bba 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Dissect.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Dissect.java @@ -8,12 +8,12 @@ package org.elasticsearch.xpack.esql.plan.logical; import org.elasticsearch.dissect.DissectParser; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java index d5ebc6738814..2946287ae21f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Drop.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java index d5db90aa0732..f418ab5da1c9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Enrich.java @@ -9,15 +9,15 @@ package org.elasticsearch.xpack.esql.plan.logical; import org.elasticsearch.common.util.Maps; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.EmptyAttribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Locale; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java index 52535beec2bf..4cc503c42037 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsRelation.java @@ -6,14 +6,14 @@ */ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.NodeUtils; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.EsField; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.EsField; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java index 610b9bab1714..6cda14600e84 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlAggregate.java @@ -7,13 +7,13 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java index 2b91ab61e43b..9c627cab8bbe 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/EsqlUnresolvedRelation.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java index cb20d3a54991..bfe11c3d33d8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Eval.java @@ -7,13 +7,13 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Explain.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Explain.java index 6a79616a8e15..8500f60bd5d6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Explain.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Explain.java @@ -7,13 +7,13 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Grok.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Grok.java index a98017ef398d..d9f28eff34ad 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Grok.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Grok.java @@ -12,18 +12,18 @@ import org.elasticsearch.grok.GrokCaptureConfig; import org.elasticsearch.grok.GrokCaptureType; import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.NamedExpressions; import org.elasticsearch.xpack.esql.parser.ParsingException; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Comparator; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java index 9ad543fba4be..4e7dc7090418 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/InlineStats.java @@ -7,15 +7,15 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java index 9e1f6644c742..a4e733437e80 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Keep.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java index 0cdcd4af0002..869d8d7dc3a2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/MvExpand.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java index 894b0a1c23a9..fe28ddcc43b4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Project.java @@ -6,15 +6,15 @@ */ package org.elasticsearch.xpack.esql.plan.logical; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Functions; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java index 7f8f5ea08aaf..5bf45fc0f61a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/RegexExtract.java @@ -7,11 +7,11 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java index 393125a143a5..7d99c566aa0c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Rename.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.plan.logical; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Row.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Row.java index 7eb6b20eef90..9af3e08a6734 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Row.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Row.java @@ -7,14 +7,14 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/TopN.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/TopN.java index 99d75a13726a..ac576eaa2cb9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/TopN.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/TopN.java @@ -7,13 +7,13 @@ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Resolvables; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Resolvables; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java index c5db2d37c263..eb6627bbdd0f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/UnresolvedRelation.java @@ -6,12 +6,12 @@ */ package org.elasticsearch.xpack.esql.plan.logical; -import org.elasticsearch.xpack.ql.capabilities.Unresolvable; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.capabilities.Unresolvable; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.Collections; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java index 7ebbd1c0dada..03a9c2b68b32 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/EsqlProject.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.plan.logical.local; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; import org.elasticsearch.xpack.esql.plan.logical.Project; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/LocalRelation.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/LocalRelation.java index da73cb13a47f..1ef8ca49b6e3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/LocalRelation.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/local/LocalRelation.java @@ -6,10 +6,10 @@ */ package org.elasticsearch.xpack.esql.plan.logical.local; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/meta/MetaFunctions.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/meta/MetaFunctions.java index 34b6fd1a31b1..32159ac3caea 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/meta/MetaFunctions.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/meta/MetaFunctions.java @@ -9,14 +9,14 @@ package org.elasticsearch.xpack.esql.plan.logical.meta; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.Strings; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.ArrayList; import java.util.Arrays; @@ -25,8 +25,8 @@ import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; public class MetaFunctions extends LeafPlan { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/show/ShowInfo.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/show/ShowInfo.java index b7fb35121f51..9ff97fe47d2a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/show/ShowInfo.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/show/ShowInfo.java @@ -9,17 +9,17 @@ package org.elasticsearch.xpack.esql.plan.logical.show; import org.apache.lucene.util.BytesRef; import org.elasticsearch.Build; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.plan.logical.LeafPlan; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.plan.logical.LeafPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.ArrayList; import java.util.List; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; public class ShowInfo extends LeafPlan { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/AggregateExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/AggregateExec.java index 490ec174eea5..c3a7f065cc80 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/AggregateExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/AggregateExec.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/DissectExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/DissectExec.java index 3d15156ac2ee..339b8e8bb4d8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/DissectExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/DissectExec.java @@ -7,11 +7,11 @@ package org.elasticsearch.xpack.esql.plan.physical; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.plan.logical.Dissect; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EnrichExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EnrichExec.java index b803d0c20d9d..bdf1c006f8b1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EnrichExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EnrichExec.java @@ -6,11 +6,11 @@ */ package org.elasticsearch.xpack.esql.plan.physical; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.plan.logical.Enrich; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java index 779df60416f0..27c000236976 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsQueryExec.java @@ -10,17 +10,17 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.common.Strings; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.querydsl.container.Sort; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.NodeUtils; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.EsField; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.querydsl.container.Sort; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.EsField; import java.util.List; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java index d44c0a24bfde..79cdf2fec58e 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsSourceExec.java @@ -8,12 +8,12 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.plan.logical.EsRelation; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.NodeUtils; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsStatsQueryExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsStatsQueryExec.java index fb62191395a6..7f5d15f907a4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsStatsQueryExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsStatsQueryExec.java @@ -9,13 +9,13 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.common.Strings; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.NodeUtils; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.Queries; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.Queries; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsTimeseriesQueryExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsTimeseriesQueryExec.java index 48cde0b8bd58..6869b5ac31f5 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsTimeseriesQueryExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EsTimeseriesQueryExec.java @@ -8,14 +8,14 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; import java.util.List; import java.util.Map; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EstimatesRowSize.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EstimatesRowSize.java index 3d626e65f6f1..39ec47221c00 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EstimatesRowSize.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EstimatesRowSize.java @@ -10,9 +10,9 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.compute.data.DocVector; import org.elasticsearch.compute.data.ElementType; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.planner.PlannerUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EvalExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EvalExec.java index a543d662fd4e..3876891b2775 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EvalExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/EvalExec.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeExec.java index f1d215d352a5..61c65c484059 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSinkExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSinkExec.java index a17ada05d720..2f7c4a93eec7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSinkExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSinkExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSourceExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSourceExec.java index bc92cd7bd8a5..44c9b38feee4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSourceExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSourceExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FieldExtractExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FieldExtractExec.java index 879d9c48968b..71ac67e931dd 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FieldExtractExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FieldExtractExec.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.NodeUtils; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.NodeUtils; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.ArrayList; import java.util.Collection; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FilterExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FilterExec.java index d1bc7396a1db..bbfd75e8c05b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FilterExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FilterExec.java @@ -6,10 +6,10 @@ */ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FragmentExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FragmentExec.java index e23a8c783e1e..95cd732eabd4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FragmentExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/FragmentExec.java @@ -8,10 +8,10 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/GrokExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/GrokExec.java index 3d36e787e153..2a5b820f25fe 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/GrokExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/GrokExec.java @@ -7,11 +7,11 @@ package org.elasticsearch.xpack.esql.plan.physical; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.plan.logical.Grok; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LeafExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LeafExec.java index ecf3aed27d70..dd8d4e4f1de2 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LeafExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LeafExec.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.Collections; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LimitExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LimitExec.java index 36aa2ed73328..0ec49015ea83 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LimitExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LimitExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LocalSourceExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LocalSourceExec.java index 9948eb2c7610..71c5955e31a1 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LocalSourceExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LocalSourceExec.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.plan.physical; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/MvExpandExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/MvExpandExec.java index 816b6261c0f3..ebf7d1aba7b8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/MvExpandExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/MvExpandExec.java @@ -6,10 +6,10 @@ */ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java index 7477bd331a66..08c16ce8cebb 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OrderExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OutputExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OutputExec.java index 8d9118cb1e01..84f83b00665f 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OutputExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/OutputExec.java @@ -8,8 +8,8 @@ package org.elasticsearch.xpack.esql.plan.physical; import org.elasticsearch.compute.data.Page; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.function.Consumer; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/PhysicalPlan.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/PhysicalPlan.java index 6e5c0d94ca45..66f571e24b95 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/PhysicalPlan.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/PhysicalPlan.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.plan.QueryPlan; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.plan.QueryPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ProjectExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ProjectExec.java index add2baf94d15..95fef43f7e6a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ProjectExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ProjectExec.java @@ -6,11 +6,11 @@ */ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RegexExtractExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RegexExtractExec.java index 689058d1ea64..6bc35fc1bdde 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RegexExtractExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RegexExtractExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RowExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RowExec.java index 326422147929..a80b2bee3629 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RowExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/RowExec.java @@ -7,11 +7,11 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ShowExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ShowExec.java index 560d23753a49..700e3282b9ef 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ShowExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/ShowExec.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/TopNExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/TopNExec.java index def6709e7a38..22785e62cebc 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/TopNExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/TopNExec.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/UnaryExec.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/UnaryExec.java index 0b25f90fd944..7125a4eeeb55 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/UnaryExec.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/UnaryExec.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql.plan.physical; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.Collections; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java index f5e4dead6734..d0481129cee8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AbstractPhysicalOperationProviders.java @@ -17,19 +17,19 @@ import org.elasticsearch.compute.operator.AggregationOperator; import org.elasticsearch.compute.operator.HashAggregationOperator.HashAggregationOperatorFactory; import org.elasticsearch.compute.operator.Operator; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; import org.elasticsearch.xpack.esql.plan.physical.ExchangeSourceExec; import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.LocalExecutionPlannerContext; import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.PhysicalOperation; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.expression.NamedExpression; import java.util.ArrayList; import java.util.HashSet; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java index a4db37713279..5b1a53e39a31 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/AggregateMapper.java @@ -11,6 +11,17 @@ import org.elasticsearch.compute.aggregation.IntermediateStateDesc; import org.elasticsearch.compute.data.ElementType; import org.elasticsearch.core.Tuple; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.AttributeMap; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; import org.elasticsearch.xpack.esql.expression.function.aggregate.CountDistinct; @@ -23,17 +34,6 @@ import org.elasticsearch.xpack.esql.expression.function.aggregate.SpatialAggrega import org.elasticsearch.xpack.esql.expression.function.aggregate.SpatialCentroid; import org.elasticsearch.xpack.esql.expression.function.aggregate.Sum; import org.elasticsearch.xpack.esql.expression.function.aggregate.Values; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.AttributeMap; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.function.Function; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/DefaultLayout.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/DefaultLayout.java index 384615f6c19d..a2d4bc636011 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/DefaultLayout.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/DefaultLayout.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.planner; -import org.elasticsearch.xpack.ql.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NameId; import java.util.ArrayList; import java.util.HashSet; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java index 733bcfc366d8..f948bdb14c0c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsPhysicalOperationProviders.java @@ -38,6 +38,9 @@ import org.elasticsearch.search.internal.AliasFilter; import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.sort.SortAndFormats; import org.elasticsearch.search.sort.SortBuilder; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec.FieldSort; @@ -46,9 +49,6 @@ import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.DriverParallel import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.LocalExecutionPlannerContext; import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.PhysicalOperation; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.type.DataType; import java.io.IOException; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java index 1edb2cfc75f8..c75b3d7f93b3 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlExpressionTranslators.java @@ -12,6 +12,26 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.geometry.Geometry; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.TypedAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.planner.ExpressionTranslator; +import org.elasticsearch.xpack.esql.core.planner.ExpressionTranslators; +import org.elasticsearch.xpack.esql.core.planner.TranslatorHandler; +import org.elasticsearch.xpack.esql.core.querydsl.query.MatchAll; +import org.elasticsearch.xpack.esql.core.querydsl.query.NotQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.querydsl.query.RangeQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.TermQuery; +import org.elasticsearch.xpack.esql.core.querydsl.query.TermsQuery; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.Check; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesFunction; import org.elasticsearch.xpack.esql.expression.function.scalar.spatial.SpatialRelatesUtils; @@ -23,26 +43,6 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Les import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThanOrEqual; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.esql.querydsl.query.SpatialRelatesQuery; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.TypedAttribute; -import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.planner.ExpressionTranslator; -import org.elasticsearch.xpack.ql.planner.ExpressionTranslators; -import org.elasticsearch.xpack.ql.planner.TranslatorHandler; -import org.elasticsearch.xpack.ql.querydsl.query.MatchAll; -import org.elasticsearch.xpack.ql.querydsl.query.NotQuery; -import org.elasticsearch.xpack.ql.querydsl.query.Query; -import org.elasticsearch.xpack.ql.querydsl.query.RangeQuery; -import org.elasticsearch.xpack.ql.querydsl.query.TermQuery; -import org.elasticsearch.xpack.ql.querydsl.query.TermsQuery; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.Check; import org.elasticsearch.xpack.versionfield.Version; import java.math.BigDecimal; @@ -55,14 +55,14 @@ import java.util.List; import java.util.Set; import java.util.function.Supplier; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.DEFAULT_DATE_TIME_FORMATTER; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.HOUR_MINUTE_SECOND; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.ipToString; import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.versionToString; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; public final class EsqlExpressionTranslators { public static final List> QUERY_TRANSLATORS = List.of( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java index 730aa75e03a2..3dfaf98d8fbf 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/EsqlTranslatorHandler.java @@ -8,18 +8,18 @@ package org.elasticsearch.xpack.esql.planner; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.scalar.ScalarFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.planner.ExpressionTranslator; +import org.elasticsearch.xpack.esql.core.planner.QlTranslatorHandler; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery; import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.ql.planner.ExpressionTranslator; -import org.elasticsearch.xpack.ql.planner.QlTranslatorHandler; -import org.elasticsearch.xpack.ql.querydsl.query.Query; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ExchangeLayout.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ExchangeLayout.java index b9227e1d638a..a12551edfdb7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ExchangeLayout.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/ExchangeLayout.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.planner; -import org.elasticsearch.xpack.ql.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NameId; import java.util.HashMap; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Layout.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Layout.java index 97885a060d63..dafba5e92322 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Layout.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Layout.java @@ -7,9 +7,9 @@ package org.elasticsearch.xpack.esql.planner; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.type.DataType; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.type.DataType; import java.util.ArrayList; import java.util.Collection; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java index e7285bae3240..20e616b38253 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java @@ -48,6 +48,15 @@ import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; import org.elasticsearch.tasks.CancellableTask; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.enrich.EnrichLookupOperator; import org.elasticsearch.xpack.esql.enrich.EnrichLookupService; import org.elasticsearch.xpack.esql.evaluator.EvalMapper; @@ -75,15 +84,6 @@ import org.elasticsearch.xpack.esql.plan.physical.ShowExec; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.util.Holder; import java.util.ArrayList; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java index 1212e77557ca..12052b92432c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/Mapper.java @@ -9,6 +9,12 @@ package org.elasticsearch.xpack.esql.planner; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Enrich; @@ -40,12 +46,6 @@ import org.elasticsearch.xpack.esql.plan.physical.ProjectExec; import org.elasticsearch.xpack.esql.plan.physical.RowExec; import org.elasticsearch.xpack.esql.plan.physical.ShowExec; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; import static org.elasticsearch.xpack.esql.plan.physical.AggregateExec.Mode; import static org.elasticsearch.xpack.esql.plan.physical.AggregateExec.Mode.FINAL; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java index 6110ed1b72c2..de86d7ae2f75 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java @@ -17,6 +17,20 @@ import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.Holder; +import org.elasticsearch.xpack.esql.core.util.Queries; import org.elasticsearch.xpack.esql.optimizer.LocalLogicalOptimizerContext; import org.elasticsearch.xpack.esql.optimizer.LocalLogicalPlanOptimizer; import org.elasticsearch.xpack.esql.optimizer.LocalPhysicalOptimizerContext; @@ -39,20 +53,6 @@ import org.elasticsearch.xpack.esql.plan.physical.TopNExec; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.stats.SearchStats; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.AttributeSet; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.predicate.Predicates; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.Holder; -import org.elasticsearch.xpack.ql.util.Queries; import java.util.ArrayList; import java.util.LinkedHashSet; @@ -62,9 +62,9 @@ import java.util.function.Predicate; import static java.util.Arrays.asList; import static org.elasticsearch.index.mapper.MappedFieldType.FieldExtractPreference.DOC_VALUES; +import static org.elasticsearch.xpack.esql.core.util.Queries.Clause.FILTER; import static org.elasticsearch.xpack.esql.optimizer.LocalPhysicalPlanOptimizer.PushFiltersToSource.canPushToSource; import static org.elasticsearch.xpack.esql.optimizer.LocalPhysicalPlanOptimizer.TRANSLATOR_HANDLER; -import static org.elasticsearch.xpack.ql.util.Queries.Clause.FILTER; public class PlannerUtils { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java index 043d07777ac4..833e540e37cf 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java @@ -55,12 +55,12 @@ import org.elasticsearch.xpack.esql.action.RestEsqlAsyncQueryAction; import org.elasticsearch.xpack.esql.action.RestEsqlDeleteAsyncResultAction; import org.elasticsearch.xpack.esql.action.RestEsqlGetAsyncResultAction; import org.elasticsearch.xpack.esql.action.RestEsqlQueryAction; +import org.elasticsearch.xpack.esql.core.index.IndexResolver; import org.elasticsearch.xpack.esql.enrich.EnrichLookupOperator; import org.elasticsearch.xpack.esql.execution.PlanExecutor; import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery; import org.elasticsearch.xpack.esql.session.EsqlIndexResolver; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; -import org.elasticsearch.xpack.ql.index.IndexResolver; import java.lang.invoke.MethodHandles; import java.util.Collection; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncGetResultsAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncGetResultsAction.java index afb7ee6f5302..1a4a5433a157 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncGetResultsAction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlAsyncGetResultsAction.java @@ -27,9 +27,9 @@ import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.action.EsqlAsyncGetResultAction; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; import org.elasticsearch.xpack.esql.action.EsqlQueryTask; +import org.elasticsearch.xpack.esql.core.plugin.AbstractTransportQlAsyncGetResultsAction; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.parser.ParsingException; -import org.elasticsearch.xpack.ql.plugin.AbstractTransportQlAsyncGetResultsAction; -import org.elasticsearch.xpack.ql.tree.Source; public class TransportEsqlAsyncGetResultsAction extends AbstractTransportQlAsyncGetResultsAction { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java index 34422a3e5c19..28191a394e69 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java @@ -33,12 +33,12 @@ import org.elasticsearch.xpack.esql.action.EsqlQueryAction; import org.elasticsearch.xpack.esql.action.EsqlQueryRequest; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; import org.elasticsearch.xpack.esql.action.EsqlQueryTask; +import org.elasticsearch.xpack.esql.core.async.AsyncTaskManagementService; import org.elasticsearch.xpack.esql.enrich.EnrichLookupService; import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolver; import org.elasticsearch.xpack.esql.execution.PlanExecutor; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.async.AsyncTaskManagementService; import java.io.IOException; import java.time.ZoneOffset; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java index 7569d8d3335b..8dd1cbdef138 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuery.java @@ -41,15 +41,15 @@ import org.elasticsearch.index.query.QueryRewriteContext; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.Warnings; -import org.elasticsearch.xpack.ql.querydsl.query.Query; -import org.elasticsearch.xpack.ql.tree.Source; import java.io.IOException; import java.util.Objects; -import static org.elasticsearch.xpack.ql.util.SourceUtils.readSource; -import static org.elasticsearch.xpack.ql.util.SourceUtils.writeSource; +import static org.elasticsearch.xpack.esql.core.util.SourceUtils.readSource; +import static org.elasticsearch.xpack.esql.core.util.SourceUtils.writeSource; /** * Lucene query that wraps another query and only selects documents that match diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java index 30cadb3e19dc..c7875e79533a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/querydsl/query/SpatialRelatesQuery.java @@ -33,10 +33,10 @@ import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.lucene.spatial.CartesianShapeDocValuesQuery; import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.esql.core.querydsl.query.Query; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.querydsl.query.Query; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.io.IOException; import java.util.Objects; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlConfiguration.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlConfiguration.java index 0c774fe8fa9d..0cfc0cf002b9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlConfiguration.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlConfiguration.java @@ -15,8 +15,8 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.compute.data.BlockStreamInput; import org.elasticsearch.xpack.esql.Column; +import org.elasticsearch.xpack.esql.core.session.Configuration; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; -import org.elasticsearch.xpack.ql.session.Configuration; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlIndexResolver.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlIndexResolver.java index b573de7cc343..6108fbe7d0ca 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlIndexResolver.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlIndexResolver.java @@ -15,17 +15,17 @@ import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.Strings; import org.elasticsearch.index.mapper.TimeSeriesParams; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.index.IndexResolver; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypeRegistry; -import org.elasticsearch.xpack.ql.type.DateEsField; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.type.InvalidMappedField; -import org.elasticsearch.xpack.ql.type.KeywordEsField; -import org.elasticsearch.xpack.ql.type.TextEsField; -import org.elasticsearch.xpack.ql.type.UnsupportedEsField; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.index.IndexResolver; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeRegistry; +import org.elasticsearch.xpack.esql.core.type.DateEsField; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.type.KeywordEsField; +import org.elasticsearch.xpack.esql.core.type.TextEsField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; import java.util.ArrayList; import java.util.Arrays; @@ -37,11 +37,11 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.OBJECT; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.OBJECT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSUPPORTED; public class EsqlIndexResolver { private final Client client; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java index 1abe994cb75c..ce4bf5d6143a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java @@ -21,6 +21,24 @@ import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; import org.elasticsearch.xpack.esql.analysis.PreAnalyzer; import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.core.analyzer.TableInfo; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedStar; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.index.IndexResolver; +import org.elasticsearch.xpack.esql.core.index.MappingException; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolver; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; @@ -38,24 +56,6 @@ import org.elasticsearch.xpack.esql.plan.physical.EstimatesRowSize; import org.elasticsearch.xpack.esql.plan.physical.FragmentExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.planner.Mapper; -import org.elasticsearch.xpack.ql.analyzer.TableInfo; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeSet; -import org.elasticsearch.xpack.ql.expression.EmptyAttribute; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedStar; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.index.IndexResolver; -import org.elasticsearch.xpack.ql.index.MappingException; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.type.InvalidMappedField; -import org.elasticsearch.xpack.ql.util.Holder; import java.util.ArrayList; import java.util.Arrays; @@ -68,9 +68,9 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; -import static org.elasticsearch.xpack.ql.index.IndexResolver.UNMAPPED; -import static org.elasticsearch.xpack.ql.util.ActionListeners.map; -import static org.elasticsearch.xpack.ql.util.StringUtils.WILDCARD; +import static org.elasticsearch.xpack.esql.core.index.IndexResolver.UNMAPPED; +import static org.elasticsearch.xpack.esql.core.util.ActionListeners.map; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.WILDCARD; public class EsqlSession { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Result.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Result.java index 275e15499370..7cbf3987af2c 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Result.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/Result.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.session; -import org.elasticsearch.xpack.ql.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Attribute; import java.util.List; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java index 025c7aba6719..d5c4a67b01e8 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/FeatureMetric.java @@ -7,6 +7,9 @@ package org.elasticsearch.xpack.esql.stats; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; import org.elasticsearch.xpack.esql.plan.logical.Aggregate; import org.elasticsearch.xpack.esql.plan.logical.Dissect; import org.elasticsearch.xpack.esql.plan.logical.Drop; @@ -20,9 +23,6 @@ import org.elasticsearch.xpack.esql.plan.logical.Rename; import org.elasticsearch.xpack.esql.plan.logical.Row; import org.elasticsearch.xpack.esql.plan.logical.meta.MetaFunctions; import org.elasticsearch.xpack.esql.plan.logical.show.ShowInfo; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; import java.util.BitSet; import java.util.Locale; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/SearchStats.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/SearchStats.java index 57458c057477..73935cea540b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/SearchStats.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/stats/SearchStats.java @@ -28,7 +28,7 @@ import org.elasticsearch.index.mapper.SeqNoFieldMapper; import org.elasticsearch.index.mapper.TextFieldMapper; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; -import org.elasticsearch.xpack.ql.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataType; import java.io.IOException; import java.util.LinkedHashMap; diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeConverter.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeConverter.java index e1360c67976c..52031f9a780b 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeConverter.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeConverter.java @@ -13,6 +13,16 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.Converter; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeConverter; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToBoolean; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToCartesianPoint; @@ -28,16 +38,6 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToString; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToUnsignedLong; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToVersion; import org.elasticsearch.xpack.esql.parser.ParsingException; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.Converter; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypeConverter; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; -import org.elasticsearch.xpack.ql.util.StringUtils; import org.elasticsearch.xpack.versionfield.Version; import java.io.IOException; @@ -54,33 +54,33 @@ import java.util.function.BiFunction; import java.util.function.Function; import static java.util.Map.entry; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeDoubleToLong; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToInt; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToLong; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToUnsignedLong; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isPrimitive; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isString; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.ONE_AS_UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.ZERO_AS_UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asUnsignedLong; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.UNSPECIFIED; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_SHAPE; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeDoubleToLong; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToInt; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToLong; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToUnsignedLong; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.NULL; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; -import static org.elasticsearch.xpack.ql.type.DataTypes.isPrimitive; -import static org.elasticsearch.xpack.ql.type.DataTypes.isString; -import static org.elasticsearch.xpack.ql.util.NumericUtils.ONE_AS_UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.util.NumericUtils.ZERO_AS_UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asUnsignedLong; -import static org.elasticsearch.xpack.ql.util.NumericUtils.unsignedLongAsNumber; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.UNSPECIFIED; public class EsqlDataTypeConverter { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistry.java index e763d54a2dcf..0372bc02b0d7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistry.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistry.java @@ -8,19 +8,19 @@ package org.elasticsearch.xpack.esql.type; import org.elasticsearch.index.mapper.TimeSeriesParams; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypeRegistry; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypeRegistry; import java.util.Collection; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isDateTime; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.DATE_PERIOD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.TIME_DURATION; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isDateTimeOrTemporal; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isNullOrDatePeriod; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isNullOrTemporalAmount; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isNullOrTimeDuration; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.isDateTime; public class EsqlDataTypeRegistry implements DataTypeRegistry { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypes.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypes.java index 44f684454469..7c8cf7c0c2a9 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypes.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/type/EsqlDataTypes.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql.type; import org.apache.lucene.util.BytesRef; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import java.util.Collection; import java.util.Collections; @@ -20,27 +20,27 @@ import java.util.stream.Stream; import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toUnmodifiableMap; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.BYTE; -import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT; -import static org.elasticsearch.xpack.ql.type.DataTypes.HALF_FLOAT; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.NESTED; -import static org.elasticsearch.xpack.ql.type.DataTypes.NULL; -import static org.elasticsearch.xpack.ql.type.DataTypes.OBJECT; -import static org.elasticsearch.xpack.ql.type.DataTypes.SCALED_FLOAT; -import static org.elasticsearch.xpack.ql.type.DataTypes.SHORT; -import static org.elasticsearch.xpack.ql.type.DataTypes.SOURCE; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSUPPORTED; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; -import static org.elasticsearch.xpack.ql.type.DataTypes.isNull; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BYTE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DATETIME; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.HALF_FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NESTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.NULL; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.OBJECT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SCALED_FLOAT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SHORT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.SOURCE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSUPPORTED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isNull; public final class EsqlDataTypes { diff --git a/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt b/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt index b64836631a39..6129c5fdffa9 100644 --- a/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt +++ b/x-pack/plugin/esql/src/main/resources/forbidden/ql-signatures.txt @@ -1,7 +1,7 @@ -org.elasticsearch.xpack.ql.plan.logical.Aggregate @ use @org.elasticsearch.xpack.esql.plan.logical.Aggregate instead -org.elasticsearch.xpack.ql.plan.logical.EsRelation @ use @org.elasticsearch.xpack.esql.plan.logical.EsRelation instead -org.elasticsearch.xpack.ql.plan.logical.Project @ use @org.elasticsearch.xpack.esql.plan.logical.Project instead -org.elasticsearch.xpack.ql.plan.logical.UnresolvedRelation @ use @org.elasticsearch.xpack.esql.plan.logical.UnresolvedRelation instead -org.elasticsearch.xpack.ql.analyzer.PreAnalyzer @ use @org.elasticsearch.xpack.esql.analysis.PreAnalyzer instead -org.elasticsearch.xpack.ql.expression.function.Functions @ use @org.elasticsearch.xpack.esql.expression.function.Functions instead -org.elasticsearch.xpack.ql.expression.function.aggregate.* @ use org.elasticsearch.xpack.esql.expression.function.aggregate instead +org.elasticsearch.xpack.esql.core.plan.logical.Aggregate @ use @org.elasticsearch.xpack.esql.plan.logical.Aggregate instead +org.elasticsearch.xpack.esql.core.plan.logical.EsRelation @ use @org.elasticsearch.xpack.esql.plan.logical.EsRelation instead +org.elasticsearch.xpack.esql.core.plan.logical.Project @ use @org.elasticsearch.xpack.esql.plan.logical.Project instead +org.elasticsearch.xpack.esql.core.plan.logical.UnresolvedRelation @ use @org.elasticsearch.xpack.esql.plan.logical.UnresolvedRelation instead +org.elasticsearch.xpack.esql.core.analyzer.PreAnalyzer @ use @org.elasticsearch.xpack.esql.analysis.PreAnalyzer instead +org.elasticsearch.xpack.esql.core.expression.function.Functions @ use @org.elasticsearch.xpack.esql.expression.function.Functions instead +org.elasticsearch.xpack.esql.core.expression.function.aggregate.* @ use org.elasticsearch.xpack.esql.expression.function.aggregate instead diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java index 0774dc50b0d1..0ff0b2c9bd9b 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/CsvTests.java @@ -52,6 +52,13 @@ import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; import org.elasticsearch.xpack.esql.analysis.PreAnalyzer; +import org.elasticsearch.xpack.esql.core.CsvSpecReader; +import org.elasticsearch.xpack.esql.core.SpecReader; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; import org.elasticsearch.xpack.esql.enrich.EnrichLookupService; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; @@ -80,13 +87,6 @@ import org.elasticsearch.xpack.esql.plugin.QueryPragmas; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.stats.DisabledSearchStats; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.CsvSpecReader; -import org.elasticsearch.xpack.ql.SpecReader; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import org.junit.After; import org.junit.Before; import org.mockito.Mockito; @@ -110,8 +110,8 @@ import static org.elasticsearch.xpack.esql.CsvTestsDataLoader.CSV_DATASET_MAP; import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER; import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping; import static org.elasticsearch.xpack.esql.action.EsqlCapabilities.cap; -import static org.elasticsearch.xpack.ql.CsvSpecReader.specParser; -import static org.elasticsearch.xpack.ql.TestUtils.classpathResources; +import static org.elasticsearch.xpack.esql.core.CsvSpecReader.specParser; +import static org.elasticsearch.xpack.esql.core.TestUtils.classpathResources; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.everyItem; import static org.hamcrest.Matchers.greaterThan; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/SerializationTestUtils.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/SerializationTestUtils.java index 185fb14503ca..047b4902ac59 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/SerializationTestUtils.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/SerializationTestUtils.java @@ -23,14 +23,14 @@ import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.query.TermsQueryBuilder; import org.elasticsearch.index.query.WildcardQueryBuilder; import org.elasticsearch.test.EqualsHashCodeTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry; import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; import org.elasticsearch.xpack.esql.io.stream.PlanStreamOutput; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import java.io.IOException; import java.io.UncheckedIOException; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java index 7e87552881d0..6360d65a1116 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryRequestTests.java @@ -33,10 +33,10 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.esql.Column; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.parser.TypedParamValue; import org.elasticsearch.xpack.esql.version.EsqlVersion; import org.elasticsearch.xpack.esql.version.EsqlVersionTests; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.io.IOException; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponseTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponseTests.java index 79939365181a..1f4331e13db5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponseTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/action/EsqlQueryResponseTests.java @@ -46,10 +46,10 @@ import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xpack.core.esql.action.ColumnInfo; import org.elasticsearch.xpack.esql.TestBlockFactory; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.elasticsearch.xpack.versionfield.Version; import org.junit.After; import org.junit.Before; @@ -67,8 +67,8 @@ import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg; import static org.elasticsearch.xpack.esql.action.EsqlQueryResponse.DROP_NULL_COLUMNS_OPTION; import static org.elasticsearch.xpack.esql.action.ResponseValueUtils.valuesToPage; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java index a94cba52f8f0..c78baabcd03a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTestUtils.java @@ -9,14 +9,14 @@ package org.elasticsearch.xpack.esql.analysis; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.parser.EsqlParser; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java index 7c2845f4c6a8..bfb6e8d6c49d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java @@ -19,6 +19,24 @@ import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.TypesTests; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.expression.function.aggregate.Count; @@ -36,24 +54,6 @@ import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.esql.session.EsqlIndexResolver; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.TypesTests; import java.io.IOException; import java.io.InputStream; @@ -73,7 +73,7 @@ import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyze; import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyzer; import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping; import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.tsdbIndexResolution; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java index 1e94c87efb1a..223ee0831647 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/ParsingTests.java @@ -8,12 +8,12 @@ package org.elasticsearch.xpack.esql.analysis; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.type.TypesTests; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.parser.EsqlParser; -import org.elasticsearch.xpack.ql.ParsingException; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.type.TypesTests; import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_CFG; import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java index 5b316d4f65cc..45f923504a46 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java @@ -9,17 +9,17 @@ package org.elasticsearch.xpack.esql.analysis; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.parser.EsqlParser; import org.elasticsearch.xpack.esql.parser.TypedParamValue; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.loadMapping; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.matchesRegex; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolverTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolverTests.java index 3d523470de6c..90fca14b7b06 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolverTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolverTests.java @@ -36,9 +36,9 @@ import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.enrich.EnrichMetadata; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; +import org.elasticsearch.xpack.esql.core.index.IndexResolver; import org.elasticsearch.xpack.esql.plan.logical.Enrich; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; -import org.elasticsearch.xpack.ql.index.IndexResolver; import org.junit.After; import org.junit.Before; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichQuerySourceOperatorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichQuerySourceOperatorTests.java index eef29f0681fb..dead11069d2e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichQuerySourceOperatorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/enrich/EnrichQuerySourceOperatorTests.java @@ -46,7 +46,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.mockito.Mockito.mock; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java index 4867b0c62a18..840bfece3937 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java @@ -41,6 +41,18 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xpack.esql.TestBlockFactory; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.evaluator.EvalMapper; import org.elasticsearch.xpack.esql.expression.function.scalar.conditional.Greatest; import org.elasticsearch.xpack.esql.expression.function.scalar.multivalue.AbstractMultivalueFunctionTestCase; @@ -50,18 +62,6 @@ import org.elasticsearch.xpack.esql.parser.ExpressionBuilder; import org.elasticsearch.xpack.esql.planner.Layout; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.expression.function.FunctionDefinition; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.util.NumericUtils; -import org.elasticsearch.xpack.ql.util.StringUtils; import org.elasticsearch.xpack.versionfield.Version; import org.hamcrest.Matcher; import org.junit.After; @@ -97,9 +97,9 @@ import java.util.stream.Stream; import static org.elasticsearch.compute.data.BlockUtils.toJavaObject; import static org.elasticsearch.xpack.esql.SerializationTestUtils.assertSerialization; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isSpatial; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.either; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DeepCopy.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DeepCopy.java index 5b67011a818a..954d26b6de13 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DeepCopy.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/DeepCopy.java @@ -12,11 +12,11 @@ import org.elasticsearch.compute.data.BlockUtils; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.UnaryExpression; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.UnaryExpression; -import org.elasticsearch.xpack.ql.tree.NodeInfo; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.function.Function; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java index 73babc87e81e..1ff9a0deec85 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistryTests.java @@ -8,22 +8,22 @@ package org.elasticsearch.xpack.esql.expression.function; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.ql.ParsingException; -import org.elasticsearch.xpack.ql.QlIllegalArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.function.FunctionDefinition; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistryTests; -import org.elasticsearch.xpack.ql.expression.function.FunctionResolutionStrategy; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.tree.SourceTests; +import org.elasticsearch.xpack.esql.core.ParsingException; +import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistryTests; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionResolutionStrategy; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.SourceTests; import java.util.Arrays; -import static org.elasticsearch.xpack.ql.TestUtils.randomConfiguration; -import static org.elasticsearch.xpack.ql.expression.function.FunctionRegistry.def; -import static org.elasticsearch.xpack.ql.expression.function.FunctionResolutionStrategy.DEFAULT; +import static org.elasticsearch.xpack.esql.core.TestUtils.randomConfiguration; +import static org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry.def; +import static org.elasticsearch.xpack.esql.core.expression.function.FunctionResolutionStrategy.DEFAULT; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.mock; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java index d6501568a85e..6ef370fd2da3 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/RailRoadDiagram.java @@ -20,7 +20,7 @@ import net.nextencia.rrdiagram.grammar.rrdiagram.RRElement; import net.nextencia.rrdiagram.grammar.rrdiagram.RRText; import org.elasticsearch.common.util.LazyInitializable; -import org.elasticsearch.xpack.ql.expression.function.FunctionDefinition; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionDefinition; import java.awt.Font; import java.awt.FontFormatException; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java index d9261a165896..405d96af622a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/TestCaseSupplier.java @@ -15,14 +15,14 @@ import org.elasticsearch.geo.ShapeTestUtils; import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.Logger; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import org.elasticsearch.xpack.versionfield.Version; import org.hamcrest.Matcher; @@ -43,8 +43,8 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.stream.Collectors; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.equalTo; /** diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/WarningsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/WarningsTests.java index f7bc8c21f9a6..5c3e595e46d7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/WarningsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/WarningsTests.java @@ -8,7 +8,7 @@ package org.elasticsearch.xpack.esql.expression.function; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; public class WarningsTests extends ESTestCase { public void testRegister() { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractConfigurationFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractConfigurationFunctionTestCase.java index 47df642a9694..074fe9e15902 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractConfigurationFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractConfigurationFunctionTestCase.java @@ -9,13 +9,13 @@ package org.elasticsearch.xpack.esql.expression.function.scalar; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.util.List; import java.util.Map; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractScalarFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractScalarFunctionTestCase.java index a0f63a46649e..4422b8375152 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractScalarFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/AbstractScalarFunctionTestCase.java @@ -7,15 +7,15 @@ package org.elasticsearch.xpack.esql.expression.function.scalar; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.tree.Location; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/VaragsTestCaseBuilder.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/VaragsTestCaseBuilder.java index c11291715872..55a8c39756fc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/VaragsTestCaseBuilder.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/VaragsTestCaseBuilder.java @@ -9,9 +9,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar; import org.apache.lucene.util.BytesRef; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseExtraTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseExtraTests.java index 19cc49c18080..85d2ed7b3017 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseExtraTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseExtraTests.java @@ -8,9 +8,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.conditional; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseTests.java index ee23cf00a37a..2011dddd986e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/CaseTests.java @@ -15,15 +15,15 @@ import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expression.TypeResolution; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expression.TypeResolution; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestTests.java index ca8e74757a6f..38092791f6d6 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/GreatestTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.VaragsTestCaseBuilder; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.Comparator; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastTests.java index c3ea444e068b..cadfb1e6d1c6 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/LeastTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.VaragsTestCaseBuilder; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Tests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Tests.java index 214b93f68e7d..62b0070e8a33 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Tests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/FromBase64Tests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.nio.charset.StandardCharsets; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Tests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Tests.java index dc3b8aff80c6..fe25e65befab 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Tests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBase64Tests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.nio.charset.StandardCharsets; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanTests.java index b00cecd3f4cc..8c37f7055066 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToBooleanTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointTests.java index 8a1993eb7ca3..d28dca0d7c53 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianPointTests.java @@ -12,21 +12,21 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.geo.ShapeTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; @FunctionName("to_cartesianpoint") public class ToCartesianPointTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeTests.java index 817af2a78d5c..0f57ea34381f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToCartesianShapeTests.java @@ -12,21 +12,21 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.geo.GeometryTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; @FunctionName("to_cartesianshape") public class ToCartesianShapeTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeTests.java index 93a0d0b5190f..4660a9a1c86a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDatetimeTests.java @@ -11,11 +11,11 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.time.Instant; @@ -66,7 +66,7 @@ public class ToDatetimeTests extends AbstractFunctionTestCase { UNSIGNED_LONG_MAX, bi -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + bi + "] out of [long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + bi + "] out of [long] range" ) ); TestCaseSupplier.forUnaryDouble( @@ -78,7 +78,7 @@ public class ToDatetimeTests extends AbstractFunctionTestCase { -9.223372036854777E18, // a "convenient" value smaller than `(double) Long.MIN_VALUE` (== ...776E18) d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [long] range" ) ); TestCaseSupplier.forUnaryDouble( @@ -90,7 +90,7 @@ public class ToDatetimeTests extends AbstractFunctionTestCase { Double.POSITIVE_INFINITY, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [long] range" ) ); TestCaseSupplier.forUnaryStrings( diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesTests.java index 776782b3828f..2368d5265989 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDegreesTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleTests.java index 5527ae4e81bb..4d1d4b909e72 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToDoubleTests.java @@ -12,14 +12,14 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointTests.java index e36634457597..c22c48767aaf 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoPointTests.java @@ -12,21 +12,21 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.geo.GeometryTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; @FunctionName("to_geopoint") public class ToGeoPointTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeTests.java index 3e6c729550d5..e7c29be3b008 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToGeoShapeTests.java @@ -12,21 +12,21 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.geo.GeometryTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; @FunctionName("to_geoshape") public class ToGeoShapeTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPTests.java index 988f5bd13797..8f106db3e97a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIPTests.java @@ -13,18 +13,18 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; import static java.util.Collections.emptyList; -import static org.elasticsearch.xpack.ql.util.StringUtils.parseIP; +import static org.elasticsearch.xpack.esql.core.util.StringUtils.parseIP; public class ToIPTests extends AbstractFunctionTestCase { public ToIPTests(@Name("TestCase") Supplier testCaseSupplier) { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerTests.java index bc27ded5a6da..0dc66fca7dd1 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToIntegerTests.java @@ -12,12 +12,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; @@ -25,7 +25,7 @@ import java.util.List; import java.util.function.Function; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToInt; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToInt; public class ToIntegerTests extends AbstractFunctionTestCase { public ToIntegerTests(@Name("TestCase") Supplier testCaseSupplier) { @@ -61,7 +61,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { l -> null, l -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + l + "] out of [integer] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + l + "] out of [integer] range" ) ); // random strings that don't look like an Integer @@ -72,7 +72,9 @@ public class ToIntegerTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [" + bytesRef.utf8ToString() + "]" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [" + + bytesRef.utf8ToString() + + "]" ) ); // from doubles within Integer's range @@ -95,7 +97,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { Integer.MIN_VALUE - 1d, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [integer] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [integer] range" ) ); // from doubles outside Integer's range, positive @@ -108,7 +110,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { Double.POSITIVE_INFINITY, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [integer] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [integer] range" ) ); @@ -132,7 +134,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { UNSIGNED_LONG_MAX, ul -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + ul + "] out of [integer] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + ul + "] out of [integer] range" ) ); @@ -157,7 +159,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { Integer.MIN_VALUE - 1L, l -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + l + "] out of [integer] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + l + "] out of [integer] range" ) ); @@ -171,7 +173,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { Long.MAX_VALUE, l -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + l + "] out of [integer] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + l + "] out of [integer] range" ) ); @@ -229,7 +231,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [" + ((BytesRef) bytesRef).utf8ToString() + "]" ) @@ -252,7 +254,7 @@ public class ToIntegerTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [" + ((BytesRef) bytesRef).utf8ToString() + "]" ) diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongTests.java index 3b123344b4b1..77ec9b4ed713 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToLongTests.java @@ -12,12 +12,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.time.Instant; @@ -52,7 +52,9 @@ public class ToLongTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [" + bytesRef.utf8ToString() + "]" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [" + + bytesRef.utf8ToString() + + "]" ) ); // from doubles within long's range @@ -75,7 +77,7 @@ public class ToLongTests extends AbstractFunctionTestCase { Long.MIN_VALUE - 1d, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [long] range" ) ); // from doubles outside long's range, positive @@ -88,7 +90,7 @@ public class ToLongTests extends AbstractFunctionTestCase { Double.POSITIVE_INFINITY, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [long] range" ) ); @@ -111,7 +113,7 @@ public class ToLongTests extends AbstractFunctionTestCase { UNSIGNED_LONG_MAX, ul -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + ul + "] out of [long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + ul + "] out of [long] range" ) ); @@ -181,7 +183,7 @@ public class ToLongTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [" + ((BytesRef) bytesRef).utf8ToString() + "]" ) @@ -204,7 +206,7 @@ public class ToLongTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: Cannot parse number [" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: Cannot parse number [" + ((BytesRef) bytesRef).utf8ToString() + "]" ) diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansTests.java index ffd1a2734d75..f2c3378a5408 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToRadiansTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.convert; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringTests.java index 9d5eed2ca2eb..6e41930fce2e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToStringTests.java @@ -13,19 +13,19 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; public class ToStringTests extends AbstractFunctionTestCase { public ToStringTests(@Name("TestCase") Supplier testCaseSupplier) { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongTests.java index 3cb9c813fd0b..e7e27e34e0a7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToUnsignedLongTests.java @@ -11,11 +11,11 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigDecimal; import java.math.BigInteger; @@ -24,8 +24,8 @@ import java.util.List; import java.util.function.Function; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.safeToUnsignedLong; -import static org.elasticsearch.xpack.ql.util.NumericUtils.UNSIGNED_LONG_MAX_AS_DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToUnsignedLong; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.UNSIGNED_LONG_MAX_AS_DOUBLE; public class ToUnsignedLongTests extends AbstractFunctionTestCase { public ToUnsignedLongTests(@Name("TestCase") Supplier testCaseSupplier) { @@ -96,7 +96,7 @@ public class ToUnsignedLongTests extends AbstractFunctionTestCase { -1d, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [unsigned_long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [unsigned_long] range" ) ); // from doubles outside Long's range, positive @@ -109,7 +109,7 @@ public class ToUnsignedLongTests extends AbstractFunctionTestCase { Double.POSITIVE_INFINITY, d -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + d + "] out of [unsigned_long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + d + "] out of [unsigned_long] range" ) ); @@ -133,7 +133,7 @@ public class ToUnsignedLongTests extends AbstractFunctionTestCase { -1L, l -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + l + "] out of [unsigned_long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + l + "] out of [unsigned_long] range" ) ); @@ -157,7 +157,7 @@ public class ToUnsignedLongTests extends AbstractFunctionTestCase { -1, l -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + l + "] out of [unsigned_long] range" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + l + "] out of [unsigned_long] range" ) ); @@ -215,7 +215,7 @@ public class ToUnsignedLongTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + ((BytesRef) bytesRef).utf8ToString() + "] out of [unsigned_long] range" ) @@ -238,7 +238,7 @@ public class ToUnsignedLongTests extends AbstractFunctionTestCase { bytesRef -> null, bytesRef -> List.of( "Line -1:-1: evaluation of [] failed, treating result as null. Only first 20 failures recorded.", - "Line -1:-1: org.elasticsearch.xpack.ql.InvalidArgumentException: [" + "Line -1:-1: org.elasticsearch.xpack.esql.core.InvalidArgumentException: [" + ((BytesRef) bytesRef).utf8ToString() + "] out of [unsigned_long] range" ) diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionTests.java index c6e2abae1444..16eac2a6f171 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/ToVersionTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.elasticsearch.xpack.versionfield.Version; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffTests.java index 15d0cca45440..f2f5846bf090 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateDiffTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.ZonedDateTime; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java index d862a07c2fd0..e2dc759b9683 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java @@ -13,14 +13,14 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractConfigurationFunctionTestCase; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Instant; import java.time.ZonedDateTime; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatTests.java index c6c544fced4c..26f0e88ff2fc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormatTests.java @@ -12,12 +12,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.lucene.BytesRefs; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractConfigurationFunctionTestCase; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseTests.java index 8aa9653ea86f..19c5ca0de72f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParseTests.java @@ -12,13 +12,13 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.operator.DriverContext; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncTests.java index 98fbff6a816c..4adf32479f10 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateTruncTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.common.Rounding; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Duration; import java.time.Instant; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchTests.java index 2325c1a5754f..c86c5938dc4b 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/ip/CIDRMatchTests.java @@ -11,13 +11,13 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsTests.java index 491680d537f3..3c1b85d51515 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AbsTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosTests.java index 2946e1d66975..02974c10480d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AcosTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinTests.java index b74bb6aa6e93..d4d13c2054fc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AsinTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Tests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Tests.java index 0a884a2311e8..226649439126 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Tests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Atan2Tests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanTests.java index 897d4b18c309..8c7000940390 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/AtanTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/BucketTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/BucketTests.java index a73b4a0dfa55..ba4c43b5020c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/BucketTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/BucketTests.java @@ -13,14 +13,14 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.Rounding; import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.grouping.Bucket; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.time.Duration; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtTests.java index 3d67b4d2b1ef..8c9ff78bcdba 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CbrtTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilTests.java index cbc7e99bf6c0..70b8eafb88d2 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CeilTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosTests.java index c7b4570dab34..981c6812d117 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CosTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshTests.java index be7e8e47a075..cb666f03494e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/CoshTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/ETests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/ETests.java index 0b786eabc1ad..01d848ea9609 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/ETests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/ETests.java @@ -12,11 +12,11 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.DoubleBlock; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorTests.java index 9a185172c997..cb4fd8a403ed 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/FloorTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10Tests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10Tests.java index 3c1bf69a7871..95bc853c890c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10Tests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Log10Tests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogTests.java index 9e7417232356..e884b63c5259 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/LogTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/NowTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/NowTests.java index b4f195c5929e..ed5a80cb81b4 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/NowTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/NowTests.java @@ -13,13 +13,13 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.LongBlock; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractConfigurationFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PiTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PiTests.java index faa860536e00..bee3a495a5aa 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PiTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PiTests.java @@ -12,11 +12,11 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.DoubleBlock; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowTests.java index f4cf955c46bb..acc1a3a10ba8 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/PowTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundTests.java index 097f3c1038cf..115ce6b7019c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/RoundTests.java @@ -11,14 +11,14 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.math.Maths; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.operator.math.Maths; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumTests.java index 416702901095..8a6d88fb399a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SignumTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinTests.java index 788b506694d5..ce23598bf980 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhTests.java index 465879b07154..5d349e09aed2 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SinhTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtTests.java index 29e75bb3f022..c7fbe713fab0 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/SqrtTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanTests.java index 1d654873f828..c138fc12881f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhTests.java index a50fbfa642dd..585e75d05e37 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TanhTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TauTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TauTests.java index 5a71344615ec..57448df4ec78 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TauTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/TauTests.java @@ -12,11 +12,11 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.DoubleBlock; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java index ba9d47d20400..dd7e36f23f5f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/AbstractMultivalueFunctionTestCase.java @@ -13,15 +13,15 @@ import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geo.ShapeTestUtils; import org.elasticsearch.geometry.Geometry; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import org.hamcrest.Matcher; import java.math.BigInteger; @@ -37,8 +37,8 @@ import java.util.stream.IntStream; import java.util.stream.LongStream; import java.util.stream.Stream; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; public abstract class AbstractMultivalueFunctionTestCase extends AbstractFunctionTestCase { /** diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvgTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvgTests.java index c6c8826c6805..0ad43f520daf 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvgTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvAvgTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.search.aggregations.metrics.CompensatedSum; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcatTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcatTests.java index b1f2d4f0657b..c5c22000671f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcatTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvConcatTests.java @@ -11,13 +11,13 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCountTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCountTests.java index 342baf405d0c..9c379990e470 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCountTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvCountTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupeTests.java index 2299d1a47d3a..0aed84d57004 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupeTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import org.hamcrest.Matcher; import org.hamcrest.Matchers; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirstTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirstTests.java index 0f52efe20399..df2c959a3b66 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirstTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvFirstTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLastTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLastTests.java index 41abab22c72e..d5616f90916e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLastTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvLastTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMaxTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMaxTests.java index c477cad17904..5af662c2642c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMaxTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMaxTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedianTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedianTests.java index 43e846714727..f6395074dbb8 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedianTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMedianTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMinTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMinTests.java index 2e47f7c24bb5..6f398c8a7ac9 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMinTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvMinTests.java @@ -10,10 +10,10 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.multivalue; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceTests.java index bf16344847bd..184ac397f4e1 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSliceTests.java @@ -13,19 +13,19 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.geo.GeometryTestUtils; import org.elasticsearch.geo.ShapeTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSortTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSortTests.java index 478e45167b85..9019de87256f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSortTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSortTests.java @@ -12,11 +12,11 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.ElementType; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.Collections; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumTests.java index 90b1bc22c45e..5dd248323923 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSumTests.java @@ -11,18 +11,18 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipTests.java index c4162f6ddc36..8d0e2a64d164 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvZipTests.java @@ -12,12 +12,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractScalarFunctionTestCase; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/CoalesceTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/CoalesceTests.java index 328f94b9c87e..b3b0fcae2f3d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/CoalesceTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/CoalesceTests.java @@ -13,17 +13,17 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.evaluator.EvalMapper; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.VaragsTestCaseBuilder; import org.elasticsearch.xpack.esql.planner.Layout; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.EsField; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNotNullTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNotNullTests.java index 2c0864d0a8fd..2b002e6c1e31 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNotNullTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNotNullTests.java @@ -12,14 +12,14 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNullTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNullTests.java index c6c67d67375d..15e6ee3672f1 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNullTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/IsNullTests.java @@ -12,14 +12,14 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BooleanBlock; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsTests.java index 37bfb6eccac5..79edf8d53eca 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialContainsTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointTests.java index 6e62af7e964f..f09975e6ff87 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialDisjointTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsTests.java index 83679ca7134e..4a4d30046bfd 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialIntersectsTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunctionTestCase.java index 64e03dec6b06..a38ad43c00f7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunctionTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialRelatesFunctionTestCase.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import joptsimple.internal.Strings; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.TypeResolutions; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import org.hamcrest.Matcher; import java.io.IOException; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinTests.java index 11dbc060b4eb..9915d3d6ebea 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/SpatialWithinTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.spatial; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXTests.java index 3227faa4417f..012ee982d3da 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StXTests.java @@ -11,18 +11,18 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.UNSPECIFIED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.UNSPECIFIED; @FunctionName("st_x") public class StXTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYTests.java index 9416b7ba8cad..776a1a461b10 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/spatial/StYTests.java @@ -11,18 +11,18 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.UNSPECIFIED; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.UNSPECIFIED; @FunctionName("st_y") public class StYTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AbstractTrimTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AbstractTrimTests.java index 229abbcdb187..f44a51b0e53b 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AbstractTrimTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/AbstractTrimTests.java @@ -8,9 +8,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.type.DataType; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatTests.java index a001aaf35424..9fc396daada9 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ConcatTests.java @@ -14,14 +14,14 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.xpack.esql.EsqlClientException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java index e882a97e8a84..6443d739e64c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/EndsWithTests.java @@ -11,11 +11,11 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.LinkedList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimTests.java index 23171545dc69..7efa5c4e17cb 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LTrimTests.java @@ -10,9 +10,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftTests.java index d9ea8c0549be..291b0c5d6ce3 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LeftTests.java @@ -13,12 +13,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthTests.java index 3c2be975dbbc..98ff38b48a7c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LengthTests.java @@ -12,11 +12,11 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.UnicodeUtil; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateTests.java index a7f4ca034278..fff74b8af7a1 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/LocateTests.java @@ -12,12 +12,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.core.Nullable; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.nio.charset.StandardCharsets; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java index 6c2e6c725cd1..84504d4cd572 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RLikeTests.java @@ -12,15 +12,15 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RLikePattern; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimTests.java index 151612bb9c56..4a714b12d6d8 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RTrimTests.java @@ -10,9 +10,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceTests.java index 6c6500bfc333..97bf5fa21e16 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ReplaceTests.java @@ -11,13 +11,13 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightTests.java index 47ab1dd8ee3f..a925410197ae 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/RightTests.java @@ -13,12 +13,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitTests.java index a157d953118f..d809c8ebc9f5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SplitTests.java @@ -16,14 +16,14 @@ import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.InvalidArgumentException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.InvalidArgumentException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java index ced1e28247c9..8b98cbd0f8ca 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/StartsWithTests.java @@ -11,11 +11,11 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringTests.java index cb3e8aaab680..36ace66290fc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/SubstringTests.java @@ -13,12 +13,12 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerTests.java index 4b1109892b00..cdc863198863 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToLowerTests.java @@ -14,17 +14,17 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DateUtils; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractConfigurationFunctionTestCase; import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.DateUtils; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperTests.java index 1d7c479cca0e..b4ed8e9fbe71 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/ToUpperTests.java @@ -14,17 +14,17 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DateUtils; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractConfigurationFunctionTestCase; import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.DateUtils; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimTests.java index 631e0f0242eb..a1f5bcd1b28b 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/TrimTests.java @@ -10,9 +10,9 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.string; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.List; import java.util.function.Supplier; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java index 9c575c1b41cd..1e98f10d3c7f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/WildcardLikeTests.java @@ -12,15 +12,15 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; import org.elasticsearch.compute.data.Block; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.FunctionName; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/AbstractBinaryOperatorTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/AbstractBinaryOperatorTestCase.java index 22c3bb6e515d..93db2ab76955 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/AbstractBinaryOperatorTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/AbstractBinaryOperatorTestCase.java @@ -9,17 +9,17 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator; import org.elasticsearch.compute.data.Block; import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.core.common.Failure; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.tree.Location; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.common.Failure; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.predicate.BinaryOperator; -import org.elasticsearch.xpack.ql.tree.Location; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.Arrays; @@ -27,9 +27,9 @@ import java.util.List; import java.util.Locale; import static org.elasticsearch.compute.data.BlockUtils.toJavaObject; +import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.commonType; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isNull; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isRepresentable; -import static org.elasticsearch.xpack.ql.type.DataTypeConverter.commonType; -import static org.elasticsearch.xpack.ql.type.DataTypes.isNull; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/BreakerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/BreakerTests.java index a09cb68c893e..bd85fc313646 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/BreakerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/BreakerTests.java @@ -21,12 +21,12 @@ import org.elasticsearch.compute.data.Page; import org.elasticsearch.compute.operator.DriverContext; import org.elasticsearch.compute.operator.EvalOperator; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.junit.After; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractArithmeticTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractArithmeticTestCase.java index 02005d51c96d..0fa5b6121a6a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractArithmeticTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractArithmeticTestCase.java @@ -7,12 +7,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.expression.predicate.operator.AbstractBinaryOperatorTestCase; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.predicate.BinaryOperator; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractDateTimeArithmeticTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractDateTimeArithmeticTestCase.java index bb462dc00463..5c137c1914d7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractDateTimeArithmeticTestCase.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AbstractDateTimeArithmeticTestCase.java @@ -7,10 +7,10 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; +import org.elasticsearch.xpack.esql.core.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.predicate.BinaryOperator; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.time.Duration; @@ -19,10 +19,10 @@ import java.time.temporal.TemporalAmount; import java.util.List; import java.util.Locale; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isDateTime; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.isNull; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isNullOrTemporalAmount; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.isTemporalAmount; -import static org.elasticsearch.xpack.ql.type.DataTypes.isDateTime; -import static org.elasticsearch.xpack.ql.type.DataTypes.isNull; import static org.hamcrest.Matchers.equalTo; public abstract class AbstractDateTimeArithmeticTestCase extends AbstractArithmeticTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddTests.java index 25ccd91f43d0..f61fb0a5b316 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/AddTests.java @@ -10,13 +10,13 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.time.Duration; @@ -29,10 +29,10 @@ import java.util.function.BiFunction; import java.util.function.BinaryOperator; import java.util.function.Supplier; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asDateTime; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asMillis; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.AbstractArithmeticTestCase.arithmeticExceptionOverflowCase; -import static org.elasticsearch.xpack.ql.type.DateUtils.asDateTime; -import static org.elasticsearch.xpack.ql.type.DateUtils.asMillis; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivTests.java index eb29a7b5ce06..173ba55cefda 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/DivTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.math.BigInteger; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModTests.java index bc6d6dd97c3e..df79ee203a3f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/ModTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import org.hamcrest.Matcher; import java.math.BigInteger; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulTests.java index 65b3ad936912..faae48920f35 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/MulTests.java @@ -10,18 +10,18 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.AbstractArithmeticTestCase.arithmeticExceptionOverflowCase; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; import static org.hamcrest.Matchers.equalTo; public class MulTests extends AbstractFunctionTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegTests.java index c65f4eed2de7..ecff55acff0c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/NegTests.java @@ -12,14 +12,14 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Block; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Duration; import java.time.Period; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubTests.java index 89ec25454cbc..e3e2af720d3e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/arithmetic/SubTests.java @@ -10,22 +10,22 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.time.Duration; import java.time.Period; import java.util.List; import java.util.function.Supplier; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asDateTime; +import static org.elasticsearch.xpack.esql.core.type.DateUtils.asMillis; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.ZERO_AS_UNSIGNED_LONG; import static org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.AbstractArithmeticTestCase.arithmeticExceptionOverflowCase; -import static org.elasticsearch.xpack.ql.type.DateUtils.asDateTime; -import static org.elasticsearch.xpack.ql.type.DateUtils.asMillis; -import static org.elasticsearch.xpack.ql.util.NumericUtils.ZERO_AS_UNSIGNED_LONG; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsTests.java index d5419d64be4b..77a80a4b60ce 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EqualsTests.java @@ -10,12 +10,12 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparisonTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparisonTests.java index ab62d6b37f79..cc282186d438 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparisonTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/EsqlBinaryComparisonTests.java @@ -13,8 +13,8 @@ import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparisonProcessor; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.EsqlBinaryComparison.BinaryComparisonOperation; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparisonProcessor; import java.io.IOException; import java.util.List; @@ -34,7 +34,8 @@ public class EsqlBinaryComparisonTests extends ESTestCase { /** * Test that a serialized - * {@link org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation} + * {@code BinaryComparisonOperation} + * from {@code org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison} * can be read back as a * {@link BinaryComparisonOperation} */ diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualTests.java index 35b3979f9991..99f4b4ff82d9 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanOrEqualTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanTests.java index f8ee18ff90c6..f0fe60c458c7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/GreaterThanTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsTests.java index e7d2fde05d49..c816c7042423 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/InsensitiveEqualsTests.java @@ -9,11 +9,11 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.ql.TestUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; public class InsensitiveEqualsTests extends ESTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualTests.java index 35da7b4dabf6..56758d43a83e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanOrEqualTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanTests.java index e5f77e15eece..fa6f3fbd0926 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/LessThanTests.java @@ -11,12 +11,12 @@ import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.NumericUtils; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.NumericUtils; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsTests.java index 8f9dbcbe9414..e03a569904dc 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/predicate/operator/comparison/NotEqualsTests.java @@ -10,11 +10,11 @@ package org.elasticsearch.xpack.esql.expression.predicate.operator.comparison; import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.math.BigInteger; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatTests.java index 80a3985be01b..6da9e8ef8ba4 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatTests.java @@ -20,7 +20,7 @@ import org.elasticsearch.xcontent.NamedXContentRegistry; import org.elasticsearch.xpack.core.esql.action.ColumnInfo; import org.elasticsearch.xpack.esql.TestBlockFactory; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; -import org.elasticsearch.xpack.ql.util.StringUtils; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import java.io.IOException; import java.io.StringWriter; @@ -34,11 +34,11 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.elasticsearch.rest.RestResponseUtils.getTextBodyContent; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.elasticsearch.xpack.esql.formatter.TextFormat.CSV; import static org.elasticsearch.xpack.esql.formatter.TextFormat.PLAIN_TEXT; import static org.elasticsearch.xpack.esql.formatter.TextFormat.TSV; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; public class TextFormatTests extends ESTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatterTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatterTests.java index cde6a242e5e6..9a89f3a1275f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatterTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/formatter/TextFormatterTests.java @@ -23,9 +23,9 @@ import java.util.Arrays; import java.util.List; import static org.elasticsearch.rest.RestResponseUtils.getTextBodyContent; -import static org.elasticsearch.xpack.ql.util.DateUtils.UTC_DATE_TIME_FORMATTER; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.CARTESIAN; -import static org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes.GEO; +import static org.elasticsearch.xpack.esql.core.util.DateUtils.UTC_DATE_TIME_FORMATTER; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN; +import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO; import static org.hamcrest.Matchers.arrayWithSize; public class TextFormatterTests extends ESTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java index 8fbce3302b25..7e5f2148ea28 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanNamedTypesTests.java @@ -17,6 +17,28 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.EqualsHashCodeTestUtils; import org.elasticsearch.xpack.esql.EsqlTestUtils; import org.elasticsearch.xpack.esql.SerializationTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.function.Function; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.ArithmeticOperation; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.DateEsField; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.type.InvalidMappedField; +import org.elasticsearch.xpack.esql.core.type.KeywordEsField; +import org.elasticsearch.xpack.esql.core.type.TextEsField; +import org.elasticsearch.xpack.esql.core.type.UnsupportedEsField; import org.elasticsearch.xpack.esql.expression.Order; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute; @@ -79,28 +101,6 @@ import org.elasticsearch.xpack.esql.plan.physical.RowExec; import org.elasticsearch.xpack.esql.plan.physical.ShowExec; import org.elasticsearch.xpack.esql.plan.physical.TopNExec; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.function.Function; -import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.ArithmeticOperation; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.DateEsField; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.type.InvalidMappedField; -import org.elasticsearch.xpack.ql.type.KeywordEsField; -import org.elasticsearch.xpack.ql.type.TextEsField; -import org.elasticsearch.xpack.ql.type.UnsupportedEsField; import java.io.IOException; import java.util.Collections; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInputTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInputTests.java index 4796b31148e2..5788f218564c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInputTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamInputTests.java @@ -8,13 +8,13 @@ package org.elasticsearch.xpack.esql.io.stream; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.NameId; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; import org.elasticsearch.xpack.esql.plan.logical.Eval; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.NameId; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Source; import java.util.ArrayList; import java.util.HashSet; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutputTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutputTests.java index bc69b4454df8..a8a59f755a59 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutputTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/io/stream/PlanStreamOutputTests.java @@ -18,9 +18,9 @@ import org.elasticsearch.compute.data.IntBlock; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.TransportVersionUtils; import org.elasticsearch.xpack.esql.Column; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.session.EsqlConfigurationSerializationTests; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.io.IOException; import java.util.Map; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/FoldNull.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/FoldNull.java index 5fa3dae74425..4e15cd27a50f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/FoldNull.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/FoldNull.java @@ -7,7 +7,7 @@ package org.elasticsearch.xpack.esql.optimizer; -import org.elasticsearch.xpack.ql.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expression; public class FoldNull extends LogicalPlanOptimizer.FoldNull { @Override diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java index 68c7b59d7b19..eca0e2c0ddde 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalLogicalPlanOptimizerTests.java @@ -12,6 +12,21 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.EsqlTestUtils; import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRulesTests; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.expression.function.scalar.nulls.Coalesce; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add; @@ -22,21 +37,6 @@ import org.elasticsearch.xpack.esql.plan.logical.Project; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; import org.elasticsearch.xpack.esql.stats.SearchStats; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRulesTests; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; import org.hamcrest.Matchers; import org.junit.BeforeClass; @@ -54,9 +54,9 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping; import static org.elasticsearch.xpack.esql.EsqlTestUtils.statsForExistingField; import static org.elasticsearch.xpack.esql.EsqlTestUtils.statsForMissingField; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; +import static org.elasticsearch.xpack.esql.core.TestUtils.getFieldAttribute; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; import static org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizerTests.greaterThanOf; -import static org.elasticsearch.xpack.ql.TestUtils.getFieldAttribute; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java index 0146325bb8ac..d25c9cdb5139 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java @@ -26,6 +26,15 @@ import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.Holder; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.plan.logical.Enrich; @@ -46,15 +55,6 @@ import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.stats.Metrics; import org.elasticsearch.xpack.esql.stats.SearchStats; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.util.Holder; import org.junit.Before; import java.io.IOException; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java index 0520ea76e3a6..9bc2ea3a5150 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java @@ -19,6 +19,39 @@ import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.AttributeSet; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Nullability; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNotNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.nulls.IsNull; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLikePattern; +import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.optimizer.OptimizerRules; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.plan.logical.UnaryPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.Holder; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.Order; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; @@ -87,39 +120,6 @@ import org.elasticsearch.xpack.esql.plan.logical.TopN; import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject; import org.elasticsearch.xpack.esql.plan.logical.local.LocalRelation; import org.elasticsearch.xpack.esql.plan.logical.local.LocalSupplier; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.AttributeSet; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Nullability; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.predicate.Predicates; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNotNull; -import org.elasticsearch.xpack.ql.expression.predicate.nulls.IsNull; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.expression.predicate.regex.RLikePattern; -import org.elasticsearch.xpack.ql.expression.predicate.regex.WildcardPattern; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.optimizer.OptimizerRules; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.plan.logical.UnaryPlan; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.util.Holder; -import org.elasticsearch.xpack.ql.util.StringUtils; import org.junit.BeforeClass; import java.lang.reflect.Constructor; @@ -144,6 +144,20 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping; import static org.elasticsearch.xpack.esql.EsqlTestUtils.localSource; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; import static org.elasticsearch.xpack.esql.analysis.Analyzer.NO_FIELDS; +import static org.elasticsearch.xpack.esql.core.TestUtils.getFieldAttribute; +import static org.elasticsearch.xpack.esql.core.expression.Literal.FALSE; +import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL; +import static org.elasticsearch.xpack.esql.core.expression.Literal.TRUE; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.BOOLEAN; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.IP; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.TEXT; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.UNSIGNED_LONG; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.VERSION; import static org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.EsqlBinaryComparison.BinaryComparisonOperation.EQ; import static org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.EsqlBinaryComparison.BinaryComparisonOperation.GT; import static org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.EsqlBinaryComparison.BinaryComparisonOperation.GTE; @@ -151,20 +165,6 @@ import static org.elasticsearch.xpack.esql.expression.predicate.operator.compari import static org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.EsqlBinaryComparison.BinaryComparisonOperation.LTE; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE; -import static org.elasticsearch.xpack.ql.TestUtils.getFieldAttribute; -import static org.elasticsearch.xpack.ql.expression.Literal.FALSE; -import static org.elasticsearch.xpack.ql.expression.Literal.NULL; -import static org.elasticsearch.xpack.ql.expression.Literal.TRUE; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; -import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.IP; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT; -import static org.elasticsearch.xpack.ql.type.DataTypes.UNSIGNED_LONG; -import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.contains; @@ -779,7 +779,7 @@ public class LogicalPlanOptimizerTests extends ESTestCase { public void testPushDownLikeRlikeFilter() { EsRelation relation = relation(); - org.elasticsearch.xpack.ql.expression.predicate.regex.RLike conditionA = rlike(getFieldAttribute("a"), "foo"); + org.elasticsearch.xpack.esql.core.expression.predicate.regex.RLike conditionA = rlike(getFieldAttribute("a"), "foo"); WildcardLike conditionB = wildcardLike(getFieldAttribute("b"), "bar"); Filter fa = new Filter(EMPTY, relation, conditionA); @@ -4089,8 +4089,8 @@ public class LogicalPlanOptimizerTests extends ESTestCase { new Order( limit.source(), salary, - org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC, - org.elasticsearch.xpack.ql.expression.Order.NullsPosition.FIRST + org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC, + org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.FIRST ) ) ); @@ -4168,20 +4168,20 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(topN.order().size(), is(3)); var firstOrder = as(topN.order().get(0), Order.class); - assertThat(firstOrder.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC)); - assertThat(firstOrder.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.FIRST)); + assertThat(firstOrder.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC)); + assertThat(firstOrder.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.FIRST)); var renamed_emp_no = as(firstOrder.child(), ReferenceAttribute.class); assertThat(renamed_emp_no.toString(), startsWith("$$emp_no$temp_name")); var secondOrder = as(topN.order().get(1), Order.class); - assertThat(secondOrder.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.DESC)); - assertThat(secondOrder.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.LAST)); + assertThat(secondOrder.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.DESC)); + assertThat(secondOrder.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.LAST)); var renamed_salary = as(secondOrder.child(), ReferenceAttribute.class); assertThat(renamed_salary.toString(), startsWith("$$salary$temp_name")); var thirdOrder = as(topN.order().get(2), Order.class); - assertThat(thirdOrder.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC)); - assertThat(thirdOrder.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.LAST)); + assertThat(thirdOrder.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC)); + assertThat(thirdOrder.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.LAST)); var renamed_emp_no2 = as(thirdOrder.child(), ReferenceAttribute.class); assertThat(renamed_emp_no2.toString(), startsWith("$$emp_no$temp_name")); @@ -4249,8 +4249,8 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(topN.order().size(), is(1)); var order = as(topN.order().get(0), Order.class); - assertThat(order.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC)); - assertThat(order.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.LAST)); + assertThat(order.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC)); + assertThat(order.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.LAST)); var expression = as(order.child(), ReferenceAttribute.class); assertThat(expression.toString(), startsWith("$$order_by$0$")); @@ -4288,14 +4288,14 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(topN.order().size(), is(2)); var order = as(topN.order().get(0), Order.class); - assertThat(order.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC)); - assertThat(order.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.LAST)); + assertThat(order.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC)); + assertThat(order.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.LAST)); ReferenceAttribute expression = as(order.child(), ReferenceAttribute.class); assertThat(expression.toString(), startsWith("$$order_by$0$")); order = as(topN.order().get(1), Order.class); - assertThat(order.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.DESC)); - assertThat(order.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.FIRST)); + assertThat(order.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.DESC)); + assertThat(order.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.FIRST)); FieldAttribute empNo = as(order.child(), FieldAttribute.class); assertThat(empNo.name(), equalTo("emp_no")); @@ -4365,14 +4365,14 @@ public class LogicalPlanOptimizerTests extends ESTestCase { assertThat(topN.order().size(), is(2)); var firstOrderExpr = as(topN.order().get(0), Order.class); - assertThat(firstOrderExpr.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC)); - assertThat(firstOrderExpr.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.LAST)); + assertThat(firstOrderExpr.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC)); + assertThat(firstOrderExpr.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.LAST)); var renamedEmpNoSalaryExpression = as(firstOrderExpr.child(), ReferenceAttribute.class); assertThat(renamedEmpNoSalaryExpression.toString(), startsWith("$$order_by$0$")); var secondOrderExpr = as(topN.order().get(1), Order.class); - assertThat(secondOrderExpr.direction(), equalTo(org.elasticsearch.xpack.ql.expression.Order.OrderDirection.DESC)); - assertThat(secondOrderExpr.nullsPosition(), equalTo(org.elasticsearch.xpack.ql.expression.Order.NullsPosition.FIRST)); + assertThat(secondOrderExpr.direction(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.DESC)); + assertThat(secondOrderExpr.nullsPosition(), equalTo(org.elasticsearch.xpack.esql.core.expression.Order.NullsPosition.FIRST)); var renamedNegatedSalaryExpression = as(secondOrderExpr.child(), ReferenceAttribute.class); assertThat(renamedNegatedSalaryExpression.toString(), startsWith("$$order_by$1$")); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java index ee10c661029c..4b62ce1a31cb 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/OptimizerRulesTests.java @@ -8,6 +8,20 @@ package org.elasticsearch.xpack.esql.optimizer; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.TestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.Predicates; +import org.elasticsearch.xpack.esql.core.expression.predicate.Range; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Equals; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.GreaterThan; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.GreaterThanOrEqual; @@ -15,30 +29,16 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThan; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThanOrEqual; import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.NotEquals; -import org.elasticsearch.xpack.ql.TestUtils; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.predicate.Predicates; -import org.elasticsearch.xpack.ql.expression.predicate.Range; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; import java.util.List; import static java.util.Arrays.asList; -import static org.elasticsearch.xpack.ql.TestUtils.rangeOf; -import static org.elasticsearch.xpack.ql.TestUtils.relation; -import static org.elasticsearch.xpack.ql.expression.Literal.FALSE; -import static org.elasticsearch.xpack.ql.expression.Literal.NULL; -import static org.elasticsearch.xpack.ql.expression.Literal.TRUE; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.TestUtils.rangeOf; +import static org.elasticsearch.xpack.esql.core.TestUtils.relation; +import static org.elasticsearch.xpack.esql.core.expression.Literal.FALSE; +import static org.elasticsearch.xpack.esql.core.expression.Literal.NULL; +import static org.elasticsearch.xpack.esql.core.expression.Literal.TRUE; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; import static org.hamcrest.Matchers.contains; public class OptimizerRulesTests extends ESTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java index 2233d281bf47..2d059a5301b5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java @@ -30,6 +30,25 @@ import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.MetadataAttribute; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.expression.function.aggregate.AggregateFunction; @@ -83,25 +102,6 @@ import org.elasticsearch.xpack.esql.querydsl.query.SpatialRelatesQuery; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.stats.SearchStats; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.MetadataAttribute; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; import org.junit.Before; import java.util.Arrays; @@ -122,16 +122,16 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping; import static org.elasticsearch.xpack.esql.EsqlTestUtils.statsForMissingField; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; import static org.elasticsearch.xpack.esql.SerializationTestUtils.assertSerialization; +import static org.elasticsearch.xpack.esql.core.expression.Expressions.name; +import static org.elasticsearch.xpack.esql.core.expression.Expressions.names; +import static org.elasticsearch.xpack.esql.core.expression.Order.OrderDirection.ASC; +import static org.elasticsearch.xpack.esql.core.expression.function.scalar.FunctionTestUtils.l; import static org.elasticsearch.xpack.esql.parser.ExpressionBuilder.MAX_EXPRESSION_DEPTH; import static org.elasticsearch.xpack.esql.parser.LogicalPlanBuilder.MAX_QUERY_DEPTH; import static org.elasticsearch.xpack.esql.plan.physical.AggregateExec.Mode.FINAL; import static org.elasticsearch.xpack.esql.plan.physical.AggregateExec.Mode.PARTIAL; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.CARTESIAN_POINT; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT; -import static org.elasticsearch.xpack.ql.expression.Expressions.name; -import static org.elasticsearch.xpack.ql.expression.Expressions.names; -import static org.elasticsearch.xpack.ql.expression.Order.OrderDirection.ASC; -import static org.elasticsearch.xpack.ql.expression.function.scalar.FunctionTestUtils.l; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PropagateNullable.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PropagateNullable.java index eee5d9b4c49d..bd2bb91cd2ea 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PropagateNullable.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PropagateNullable.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql.optimizer; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; public class PropagateNullable extends LogicalPlanOptimizer.PropagateNullable { @Override diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPhysicalPlanOptimizer.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPhysicalPlanOptimizer.java index 1e994a0d5721..9c8886dbf0b6 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPhysicalPlanOptimizer.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/TestPhysicalPlanOptimizer.java @@ -7,8 +7,8 @@ package org.elasticsearch.xpack.esql.optimizer; +import org.elasticsearch.xpack.esql.core.rule.RuleExecutor; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; -import org.elasticsearch.xpack.ql.rule.RuleExecutor; public class TestPhysicalPlanOptimizer extends PhysicalPlanOptimizer { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java index 9157f186ade9..1123b16ee45e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/ExpressionTests.java @@ -8,6 +8,18 @@ package org.elasticsearch.xpack.esql.parser; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedStar; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.UnresolvedNamePattern; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Div; @@ -21,18 +33,6 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Les import org.elasticsearch.xpack.esql.plan.logical.Drop; import org.elasticsearch.xpack.esql.plan.logical.Project; import org.elasticsearch.xpack.esql.plan.logical.Rename; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedStar; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.type.DataType; import java.time.Duration; import java.time.Period; @@ -42,14 +42,14 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import static org.elasticsearch.xpack.esql.EsqlTestUtils.as; +import static org.elasticsearch.xpack.esql.core.expression.function.FunctionResolutionStrategy.DEFAULT; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.DOUBLE; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.INTEGER; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.LONG; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.DATE_PERIOD; import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.TIME_DURATION; -import static org.elasticsearch.xpack.ql.expression.function.FunctionResolutionStrategy.DEFAULT; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; -import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE; -import static org.elasticsearch.xpack.ql.type.DataTypes.INTEGER; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.type.DataTypes.LONG; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java index 633e0479b11d..a129fc8fd12e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java @@ -12,6 +12,26 @@ import org.elasticsearch.Build; import org.elasticsearch.core.Tuple; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.VerificationException; +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.expression.Alias; +import org.elasticsearch.xpack.esql.core.expression.EmptyAttribute; +import org.elasticsearch.xpack.esql.core.expression.Expressions; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.NamedExpression; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.ReferenceAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.operator.comparison.BinaryComparison; +import org.elasticsearch.xpack.esql.core.plan.TableIdentifier; +import org.elasticsearch.xpack.esql.core.plan.logical.Filter; +import org.elasticsearch.xpack.esql.core.plan.logical.Limit; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.plan.logical.OrderBy; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.expression.function.scalar.string.RLike; import org.elasticsearch.xpack.esql.expression.function.scalar.string.WildcardLike; import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.Add; @@ -31,26 +51,6 @@ import org.elasticsearch.xpack.esql.plan.logical.InlineStats; import org.elasticsearch.xpack.esql.plan.logical.MvExpand; import org.elasticsearch.xpack.esql.plan.logical.Project; import org.elasticsearch.xpack.esql.plan.logical.Row; -import org.elasticsearch.xpack.ql.capabilities.UnresolvedException; -import org.elasticsearch.xpack.ql.expression.Alias; -import org.elasticsearch.xpack.ql.expression.EmptyAttribute; -import org.elasticsearch.xpack.ql.expression.Expressions; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.NamedExpression; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.ReferenceAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.BinaryComparison; -import org.elasticsearch.xpack.ql.plan.TableIdentifier; -import org.elasticsearch.xpack.ql.plan.logical.Filter; -import org.elasticsearch.xpack.ql.plan.logical.Limit; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.plan.logical.OrderBy; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.util.StringUtils; import org.elasticsearch.xpack.versionfield.Version; import java.math.BigInteger; @@ -63,13 +63,13 @@ import java.util.Map; import java.util.function.Function; import static org.elasticsearch.xpack.esql.EsqlTestUtils.as; +import static org.elasticsearch.xpack.esql.core.expression.Literal.FALSE; +import static org.elasticsearch.xpack.esql.core.expression.Literal.TRUE; +import static org.elasticsearch.xpack.esql.core.expression.function.FunctionResolutionStrategy.DEFAULT; +import static org.elasticsearch.xpack.esql.core.tree.Source.EMPTY; +import static org.elasticsearch.xpack.esql.core.type.DataTypes.KEYWORD; +import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned; import static org.elasticsearch.xpack.esql.parser.ExpressionBuilder.breakIntoFragments; -import static org.elasticsearch.xpack.ql.expression.Literal.FALSE; -import static org.elasticsearch.xpack.ql.expression.Literal.TRUE; -import static org.elasticsearch.xpack.ql.expression.function.FunctionResolutionStrategy.DEFAULT; -import static org.elasticsearch.xpack.ql.tree.Source.EMPTY; -import static org.elasticsearch.xpack.ql.type.DataTypes.KEYWORD; -import static org.elasticsearch.xpack.ql.util.NumericUtils.asLongUnsigned; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/EvalMapperTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/EvalMapperTests.java index 880caf2cc67c..d85f1c0964de 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/EvalMapperTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/EvalMapperTests.java @@ -18,6 +18,17 @@ import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.esql.SerializationTestUtils; import org.elasticsearch.xpack.esql.TestBlockFactory; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.And; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Not; +import org.elasticsearch.xpack.esql.core.expression.predicate.logical.Or; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.evaluator.EvalMapper; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateFormat; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; @@ -41,17 +52,6 @@ import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.Les import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.LessThanOrEqual; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.predicate.logical.And; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Not; -import org.elasticsearch.xpack.ql.expression.predicate.logical.Or; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.util.StringUtils; import java.time.Duration; import java.time.ZoneOffset; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java index aedb37933817..78e3ee134b6d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/FilterTests.java @@ -21,6 +21,11 @@ import org.elasticsearch.xpack.esql.EsqlTestUtils; import org.elasticsearch.xpack.esql.SerializationTestUtils; import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.Queries; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.optimizer.LogicalOptimizerContext; import org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer; @@ -30,11 +35,6 @@ import org.elasticsearch.xpack.esql.parser.EsqlParser; import org.elasticsearch.xpack.esql.plan.physical.FragmentExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.util.Queries; import org.junit.BeforeClass; import java.io.IOException; @@ -49,10 +49,10 @@ import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER; import static org.elasticsearch.xpack.esql.EsqlTestUtils.loadMapping; import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning; import static org.elasticsearch.xpack.esql.SerializationTestUtils.assertSerialization; -import static org.elasticsearch.xpack.ql.util.Queries.Clause.FILTER; -import static org.elasticsearch.xpack.ql.util.Queries.Clause.MUST; -import static org.elasticsearch.xpack.ql.util.Queries.Clause.SHOULD; -import static org.elasticsearch.xpack.ql.util.SourceUtils.writeSource; +import static org.elasticsearch.xpack.esql.core.util.Queries.Clause.FILTER; +import static org.elasticsearch.xpack.esql.core.util.Queries.Clause.MUST; +import static org.elasticsearch.xpack.esql.core.util.Queries.Clause.SHOULD; +import static org.elasticsearch.xpack.esql.core.util.SourceUtils.writeSource; import static org.hamcrest.Matchers.nullValue; public class FilterTests extends ESTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java index 89c7e2f81b13..9936c95e1800 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlannerTests.java @@ -29,18 +29,18 @@ import org.elasticsearch.index.cache.query.TrivialQueryCachingPolicy; import org.elasticsearch.index.mapper.MapperServiceTestCase; import org.elasticsearch.search.internal.ContextIndexSearcher; import org.elasticsearch.xpack.esql.TestBlockFactory; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; +import org.elasticsearch.xpack.esql.core.util.StringUtils; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; -import org.elasticsearch.xpack.ql.util.StringUtils; import org.hamcrest.Matcher; import org.junit.After; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/QueryTranslatorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/QueryTranslatorTests.java index 4499c935941e..26db9975b30d 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/QueryTranslatorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/QueryTranslatorTests.java @@ -13,13 +13,13 @@ import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; import org.elasticsearch.xpack.esql.analysis.Verifier; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.optimizer.TestPlannerOptimizer; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.stats.Metrics; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; import org.hamcrest.Matcher; import org.junit.BeforeClass; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java index 05943f85f71e..5c96c410f27e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/planner/TestPhysicalOperationProviders.java @@ -31,15 +31,15 @@ import org.elasticsearch.compute.operator.SourceOperator.SourceOperatorFactory; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.TestBlockFactory; +import org.elasticsearch.xpack.esql.core.expression.Attribute; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes; import org.elasticsearch.xpack.esql.plan.physical.AggregateExec; import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec; import org.elasticsearch.xpack.esql.plan.physical.FieldExtractExec; import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.LocalExecutionPlannerContext; import org.elasticsearch.xpack.esql.planner.LocalExecutionPlanner.PhysicalOperation; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.expression.Attribute; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.util.SpatialCoordinateTypes; import java.util.List; import java.util.Random; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestTests.java index c9c5091db289..d45141ab4c47 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/DataNodeRequestTests.java @@ -20,6 +20,11 @@ import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.xpack.esql.EsqlTestUtils; import org.elasticsearch.xpack.esql.analysis.Analyzer; import org.elasticsearch.xpack.esql.analysis.AnalyzerContext; +import org.elasticsearch.xpack.esql.core.expression.function.FunctionRegistry; +import org.elasticsearch.xpack.esql.core.index.EsIndex; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; import org.elasticsearch.xpack.esql.optimizer.LogicalOptimizerContext; import org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer; @@ -29,11 +34,6 @@ import org.elasticsearch.xpack.esql.parser.EsqlParser; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.planner.Mapper; import org.elasticsearch.xpack.esql.session.EsqlConfigurationSerializationTests; -import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.type.EsField; import java.io.IOException; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryNegateTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryNegateTests.java index 8a3baebb3da3..2545a93b326a 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryNegateTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryNegateTests.java @@ -8,9 +8,9 @@ package org.elasticsearch.xpack.esql.querydsl.query; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.ql.querydsl.query.MatchAll; -import org.elasticsearch.xpack.ql.querydsl.query.NotQuery; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.querydsl.query.MatchAll; +import org.elasticsearch.xpack.esql.core.querydsl.query.NotQuery; +import org.elasticsearch.xpack.esql.core.tree.Source; import static org.hamcrest.Matchers.equalTo; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuerySerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuerySerializationTests.java index 63b674aad7a9..34c66675fccd 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuerySerializationTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQuerySerializationTests.java @@ -12,7 +12,7 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.util.List; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryTests.java index 1324b3977786..5c794d707f5f 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/querydsl/query/SingleValueQueryTests.java @@ -29,9 +29,9 @@ import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xpack.ql.querydsl.query.MatchAll; -import org.elasticsearch.xpack.ql.querydsl.query.RangeQuery; -import org.elasticsearch.xpack.ql.tree.Source; +import org.elasticsearch.xpack.esql.core.querydsl.query.MatchAll; +import org.elasticsearch.xpack.esql.core.querydsl.query.RangeQuery; +import org.elasticsearch.xpack.esql.core.tree.Source; import java.io.IOException; import java.util.ArrayList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlConfigurationSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlConfigurationSerializationTests.java index 41c39e88b943..fe3bb0f06473 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlConfigurationSerializationTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/EsqlConfigurationSerializationTests.java @@ -24,10 +24,10 @@ import org.elasticsearch.core.Releasables; import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.xpack.esql.Column; import org.elasticsearch.xpack.esql.action.ParseTables; +import org.elasticsearch.xpack.esql.core.type.DataType; import org.elasticsearch.xpack.esql.expression.function.AbstractFunctionTestCase; import org.elasticsearch.xpack.esql.planner.PlannerUtils; import org.elasticsearch.xpack.esql.plugin.QueryPragmas; -import org.elasticsearch.xpack.ql.type.DataType; import java.time.ZoneId; import java.util.HashMap; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java index ff6c60310fd8..8d1353cbddd4 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java @@ -13,8 +13,8 @@ import org.elasticsearch.xpack.esql.parser.EsqlParser; import java.util.Collections; import java.util.Set; -import static org.elasticsearch.xpack.ql.index.IndexResolver.ALL_FIELDS; -import static org.elasticsearch.xpack.ql.index.IndexResolver.INDEX_METADATA_FIELD; +import static org.elasticsearch.xpack.esql.core.index.IndexResolver.ALL_FIELDS; +import static org.elasticsearch.xpack.esql.core.index.IndexResolver.INDEX_METADATA_FIELD; import static org.hamcrest.Matchers.equalTo; public class IndexResolverFieldNamesTests extends ESTestCase { diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/DisabledSearchStats.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/DisabledSearchStats.java index 1cda9323af89..564d34149da0 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/DisabledSearchStats.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/DisabledSearchStats.java @@ -8,7 +8,7 @@ package org.elasticsearch.xpack.esql.stats; import org.apache.lucene.util.BytesRef; -import org.elasticsearch.xpack.ql.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataType; import static java.util.Collections.emptyList; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java index f90e441b8c30..d3011506bb5e 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java @@ -20,12 +20,12 @@ import org.elasticsearch.xpack.esql.EsqlTestUtils; import org.elasticsearch.xpack.esql.VerificationException; import org.elasticsearch.xpack.esql.action.EsqlQueryRequest; import org.elasticsearch.xpack.esql.analysis.EnrichResolution; +import org.elasticsearch.xpack.esql.core.index.IndexResolver; import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolver; import org.elasticsearch.xpack.esql.execution.PlanExecutor; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.session.EsqlIndexResolver; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; -import org.elasticsearch.xpack.ql.index.IndexResolver; import org.junit.After; import org.junit.Before; import org.mockito.stubbing.Answer; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/tree/EsqlNodeSubclassTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/tree/EsqlNodeSubclassTests.java index 43dec76c7de2..b72bd5c5d6fb 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/tree/EsqlNodeSubclassTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/tree/EsqlNodeSubclassTests.java @@ -11,6 +11,20 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import org.elasticsearch.compute.data.Page; import org.elasticsearch.dissect.DissectParser; +import org.elasticsearch.xpack.esql.core.capabilities.UnresolvedException; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FieldAttribute; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.expression.Order; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.esql.core.expression.UnresolvedNamedExpression; +import org.elasticsearch.xpack.esql.core.expression.function.UnresolvedFunction; +import org.elasticsearch.xpack.esql.core.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.esql.core.tree.Node; +import org.elasticsearch.xpack.esql.core.tree.NodeSubclassTests; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; import org.elasticsearch.xpack.esql.expression.function.scalar.math.Pow; import org.elasticsearch.xpack.esql.expression.function.scalar.string.Concat; @@ -22,22 +36,6 @@ import org.elasticsearch.xpack.esql.plan.physical.EsStatsQueryExec.StatsType; import org.elasticsearch.xpack.esql.plan.physical.OutputExec; import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; -import org.elasticsearch.xpack.ql.capabilities.UnresolvedException; -import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.expression.FieldAttribute; -import org.elasticsearch.xpack.ql.expression.Literal; -import org.elasticsearch.xpack.ql.expression.Order; -import org.elasticsearch.xpack.ql.expression.UnresolvedAlias; -import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; -import org.elasticsearch.xpack.ql.expression.UnresolvedNamedExpression; -import org.elasticsearch.xpack.ql.expression.UnresolvedStar; -import org.elasticsearch.xpack.ql.expression.function.UnresolvedFunction; -import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; -import org.elasticsearch.xpack.ql.tree.Node; -import org.elasticsearch.xpack.ql.tree.NodeSubclassTests; -import org.elasticsearch.xpack.ql.tree.Source; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.EsField; import java.io.IOException; import java.lang.reflect.Modifier; @@ -56,11 +54,9 @@ public class EsqlNodeSubclassTests> extends NodeS // List of classes that are "unresolved" NamedExpression subclasses, therefore not suitable for use with logical/physical plan nodes. private static final List> UNRESOLVED_CLASSES = List.of( UnresolvedAttribute.class, - UnresolvedAlias.class, UnresolvedException.class, UnresolvedFunction.class, - UnresolvedNamedExpression.class, - UnresolvedStar.class + UnresolvedNamedExpression.class ); public EsqlNodeSubclassTests(Class subclass) { @@ -114,7 +110,7 @@ public class EsqlNodeSubclassTests> extends NodeS return CLASSES_WITH_MIN_TWO_CHILDREN.stream().anyMatch(toBuildClass::equals); } - static final Predicate CLASSNAME_FILTER = className -> (className.startsWith("org.elasticsearch.xpack.ql") != false + static final Predicate CLASSNAME_FILTER = className -> (className.startsWith("org.elasticsearch.xpack.esql.core") != false || className.startsWith("org.elasticsearch.xpack.esql") != false); @Override @@ -142,8 +138,8 @@ public class EsqlNodeSubclassTests> extends NodeS Class asNodeSubclass = (Class) argClass; if (Modifier.isAbstract(argClass.getModifiers())) { while (true) { - var candidate = randomFrom(subclassesOf(asNodeSubclass)); - if (UNRESOLVED_CLASSES.contains(candidate) == false) { + var candidate = randomFrom(subclassesOf(asNodeSubclass, CLASSNAME_FILTER)); + if (UNRESOLVED_CLASSES.stream().allMatch(unresolved -> unresolved.isAssignableFrom(candidate) == false)) { asNodeSubclass = candidate; break; } diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistryTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistryTests.java index 23d2f8da488e..61b5f1e5fdd5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistryTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/type/EsqlDataTypeRegistryTests.java @@ -11,11 +11,11 @@ import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse; import org.elasticsearch.action.fieldcaps.IndexFieldCapabilities; import org.elasticsearch.index.mapper.TimeSeriesParams; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.esql.core.index.IndexResolution; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.core.type.DataTypes; +import org.elasticsearch.xpack.esql.core.type.EsField; import org.elasticsearch.xpack.esql.session.EsqlIndexResolver; -import org.elasticsearch.xpack.ql.index.IndexResolution; -import org.elasticsearch.xpack.ql.type.DataType; -import org.elasticsearch.xpack.ql.type.DataTypes; -import org.elasticsearch.xpack.ql.type.EsField; import java.util.List; import java.util.Map; diff --git a/x-pack/plugin/ml/qa/native-multi-node-tests/build.gradle b/x-pack/plugin/ml/qa/native-multi-node-tests/build.gradle index eb1f9b9671bd..c9e860f27a5d 100644 --- a/x-pack/plugin/ml/qa/native-multi-node-tests/build.gradle +++ b/x-pack/plugin/ml/qa/native-multi-node-tests/build.gradle @@ -15,7 +15,7 @@ dependencies { javaRestTestImplementation project(path: xpackModule('monitoring')) javaRestTestImplementation project(path: xpackModule('transform')) javaRestTestImplementation project(path: xpackModule('rank-rrf')) - javaRestTestImplementation project(path: xpackModule('ql')) + javaRestTestImplementation project(path: xpackModule('esql-core')) javaRestTestImplementation project(path: xpackModule('esql')) } diff --git a/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeIntegTestCase.java b/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeIntegTestCase.java index 7addedf77945..861d5a8c2f59 100644 --- a/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeIntegTestCase.java +++ b/x-pack/plugin/ml/qa/native-multi-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/ml/integration/MlNativeIntegTestCase.java @@ -91,11 +91,11 @@ import org.elasticsearch.xpack.core.ml.job.persistence.AnomalyDetectorsIndexFiel import org.elasticsearch.xpack.core.ml.notifications.NotificationsIndex; import org.elasticsearch.xpack.core.security.SecurityField; import org.elasticsearch.xpack.core.security.authc.TokenMetadata; +import org.elasticsearch.xpack.esql.core.plugin.EsqlCorePlugin; import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.ilm.IndexLifecycle; import org.elasticsearch.xpack.ml.LocalStateMachineLearning; import org.elasticsearch.xpack.ml.autoscaling.MlScalingReason; -import org.elasticsearch.xpack.ql.plugin.QlPlugin; import org.elasticsearch.xpack.slm.SnapshotLifecycle; import org.elasticsearch.xpack.slm.history.SnapshotLifecycleTemplateRegistry; import org.elasticsearch.xpack.transform.Transform; @@ -159,7 +159,7 @@ abstract class MlNativeIntegTestCase extends ESIntegTestCase { Transform.class, DataStreamsPlugin.class, // ESQL and its dependency needed for node features - QlPlugin.class, + EsqlCorePlugin.class, EsqlPlugin.class ); } diff --git a/x-pack/plugin/security/qa/consistency-checks/build.gradle b/x-pack/plugin/security/qa/consistency-checks/build.gradle index 807bd19bdc34..6fa3deb773e4 100644 --- a/x-pack/plugin/security/qa/consistency-checks/build.gradle +++ b/x-pack/plugin/security/qa/consistency-checks/build.gradle @@ -15,6 +15,7 @@ dependencies { testImplementation project(path: xpackModule('downsample')) testImplementation project(path: xpackModule('eql')) testImplementation project(path: xpackModule('esql')) + testImplementation project(path: xpackModule('esql-core')) testImplementation project(path: xpackModule('frozen-indices')) testImplementation project(path: xpackModule('graph')) testImplementation project(path: xpackModule('ilm')) diff --git a/x-pack/qa/multi-cluster-search-security/legacy-with-basic-license/build.gradle b/x-pack/qa/multi-cluster-search-security/legacy-with-basic-license/build.gradle index ca44d7fe6a85..b5b849587025 100644 --- a/x-pack/qa/multi-cluster-search-security/legacy-with-basic-license/build.gradle +++ b/x-pack/qa/multi-cluster-search-security/legacy-with-basic-license/build.gradle @@ -23,7 +23,7 @@ def fulfillingCluster = testClusters.register('fulfilling-cluster') { module ':modules:data-streams' module ':x-pack:plugin:mapper-constant-keyword' module ':x-pack:plugin:async-search' - module ':x-pack:plugin:ql' + module ':x-pack:plugin:esql-core' module ':x-pack:plugin:esql' module ':modules:ingest-common' module ':x-pack:plugin:enrich' @@ -38,7 +38,7 @@ def queryingCluster = testClusters.register('querying-cluster') { module ':modules:data-streams' module ':x-pack:plugin:mapper-constant-keyword' module ':x-pack:plugin:async-search' - module ':x-pack:plugin:ql' + module ':x-pack:plugin:esql-core' module ':x-pack:plugin:esql' module ':modules:ingest-common' module ':x-pack:plugin:enrich'