in x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/optimizer/OptimizerRules.java [345:478]
private static Expression propagate(And and) {
List<Range> ranges = new ArrayList<>();
// Only equalities, not-equalities and inequalities with a foldable .right are extracted separately;
// the others go into the general 'exps'.
List<BinaryComparison> equals = new ArrayList<>();
List<NotEquals> notEquals = new ArrayList<>();
List<BinaryComparison> inequalities = new ArrayList<>();
List<Expression> exps = new ArrayList<>();
boolean changed = false;
for (Expression ex : Predicates.splitAnd(and)) {
if (ex instanceof Range) {
ranges.add((Range) ex);
} else if (ex instanceof Equals || ex instanceof NullEquals) {
BinaryComparison otherEq = (BinaryComparison) ex;
// equals on different values evaluate to FALSE
// ignore date/time fields as equality comparison might actually be a range check
if (otherEq.right().foldable() && DataTypes.isDateTime(otherEq.left().dataType()) == false) {
for (BinaryComparison eq : equals) {
if (otherEq.left().semanticEquals(eq.left())) {
Integer comp = BinaryComparison.compare(eq.right().fold(), otherEq.right().fold());
if (comp != null) {
// var cannot be equal to two different values at the same time
if (comp != 0) {
return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN);
}
}
}
}
equals.add(otherEq);
} else {
exps.add(otherEq);
}
} else if (ex instanceof GreaterThan
|| ex instanceof GreaterThanOrEqual
|| ex instanceof LessThan
|| ex instanceof LessThanOrEqual) {
BinaryComparison bc = (BinaryComparison) ex;
if (bc.right().foldable()) {
inequalities.add(bc);
} else {
exps.add(ex);
}
} else if (ex instanceof NotEquals otherNotEq) {
if (otherNotEq.right().foldable()) {
notEquals.add(otherNotEq);
} else {
exps.add(ex);
}
} else {
exps.add(ex);
}
}
// check
for (BinaryComparison eq : equals) {
Object eqValue = eq.right().fold();
for (Iterator<Range> iterator = ranges.iterator(); iterator.hasNext();) {
Range range = iterator.next();
if (range.value().semanticEquals(eq.left())) {
// if equals is outside the interval, evaluate the whole expression to FALSE
if (range.lower().foldable()) {
Integer compare = BinaryComparison.compare(range.lower().fold(), eqValue);
if (compare != null && (
// eq outside the lower boundary
compare > 0 ||
// eq matches the boundary but should not be included
(compare == 0 && range.includeLower() == false))) {
return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN);
}
}
if (range.upper().foldable()) {
Integer compare = BinaryComparison.compare(range.upper().fold(), eqValue);
if (compare != null && (
// eq outside the upper boundary
compare < 0 ||
// eq matches the boundary but should not be included
(compare == 0 && range.includeUpper() == false))) {
return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN);
}
}
// it's in the range and thus, remove it
iterator.remove();
changed = true;
}
}
// evaluate all NotEquals against the Equal
for (Iterator<NotEquals> iter = notEquals.iterator(); iter.hasNext();) {
NotEquals neq = iter.next();
if (eq.left().semanticEquals(neq.left())) {
Integer comp = BinaryComparison.compare(eqValue, neq.right().fold());
if (comp != null) {
if (comp == 0) { // clashing and conflicting: a = 1 AND a != 1
return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN);
} else { // clashing and redundant: a = 1 AND a != 2
iter.remove();
changed = true;
}
}
}
}
// evaluate all inequalities against the Equal
for (Iterator<BinaryComparison> iter = inequalities.iterator(); iter.hasNext();) {
BinaryComparison bc = iter.next();
if (eq.left().semanticEquals(bc.left())) {
Integer compare = BinaryComparison.compare(eqValue, bc.right().fold());
if (compare != null) {
if (bc instanceof LessThan || bc instanceof LessThanOrEqual) { // a = 2 AND a </<= ?
if ((compare == 0 && bc instanceof LessThan) || // a = 2 AND a < 2
0 < compare) { // a = 2 AND a </<= 1
return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN);
}
} else if (bc instanceof GreaterThan || bc instanceof GreaterThanOrEqual) { // a = 2 AND a >/>= ?
if ((compare == 0 && bc instanceof GreaterThan) || // a = 2 AND a > 2
compare < 0) { // a = 2 AND a >/>= 3
return new Literal(and.source(), Boolean.FALSE, DataTypes.BOOLEAN);
}
}
iter.remove();
changed = true;
}
}
}
}
return changed ? Predicates.combineAnd(CollectionUtils.combine(exps, equals, notEquals, inequalities, ranges)) : and;
}