* Move In, InPipe and InProcessor out of SQL to the common QL project. * Move tests classes to the QL project. * Create SQL dedicated In class to handle SQL specific data types. * Update SQL classes to use the InPipe and InProcessor QL classes. * Extract common Foldables methods in QL project. * Be more explicit when folding and converting a foldable value, by removing most of the code inside Foldables class. (cherry picked from commit 7425042f86f66df8c207c5e96f9b9848bda2b4c3)
This commit is contained in:
parent
a674085903
commit
c3a167830f
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ql.expression;
|
||||
|
||||
import org.elasticsearch.xpack.ql.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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.Expressions;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.Nullability;
|
||||
import org.elasticsearch.xpack.ql.expression.TypeResolutions;
|
||||
import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.ql.expression.gen.pipeline.Pipe;
|
||||
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.DataTypeConverter;
|
||||
import org.elasticsearch.xpack.ql.type.DataTypes;
|
||||
import org.elasticsearch.xpack.ql.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.ql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
import static org.elasticsearch.xpack.ql.util.StringUtils.ordinal;
|
||||
|
||||
public class In extends ScalarFunction {
|
||||
|
||||
private final Expression value;
|
||||
private final List<Expression> list;
|
||||
|
||||
public In(Source source, Expression value, List<Expression> list) {
|
||||
super(source, CollectionUtils.combine(list, value));
|
||||
this.value = value;
|
||||
this.list = new ArrayList<>(new LinkedHashSet<>(list));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<In> info() {
|
||||
return NodeInfo.create(this, In::new, value(), list());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression replaceChildren(List<Expression> newChildren) {
|
||||
if (newChildren.size() < 2) {
|
||||
throw new IllegalArgumentException("expected at least [2] children but received [" + newChildren.size() + "]");
|
||||
}
|
||||
return new In(source(), newChildren.get(newChildren.size() - 1), newChildren.subList(0, newChildren.size() - 1));
|
||||
}
|
||||
|
||||
public Expression value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public List<Expression> 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
|
||||
public ScriptTemplate asScript() {
|
||||
ScriptTemplate leftScript = asScript(value);
|
||||
|
||||
// fold & remove duplicates
|
||||
List<Object> values = new ArrayList<>(new LinkedHashSet<>(foldAndConvertListOfValues(list, value.dataType())));
|
||||
|
||||
return new ScriptTemplate(
|
||||
formatTemplate(format("{sql}.","in({}, {})", leftScript.template())),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params())
|
||||
.variable(values)
|
||||
.build(),
|
||||
dataType());
|
||||
}
|
||||
|
||||
protected List<Object> foldAndConvertListOfValues(List<Expression> list, DataType dataType) {
|
||||
List<Object> values = new ArrayList<>(list.size());
|
||||
for (Expression e : list) {
|
||||
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(), Expressions.ParamOrdinal.DEFAULT);
|
||||
if (resolution.unresolved()) {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
for (Expression ex : list) {
|
||||
if (ex.foldable() == false) {
|
||||
return new TypeResolution(format(null, "Comparisons against variables 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);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.gen.pipeline.MultiPipe;
|
|
@ -3,12 +3,11 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.ql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.Comparisons;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
|
@ -3,7 +3,7 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
||||
|
@ -11,9 +11,9 @@ import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
|||
import org.elasticsearch.xpack.ql.TestUtils;
|
||||
import org.elasticsearch.xpack.ql.expression.Literal;
|
||||
import org.elasticsearch.xpack.ql.expression.gen.processor.ConstantProcessor;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.In;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.InProcessor;
|
||||
import org.elasticsearch.xpack.ql.expression.processor.Processors;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InProcessor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
@ -3,12 +3,12 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
package org.elasticsearch.xpack.ql.expression.predicate.operator.comparison;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.ql.TestUtils;
|
||||
import org.elasticsearch.xpack.ql.expression.Literal;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.In;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
@ -15,6 +15,7 @@ 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.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.NamedExpression;
|
||||
import org.elasticsearch.xpack.ql.expression.Order;
|
||||
import org.elasticsearch.xpack.ql.expression.ReferenceAttribute;
|
||||
|
@ -46,7 +47,6 @@ 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.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.expression.SubQueryExpression;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.Cast;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.Join;
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression;
|
||||
|
||||
import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.type.DataType;
|
||||
import org.elasticsearch.xpack.ql.type.DataTypes;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class Foldables {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T valueOf(Expression e, DataType to) {
|
||||
if (e.foldable()) {
|
||||
return (T) SqlDataTypeConverter.convert(e.fold(), to);
|
||||
}
|
||||
throw new QlIllegalArgumentException("Cannot determine value for {}", e);
|
||||
}
|
||||
|
||||
public static Object valueOf(Expression e) {
|
||||
if (e.foldable()) {
|
||||
return e.fold();
|
||||
}
|
||||
throw new QlIllegalArgumentException("Cannot determine value for {}", e);
|
||||
}
|
||||
|
||||
public static Integer intValueOf(Expression e) {
|
||||
return valueOf(e, DataTypes.INTEGER);
|
||||
}
|
||||
|
||||
public static double doubleValueOf(Expression e) {
|
||||
return valueOf(e, DataTypes.DOUBLE);
|
||||
}
|
||||
|
||||
public static <T> List<T> valuesOf(List<Expression> list, DataType to) {
|
||||
return foldTo(list, to, new ArrayList<>(list.size()));
|
||||
}
|
||||
|
||||
public static <T> Set<T> valuesUnique(List<Expression> list, DataType to) {
|
||||
return foldTo(list, to, new LinkedHashSet<>(list.size()));
|
||||
}
|
||||
|
||||
private static <T, C extends Collection<T>> C foldTo(Collection<Expression> expressions, DataType to, C values) {
|
||||
for (Expression e : expressions) {
|
||||
values.add(valueOf(e, to));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public static List<Double> doubleValuesOf(List<Expression> list) {
|
||||
return valuesOf(list, DataTypes.DOUBLE);
|
||||
}
|
||||
}
|
|
@ -7,12 +7,13 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.function.aggregate.EnclosedAgg;
|
||||
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.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -68,6 +69,7 @@ public class Percentile extends NumericAggregate implements EnclosedAgg {
|
|||
|
||||
@Override
|
||||
public String innerName() {
|
||||
return Double.toString(Foldables.doubleValueOf(percent));
|
||||
Double value = (Double) SqlDataTypeConverter.convert(Foldables.valueOf(percent), DataTypes.DOUBLE);
|
||||
return Double.toString(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@ package org.elasticsearch.xpack.sql.expression.function.aggregate;
|
|||
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.function.aggregate.AggregateFunction;
|
||||
import org.elasticsearch.xpack.ql.expression.function.aggregate.EnclosedAgg;
|
||||
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.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -69,6 +70,7 @@ public class PercentileRank extends AggregateFunction implements EnclosedAgg {
|
|||
|
||||
@Override
|
||||
public String innerName() {
|
||||
return Double.toString(Foldables.doubleValueOf(value));
|
||||
Double doubleValue = (Double) SqlDataTypeConverter.convert(Foldables.valueOf(value), DataTypes.DOUBLE);
|
||||
return Double.toString(doubleValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
|||
import org.elasticsearch.xpack.ql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.nulls.CheckNullProcessor;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryArithmeticOperation;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.InProcessor;
|
||||
import org.elasticsearch.xpack.ql.type.Converter;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateAddProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateDiffProcessor;
|
||||
|
@ -38,7 +39,6 @@ import org.elasticsearch.xpack.sql.expression.predicate.conditional.CaseProcesso
|
|||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.ConditionalProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIfProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.SqlBinaryArithmeticOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InProcessor;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter.SqlConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.script.JodaCompatibleZonedDateTime;
|
|||
import org.elasticsearch.xpack.ql.expression.function.scalar.whitelist.InternalQlScriptUtils;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor.UnaryArithmeticOperation;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.InProcessor;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.regex.RegexProcessor.RegexOperation;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateAddProcessor;
|
||||
|
@ -43,7 +44,6 @@ import org.elasticsearch.xpack.sql.expression.predicate.conditional.CaseProcesso
|
|||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.ConditionalProcessor.ConditionalOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIfProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.SqlBinaryArithmeticOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InProcessor;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypes;
|
||||
import org.elasticsearch.xpack.sql.util.DateUtils;
|
||||
|
|
|
@ -9,12 +9,12 @@ package org.elasticsearch.xpack.sql.expression.literal.interval;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.xpack.ql.ParsingException;
|
||||
import org.elasticsearch.xpack.ql.QlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
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.util.Check;
|
||||
import org.elasticsearch.xpack.ql.util.StringUtils;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Period;
|
||||
|
|
|
@ -7,13 +7,15 @@
|
|||
package org.elasticsearch.xpack.sql.expression.predicate.conditional;
|
||||
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.ql.tree.Source;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.predicate.conditional.ConditionalProcessor.ConditionalOperation.GREATEST;
|
||||
|
||||
|
@ -35,6 +37,10 @@ public class Greatest extends ArbitraryConditionalFunction {
|
|||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return GREATEST.apply(Foldables.valuesUnique(children(), dataType));
|
||||
Set<Object> values = new LinkedHashSet<>(children().size());
|
||||
for (Expression e : children()) {
|
||||
values.add(SqlDataTypeConverter.convert(Foldables.valueOf(e), dataType));
|
||||
}
|
||||
return GREATEST.apply(values);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,15 @@
|
|||
package org.elasticsearch.xpack.sql.expression.predicate.conditional;
|
||||
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.ql.tree.Source;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.predicate.conditional.ConditionalProcessor.ConditionalOperation.LEAST;
|
||||
|
||||
|
@ -35,6 +37,10 @@ public class Least extends ArbitraryConditionalFunction {
|
|||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return LEAST.apply(Foldables.valuesUnique(children(), dataType));
|
||||
Set<Object> values = new LinkedHashSet<>(children().size());
|
||||
for (Expression e : children()) {
|
||||
values.add(SqlDataTypeConverter.convert(Foldables.valueOf(e), dataType));
|
||||
}
|
||||
return LEAST.apply(values);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,47 +3,29 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison;
|
||||
|
||||
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.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.ql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
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 org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.ql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
import static org.elasticsearch.xpack.ql.util.StringUtils.ordinal;
|
||||
|
||||
public class In extends ScalarFunction {
|
||||
|
||||
private final Expression value;
|
||||
private final List<Expression> list;
|
||||
public class In extends org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.In {
|
||||
|
||||
public In(Source source, Expression value, List<Expression> list) {
|
||||
super(source, CollectionUtils.combine(list, value));
|
||||
this.value = value;
|
||||
this.list = new ArrayList<>(new LinkedHashSet<>(list));
|
||||
super(source, value, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<In> info() {
|
||||
return NodeInfo.create(this, In::new, value, list);
|
||||
protected NodeInfo<org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.In> info() {
|
||||
return NodeInfo.create(this, In::new, value(), list());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -54,107 +36,17 @@ public class In extends ScalarFunction {
|
|||
return new In(source(), newChildren.get(newChildren.size() - 1), newChildren.subList(0, newChildren.size() - 1));
|
||||
}
|
||||
|
||||
public Expression value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public List<Expression> 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;
|
||||
protected List<Object> foldAndConvertListOfValues(List<Expression> list, DataType dataType) {
|
||||
List<Object> values = new ArrayList<>(list.size());
|
||||
for (Expression e : list) {
|
||||
values.add(SqlDataTypeConverter.convert(Foldables.valueOf(e), dataType));
|
||||
}
|
||||
return InProcessor.apply(value.fold(), Foldables.valuesOf(list, value.dataType()));
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate asScript() {
|
||||
ScriptTemplate leftScript = asScript(value);
|
||||
|
||||
// fold & remove duplicates
|
||||
List<Object> values = new ArrayList<>(new LinkedHashSet<>(Foldables.valuesOf(list, value.dataType())));
|
||||
|
||||
return new ScriptTemplate(
|
||||
formatTemplate(format("{sql}.","in({}, {})", leftScript.template())),
|
||||
paramsBuilder()
|
||||
.script(leftScript.params())
|
||||
.variable(values)
|
||||
.build(),
|
||||
dataType());
|
||||
}
|
||||
|
||||
@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(), Expressions.ParamOrdinal.DEFAULT);
|
||||
if (resolution.unresolved()) {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
for (Expression ex : list) {
|
||||
if (ex.foldable() == false) {
|
||||
return new TypeResolution(format(null, "Comparisons against variables 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 (SqlDataTypes.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);
|
||||
protected boolean areCompatible(DataType left, DataType right) {
|
||||
return SqlDataTypes.areCompatible(left, right);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ 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.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.Literal;
|
||||
import org.elasticsearch.xpack.ql.expression.NamedExpression;
|
||||
import org.elasticsearch.xpack.ql.expression.Order;
|
||||
|
@ -34,8 +35,8 @@ import org.elasticsearch.xpack.ql.planner.ExpressionTranslators;
|
|||
import org.elasticsearch.xpack.ql.querydsl.query.Query;
|
||||
import org.elasticsearch.xpack.ql.rule.Rule;
|
||||
import org.elasticsearch.xpack.ql.rule.RuleExecutor;
|
||||
import org.elasticsearch.xpack.ql.type.DataTypes;
|
||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.expression.function.Score;
|
||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.CompoundNumericAggregate;
|
||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.TopHits;
|
||||
|
@ -78,6 +79,7 @@ import org.elasticsearch.xpack.sql.querydsl.container.Sort.Direction;
|
|||
import org.elasticsearch.xpack.sql.querydsl.container.Sort.Missing;
|
||||
import org.elasticsearch.xpack.sql.querydsl.container.TopHitsAggRef;
|
||||
import org.elasticsearch.xpack.sql.session.EmptyExecutable;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
import org.elasticsearch.xpack.sql.util.Check;
|
||||
import org.elasticsearch.xpack.sql.util.DateUtils;
|
||||
|
||||
|
@ -372,12 +374,14 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
|||
}
|
||||
// numeric histogram
|
||||
else {
|
||||
if (field instanceof FieldAttribute) {
|
||||
key = new GroupByNumericHistogram(aggId, QueryTranslator.nameOf(field),
|
||||
Foldables.doubleValueOf(h.interval()));
|
||||
} else if (field instanceof Function) {
|
||||
key = new GroupByNumericHistogram(aggId, ((Function) field).asScript(),
|
||||
Foldables.doubleValueOf(h.interval()));
|
||||
if (field instanceof FieldAttribute || field instanceof Function) {
|
||||
Double interval = (Double) SqlDataTypeConverter.convert(Foldables.valueOf(h.interval()),
|
||||
DataTypes.DOUBLE);
|
||||
if (field instanceof FieldAttribute) {
|
||||
key = new GroupByNumericHistogram(aggId, QueryTranslator.nameOf(field), interval);
|
||||
} else {
|
||||
key = new GroupByNumericHistogram(aggId, ((Function) field).asScript(), interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key == null) {
|
||||
|
@ -754,7 +758,7 @@ class QueryFolder extends RuleExecutor<PhysicalPlan> {
|
|||
protected PhysicalPlan rule(LimitExec plan) {
|
||||
if (plan.child() instanceof EsQueryExec) {
|
||||
EsQueryExec exec = (EsQueryExec) plan.child();
|
||||
int limit = Foldables.intValueOf(plan.limit());
|
||||
int limit = (Integer) SqlDataTypeConverter.convert(Foldables.valueOf(plan.limit()), DataTypes.INTEGER);
|
||||
int currentSize = exec.queryContainer().limit();
|
||||
int newSize = currentSize < 0 ? limit : Math.min(currentSize, limit);
|
||||
return exec.with(exec.queryContainer().withLimit(newSize));
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.geometry.Point;
|
|||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.FieldAttribute;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.Literal;
|
||||
import org.elasticsearch.xpack.ql.expression.NamedExpression;
|
||||
import org.elasticsearch.xpack.ql.expression.function.Function;
|
||||
|
@ -81,6 +82,7 @@ import org.elasticsearch.xpack.sql.querydsl.agg.TopHitsAgg;
|
|||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
import org.elasticsearch.xpack.sql.util.Check;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
@ -88,8 +90,7 @@ import java.util.Set;
|
|||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.elasticsearch.xpack.ql.expression.Expressions.id;
|
||||
import static org.elasticsearch.xpack.sql.expression.Foldables.doubleValuesOf;
|
||||
import static org.elasticsearch.xpack.sql.expression.Foldables.valueOf;
|
||||
import static org.elasticsearch.xpack.ql.expression.Foldables.valueOf;
|
||||
|
||||
final class QueryTranslator {
|
||||
|
||||
|
@ -636,7 +637,7 @@ final class QueryTranslator {
|
|||
|
||||
@Override
|
||||
protected LeafAgg toAgg(String id, Percentiles p) {
|
||||
return new PercentilesAgg(id, field(p), doubleValuesOf(p.percents()));
|
||||
return new PercentilesAgg(id, field(p), foldAndConvertToDoubles(p.percents()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,7 +645,7 @@ final class QueryTranslator {
|
|||
|
||||
@Override
|
||||
protected LeafAgg toAgg(String id, PercentileRanks p) {
|
||||
return new PercentileRanksAgg(id, field(p), doubleValuesOf(p.values()));
|
||||
return new PercentileRanksAgg(id, field(p), foldAndConvertToDoubles(p.values()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -697,4 +698,12 @@ final class QueryTranslator {
|
|||
|
||||
protected abstract LeafAgg toAgg(String id, C f);
|
||||
}
|
||||
|
||||
private static List<Double> foldAndConvertToDoubles(List<Expression> list) {
|
||||
List<Double> values = new ArrayList<>(list.size());
|
||||
for (Expression e : list) {
|
||||
values.add((Double) SqlDataTypeConverter.convert(Foldables.valueOf(e), DataTypes.DOUBLE));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
|
@ -9,9 +9,11 @@ package org.elasticsearch.xpack.sql.util;
|
|||
import org.elasticsearch.common.time.DateFormatter;
|
||||
import org.elasticsearch.common.time.DateFormatters;
|
||||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.ql.type.DataTypes;
|
||||
import org.elasticsearch.xpack.sql.parser.ParsingException;
|
||||
import org.elasticsearch.xpack.sql.proto.StringUtils;
|
||||
import org.elasticsearch.xpack.sql.type.SqlDataTypeConverter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
|
@ -187,7 +189,7 @@ public final class DateUtils {
|
|||
|
||||
if (precisionExpression != null) {
|
||||
try {
|
||||
precision = Foldables.intValueOf(precisionExpression);
|
||||
precision = (Integer) SqlDataTypeConverter.convert(Foldables.valueOf(precisionExpression), DataTypes.INTEGER);
|
||||
} catch (Exception e) {
|
||||
throw new ParsingException(precisionExpression.source(), "invalid precision; " + e.getMessage());
|
||||
}
|
||||
|
|
|
@ -56,7 +56,6 @@ import org.elasticsearch.xpack.ql.type.EsField;
|
|||
import org.elasticsearch.xpack.ql.util.CollectionUtils;
|
||||
import org.elasticsearch.xpack.ql.util.StringUtils;
|
||||
import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer.PruneSubqueryAliases;
|
||||
import org.elasticsearch.xpack.sql.expression.Foldables;
|
||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Avg;
|
||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.ExtendedStats;
|
||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.First;
|
||||
|
@ -278,7 +277,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
assertEquals(1, p.projections().size());
|
||||
Alias a = (Alias) p.projections().get(0);
|
||||
In i = (In) a.child();
|
||||
assertThat(Foldables.valuesOf(i.list(), INTEGER), contains(1, 2, 3, 4));
|
||||
assertThat(i.list(), contains(ONE, TWO, THREE, FOUR));
|
||||
}
|
||||
|
||||
public void testConstantFoldingIn_RightValueIsNull() {
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.sql.tree;
|
|||
import org.elasticsearch.xpack.ql.expression.Expression;
|
||||
import org.elasticsearch.xpack.ql.expression.Literal;
|
||||
import org.elasticsearch.xpack.ql.expression.LiteralTests;
|
||||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.InPipe;
|
||||
import org.elasticsearch.xpack.ql.tree.Node;
|
||||
import org.elasticsearch.xpack.ql.tree.NodeSubclassTests;
|
||||
import org.elasticsearch.xpack.ql.tree.SourceTests;
|
||||
|
@ -22,7 +23,6 @@ import org.elasticsearch.xpack.sql.expression.predicate.conditional.IfConditiona
|
|||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IfNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.Iif;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InPipe;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
Loading…
Reference in New Issue