SQL: Refactor args verification of In & conditionals (#40916)
Move verification of arguments for Conditional functions and IN from `Verifier` to the `resolveType()` method of the functions. (cherry picked from commit 241644aac57baee1eb128b993ee410c7d08172a5)
This commit is contained in:
parent
8eef92fafd
commit
2206491277
|
@ -26,8 +26,6 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.TopHits;
|
|||
import org.elasticsearch.xpack.sql.expression.function.grouping.GroupingFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.grouping.GroupingFunctionAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.ConditionalFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.Aggregate;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.Distinct;
|
||||
import org.elasticsearch.xpack.sql.plan.logical.Filter;
|
||||
|
@ -228,9 +226,6 @@ public final class Verifier {
|
|||
|
||||
Set<Failure> localFailures = new LinkedHashSet<>();
|
||||
|
||||
validateInExpression(p, localFailures);
|
||||
validateConditional(p, localFailures);
|
||||
|
||||
checkGroupingFunctionInGroupBy(p, localFailures);
|
||||
checkFilterOnAggs(p, localFailures);
|
||||
checkFilterOnGrouping(p, localFailures);
|
||||
|
@ -724,52 +719,4 @@ public final class Verifier {
|
|||
fail(nested.get(0), "HAVING isn't (yet) compatible with nested fields " + new AttributeSet(nested).names()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateInExpression(LogicalPlan p, Set<Failure> localFailures) {
|
||||
p.forEachExpressions(e ->
|
||||
e.forEachUp((In in) -> {
|
||||
DataType dt = in.value().dataType();
|
||||
for (Expression value : in.list()) {
|
||||
if (areTypesCompatible(dt, value.dataType()) == false) {
|
||||
localFailures.add(fail(value, "expected data type [{}], value provided is of type [{}]",
|
||||
dt.typeName, value.dataType().typeName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
In.class));
|
||||
}
|
||||
|
||||
private static void validateConditional(LogicalPlan p, Set<Failure> localFailures) {
|
||||
p.forEachExpressions(e ->
|
||||
e.forEachUp((ConditionalFunction cf) -> {
|
||||
DataType dt = DataType.NULL;
|
||||
|
||||
for (Expression child : cf.children()) {
|
||||
if (dt == DataType.NULL) {
|
||||
if (Expressions.isNull(child) == false) {
|
||||
dt = child.dataType();
|
||||
}
|
||||
} else {
|
||||
if (areTypesCompatible(dt, child.dataType()) == false) {
|
||||
localFailures.add(fail(child, "expected data type [{}], value provided is of type [{}]",
|
||||
dt.typeName, child.dataType().typeName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ConditionalFunction.class));
|
||||
}
|
||||
|
||||
private static boolean areTypesCompatible(DataType left, DataType right) {
|
||||
if (left == right) {
|
||||
return true;
|
||||
} else {
|
||||
return
|
||||
(left == DataType.NULL || right == DataType.NULL) ||
|
||||
(left.isString() && right.isString()) ||
|
||||
(left.isNumeric() && right.isNumeric());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -262,7 +262,7 @@ public class FunctionRegistry {
|
|||
for (String alias : f.aliases()) {
|
||||
Object old = batchMap.put(alias, f);
|
||||
if (old != null || defs.containsKey(alias)) {
|
||||
throw new IllegalArgumentException("alias [" + alias + "] is used by "
|
||||
throw new SqlIllegalArgumentException("alias [" + alias + "] is used by "
|
||||
+ "[" + (old != null ? old : defs.get(alias).name()) + "] and [" + f.name() + "]");
|
||||
}
|
||||
aliases.put(alias, f.name());
|
||||
|
@ -321,10 +321,10 @@ public class FunctionRegistry {
|
|||
java.util.function.Function<Source, T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (false == children.isEmpty()) {
|
||||
throw new IllegalArgumentException("expects no arguments");
|
||||
throw new SqlIllegalArgumentException("expects no arguments");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.apply(source);
|
||||
};
|
||||
|
@ -341,10 +341,10 @@ public class FunctionRegistry {
|
|||
ConfigurationAwareFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (false == children.isEmpty()) {
|
||||
throw new IllegalArgumentException("expects no arguments");
|
||||
throw new SqlIllegalArgumentException("expects no arguments");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, cfg);
|
||||
};
|
||||
|
@ -365,10 +365,10 @@ public class FunctionRegistry {
|
|||
UnaryConfigurationAwareFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (children.size() > 1) {
|
||||
throw new IllegalArgumentException("expects exactly one argument");
|
||||
throw new SqlIllegalArgumentException("expects exactly one argument");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
Expression ex = children.size() == 1 ? children.get(0) : null;
|
||||
return ctorRef.build(source, ex, cfg);
|
||||
|
@ -390,10 +390,10 @@ public class FunctionRegistry {
|
|||
BiFunction<Source, Expression, T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (children.size() != 1) {
|
||||
throw new IllegalArgumentException("expects exactly one argument");
|
||||
throw new SqlIllegalArgumentException("expects exactly one argument");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.apply(source, children.get(0));
|
||||
};
|
||||
|
@ -409,7 +409,7 @@ public class FunctionRegistry {
|
|||
MultiFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, children);
|
||||
};
|
||||
|
@ -429,7 +429,7 @@ public class FunctionRegistry {
|
|||
DistinctAwareUnaryFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (children.size() != 1) {
|
||||
throw new IllegalArgumentException("expects exactly one argument");
|
||||
throw new SqlIllegalArgumentException("expects exactly one argument");
|
||||
}
|
||||
return ctorRef.build(source, children.get(0), distinct);
|
||||
};
|
||||
|
@ -449,10 +449,10 @@ public class FunctionRegistry {
|
|||
DatetimeUnaryFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (children.size() != 1) {
|
||||
throw new IllegalArgumentException("expects exactly one argument");
|
||||
throw new SqlIllegalArgumentException("expects exactly one argument");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, children.get(0), cfg.zoneId());
|
||||
};
|
||||
|
@ -471,10 +471,10 @@ public class FunctionRegistry {
|
|||
static <T extends Function> FunctionDefinition def(Class<T> function, DatetimeBinaryFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (children.size() != 2) {
|
||||
throw new IllegalArgumentException("expects exactly two arguments");
|
||||
throw new SqlIllegalArgumentException("expects exactly two arguments");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, children.get(0), children.get(1), cfg.zoneId());
|
||||
};
|
||||
|
@ -496,13 +496,13 @@ public class FunctionRegistry {
|
|||
boolean isBinaryOptionalParamFunction = function.isAssignableFrom(Round.class) || function.isAssignableFrom(Truncate.class)
|
||||
|| TopHits.class.isAssignableFrom(function);
|
||||
if (isBinaryOptionalParamFunction && (children.size() > 2 || children.size() < 1)) {
|
||||
throw new IllegalArgumentException("expects one or two arguments");
|
||||
throw new SqlIllegalArgumentException("expects one or two arguments");
|
||||
} else if (!isBinaryOptionalParamFunction && children.size() != 2) {
|
||||
throw new IllegalArgumentException("expects exactly two arguments");
|
||||
throw new SqlIllegalArgumentException("expects exactly two arguments");
|
||||
}
|
||||
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, children.get(0), children.size() == 2 ? children.get(1) : null);
|
||||
};
|
||||
|
@ -527,7 +527,7 @@ public class FunctionRegistry {
|
|||
FunctionDefinition.Builder realBuilder = (uf, distinct, cfg) -> {
|
||||
try {
|
||||
return builder.build(uf.source(), uf.children(), distinct, cfg);
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (SqlIllegalArgumentException e) {
|
||||
throw new ParsingException(uf.source(), "error building [" + primaryName + "]: " + e.getMessage(), e);
|
||||
}
|
||||
};
|
||||
|
@ -544,12 +544,12 @@ public class FunctionRegistry {
|
|||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
boolean isLocateFunction = function.isAssignableFrom(Locate.class);
|
||||
if (isLocateFunction && (children.size() > 3 || children.size() < 2)) {
|
||||
throw new IllegalArgumentException("expects two or three arguments");
|
||||
throw new SqlIllegalArgumentException("expects two or three arguments");
|
||||
} else if (!isLocateFunction && children.size() != 3) {
|
||||
throw new IllegalArgumentException("expects exactly three arguments");
|
||||
throw new SqlIllegalArgumentException("expects exactly three arguments");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, children.get(0), children.get(1), children.size() == 3 ? children.get(2) : null);
|
||||
};
|
||||
|
@ -565,10 +565,10 @@ public class FunctionRegistry {
|
|||
FourParametersFunctionBuilder<T> ctorRef, String... names) {
|
||||
FunctionBuilder builder = (source, children, distinct, cfg) -> {
|
||||
if (children.size() != 4) {
|
||||
throw new IllegalArgumentException("expects exactly four arguments");
|
||||
throw new SqlIllegalArgumentException("expects exactly four arguments");
|
||||
}
|
||||
if (distinct) {
|
||||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
throw new SqlIllegalArgumentException("does not support DISTINCT yet it was specified");
|
||||
}
|
||||
return ctorRef.build(source, children.get(0), children.get(1), children.get(2), children.get(3));
|
||||
};
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder;
|
|||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.ConditionalProcessor.ConditionalOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Source;
|
||||
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -33,14 +32,6 @@ public abstract class ArbitraryConditionalFunction extends ConditionalFunction {
|
|||
this.operation = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeResolution resolveType() {
|
||||
for (Expression e : children()) {
|
||||
dataType = DataTypeConversion.commonType(dataType, e.dataType());
|
||||
}
|
||||
return TypeResolution.TYPE_RESOLVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
return new ConditionalPipe(source(), this, Expressions.pipe(children()), operation);
|
||||
|
|
|
@ -12,9 +12,14 @@ import org.elasticsearch.xpack.sql.expression.Nullability;
|
|||
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
|
||||
import org.elasticsearch.xpack.sql.tree.Source;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
|
||||
import static org.elasticsearch.xpack.sql.type.DataTypes.areTypesCompatible;
|
||||
import static org.elasticsearch.xpack.sql.util.StringUtils.ordinal;
|
||||
|
||||
/**
|
||||
* Base class for conditional predicates.
|
||||
*/
|
||||
|
@ -36,6 +41,31 @@ public abstract class ConditionalFunction extends ScalarFunction {
|
|||
return Expressions.foldable(children());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeResolution resolveType() {
|
||||
DataType dt = DataType.NULL;
|
||||
|
||||
for (int i = 0; i < children().size(); i++) {
|
||||
Expression child = children().get(i);
|
||||
if (dt == DataType.NULL) {
|
||||
if (Expressions.isNull(child) == false) {
|
||||
dt = child.dataType();
|
||||
}
|
||||
} else {
|
||||
if (areTypesCompatible(dt, child.dataType()) == false) {
|
||||
return new TypeResolution(format(null, "{} argument of [{}] must be [{}], found value [{}] type [{}]",
|
||||
ordinal(i + 1),
|
||||
sourceText(),
|
||||
dt.typeName,
|
||||
Expressions.name(child),
|
||||
child.dataType().typeName));
|
||||
}
|
||||
}
|
||||
dataType = DataTypeConversion.commonType(dataType, child.dataType());
|
||||
}
|
||||
return TypeResolution.TYPE_RESOLVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Nullability nullable() {
|
||||
return Nullability.UNKNOWN;
|
||||
|
|
|
@ -39,12 +39,6 @@ public class NullIf extends ConditionalFunction {
|
|||
return new NullIf(source(), newChildren.get(0), newChildren.get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeResolution resolveType() {
|
||||
dataType = children().get(0).dataType();
|
||||
return TypeResolution.TYPE_RESOLVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return NullIfProcessor.apply(children().get(0).fold(), children().get(1).fold());
|
||||
|
|
|
@ -26,6 +26,8 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
import static org.elasticsearch.xpack.sql.type.DataTypes.areTypesCompatible;
|
||||
import static org.elasticsearch.xpack.sql.util.StringUtils.ordinal;
|
||||
|
||||
public class In extends ScalarFunction {
|
||||
|
||||
|
@ -109,7 +111,7 @@ public class In extends ScalarFunction {
|
|||
@Override
|
||||
protected TypeResolution resolveType() {
|
||||
TypeResolution resolution = TypeResolutions.isExact(value, functionName(), Expressions.ParamOrdinal.DEFAULT);
|
||||
if (resolution != TypeResolution.TYPE_RESOLVED) {
|
||||
if (resolution.unresolved()) {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
|
@ -120,6 +122,20 @@ public class In extends ScalarFunction {
|
|||
name()));
|
||||
}
|
||||
}
|
||||
|
||||
DataType dt = value.dataType();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Expression listValue = list.get(i);
|
||||
if (areTypesCompatible(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();
|
||||
}
|
||||
|
||||
|
|
|
@ -230,4 +230,15 @@ public final class DataTypes {
|
|||
}
|
||||
return t.displaySize;
|
||||
}
|
||||
|
||||
public static boolean areTypesCompatible(DataType left, DataType right) {
|
||||
if (left == right) {
|
||||
return true;
|
||||
} else {
|
||||
return
|
||||
(left == DataType.NULL || right == DataType.NULL) ||
|
||||
(left.isString() && right.isString()) ||
|
||||
(left.isNumeric() && right.isNumeric());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,16 @@ import java.util.Locale;
|
|||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public abstract class StringUtils {
|
||||
public final class StringUtils {
|
||||
|
||||
private StringUtils() {}
|
||||
|
||||
public static final String EMPTY = "";
|
||||
public static final String NEW_LINE = "\n";
|
||||
public static final String SQL_WILDCARD = "%";
|
||||
|
||||
private static final String[] INTEGER_ORDINALS = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
|
||||
|
||||
//CamelCase to camel_case
|
||||
public static String camelCaseToUnderscore(String string) {
|
||||
if (!Strings.hasText(string)) {
|
||||
|
@ -86,10 +90,6 @@ public abstract class StringUtils {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String nullAsEmpty(String string) {
|
||||
return string == null ? EMPTY : string;
|
||||
}
|
||||
|
||||
// % -> .*
|
||||
// _ -> .
|
||||
// escape character - can be 0 (in which case every regex gets escaped) or
|
||||
|
@ -297,4 +297,16 @@ public abstract class StringUtils {
|
|||
throw new SqlIllegalArgumentException("Cannot parse number [{}]", string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String ordinal(int i) {
|
||||
switch (i % 100) {
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
return i + "th";
|
||||
default:
|
||||
return i + INTEGER_ORDINALS[i % 10];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -420,46 +420,16 @@ public class VerifierErrorMessagesTests extends ESTestCase {
|
|||
error("SELECT int FROM test GROUP BY int HAVING 2 < ABS(int)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypes_SelectClause() {
|
||||
assertEquals("1:17: expected data type [integer], value provided is of type [keyword]",
|
||||
public void testInWithDifferentDataTypes() {
|
||||
assertEquals("1:8: 2nd argument of [1 IN (2, '3', 4)] must be [integer], found value ['3'] type [keyword]",
|
||||
error("SELECT 1 IN (2, '3', 4)"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypes_SelectClause() {
|
||||
assertEquals("1:27: expected data type [integer], value provided is of type [keyword]",
|
||||
error("SELECT 1 = 1 OR 1 IN (2, '3', 4)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypesFromLeftValue_SelectClause() {
|
||||
assertEquals("1:14: expected data type [integer], value provided is of type [keyword]",
|
||||
public void testInWithDifferentDataTypesFromLeftValue() {
|
||||
assertEquals("1:8: 1st argument of [1 IN ('foo', 'bar')] must be [integer], found value ['foo'] type [keyword]",
|
||||
error("SELECT 1 IN ('foo', 'bar')"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypesFromLeftValue_SelectClause() {
|
||||
assertEquals("1:29: expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT 1 = 1 OR 'foo' IN (2, 3)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypes_WhereClause() {
|
||||
assertEquals("1:52: expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT * FROM test WHERE keyword IN ('foo', 'bar', 4)"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypes_WhereClause() {
|
||||
assertEquals("1:63: expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT * FROM test WHERE int = 1 OR keyword IN ('foo', 'bar', 2)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypesFromLeftValue_WhereClause() {
|
||||
assertEquals("1:38: expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT * FROM test WHERE keyword IN (1, 2)"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypesFromLeftValue_WhereClause() {
|
||||
assertEquals("1:49: expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT * FROM test WHERE int = 1 OR keyword IN (1, 2)"));
|
||||
}
|
||||
|
||||
public void testInWithFieldInListOfValues() {
|
||||
assertEquals("1:26: Comparisons against variables are not (currently) supported; offender [int] in [int IN (1, int)]",
|
||||
error("SELECT * FROM test WHERE int IN (1, int)"));
|
||||
|
@ -615,32 +585,17 @@ public class VerifierErrorMessagesTests extends ESTestCase {
|
|||
incompatibleError("SELECT languages FROM \"*\" ORDER BY SIGN(ABS(emp_no))"));
|
||||
}
|
||||
|
||||
public void testConditionalWithDifferentDataTypes_SelectClause() {
|
||||
public void testConditionalWithDifferentDataTypes() {
|
||||
@SuppressWarnings("unchecked")
|
||||
String function = randomFrom(IfNull.class, NullIf.class).getSimpleName();
|
||||
assertEquals("1:" + (22 + function.length()) +
|
||||
": expected data type [integer], value provided is of type [keyword]",
|
||||
error("SELECT 1 = 1 OR " + function + "(3, '4') > 1"));
|
||||
assertEquals("1:17: 2nd argument of [" + function + "(3, '4')] must be [integer], found value ['4'] type [keyword]",
|
||||
error("SELECT 1 = 1 OR " + function + "(3, '4') > 1"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
String arbirtraryArgsfunction = randomFrom(Coalesce.class, Greatest.class, Least.class).getSimpleName();
|
||||
assertEquals("1:" + (34 + arbirtraryArgsfunction.length()) +
|
||||
": expected data type [integer], value provided is of type [keyword]",
|
||||
error("SELECT 1 = 1 OR " + arbirtraryArgsfunction + "(null, null, 3, '4') > 1"));
|
||||
}
|
||||
|
||||
public void testConditionalWithDifferentDataTypes_WhereClause() {
|
||||
@SuppressWarnings("unchecked")
|
||||
String function = randomFrom(IfNull.class, NullIf.class).getSimpleName();
|
||||
assertEquals("1:" + (34 + function.length()) +
|
||||
": expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT * FROM test WHERE " + function + "('foo', 4) > 1"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
String arbirtraryArgsfunction = randomFrom(Coalesce.class, Greatest.class, Least.class).getSimpleName();
|
||||
assertEquals("1:" + (46 + arbirtraryArgsfunction.length()) +
|
||||
": expected data type [keyword], value provided is of type [integer]",
|
||||
error("SELECT * FROM test WHERE " + arbirtraryArgsfunction + "(null, null, 'foo', 4) > 1"));
|
||||
String arbirtraryArgsFunction = randomFrom(Coalesce.class, Greatest.class, Least.class).getSimpleName();
|
||||
assertEquals("1:17: 3rd argument of [" + arbirtraryArgsFunction + "(null, 3, '4')] must be [integer], " +
|
||||
"found value ['4'] type [keyword]",
|
||||
error("SELECT 1 = 1 OR " + arbirtraryArgsFunction + "(null, 3, '4') > 1"));
|
||||
}
|
||||
|
||||
public void testAggsInWhere() {
|
||||
|
|
|
@ -165,13 +165,13 @@ public class FunctionRegistryTests extends ESTestCase {
|
|||
|
||||
public void testAliasNameIsTheSameAsAFunctionName() {
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS"));
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
|
||||
SqlIllegalArgumentException iae = expectThrows(SqlIllegalArgumentException.class, () ->
|
||||
r.addToMap(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() {
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
|
||||
SqlIllegalArgumentException iae = expectThrows(SqlIllegalArgumentException.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());
|
||||
|
@ -179,7 +179,7 @@ public class FunctionRegistryTests extends ESTestCase {
|
|||
|
||||
public void testDuplicateAliasInTwoDifferentFunctionsFromTwoDifferentBatches() {
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS"));
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
|
||||
SqlIllegalArgumentException iae = expectThrows(SqlIllegalArgumentException.class, () ->
|
||||
r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "ALIAS")));
|
||||
assertEquals("alias [ALIAS] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]", iae.getMessage());
|
||||
}
|
||||
|
|
|
@ -108,7 +108,10 @@ import static java.util.Arrays.asList;
|
|||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.elasticsearch.xpack.sql.expression.Literal.FALSE;
|
||||
import static org.elasticsearch.xpack.sql.expression.Literal.NULL;
|
||||
import static org.elasticsearch.xpack.sql.expression.Literal.TRUE;
|
||||
import static org.elasticsearch.xpack.sql.expression.Literal.of;
|
||||
import static org.elasticsearch.xpack.sql.tree.Source.EMPTY;
|
||||
import static org.elasticsearch.xpack.sql.util.DateUtils.UTC;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
|
@ -174,7 +177,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private static Literal L(Object value) {
|
||||
return Literal.of(EMPTY, value);
|
||||
return of(EMPTY, value);
|
||||
}
|
||||
|
||||
private static FieldAttribute getFieldAttribute() {
|
||||
|
@ -190,8 +193,8 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testDuplicateFunctions() {
|
||||
AggregateFunction f1 = new Count(EMPTY, Literal.TRUE, false);
|
||||
AggregateFunction f2 = new Count(EMPTY, Literal.TRUE, false);
|
||||
AggregateFunction f1 = new Count(EMPTY, TRUE, false);
|
||||
AggregateFunction f2 = new Count(EMPTY, TRUE, false);
|
||||
|
||||
assertTrue(f1.functionEquals(f2));
|
||||
|
||||
|
@ -284,34 +287,34 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testConstantFoldingBinaryComparison() {
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new GreaterThan(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new GreaterThanOrEqual(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new Equals(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new NullEquals(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new NullEquals(EMPTY, TWO, NULL)).canonical());
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new NotEquals(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new LessThanOrEqual(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new LessThan(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new GreaterThan(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new GreaterThanOrEqual(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new Equals(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new NullEquals(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new NullEquals(EMPTY, TWO, NULL)).canonical());
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new NotEquals(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new LessThanOrEqual(EMPTY, TWO, THREE)).canonical());
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new LessThan(EMPTY, TWO, THREE)).canonical());
|
||||
}
|
||||
|
||||
public void testConstantFoldingBinaryLogic() {
|
||||
assertEquals(Literal.FALSE,
|
||||
new ConstantFolding().rule(new And(EMPTY, new GreaterThan(EMPTY, TWO, THREE), Literal.TRUE)).canonical());
|
||||
assertEquals(Literal.TRUE,
|
||||
new ConstantFolding().rule(new Or(EMPTY, new GreaterThanOrEqual(EMPTY, TWO, THREE), Literal.TRUE)).canonical());
|
||||
assertEquals(FALSE,
|
||||
new ConstantFolding().rule(new And(EMPTY, new GreaterThan(EMPTY, TWO, THREE), TRUE)).canonical());
|
||||
assertEquals(TRUE,
|
||||
new ConstantFolding().rule(new Or(EMPTY, new GreaterThanOrEqual(EMPTY, TWO, THREE), TRUE)).canonical());
|
||||
}
|
||||
|
||||
public void testConstantFoldingBinaryLogic_WithNullHandling() {
|
||||
assertEquals(NULL, new ConstantFolding().rule(new And(EMPTY, NULL, Literal.TRUE)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new And(EMPTY, Literal.TRUE, NULL)).canonical());
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new And(EMPTY, NULL, Literal.FALSE)).canonical());
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new And(EMPTY, Literal.FALSE, NULL)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new And(EMPTY, NULL, TRUE)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new And(EMPTY, TRUE, NULL)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new And(EMPTY, NULL, FALSE)).canonical());
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new And(EMPTY, FALSE, NULL)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new And(EMPTY, NULL, NULL)).canonical());
|
||||
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new Or(EMPTY, NULL, Literal.TRUE)).canonical());
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new Or(EMPTY, Literal.TRUE, NULL)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new Or(EMPTY, NULL, Literal.FALSE)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new Or(EMPTY, Literal.FALSE, NULL)).canonical());
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new Or(EMPTY, NULL, TRUE)).canonical());
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new Or(EMPTY, TRUE, NULL)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new Or(EMPTY, NULL, FALSE)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new Or(EMPTY, FALSE, NULL)).canonical());
|
||||
assertEquals(NULL, new ConstantFolding().rule(new Or(EMPTY, NULL, NULL)).canonical());
|
||||
}
|
||||
|
||||
|
@ -321,25 +324,25 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testConstantIsNotNull() {
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new IsNotNull(EMPTY, L(null))));
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new IsNotNull(EMPTY, FIVE)));
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new IsNotNull(EMPTY, L(null))));
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new IsNotNull(EMPTY, FIVE)));
|
||||
}
|
||||
|
||||
public void testConstantNot() {
|
||||
assertEquals(Literal.FALSE, new ConstantFolding().rule(new Not(EMPTY, Literal.TRUE)));
|
||||
assertEquals(Literal.TRUE, new ConstantFolding().rule(new Not(EMPTY, Literal.FALSE)));
|
||||
assertEquals(FALSE, new ConstantFolding().rule(new Not(EMPTY, TRUE)));
|
||||
assertEquals(TRUE, new ConstantFolding().rule(new Not(EMPTY, FALSE)));
|
||||
}
|
||||
|
||||
public void testConstantFoldingLikes() {
|
||||
assertEquals(Literal.TRUE,
|
||||
new ConstantFolding().rule(new Like(EMPTY, Literal.of(EMPTY, "test_emp"), new LikePattern("test%", (char) 0)))
|
||||
assertEquals(TRUE,
|
||||
new ConstantFolding().rule(new Like(EMPTY, of(EMPTY, "test_emp"), new LikePattern("test%", (char) 0)))
|
||||
.canonical());
|
||||
assertEquals(Literal.TRUE,
|
||||
new ConstantFolding().rule(new RLike(EMPTY, Literal.of(EMPTY, "test_emp"), "test.emp")).canonical());
|
||||
assertEquals(TRUE,
|
||||
new ConstantFolding().rule(new RLike(EMPTY, of(EMPTY, "test_emp"), "test.emp")).canonical());
|
||||
}
|
||||
|
||||
public void testConstantFoldingDatetime() {
|
||||
Expression cast = new Cast(EMPTY, Literal.of(EMPTY, "2018-01-19T10:23:27Z"), DataType.DATETIME);
|
||||
Expression cast = new Cast(EMPTY, of(EMPTY, "2018-01-19T10:23:27Z"), DataType.DATETIME);
|
||||
assertEquals(2018, foldFunction(new Year(EMPTY, cast, UTC)));
|
||||
assertEquals(1, foldFunction(new MonthOfYear(EMPTY, cast, UTC)));
|
||||
assertEquals(19, foldFunction(new DayOfMonth(EMPTY, cast, UTC)));
|
||||
|
@ -407,44 +410,44 @@ public class OptimizerTests extends ESTestCase {
|
|||
|
||||
public void testNullFoldingIsNull() {
|
||||
FoldNull foldNull = new FoldNull();
|
||||
assertEquals(true, foldNull.rule(new IsNull(EMPTY, Literal.NULL)).fold());
|
||||
assertEquals(false, foldNull.rule(new IsNull(EMPTY, Literal.TRUE)).fold());
|
||||
assertEquals(true, foldNull.rule(new IsNull(EMPTY, NULL)).fold());
|
||||
assertEquals(false, foldNull.rule(new IsNull(EMPTY, TRUE)).fold());
|
||||
}
|
||||
|
||||
public void testNullFoldingIsNotNull() {
|
||||
FoldNull foldNull = new FoldNull();
|
||||
assertEquals(true, foldNull.rule(new IsNotNull(EMPTY, Literal.TRUE)).fold());
|
||||
assertEquals(false, foldNull.rule(new IsNotNull(EMPTY, Literal.NULL)).fold());
|
||||
assertEquals(true, foldNull.rule(new IsNotNull(EMPTY, TRUE)).fold());
|
||||
assertEquals(false, foldNull.rule(new IsNotNull(EMPTY, NULL)).fold());
|
||||
}
|
||||
|
||||
public void testGenericNullableExpression() {
|
||||
FoldNull rule = new FoldNull();
|
||||
// date-time
|
||||
assertNullLiteral(rule.rule(new DayName(EMPTY, Literal.NULL, randomZone())));
|
||||
assertNullLiteral(rule.rule(new DayName(EMPTY, NULL, randomZone())));
|
||||
// math function
|
||||
assertNullLiteral(rule.rule(new Cos(EMPTY, Literal.NULL)));
|
||||
assertNullLiteral(rule.rule(new Cos(EMPTY, NULL)));
|
||||
// string function
|
||||
assertNullLiteral(rule.rule(new Ascii(EMPTY, Literal.NULL)));
|
||||
assertNullLiteral(rule.rule(new Repeat(EMPTY, getFieldAttribute(), Literal.NULL)));
|
||||
assertNullLiteral(rule.rule(new Ascii(EMPTY, NULL)));
|
||||
assertNullLiteral(rule.rule(new Repeat(EMPTY, getFieldAttribute(), NULL)));
|
||||
// arithmetic
|
||||
assertNullLiteral(rule.rule(new Add(EMPTY, getFieldAttribute(), Literal.NULL)));
|
||||
assertNullLiteral(rule.rule(new Add(EMPTY, getFieldAttribute(), NULL)));
|
||||
// comparison
|
||||
assertNullLiteral(rule.rule(new GreaterThan(EMPTY, getFieldAttribute(), Literal.NULL)));
|
||||
assertNullLiteral(rule.rule(new GreaterThan(EMPTY, getFieldAttribute(), NULL)));
|
||||
// regex
|
||||
assertNullLiteral(rule.rule(new RLike(EMPTY, Literal.NULL, "123")));
|
||||
assertNullLiteral(rule.rule(new RLike(EMPTY, NULL, "123")));
|
||||
}
|
||||
|
||||
public void testNullFoldingDoesNotApplyOnLogicalExpressions() {
|
||||
FoldNull rule = new FoldNull();
|
||||
|
||||
Or or = new Or(EMPTY, Literal.NULL, Literal.TRUE);
|
||||
Or or = new Or(EMPTY, NULL, TRUE);
|
||||
assertEquals(or, rule.rule(or));
|
||||
or = new Or(EMPTY, Literal.NULL, Literal.NULL);
|
||||
or = new Or(EMPTY, NULL, NULL);
|
||||
assertEquals(or, rule.rule(or));
|
||||
|
||||
And and = new And(EMPTY, Literal.NULL, Literal.TRUE);
|
||||
And and = new And(EMPTY, NULL, TRUE);
|
||||
assertEquals(and, rule.rule(and));
|
||||
and = new And(EMPTY, Literal.NULL, Literal.NULL);
|
||||
and = new And(EMPTY, NULL, NULL);
|
||||
assertEquals(and, rule.rule(and));
|
||||
}
|
||||
|
||||
|
@ -455,11 +458,11 @@ public class OptimizerTests extends ESTestCase {
|
|||
Class<ConditionalFunction> clazz =
|
||||
(Class<ConditionalFunction>) randomFrom(IfNull.class, NullIf.class);
|
||||
Constructor<ConditionalFunction> ctor = clazz.getConstructor(Source.class, Expression.class, Expression.class);
|
||||
ConditionalFunction conditionalFunction = ctor.newInstance(EMPTY, Literal.NULL, ONE);
|
||||
ConditionalFunction conditionalFunction = ctor.newInstance(EMPTY, NULL, ONE);
|
||||
assertEquals(conditionalFunction, rule.rule(conditionalFunction));
|
||||
conditionalFunction = ctor.newInstance(EMPTY, ONE, Literal.NULL);
|
||||
conditionalFunction = ctor.newInstance(EMPTY, ONE, NULL);
|
||||
assertEquals(conditionalFunction, rule.rule(conditionalFunction));
|
||||
conditionalFunction = ctor.newInstance(EMPTY, Literal.NULL, Literal.NULL);
|
||||
conditionalFunction = ctor.newInstance(EMPTY, NULL, NULL);
|
||||
assertEquals(conditionalFunction, rule.rule(conditionalFunction));
|
||||
}
|
||||
|
||||
|
@ -470,14 +473,14 @@ public class OptimizerTests extends ESTestCase {
|
|||
Class<ArbitraryConditionalFunction> clazz =
|
||||
(Class<ArbitraryConditionalFunction>) randomFrom(Coalesce.class, Greatest.class, Least.class);
|
||||
Constructor<ArbitraryConditionalFunction> ctor = clazz.getConstructor(Source.class, List.class);
|
||||
ArbitraryConditionalFunction conditionalFunction = ctor.newInstance(EMPTY, Arrays.asList(Literal.NULL, ONE, TWO));
|
||||
ArbitraryConditionalFunction conditionalFunction = ctor.newInstance(EMPTY, Arrays.asList(NULL, ONE, TWO));
|
||||
assertEquals(conditionalFunction, rule.rule(conditionalFunction));
|
||||
conditionalFunction = ctor.newInstance(EMPTY, Arrays.asList(Literal.NULL, NULL, NULL));
|
||||
conditionalFunction = ctor.newInstance(EMPTY, Arrays.asList(NULL, NULL, NULL));
|
||||
assertEquals(conditionalFunction, rule.rule(conditionalFunction));
|
||||
}
|
||||
|
||||
public void testSimplifyCoalesceNulls() {
|
||||
Expression e = new SimplifyConditional().rule(new Coalesce(EMPTY, asList(Literal.NULL, Literal.NULL)));
|
||||
Expression e = new SimplifyConditional().rule(new Coalesce(EMPTY, asList(NULL, NULL)));
|
||||
assertEquals(Coalesce.class, e.getClass());
|
||||
assertEquals(0, e.children().size());
|
||||
}
|
||||
|
@ -491,51 +494,51 @@ public class OptimizerTests extends ESTestCase {
|
|||
public void testSimplifyCoalesceRandomNullsWithValue() {
|
||||
Expression e = new SimplifyConditional().rule(new Coalesce(EMPTY,
|
||||
CollectionUtils.combine(
|
||||
CollectionUtils.combine(randomListOfNulls(), Literal.TRUE, Literal.FALSE, Literal.TRUE),
|
||||
CollectionUtils.combine(randomListOfNulls(), TRUE, FALSE, TRUE),
|
||||
randomListOfNulls())));
|
||||
assertEquals(1, e.children().size());
|
||||
assertEquals(Literal.TRUE, e.children().get(0));
|
||||
assertEquals(TRUE, e.children().get(0));
|
||||
}
|
||||
|
||||
private List<Expression> randomListOfNulls() {
|
||||
return asList(randomArray(1, 10, Literal[]::new, () -> Literal.NULL));
|
||||
return asList(randomArray(1, 10, Literal[]::new, () -> NULL));
|
||||
}
|
||||
|
||||
public void testSimplifyCoalesceFirstLiteral() {
|
||||
Expression e = new SimplifyConditional()
|
||||
.rule(new Coalesce(EMPTY,
|
||||
Arrays.asList(Literal.NULL, Literal.TRUE, Literal.FALSE, new Abs(EMPTY, getFieldAttribute()))));
|
||||
Arrays.asList(NULL, TRUE, FALSE, new Abs(EMPTY, getFieldAttribute()))));
|
||||
assertEquals(Coalesce.class, e.getClass());
|
||||
assertEquals(1, e.children().size());
|
||||
assertEquals(Literal.TRUE, e.children().get(0));
|
||||
assertEquals(TRUE, e.children().get(0));
|
||||
}
|
||||
|
||||
public void testSimplifyIfNullNulls() {
|
||||
Expression e = new SimplifyConditional().rule(new IfNull(EMPTY, Literal.NULL, Literal.NULL));
|
||||
Expression e = new SimplifyConditional().rule(new IfNull(EMPTY, NULL, NULL));
|
||||
assertEquals(IfNull.class, e.getClass());
|
||||
assertEquals(0, e.children().size());
|
||||
}
|
||||
|
||||
public void testSimplifyIfNullWithNullAndValue() {
|
||||
Expression e = new SimplifyConditional().rule(new IfNull(EMPTY, Literal.NULL, ONE));
|
||||
Expression e = new SimplifyConditional().rule(new IfNull(EMPTY, NULL, ONE));
|
||||
assertEquals(IfNull.class, e.getClass());
|
||||
assertEquals(1, e.children().size());
|
||||
assertEquals(ONE, e.children().get(0));
|
||||
|
||||
e = new SimplifyConditional().rule(new IfNull(EMPTY, ONE, Literal.NULL));
|
||||
e = new SimplifyConditional().rule(new IfNull(EMPTY, ONE, NULL));
|
||||
assertEquals(IfNull.class, e.getClass());
|
||||
assertEquals(1, e.children().size());
|
||||
assertEquals(ONE, e.children().get(0));
|
||||
}
|
||||
|
||||
public void testFoldNullNotAppliedOnNullIf() {
|
||||
Expression orig = new NullIf(EMPTY, ONE, Literal.NULL);
|
||||
Expression orig = new NullIf(EMPTY, ONE, NULL);
|
||||
Expression f = new FoldNull().rule(orig);
|
||||
assertEquals(orig, f);
|
||||
}
|
||||
|
||||
public void testSimplifyGreatestNulls() {
|
||||
Expression e = new SimplifyConditional().rule(new Greatest(EMPTY, asList(Literal.NULL, Literal.NULL)));
|
||||
Expression e = new SimplifyConditional().rule(new Greatest(EMPTY, asList(NULL, NULL)));
|
||||
assertEquals(Greatest.class, e.getClass());
|
||||
assertEquals(0, e.children().size());
|
||||
}
|
||||
|
@ -556,7 +559,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testSimplifyLeastNulls() {
|
||||
Expression e = new SimplifyConditional().rule(new Least(EMPTY, asList(Literal.NULL, Literal.NULL)));
|
||||
Expression e = new SimplifyConditional().rule(new Least(EMPTY, asList(NULL, NULL)));
|
||||
assertEquals(Least.class, e.getClass());
|
||||
assertEquals(0, e.children().size());
|
||||
}
|
||||
|
@ -578,9 +581,9 @@ public class OptimizerTests extends ESTestCase {
|
|||
|
||||
public void testConcatFoldingIsNotNull() {
|
||||
FoldNull foldNull = new FoldNull();
|
||||
assertEquals(1, foldNull.rule(new Concat(EMPTY, Literal.NULL, ONE)).fold());
|
||||
assertEquals(1, foldNull.rule(new Concat(EMPTY, ONE, Literal.NULL)).fold());
|
||||
assertEquals(StringUtils.EMPTY, foldNull.rule(new Concat(EMPTY, Literal.NULL, Literal.NULL)).fold());
|
||||
assertEquals(1, foldNull.rule(new Concat(EMPTY, NULL, ONE)).fold());
|
||||
assertEquals(1, foldNull.rule(new Concat(EMPTY, ONE, NULL)).fold());
|
||||
assertEquals(StringUtils.EMPTY, foldNull.rule(new Concat(EMPTY, NULL, NULL)).fold());
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -593,15 +596,15 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testBinaryComparisonSimplification() {
|
||||
assertEquals(Literal.TRUE, new BinaryComparisonSimplification().rule(new Equals(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(Literal.TRUE, new BinaryComparisonSimplification().rule(new NullEquals(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(Literal.TRUE, new BinaryComparisonSimplification().rule(new NullEquals(EMPTY, NULL, NULL)));
|
||||
assertEquals(Literal.FALSE, new BinaryComparisonSimplification().rule(new NotEquals(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(Literal.TRUE, new BinaryComparisonSimplification().rule(new GreaterThanOrEqual(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(Literal.TRUE, new BinaryComparisonSimplification().rule(new LessThanOrEqual(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(TRUE, new BinaryComparisonSimplification().rule(new Equals(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(TRUE, new BinaryComparisonSimplification().rule(new NullEquals(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(TRUE, new BinaryComparisonSimplification().rule(new NullEquals(EMPTY, NULL, NULL)));
|
||||
assertEquals(FALSE, new BinaryComparisonSimplification().rule(new NotEquals(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(TRUE, new BinaryComparisonSimplification().rule(new GreaterThanOrEqual(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(TRUE, new BinaryComparisonSimplification().rule(new LessThanOrEqual(EMPTY, FIVE, FIVE)));
|
||||
|
||||
assertEquals(Literal.FALSE, new BinaryComparisonSimplification().rule(new GreaterThan(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(Literal.FALSE, new BinaryComparisonSimplification().rule(new LessThan(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(FALSE, new BinaryComparisonSimplification().rule(new GreaterThan(EMPTY, FIVE, FIVE)));
|
||||
assertEquals(FALSE, new BinaryComparisonSimplification().rule(new LessThan(EMPTY, FIVE, FIVE)));
|
||||
}
|
||||
|
||||
public void testNullEqualsWithNullLiteralBecomesIsNull() {
|
||||
|
@ -648,25 +651,25 @@ public class OptimizerTests extends ESTestCase {
|
|||
public void testBoolSimplifyOr() {
|
||||
BooleanSimplification simplification = new BooleanSimplification();
|
||||
|
||||
assertEquals(Literal.TRUE, simplification.rule(new Or(EMPTY, Literal.TRUE, Literal.TRUE)));
|
||||
assertEquals(Literal.TRUE, simplification.rule(new Or(EMPTY, Literal.TRUE, DUMMY_EXPRESSION)));
|
||||
assertEquals(Literal.TRUE, simplification.rule(new Or(EMPTY, DUMMY_EXPRESSION, Literal.TRUE)));
|
||||
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(Literal.FALSE, simplification.rule(new Or(EMPTY, Literal.FALSE, Literal.FALSE)));
|
||||
assertEquals(DUMMY_EXPRESSION, simplification.rule(new Or(EMPTY, Literal.FALSE, DUMMY_EXPRESSION)));
|
||||
assertEquals(DUMMY_EXPRESSION, simplification.rule(new Or(EMPTY, DUMMY_EXPRESSION, Literal.FALSE)));
|
||||
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(Literal.TRUE, simplification.rule(new And(EMPTY, Literal.TRUE, Literal.TRUE)));
|
||||
assertEquals(DUMMY_EXPRESSION, simplification.rule(new And(EMPTY, Literal.TRUE, DUMMY_EXPRESSION)));
|
||||
assertEquals(DUMMY_EXPRESSION, simplification.rule(new And(EMPTY, DUMMY_EXPRESSION, Literal.TRUE)));
|
||||
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(Literal.FALSE, simplification.rule(new And(EMPTY, Literal.FALSE, Literal.FALSE)));
|
||||
assertEquals(Literal.FALSE, simplification.rule(new And(EMPTY, Literal.FALSE, DUMMY_EXPRESSION)));
|
||||
assertEquals(Literal.FALSE, simplification.rule(new And(EMPTY, DUMMY_EXPRESSION, Literal.FALSE)));
|
||||
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() {
|
||||
|
@ -710,7 +713,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
public void testCombineBinaryComparisonsNotComparable() {
|
||||
FieldAttribute fa = getFieldAttribute();
|
||||
LessThanOrEqual lte = new LessThanOrEqual(EMPTY, fa, SIX);
|
||||
LessThan lt = new LessThan(EMPTY, fa, Literal.FALSE);
|
||||
LessThan lt = new LessThan(EMPTY, fa, FALSE);
|
||||
|
||||
CombineBinaryComparisons rule = new CombineBinaryComparisons();
|
||||
And and = new And(EMPTY, lte, lt);
|
||||
|
@ -790,7 +793,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
CombineBinaryComparisons rule = new CombineBinaryComparisons();
|
||||
|
||||
// TRUE AND a != 5 AND 4 < a <= 7
|
||||
Expression exp = rule.rule(new And(EMPTY, gte, new And(EMPTY, Literal.TRUE, new And(EMPTY, gt, new And(EMPTY, ne, lte)))));
|
||||
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());
|
||||
|
@ -943,7 +946,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
FieldAttribute fa = getFieldAttribute();
|
||||
|
||||
GreaterThan gt1 = new GreaterThan(EMPTY, fa, ONE);
|
||||
GreaterThan gt2 = new GreaterThan(EMPTY, fa, Literal.FALSE);
|
||||
GreaterThan gt2 = new GreaterThan(EMPTY, fa, FALSE);
|
||||
|
||||
Or or = new Or(EMPTY, gt1, gt2);
|
||||
|
||||
|
@ -1056,7 +1059,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
FieldAttribute fa = getFieldAttribute();
|
||||
|
||||
Range r1 = new Range(EMPTY, fa, TWO, false, THREE, false);
|
||||
Range r2 = new Range(EMPTY, fa, ONE, false, Literal.FALSE, false);
|
||||
Range r2 = new Range(EMPTY, fa, ONE, false, FALSE, false);
|
||||
|
||||
Or or = new Or(EMPTY, r1, r2);
|
||||
|
||||
|
@ -1194,7 +1197,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
|
||||
PropagateEquals rule = new PropagateEquals();
|
||||
Expression exp = rule.rule(new And(EMPTY, eq1, eq2));
|
||||
assertEquals(Literal.FALSE, rule.rule(exp));
|
||||
assertEquals(FALSE, rule.rule(exp));
|
||||
}
|
||||
|
||||
// a <=> 1 AND a <=> 2 -> FALSE
|
||||
|
@ -1205,7 +1208,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
|
||||
PropagateEquals rule = new PropagateEquals();
|
||||
Expression exp = rule.rule(new And(EMPTY, eq1, eq2));
|
||||
assertEquals(Literal.FALSE, rule.rule(exp));
|
||||
assertEquals(FALSE, rule.rule(exp));
|
||||
}
|
||||
|
||||
// 1 < a < 10 AND a == 10 -> FALSE
|
||||
|
@ -1216,7 +1219,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
|
||||
PropagateEquals rule = new PropagateEquals();
|
||||
Expression exp = rule.rule(new And(EMPTY, eq1, r));
|
||||
assertEquals(Literal.FALSE, rule.rule(exp));
|
||||
assertEquals(FALSE, rule.rule(exp));
|
||||
}
|
||||
|
||||
// 1 < a < 10 AND a <=> 10 -> FALSE
|
||||
|
@ -1227,7 +1230,7 @@ public class OptimizerTests extends ESTestCase {
|
|||
|
||||
PropagateEquals rule = new PropagateEquals();
|
||||
Expression exp = rule.rule(new And(EMPTY, eq1, r));
|
||||
assertEquals(Literal.FALSE, rule.rule(exp));
|
||||
assertEquals(FALSE, rule.rule(exp));
|
||||
}
|
||||
|
||||
public void testTranslateMinToFirst() {
|
||||
|
|
Loading…
Reference in New Issue