Explorar o código

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
Costin Leau %!s(int64=7) %!d(string=hai) anos
pai
achega
5a7b8c0e69
Modificáronse 19 ficheiros con 250 adicións e 107 borrados
  1. 3 6
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Cast.java
  2. 12 0
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/UnaryScalarFunction.java
  3. 5 7
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java
  4. 3 5
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/NamedDateTimeFunction.java
  5. 3 5
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/Quarter.java
  6. 3 5
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/math/MathFunction.java
  7. 3 5
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringFunction.java
  8. 8 10
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/string/UnaryStringIntFunction.java
  9. 21 6
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java
  10. 8 4
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/gen/script/Scripts.java
  11. 13 19
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNull.java
  12. 51 0
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNullProcessor.java
  13. 2 2
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/BinaryLogicProcessor.java
  14. 8 11
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/Not.java
  15. 60 0
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/NotProcessor.java
  16. 7 7
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/operator/arithmetic/Neg.java
  17. 29 14
      x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryTranslator.java
  18. 4 1
      x-pack/plugin/sql/src/main/resources/org/elasticsearch/xpack/sql/plugin/sql_whitelist.txt
  19. 7 0
      x-pack/qa/sql/src/main/resources/agg.sql-spec

+ 3 - 6
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 @@ public class Cast extends UnaryScalarFunction {
     }
 
     @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

+ 12 - 0
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 abstract class UnaryScalarFunction extends ScalarFunction {
         }
         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();

+ 5 - 7
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 abstract class DateTimeFunction extends BaseDateTimeFunction {
      */
     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;

+ 3 - 5
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 @@ abstract class NamedDateTimeFunction extends BaseDateTimeFunction {
     }
 
     @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

+ 3 - 5
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 @@ public class Quarter extends BaseDateTimeFunction {
     }
 
     @Override
-    protected Pipe makePipe() {
-        return new UnaryPipe(location(), this, Expressions.pipe(field()), new QuarterProcessor(timeZone()));
+    protected Processor makeProcessor() {
+        return new QuarterProcessor(timeZone());
     }
 
     @Override

+ 3 - 5
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 @@ public abstract class MathFunction extends UnaryScalarFunction {
     }
 
     @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();

+ 3 - 5
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 @@ public abstract class UnaryStringFunction extends UnaryScalarFunction {
     }
 
     @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();

+ 8 - 10
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 @@ public abstract class UnaryStringIntFunction extends UnaryScalarFunction {
     }
 
     @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 abstract class UnaryStringIntFunction extends UnaryScalarFunction {
                         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 abstract class UnaryStringIntFunction extends UnaryScalarFunction {
         UnaryStringIntFunction other = (UnaryStringIntFunction) obj;
         return Objects.equals(other.field(), field());
     }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(field());
-    }
 }

+ 21 - 6
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.LocateFunct
 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 final class InternalSqlScriptUtils {
         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 final class InternalSqlScriptUtils {
         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) {

+ 8 - 4
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/gen/script/Scripts.java

@@ -24,12 +24,16 @@ import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.pa
 
 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<Pattern, String> 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 final class Scripts {
                     .build(),
                 dataType);
     }
-}
+}

+ 13 - 19
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<IsNotNull> info() {
-        return NodeInfo.create(this, IsNotNull::new, child());
+        return NodeInfo.create(this, IsNotNull::new, field());
     }
 
     @Override
@@ -33,17 +32,17 @@ public class IsNotNull extends UnaryExpression {
 
     @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 class IsNotNull extends UnaryExpression {
     public DataType dataType() {
         return DataType.BOOLEAN;
     }
-
-    @Override
-    public String toString() {
-        return child().toString() + " IS NOT NULL";
-    }
-}
+}

+ 51 - 0
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();
+    }
+}

+ 2 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/logical/BinaryLogicProcessor.java

@@ -26,7 +26,7 @@ public class BinaryLogicProcessor extends FunctionalBinaryProcessor<Boolean, Boo
             if (l == null || r == null) {
                 return null;
             }
-            return l.booleanValue() && r.booleanValue();
+            return Boolean.logicalAnd(l.booleanValue(), r.booleanValue());
         }, "&&"),
         OR((l, r) -> {
             if (Boolean.TRUE.equals(l) || Boolean.TRUE.equals(r)) {
@@ -35,7 +35,7 @@ public class BinaryLogicProcessor extends FunctionalBinaryProcessor<Boolean, Boo
             if (l == null || r == null) {
                 return null;
             }
-            return l.booleanValue() || r.booleanValue();
+            return Boolean.logicalOr(l.booleanValue(), r.booleanValue());
         }, "||");
 
         private final BiFunction<Boolean, Boolean, Boolean> process;

+ 8 - 11
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 @@ public class Not extends UnaryScalarFunction {
 
     @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 @@ public class Not extends UnaryScalarFunction {
     public DataType dataType() {
         return DataType.BOOLEAN;
     }
-}
+}

+ 60 - 0
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();
+    }
+}

+ 7 - 7
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.Expression;
 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 class Neg extends UnaryScalarFunction implements ScriptWeaver {
     }
 
     @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);
     }
-}
+}

+ 29 - 14
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/planner/QueryTranslator.java

@@ -13,7 +13,6 @@ import org.elasticsearch.xpack.sql.expression.Expressions;
 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 @@ final class QueryTranslator {
         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 @@ final class QueryTranslator {
 
         @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<UnaryExpression> {
+    static class Nulls extends ExpressionTranslator<IsNotNull> {
 
         @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);
         }
     }
 

+ 4 - 1
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)

+ 7 - 0
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