From a21316b2629484212ef68652ef2a48355f546f7c Mon Sep 17 00:00:00 2001 From: Marios Trivyzas Date: Mon, 5 Nov 2018 22:23:07 +0100 Subject: [PATCH] SQL: Introduce NotEquals node to simplify expressions (#35234) Add NotEquals node in parser to simplify expressions so that != is no longer translated internally to NOT( = ) Closes: #35210 Fixes: #35233 --- .../whitelist/InternalSqlScriptUtils.java | 7 ++- .../comparison/BinaryComparisonProcessor.java | 3 +- .../operator/comparison/Comparisons.java | 8 ++++ .../predicate/operator/comparison/Equals.java | 8 +++- .../operator/comparison/NotEquals.java | 39 ++++++++++++++++ .../xpack/sql/optimizer/Optimizer.java | 3 +- .../xpack/sql/parser/ExpressionBuilder.java | 3 +- .../xpack/sql/planner/QueryTranslator.java | 21 +++++---- .../xpack/sql/querydsl/query/NotQuery.java | 4 +- .../xpack/sql/plugin/sql_whitelist.txt | 1 + .../BinaryComparisonProcessorTests.java | 24 +++++----- .../xpack/sql/optimizer/OptimizerTests.java | 7 ++- .../xpack/sql/parser/ExpressionTests.java | 18 ++++++++ .../sql/planner/QueryTranslatorTests.java | 2 +- x-pack/qa/sql/src/main/resources/agg.sql-spec | 4 ++ .../sql/src/main/resources/functions.csv-spec | 17 ++----- .../qa/sql/src/main/resources/select.csv-spec | 44 +++++++++++++++++++ 17 files changed, 169 insertions(+), 44 deletions(-) create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/NotEquals.java diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java index 1c2ccfeeb29cb..12b50ff82fca8 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java @@ -40,6 +40,7 @@ * Acts as a registry of the various static methods used internally by the scalar functions * (to simplify the whitelist definition). */ +@SuppressWarnings("unused") public final class InternalSqlScriptUtils { private InternalSqlScriptUtils() {} @@ -52,7 +53,7 @@ private InternalSqlScriptUtils() {} public static Object docValue(Map> doc, String fieldName) { if (doc.containsKey(fieldName)) { ScriptDocValues docValues = doc.get(fieldName); - if (docValues.size() > 0) { + if (!docValues.isEmpty()) { return docValues.get(0); } } @@ -83,6 +84,10 @@ public static Boolean eq(Object left, Object right) { return BinaryComparisonOperation.EQ.apply(left, right); } + public static Boolean neq(Object left, Object right) { + return BinaryComparisonOperation.NEQ.apply(left, right); + } + public static Boolean lt(Object left, Object right) { return BinaryComparisonOperation.LT.apply(left, right); } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessor.java index e33d7b282006d..7c7983cf2c1bb 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessor.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessor.java @@ -19,6 +19,7 @@ public class BinaryComparisonProcessor extends FunctionalBinaryProcessor { EQ(Comparisons::eq, "=="), + NEQ(Comparisons::neq, "!="), GT(Comparisons::gt, ">"), GTE(Comparisons::gte, ">="), LT(Comparisons::lt, "<"), @@ -62,4 +63,4 @@ public BinaryComparisonProcessor(StreamInput in) throws IOException { public String getWriteableName() { return NAME; } -} \ No newline at end of file +} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Comparisons.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Comparisons.java index 79d3f2b318b59..7c45371a24848 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Comparisons.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Comparisons.java @@ -19,6 +19,11 @@ public static Boolean eq(Object l, Object r) { return i == null ? null : i.intValue() == 0; } + static Boolean neq(Object l, Object r) { + Integer i = compare(l, r); + return i == null ? null : i.intValue() != 0; + } + static Boolean lt(Object l, Object r) { Integer i = compare(l, r); return i == null ? null : i.intValue() < 0; @@ -50,6 +55,9 @@ static Boolean in(Object l, Set r) { */ @SuppressWarnings({ "rawtypes", "unchecked" }) static Integer compare(Object l, Object r) { + if (l == null || r == null) { + return null; + } // typical number comparison if (l instanceof Number && r instanceof Number) { return compare((Number) l, (Number) r); diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Equals.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Equals.java index 15dbacafc4add..23b8b879123b3 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Equals.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/Equals.java @@ -6,11 +6,12 @@ package org.elasticsearch.xpack.sql.expression.predicate.operator.comparison; import org.elasticsearch.xpack.sql.expression.Expression; +import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.NodeInfo; -public class Equals extends BinaryComparison { +public class Equals extends BinaryComparison implements BinaryOperator.Negateable { public Equals(Location location, Expression left, Expression right) { super(location, left, right, BinaryComparisonOperation.EQ); @@ -30,4 +31,9 @@ protected Equals replaceChildren(Expression newLeft, Expression newRight) { public Equals swapLeftAndRight() { return new Equals(location(), right(), left()); } + + @Override + public BinaryOperator negate() { + return new NotEquals(location(), left(), right()); + } } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/NotEquals.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/NotEquals.java new file mode 100644 index 0000000000000..41e0a939fbd07 --- /dev/null +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/NotEquals.java @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * 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.sql.expression.Expression; +import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; +import org.elasticsearch.xpack.sql.tree.Location; +import org.elasticsearch.xpack.sql.tree.NodeInfo; + +public class NotEquals extends BinaryComparison implements BinaryOperator.Negateable { + + public NotEquals(Location location, Expression left, Expression right) { + super(location, left, right, BinaryComparisonOperation.NEQ); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, NotEquals::new, left(), right()); + } + + @Override + protected NotEquals replaceChildren(Expression newLeft, Expression newRight) { + return new NotEquals(location(), newLeft, newRight); + } + + @Override + public NotEquals swapLeftAndRight() { + return new NotEquals(location(), right(), left()); + } + + @Override + public BinaryOperator negate() { + return new Equals(location(), left(), right()); + } +} diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/optimizer/Optimizer.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/optimizer/Optimizer.java index e2b8d02589ac0..ca69a53ca86ef 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/optimizer/Optimizer.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/optimizer/Optimizer.java @@ -52,6 +52,7 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThan; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.sql.plan.logical.Aggregate; import org.elasticsearch.xpack.sql.plan.logical.EsRelation; import org.elasticsearch.xpack.sql.plan.logical.Filter; @@ -1313,7 +1314,7 @@ private Expression simplify(BinaryComparison bc) { } // false for equality - if (bc instanceof GreaterThan || bc instanceof LessThan) { + if (bc instanceof NotEquals || bc instanceof GreaterThan || bc instanceof LessThan) { if (!l.nullable() && !r.nullable() && l.semanticEquals(r)) { return FALSE; } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java index 893f71c8bcb1b..5d816d5ff983d 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/ExpressionBuilder.java @@ -44,6 +44,7 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThanOrEqual; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThan; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.sql.expression.predicate.regex.Like; import org.elasticsearch.xpack.sql.expression.predicate.regex.LikePattern; import org.elasticsearch.xpack.sql.expression.predicate.regex.RLike; @@ -165,7 +166,7 @@ public Expression visitComparison(ComparisonContext ctx) { case SqlBaseParser.EQ: return new Equals(loc, left, right); case SqlBaseParser.NEQ: - return new Not(loc, new Equals(loc, left, right)); + return new NotEquals(loc, left, right); case SqlBaseParser.LT: return new LessThan(loc, left, right); case SqlBaseParser.LTE: diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryTranslator.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryTranslator.java index 4e0bdea88b80b..4e98488ea1ee1 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryTranslator.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryTranslator.java @@ -31,7 +31,6 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeHistogramFunction; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.sql.expression.predicate.IsNotNull; import org.elasticsearch.xpack.sql.expression.predicate.Range; import org.elasticsearch.xpack.sql.expression.predicate.fulltext.MatchQueryPredicate; @@ -44,8 +43,10 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThan; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThan; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.sql.expression.predicate.regex.Like; import org.elasticsearch.xpack.sql.expression.predicate.regex.LikePattern; import org.elasticsearch.xpack.sql.expression.predicate.regex.RLike; @@ -536,16 +537,15 @@ protected QueryTranslation asQuery(BinaryComparison bc, boolean onAggs) { // // Agg context means HAVING -> PipelineAggs // - ScriptTemplate script = bc.asScript(); if (onAggs) { - aggFilter = new AggFilter(at.id().toString(), script); + aggFilter = new AggFilter(at.id().toString(), bc.asScript()); } else { // query directly on the field if (at instanceof FieldAttribute) { query = wrapIfNested(translateQuery(bc), ne); } else { - query = new ScriptQuery(at.location(), script); + query = new ScriptQuery(at.location(), bc.asScript()); } } return new QueryTranslation(query, aggFilter); @@ -576,7 +576,7 @@ private static Query translateQuery(BinaryComparison bc) { if (bc instanceof LessThanOrEqual) { return new RangeQuery(loc, name, null, false, value, true, format); } - if (bc instanceof Equals) { + if (bc instanceof Equals || bc instanceof NotEquals) { if (bc.left() instanceof FieldAttribute) { FieldAttribute fa = (FieldAttribute) bc.left(); // equality should always be against an exact match @@ -585,7 +585,11 @@ private static Query translateQuery(BinaryComparison bc) { name = fa.exactAttribute().name(); } } - return new TermQuery(loc, name, value); + Query query = new TermQuery(loc, name, value); + if (bc instanceof NotEquals) { + query = new NotQuery(loc, query); + } + return query; } throw new SqlIllegalArgumentException("Don't know how to translate binary comparison [{}] in [{}]", bc.right().nodeString(), @@ -655,11 +659,10 @@ protected QueryTranslation asQuery(Range r, boolean onAggs) { // // Agg context means HAVING -> PipelineAggs // - ScriptTemplate script = r.asScript(); Attribute at = ((NamedExpression) e).toAttribute(); if (onAggs) { - aggFilter = new AggFilter(at.id().toString(), script); + aggFilter = new AggFilter(at.id().toString(), r.asScript()); } else { // typical range; no scripting involved if (at instanceof FieldAttribute) { @@ -669,7 +672,7 @@ protected QueryTranslation asQuery(Range r, boolean onAggs) { } // scripted query else { - query = new ScriptQuery(at.location(), script); + query = new ScriptQuery(at.location(), r.asScript()); } } return new QueryTranslation(query, aggFilter); diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/NotQuery.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/NotQuery.java index b3d50b8149a43..1e76cb296fed7 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/NotQuery.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/query/NotQuery.java @@ -9,10 +9,10 @@ import org.elasticsearch.search.sort.NestedSortBuilder; import org.elasticsearch.xpack.sql.tree.Location; -import static org.elasticsearch.index.query.QueryBuilders.boolQuery; - import java.util.Objects; +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; + public class NotQuery extends Query { private final Query child; diff --git a/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt b/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt index 827947424b08e..ee46b3fab949a 100644 --- a/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt +++ b/x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt @@ -20,6 +20,7 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS # Comparison # Boolean eq(Object, Object) + Boolean neq(Object, Object) Boolean lt(Object, Object) Boolean lte(Object, Object) Boolean gt(Object, Object) diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java index 0761ec5f2fa21..394818be2408a 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/operator/comparison/BinaryComparisonProcessorTests.java @@ -11,12 +11,6 @@ import org.elasticsearch.xpack.sql.expression.Literal; import org.elasticsearch.xpack.sql.expression.function.scalar.Processors; import org.elasticsearch.xpack.sql.expression.gen.processor.ConstantProcessor; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThan; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThanOrEqual; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThan; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThanOrEqual; import static org.elasticsearch.xpack.sql.tree.Location.EMPTY; @@ -48,6 +42,11 @@ public void testEq() { assertEquals(false, new Equals(EMPTY, l(3), l(4)).makePipe().asProcessor().process(null)); } + public void testNEq() { + assertEquals(false, new NotEquals(EMPTY, l(4), l(4)).makePipe().asProcessor().process(null)); + assertEquals(true, new NotEquals(EMPTY, l(3), l(4)).makePipe().asProcessor().process(null)); + } + public void testGt() { assertEquals(true, new GreaterThan(EMPTY, l(4), l(3)).makePipe().asProcessor().process(null)); assertEquals(false, new GreaterThan(EMPTY, l(3), l(4)).makePipe().asProcessor().process(null)); @@ -73,14 +72,15 @@ public void testLte() { } public void testHandleNull() { - assertNull(new Equals(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); - assertNull(new GreaterThan(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); - assertNull(new GreaterThanOrEqual(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); - assertNull(new LessThan(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); - assertNull(new LessThanOrEqual(EMPTY, l(null), l(3)).makePipe().asProcessor().process(null)); + assertNull(new Equals(EMPTY, Literal.NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(new NotEquals(EMPTY, Literal.NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(new GreaterThan(EMPTY, Literal.NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(new GreaterThanOrEqual(EMPTY, Literal.NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(new LessThan(EMPTY, Literal.NULL, l(3)).makePipe().asProcessor().process(null)); + assertNull(new LessThanOrEqual(EMPTY, Literal.NULL, l(3)).makePipe().asProcessor().process(null)); } private static Literal l(Object value) { return Literal.of(EMPTY, value); } -} \ No newline at end of file +} diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java index 68a0ea9e9490a..8620fc9506631 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java @@ -35,7 +35,6 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.Ascii; import org.elasticsearch.xpack.sql.expression.function.scalar.string.Repeat; import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator; -import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.sql.expression.predicate.IsNotNull; import org.elasticsearch.xpack.sql.expression.predicate.Range; import org.elasticsearch.xpack.sql.expression.predicate.logical.And; @@ -49,8 +48,10 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThan; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.GreaterThanOrEqual; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThan; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.LessThanOrEqual; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.sql.expression.predicate.regex.Like; import org.elasticsearch.xpack.sql.expression.predicate.regex.LikePattern; import org.elasticsearch.xpack.sql.expression.predicate.regex.RLike; @@ -265,6 +266,7 @@ 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.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()); } @@ -406,11 +408,12 @@ public void testGenericNullableExpression() { private void assertNullLiteral(Expression expression) { assertEquals(Literal.class, expression.getClass()); - assertNull(((Literal) expression).fold()); + assertNull(expression.fold()); } public void testBinaryComparisonSimplification() { assertEquals(Literal.TRUE, new BinaryComparisonSimplification().rule(new Equals(EMPTY, FIVE, FIVE))); + 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))); diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/ExpressionTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/ExpressionTests.java index 0ee0c9bcca122..70ff5ac8c0e7d 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/ExpressionTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/parser/ExpressionTests.java @@ -14,6 +14,8 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Mul; import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Neg; import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Sub; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals; +import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.NotEquals; import org.elasticsearch.xpack.sql.type.DataType; import static org.hamcrest.core.StringStartsWith.startsWith; @@ -158,6 +160,22 @@ public void testComplexArithmetic() { assertEquals("2", ((Literal) sub2.children().get(1)).name()); } + public void testEquals() { + Expression expr = parser.createExpression("a = 10"); + assertEquals(Equals.class, expr.getClass()); + Equals eq = (Equals) expr; + assertEquals("(a) == 10", eq.name()); + assertEquals(2, eq.children().size()); + } + + public void testNotEquals() { + Expression expr = parser.createExpression("a != 10"); + assertEquals(NotEquals.class, expr.getClass()); + NotEquals neq = (NotEquals) expr; + assertEquals("(a) != 10", neq.name()); + assertEquals(2, neq.children().size()); + } + public void testCastWithUnquotedDataType() { Expression expr = parser.createExpression("CAST(10*2 AS long)"); assertEquals(Cast.class, expr.getClass()); diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java index 08adeb54356a5..4423887c16135 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/planner/QueryTranslatorTests.java @@ -34,7 +34,7 @@ import java.util.TimeZone; import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.core.StringStartsWith.startsWith; +import static org.hamcrest.Matchers.startsWith; public class QueryTranslatorTests extends ESTestCase { diff --git a/x-pack/qa/sql/src/main/resources/agg.sql-spec b/x-pack/qa/sql/src/main/resources/agg.sql-spec index 9e4748d266f82..9adbe79edc685 100644 --- a/x-pack/qa/sql/src/main/resources/agg.sql-spec +++ b/x-pack/qa/sql/src/main/resources/agg.sql-spec @@ -129,6 +129,10 @@ aggCountAndHaving SELECT gender g, COUNT(*) c FROM "test_emp" GROUP BY g HAVING COUNT(*) > 10 ORDER BY gender; aggCountAndHavingEquality SELECT gender g, COUNT(*) c FROM "test_emp" GROUP BY g HAVING COUNT(*) = 10 ORDER BY gender; +aggCountAndHavingNotEquals +SELECT gender g, COUNT(*) c FROM "test_emp" GROUP BY g HAVING COUNT(*) != 10 ORDER BY gender; +aggCountAndHavingNegateEquality +SELECT gender g, COUNT(*) c FROM "test_emp" GROUP BY g HAVING NOT COUNT(*) = 10 ORDER BY gender; aggCountOnColumnAndHaving SELECT gender g, COUNT(gender) c FROM "test_emp" GROUP BY g HAVING COUNT(gender) > 10 ORDER BY gender; aggCountOnColumnAndWildcardAndHaving diff --git a/x-pack/qa/sql/src/main/resources/functions.csv-spec b/x-pack/qa/sql/src/main/resources/functions.csv-spec index 6e6ccf872b585..930a15f9438a4 100644 --- a/x-pack/qa/sql/src/main/resources/functions.csv-spec +++ b/x-pack/qa/sql/src/main/resources/functions.csv-spec @@ -232,21 +232,13 @@ SELECT POSITION('x',LCASE("first_name")) pos, "first_name" FROM "test_emp" WHERE pos:i | first_name:s ---------------+--------------- 4 |Guoxiang -null |null -null |null -null |null -null |null -null |null -null |null -null |null -null |null -null |null -null |null -1 |Xinglin +1 |Xinglin ; selectPositionWithLcaseAndConditionWithGroupByAndOrderBy -SELECT POSITION('m',LCASE("first_name")), COUNT(*) pos FROM "test_emp" WHERE POSITION('m',LCASE("first_name")) != 0 GROUP BY POSITION('m',LCASE("first_name")) ORDER BY POSITION('m',LCASE("first_name")) DESC; +SELECT POSITION('m',LCASE("first_name")), COUNT(*) pos FROM "test_emp" + WHERE POSITION('m',LCASE("first_name")) != 0 + GROUP BY POSITION('m',LCASE("first_name")) ORDER BY POSITION('m',LCASE("first_name")) DESC; POSITION(m,LCASE(first_name)):i| pos:l -------------------------------+--------------- @@ -256,7 +248,6 @@ POSITION(m,LCASE(first_name)):i| pos:l 3 |6 2 |1 1 |9 -null |10 ; selectInsertWithPositionAndCondition diff --git a/x-pack/qa/sql/src/main/resources/select.csv-spec b/x-pack/qa/sql/src/main/resources/select.csv-spec index 6536c33b55344..50f7c43c39410 100644 --- a/x-pack/qa/sql/src/main/resources/select.csv-spec +++ b/x-pack/qa/sql/src/main/resources/select.csv-spec @@ -1,4 +1,48 @@ +// +// SELECT with = and != +// +equalsSelectClause +SELECT CAST(4 = 4 AS STRING), CAST(NOT 4 = 4 AS STRING), CAST(3 = 4 AS STRING), CAST(NOT 3 = 4 AS STRING), CAST(1 = null AS STRING), CAST(NOT null = 1 AS STRING); + + CAST(4 == 4 AS VARCHAR):s | CAST(NOT(4 == 4) AS VARCHAR):s | CAST(3 == 4 AS VARCHAR):s | CAST(NOT(3 == 4) AS VARCHAR):s | CAST(1 == null AS VARCHAR):s | CAST(NOT(null == 1) AS VARCHAR):s +----------------------------+---------------------------------+----------------------------+---------------------------------+-------------------------------+----------------------------------- +true |false |false |true |null |null +; + +notEqualsSelectClause +SELECT CAST(4 != 4 AS STRING), CAST(NOT 4 != 4 AS STRING), CAST(3 != 4 AS STRING), CAST(NOT 3 != 4 AS STRING), CAST(1 != null AS STRING), CAST(NOT 1 != null AS STRING); + + CAST(4 != 4 AS VARCHAR):s | CAST(NOT(4 != 4) AS VARCHAR):s | CAST(3 != 4 AS VARCHAR):s | CAST(NOT(3 != 4) AS VARCHAR):s | CAST(1 != null AS VARCHAR):s | CAST(NOT(1 != null) AS VARCHAR):s +----------------------------+---------------------------------+----------------------------+---------------------------------+-------------------------------+----------------------------------- +false |true |true |false |null |null +; + +equalSelectClauseWithTableColumns +SELECT CAST(languages = 2 AS STRING), CAST(NOT languages = 2 AS STRING), CAST(languages = null AS STRING), CAST(NOT languages = null AS STRING) +FROM "test_emp" WHERE emp_no IN(10018, 10019, 10020) ORDER BY emp_no; + + CAST((languages) == 2 AS VARCHAR):s | CAST(NOT((languages) == 2) AS VARCHAR):s | CAST((languages) == null AS VARCHAR):s | CAST(NOT((languages) == null) AS VARCHAR):s +--------------------------------------+-------------------------------------------+-----------------------------------------+--------------------------------------------- +true |false |null |null +false |true |null |null +null |null |null |null +; + +notEqualsAndNotEqualsSelectClauseWithTableColumns +SELECT CAST(languages != 2 AS STRING), CAST(NOT languages != 2 AS STRING), CAST(languages != null AS STRING), CAST(NOT languages != null AS STRING) +FROM "test_emp" WHERE emp_no IN(10018, 10019, 10020) ORDER BY emp_no; + + CAST((languages) != 2 AS VARCHAR):s | CAST(NOT((languages) != 2) AS VARCHAR):s | CAST((languages) != null AS VARCHAR):s | CAST(NOT((languages) != null) AS VARCHAR):s +--------------------------------------+-------------------------------------------+-----------------------------------------+--------------------------------------------- +false |true |null |null +true |false |null |null +null |null |null |null +; + + +// // SELECT with IN +// inWithLiterals SELECT 1 IN (1, 2, 3), 1 IN (2, 3);