SQL: refactor In predicate moving it to QL project (#52870) (#52938)

* 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:
Andrei Stefan 2020-02-28 14:04:10 +02:00 committed by GitHub
parent a674085903
commit c3a167830f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 270 additions and 222 deletions

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
@Override
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));
}
public List<Expression> list() {
return list;
return values;
}
@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(), Foldables.valuesOf(list, value.dataType()));
}
@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);
}
}

View File

@ -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 || 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),
Foldables.doubleValueOf(h.interval()));
} else if (field instanceof Function) {
key = new GroupByNumericHistogram(aggId, ((Function) field).asScript(),
Foldables.doubleValueOf(h.interval()));
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));

View File

@ -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;
}
}

View File

@ -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());
}

View File

@ -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() {

View File

@ -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;