From f041419f7459005ec65507fa2d5ec46cbafd6ef0 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Fri, 26 Oct 2018 18:21:14 +0300 Subject: [PATCH] SQL: Provide null-safe scripts for Not and Neg (#34877) Introduce null-safe Painless scripts for Not and Neg Simplify script generation for Unary functions Close #34848 --- .../sql/expression/function/scalar/Cast.java | 9 +-- .../function/scalar/UnaryScalarFunction.java | 12 ++++ .../scalar/datetime/DateTimeFunction.java | 12 ++-- .../datetime/NamedDateTimeFunction.java | 8 +-- .../function/scalar/datetime/Quarter.java | 8 +-- .../function/scalar/math/MathFunction.java | 8 +-- .../scalar/string/UnaryStringFunction.java | 8 +-- .../scalar/string/UnaryStringIntFunction.java | 18 +++--- .../whitelist/InternalSqlScriptUtils.java | 27 +++++++-- .../sql/expression/gen/script/Scripts.java | 12 ++-- .../sql/expression/predicate/IsNotNull.java | 32 ++++------ .../predicate/IsNotNullProcessor.java | 51 ++++++++++++++++ .../logical/BinaryLogicProcessor.java | 4 +- .../sql/expression/predicate/logical/Not.java | 19 +++--- .../predicate/logical/NotProcessor.java | 60 +++++++++++++++++++ .../predicate/operator/arithmetic/Neg.java | 14 ++--- .../xpack/sql/planner/QueryTranslator.java | 43 ++++++++----- .../xpack/sql/plugin/sql_whitelist.txt | 5 +- x-pack/qa/sql/src/main/resources/agg.sql-spec | 7 +++ 19 files changed, 250 insertions(+), 107 deletions(-) create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNullProcessor.java create mode 100644 x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/NotProcessor.java diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Cast.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Cast.java index a8dfe43174911..298039640446e 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Cast.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Cast.java @@ -6,9 +6,7 @@ package org.elasticsearch.xpack.sql.expression.function.scalar; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.NodeInfo; import org.elasticsearch.xpack.sql.type.DataType; @@ -71,9 +69,8 @@ protected TypeResolution resolveType() { } @Override - protected Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), - new CastProcessor(DataTypeConversion.conversionFor(from(), to()))); + protected Processor makeProcessor() { + return new CastProcessor(DataTypeConversion.conversionFor(from(), to())); } @Override diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/UnaryScalarFunction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/UnaryScalarFunction.java index 54fe2e834db02..1b639287a1289 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/UnaryScalarFunction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/UnaryScalarFunction.java @@ -6,6 +6,10 @@ package org.elasticsearch.xpack.sql.expression.function.scalar; import org.elasticsearch.xpack.sql.expression.Expression; +import org.elasticsearch.xpack.sql.expression.Expressions; +import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; +import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; import org.elasticsearch.xpack.sql.tree.Location; @@ -34,12 +38,20 @@ public final UnaryScalarFunction replaceChildren(List newChildren) { } return replaceChild(newChildren.get(0)); } + protected abstract UnaryScalarFunction replaceChild(Expression newChild); public Expression field() { return field; } + @Override + public final Pipe makePipe() { + return new UnaryPipe(location(), this, Expressions.pipe(field()), makeProcessor()); + } + + protected abstract Processor makeProcessor(); + @Override public boolean foldable() { return field.foldable(); diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java index fbb095f2f00b5..8d5a384b1f456 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java @@ -6,11 +6,9 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.datetime; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.FieldAttribute; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; import org.elasticsearch.xpack.sql.tree.Location; @@ -63,13 +61,13 @@ public ScriptTemplate scriptWithField(FieldAttribute field) { */ protected abstract ChronoField chronoField(); + protected abstract DateTimeExtractor extractor(); + @Override - protected Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new DateTimeProcessor(extractor(), timeZone())); + protected Processor makeProcessor() { + return new DateTimeProcessor(extractor(), timeZone()); } - protected abstract DateTimeExtractor extractor(); - @Override public DataType dataType() { return DataType.INTEGER; diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/NamedDateTimeFunction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/NamedDateTimeFunction.java index ed43996fe8e33..a8e6e02057a22 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/NamedDateTimeFunction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/NamedDateTimeFunction.java @@ -6,11 +6,9 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.datetime; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.FieldAttribute; import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.type.DataType; @@ -51,8 +49,8 @@ public ScriptTemplate scriptWithField(FieldAttribute field) { } @Override - protected final Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new NamedDateTimeProcessor(nameExtractor, timeZone())); + protected Processor makeProcessor() { + return new NamedDateTimeProcessor(nameExtractor, timeZone()); } @Override diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/Quarter.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/Quarter.java index c9a1d4ee721aa..51b9501c6eb00 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/Quarter.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/Quarter.java @@ -7,10 +7,8 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.datetime; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.FieldAttribute; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2; @@ -53,8 +51,8 @@ protected Quarter replaceChild(Expression newChild) { } @Override - protected Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new QuarterProcessor(timeZone())); + protected Processor makeProcessor() { + return new QuarterProcessor(timeZone()); } @Override diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunction.java index 4b7ed1e74429a..cd37e539bfcd9 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunction.java @@ -6,11 +6,9 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.math; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.type.DataType; @@ -64,8 +62,8 @@ protected TypeResolution resolveType() { } @Override - protected final Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new MathProcessor(operation())); + protected Processor makeProcessor() { + return new MathProcessor(operation()); } protected abstract MathOperation operation(); diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringFunction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringFunction.java index d387fe7e4a1bf..af9bd05fd15cc 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringFunction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringFunction.java @@ -6,12 +6,10 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.string; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.FieldAttribute; import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor.StringOperation; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.util.StringUtils; @@ -49,8 +47,8 @@ protected TypeResolution resolveType() { } @Override - protected final Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new StringProcessor(operation())); + protected Processor makeProcessor() { + return new StringProcessor(operation()); } protected abstract StringOperation operation(); diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringIntFunction.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringIntFunction.java index 613b37dd7e8b5..0753af03f147f 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringIntFunction.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringIntFunction.java @@ -6,12 +6,10 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.string; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.FieldAttribute; import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor.StringOperation; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; import org.elasticsearch.xpack.sql.tree.Location; @@ -51,8 +49,8 @@ protected TypeResolution resolveType() { } @Override - protected final Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new StringProcessor(operation())); + protected Processor makeProcessor() { + return new StringProcessor(operation()); } protected abstract StringOperation operation(); @@ -72,6 +70,11 @@ public String processScript(String template) { template)); } + @Override + public int hashCode() { + return Objects.hash(field()); + } + @Override public boolean equals(Object obj) { if (obj == null || obj.getClass() != getClass()) { @@ -80,9 +83,4 @@ public boolean equals(Object obj) { UnaryStringIntFunction other = (UnaryStringIntFunction) obj; return Objects.equals(other.field(), field()); } - - @Override - public int hashCode() { - return Objects.hash(field()); - } } \ No newline at end of file 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 c6f445c0590e6..9aabb3f10ecdc 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 @@ -21,8 +21,11 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.ReplaceFunctionProcessor; import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor.StringOperation; import org.elasticsearch.xpack.sql.expression.function.scalar.string.SubstringFunctionProcessor; +import org.elasticsearch.xpack.sql.expression.predicate.IsNotNullProcessor; import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation; +import org.elasticsearch.xpack.sql.expression.predicate.logical.NotProcessor; import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation; +import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor.UnaryArithmeticOperation; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation; import org.elasticsearch.xpack.sql.expression.predicate.regex.RegexProcessor.RegexOperation; import org.elasticsearch.xpack.sql.util.StringUtils; @@ -102,6 +105,14 @@ public static Boolean or(Boolean left, Boolean right) { return BinaryLogicOperation.OR.apply(left, right); } + public static Boolean not(Boolean expression) { + return NotProcessor.apply(expression); + } + + public static Boolean notNull(Object expression) { + return IsNotNullProcessor.apply(expression); + } + // // Regex // @@ -116,20 +127,24 @@ public static Number add(Number left, Number right) { return BinaryArithmeticOperation.ADD.apply(left, right); } - public static Number sub(Number left, Number right) { - return BinaryArithmeticOperation.SUB.apply(left, right); + public static Number div(Number left, Number right) { + return BinaryArithmeticOperation.DIV.apply(left, right); + } + + public static Number mod(Number left, Number right) { + return BinaryArithmeticOperation.MOD.apply(left, right); } public static Number mul(Number left, Number right) { return BinaryArithmeticOperation.MUL.apply(left, right); } - public static Number div(Number left, Number right) { - return BinaryArithmeticOperation.DIV.apply(left, right); + public static Number neg(Number value) { + return UnaryArithmeticOperation.NEGATE.apply(value); } - public static Number mod(Number left, Number right) { - return BinaryArithmeticOperation.MOD.apply(left, right); + public static Number sub(Number left, Number right) { + return BinaryArithmeticOperation.SUB.apply(left, right); } public static Number round(Number v, Number s) { diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/gen/script/Scripts.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/gen/script/Scripts.java index 69ad3661dc5bb..f9e2588a9c035 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/gen/script/Scripts.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/gen/script/Scripts.java @@ -24,12 +24,16 @@ public final class Scripts { + public static final String DOC_VALUE = "doc[{}].value"; + public static final String SQL_SCRIPTS = "{sql}"; + public static final String PARAM = "{}"; + private Scripts() {} private static final Map FORMATTING_PATTERNS = Collections.unmodifiableMap(Stream.of( - new SimpleEntry<>("doc[{}].value", "{sql}.docValue(doc,{})"), - new SimpleEntry<>("{sql}", InternalSqlScriptUtils.class.getSimpleName()), - new SimpleEntry<>("{}", "params.%s")) + new SimpleEntry<>(DOC_VALUE, SQL_SCRIPTS + ".docValue(doc,{})"), + new SimpleEntry<>(SQL_SCRIPTS, InternalSqlScriptUtils.class.getSimpleName()), + new SimpleEntry<>(PARAM, "params.%s")) .collect(toMap(e -> Pattern.compile(e.getKey(), Pattern.LITERAL), Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new))); /** @@ -83,4 +87,4 @@ public static ScriptTemplate binaryMethod(String methodName, ScriptTemplate left .build(), dataType); } -} +} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNull.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNull.java index cabca2aaf2dd6..bd3fd5bf0811b 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNull.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNull.java @@ -5,25 +5,24 @@ */ package org.elasticsearch.xpack.sql.expression.predicate; -import org.elasticsearch.xpack.sql.SqlIllegalArgumentException; import org.elasticsearch.xpack.sql.expression.Expression; -import org.elasticsearch.xpack.sql.expression.UnaryExpression; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; +import org.elasticsearch.xpack.sql.expression.gen.script.Scripts; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.NodeInfo; import org.elasticsearch.xpack.sql.type.DataType; import org.elasticsearch.xpack.sql.type.DataTypes; -public class IsNotNull extends UnaryExpression { +public class IsNotNull extends UnaryScalarFunction { - public IsNotNull(Location location, Expression child) { - super(location, child); + public IsNotNull(Location location, Expression field) { + super(location, field); } @Override protected NodeInfo info() { - return NodeInfo.create(this, IsNotNull::new, child()); + return NodeInfo.create(this, IsNotNull::new, field()); } @Override @@ -33,17 +32,17 @@ protected IsNotNull replaceChild(Expression newChild) { @Override public Object fold() { - return child().fold() != null && !DataTypes.isNull(child().dataType()); + return field().fold() != null && !DataTypes.isNull(field().dataType()); } @Override - protected Pipe makePipe() { - throw new SqlIllegalArgumentException("Not supported yet"); + protected Processor makeProcessor() { + return IsNotNullProcessor.INSTANCE; } @Override - public ScriptTemplate asScript() { - throw new SqlIllegalArgumentException("Not supported yet"); + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".notNull(" + script + ")"); } @Override @@ -55,9 +54,4 @@ public boolean nullable() { public DataType dataType() { return DataType.BOOLEAN; } - - @Override - public String toString() { - return child().toString() + " IS NOT NULL"; - } -} +} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNullProcessor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNullProcessor.java new file mode 100644 index 0000000000000..b29ae263f3907 --- /dev/null +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNullProcessor.java @@ -0,0 +1,51 @@ +/* + * 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; + +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; + +import java.io.IOException; + +public class IsNotNullProcessor implements Processor { + + static final IsNotNullProcessor INSTANCE = new IsNotNullProcessor(); + + public static final String NAME = "inn"; + + private IsNotNullProcessor() {} + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException {} + + @Override + public Object process(Object input) { + return apply(input); + } + + public static Boolean apply(Object input) { + return input != null ? Boolean.TRUE : Boolean.FALSE; + } + + @Override + public int hashCode() { + return IsNotNullProcessor.class.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + return obj == null || getClass() != obj.getClass(); + } +} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/BinaryLogicProcessor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/BinaryLogicProcessor.java index 7e3aef2b8c721..334a80b7d578d 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/BinaryLogicProcessor.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/BinaryLogicProcessor.java @@ -26,7 +26,7 @@ public enum BinaryLogicOperation implements PredicateBiFunction { if (Boolean.TRUE.equals(l) || Boolean.TRUE.equals(r)) { @@ -35,7 +35,7 @@ public enum BinaryLogicOperation implements PredicateBiFunction process; diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/Not.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/Not.java index 48a307fa0621a..55115ffb4df11 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/Not.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/Not.java @@ -5,19 +5,16 @@ */ package org.elasticsearch.xpack.sql.expression.predicate.logical; -import org.elasticsearch.xpack.sql.SqlIllegalArgumentException; import org.elasticsearch.xpack.sql.expression.Expression; import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; +import org.elasticsearch.xpack.sql.expression.gen.script.Scripts; import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.NodeInfo; import org.elasticsearch.xpack.sql.type.DataType; -import java.util.Objects; - public class Not extends UnaryScalarFunction { public Not(Location location, Expression child) { @@ -45,17 +42,17 @@ protected TypeResolution resolveType() { @Override public Object fold() { - return Objects.equals(field().fold(), Boolean.TRUE) ? Boolean.FALSE : Boolean.TRUE; + return NotProcessor.INSTANCE.process(field().fold()); } @Override - protected Pipe makePipe() { - throw new SqlIllegalArgumentException("Not supported yet"); + protected Processor makeProcessor() { + return NotProcessor.INSTANCE; } @Override - public ScriptTemplate asScript() { - throw new SqlIllegalArgumentException("Not supported yet"); + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".not(" + script + ")"); } @Override @@ -71,4 +68,4 @@ protected Expression canonicalize() { public DataType dataType() { return DataType.BOOLEAN; } -} +} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/NotProcessor.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/NotProcessor.java new file mode 100644 index 0000000000000..14425d35578ac --- /dev/null +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/NotProcessor.java @@ -0,0 +1,60 @@ +/* + * 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.logical; + +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.xpack.sql.SqlIllegalArgumentException; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; + +import java.io.IOException; + +public class NotProcessor implements Processor { + + static final NotProcessor INSTANCE = new NotProcessor(); + + public static final String NAME = "ln"; + + private NotProcessor() {} + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException {} + + @Override + public Object process(Object input) { + return apply(input); + } + + public static Boolean apply(Object input) { + if (input == null) { + return null; + } + + if (!(input instanceof Boolean)) { + throw new SqlIllegalArgumentException("A boolean is required; received {}", input); + } + + return ((Boolean) input).booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + @Override + public int hashCode() { + return NotProcessor.class.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + return obj == null || getClass() != obj.getClass(); + } +} \ No newline at end of file diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/Neg.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/Neg.java index c5758b787f0ff..47ea773f514fa 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/Neg.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/Neg.java @@ -9,9 +9,9 @@ import org.elasticsearch.xpack.sql.expression.Expressions; import org.elasticsearch.xpack.sql.expression.NamedExpression; import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe; -import org.elasticsearch.xpack.sql.expression.gen.pipeline.UnaryPipe; +import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.script.ScriptWeaver; +import org.elasticsearch.xpack.sql.expression.gen.script.Scripts; import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor.UnaryArithmeticOperation; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.NodeInfo; @@ -57,12 +57,12 @@ public String name() { } @Override - public String processScript(String template) { - return super.processScript("-" + template); + public String processScript(String script) { + return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".neg(" + script + ")"); } @Override - protected Pipe makePipe() { - return new UnaryPipe(location(), this, Expressions.pipe(field()), new UnaryArithmeticProcessor(UnaryArithmeticOperation.NEGATE)); + protected Processor makeProcessor() { + return new UnaryArithmeticProcessor(UnaryArithmeticOperation.NEGATE); } -} +} \ No newline at end of file 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 453660f07da8a..9fcd542ef631d 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 @@ -13,7 +13,6 @@ import org.elasticsearch.xpack.sql.expression.FieldAttribute; import org.elasticsearch.xpack.sql.expression.Literal; import org.elasticsearch.xpack.sql.expression.NamedExpression; -import org.elasticsearch.xpack.sql.expression.UnaryExpression; import org.elasticsearch.xpack.sql.expression.function.Function; import org.elasticsearch.xpack.sql.expression.function.Functions; import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunction; @@ -354,11 +353,6 @@ static Query or(Location loc, Query left, Query right) { return new BoolQuery(loc, false, left, right); } - static Query not(Query query) { - Check.isTrue(query != null, "Expressions is null"); - return new NotQuery(query.location(), query); - } - static String nameOf(Expression e) { if (e instanceof DateTimeFunction) { return nameOf(((DateTimeFunction) e).field()); @@ -484,20 +478,41 @@ static class Nots extends ExpressionTranslator { @Override protected QueryTranslation asQuery(Not not, boolean onAggs) { - QueryTranslation translation = toQuery(not.field(), onAggs); - return new QueryTranslation(not(translation.query), translation.aggFilter); + Query query = null; + AggFilter aggFilter = null; + + if (onAggs) { + aggFilter = new AggFilter(not.id().toString(), not.asScript()); + } else { + query = new NotQuery(not.location(), toQuery(not.field(), false).query); + // query directly on the field + if (not.field() instanceof FieldAttribute) { + query = wrapIfNested(query, not.field()); + } + } + + return new QueryTranslation(query, aggFilter); } } - static class Nulls extends ExpressionTranslator { + static class Nulls extends ExpressionTranslator { @Override - protected QueryTranslation asQuery(UnaryExpression ue, boolean onAggs) { - // TODO: handle onAggs - missing bucket aggregation - if (ue instanceof IsNotNull) { - return new QueryTranslation(new ExistsQuery(ue.location(), nameOf(ue.child()))); + protected QueryTranslation asQuery(IsNotNull inn, boolean onAggs) { + Query query = null; + AggFilter aggFilter = null; + + if (onAggs) { + aggFilter = new AggFilter(inn.id().toString(), inn.asScript()); + } else { + query = new ExistsQuery(inn.location(), nameOf(inn.field())); + // query directly on the field + if (inn.field() instanceof NamedExpression) { + query = wrapIfNested(query, inn.field()); + } } - return null; + + return new QueryTranslation(query, aggFilter); } } 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 ea229940193a3..998dab84783f0 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 @@ -29,7 +29,9 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS # Logical # Boolean and(Boolean, Boolean) - Boolean or(Boolean, Boolean) + Boolean or(Boolean, Boolean) + Boolean not(Boolean) + Boolean notNull(Object) # # Regex @@ -43,6 +45,7 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS Number div(Number, Number) Number mod(Number, Number) Number mul(Number, Number) + Number neg(Number) Number sub(Number, Number) Number round(Number, Number) Number truncate(Number, Number) 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 dab4c386a55ba..2fafb75d69bb5 100644 --- a/x-pack/qa/sql/src/main/resources/agg.sql-spec +++ b/x-pack/qa/sql/src/main/resources/agg.sql-spec @@ -456,6 +456,13 @@ selectHireDateGroupByHireDate SELECT hire_date HD, COUNT(*) c FROM test_emp GROUP BY hire_date ORDER BY hire_date DESC; selectSalaryGroupBySalary SELECT salary, COUNT(*) c FROM test_emp GROUP BY salary ORDER BY salary DESC; +selectLangGroupByLangHavingCountIsNotNull +SELECT languages, COUNT(*) c FROM test_emp GROUP BY languages HAVING COUNT(*) IS NOT NULL ORDER BY languages DESC; +selectLangGroupByLangHavingNotEquality +SELECT languages, COUNT(*) c FROM test_emp GROUP BY languages HAVING NOT COUNT(*) = 1 ORDER BY languages DESC; +selectLangGroupByLangHavingDifferent +SELECT languages, COUNT(*) c FROM test_emp GROUP BY languages HAVING COUNT(*) <> 1 ORDER BY languages DESC; + // filter with IN aggMultiWithHavingUsingInAndNullHandling