Skip to content

Commit 97adb4b

Browse files
Marios Trivyzasmatriv
Marios Trivyzas
authored andcommitted
SQL: Introduce IsNull node to simplify expressions (elastic#35206)
Add `IsNull` node in parser to simplify expressions so that `<value> IS NULL` is no longer translated internally to `NOT(<value> IS NOT NULL)` Replace `IsNotNullProcessor` with `CheckNullProcessor` to encapsulate both isNull and isNotNull functionality. Closes: elastic#34876 Fixes: elastic#35171
1 parent 58d3c70 commit 97adb4b

File tree

30 files changed

+443
-122
lines changed

30 files changed

+443
-122
lines changed

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/Expressions.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ public static boolean anyMatch(List<? extends Expression> exps, Predicate<? supe
7171

7272
public static boolean nullable(List<? extends Expression> exps) {
7373
for (Expression exp : exps) {
74-
if (!exp.nullable()) {
75-
return false;
74+
if (exp.nullable()) {
75+
return true;
7676
}
7777
}
78-
return true;
78+
return false;
7979
}
8080

8181
public static boolean foldable(List<? extends Expression> exps) {

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Processors.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
import org.elasticsearch.xpack.sql.expression.gen.processor.ConstantProcessor;
2626
import org.elasticsearch.xpack.sql.expression.gen.processor.HitExtractorProcessor;
2727
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
28-
import org.elasticsearch.xpack.sql.expression.predicate.IsNotNullProcessor;
2928
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor;
3029
import org.elasticsearch.xpack.sql.expression.predicate.logical.NotProcessor;
30+
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor;
3131
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor;
3232
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor;
3333
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor;
@@ -58,7 +58,7 @@ public static List<NamedWriteableRegistry.Entry> getNamedWriteables() {
5858
entries.add(new Entry(Processor.class, BinaryLogicProcessor.NAME, BinaryLogicProcessor::new));
5959
entries.add(new Entry(Processor.class, NotProcessor.NAME, NotProcessor::new));
6060
// null
61-
entries.add(new Entry(Processor.class, IsNotNullProcessor.NAME, IsNotNullProcessor::new));
61+
entries.add(new Entry(Processor.class, CheckNullProcessor.NAME, CheckNullProcessor::new));
6262

6363
// arithmetic
6464
entries.add(new Entry(Processor.class, BinaryArithmeticProcessor.NAME, BinaryArithmeticProcessor::new));

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/whitelist/InternalSqlScriptUtils.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ReplaceFunctionProcessor;
2222
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor.StringOperation;
2323
import org.elasticsearch.xpack.sql.expression.function.scalar.string.SubstringFunctionProcessor;
24-
import org.elasticsearch.xpack.sql.expression.predicate.IsNotNullProcessor;
2524
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
2625
import org.elasticsearch.xpack.sql.expression.predicate.logical.NotProcessor;
26+
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation;
2727
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
2828
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.UnaryArithmeticProcessor.UnaryArithmeticOperation;
2929
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation;
@@ -116,8 +116,12 @@ public static Boolean not(Boolean expression) {
116116
return NotProcessor.apply(expression);
117117
}
118118

119-
public static Boolean notNull(Object expression) {
120-
return IsNotNullProcessor.apply(expression);
119+
public static Boolean isNull(Object expression) {
120+
return CheckNullOperation.IS_NULL.apply(expression);
121+
}
122+
123+
public static Boolean isNotNull(Object expression) {
124+
return CheckNullOperation.IS_NOT_NULL.apply(expression);
121125
}
122126

123127
public static Boolean in(Object value, List<Object> values) {

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/BinaryOperator.java

-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
*/
1717
public abstract class BinaryOperator<T, U, R, F extends PredicateBiFunction<T, U, R>> extends BinaryPredicate<T, U, R, F> {
1818

19-
public interface Negateable {
20-
BinaryOperator<?, ?, ?, ?> negate();
21-
}
22-
2319
protected BinaryOperator(Location location, Expression left, Expression right, F function) {
2420
super(location, left, right, function);
2521
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNullProcessor.java

-54
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.sql.expression.predicate;
7+
8+
import org.elasticsearch.xpack.sql.expression.function.scalar.ScalarFunction;
9+
10+
public interface Negatable<T extends ScalarFunction> {
11+
12+
T negate();
13+
14+
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
package org.elasticsearch.xpack.sql.expression.predicate.logical;
77

88
import org.elasticsearch.xpack.sql.expression.Expression;
9-
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable;
9+
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
1010
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
1111
import org.elasticsearch.xpack.sql.tree.Location;
1212
import org.elasticsearch.xpack.sql.tree.NodeInfo;
1313

14-
public class And extends BinaryLogic implements Negateable {
14+
public class And extends BinaryLogic implements Negatable<BinaryLogic> {
1515

1616
public And(Location location, Expression left, Expression right) {
1717
super(location, left, right, BinaryLogicOperation.AND);

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
1212
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
1313
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
14-
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable;
14+
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
1515
import org.elasticsearch.xpack.sql.tree.Location;
1616
import org.elasticsearch.xpack.sql.tree.NodeInfo;
1717
import org.elasticsearch.xpack.sql.type.DataType;
@@ -58,8 +58,8 @@ public String processScript(String script) {
5858
@Override
5959
protected Expression canonicalize() {
6060
Expression canonicalChild = field().canonical();
61-
if (canonicalChild instanceof Negateable) {
62-
return ((Negateable) canonicalChild).negate();
61+
if (canonicalChild instanceof Negatable) {
62+
return ((Negatable) canonicalChild).negate();
6363
}
6464
return this;
6565
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
package org.elasticsearch.xpack.sql.expression.predicate.logical;
77

88
import org.elasticsearch.xpack.sql.expression.Expression;
9-
import org.elasticsearch.xpack.sql.expression.predicate.BinaryOperator.Negateable;
9+
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
1010
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor.BinaryLogicOperation;
1111
import org.elasticsearch.xpack.sql.tree.Location;
1212
import org.elasticsearch.xpack.sql.tree.NodeInfo;
1313

14-
public class Or extends BinaryLogic implements Negateable {
14+
public class Or extends BinaryLogic implements Negatable<BinaryLogic> {
1515

1616
public Or(Location location, Expression left, Expression right) {
1717
super(location, left, right, BinaryLogicOperation.OR);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.sql.expression.predicate.nulls;
7+
8+
import org.elasticsearch.common.io.stream.StreamInput;
9+
import org.elasticsearch.common.io.stream.StreamOutput;
10+
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
11+
12+
import java.io.IOException;
13+
import java.util.Objects;
14+
import java.util.function.Function;
15+
16+
public class CheckNullProcessor implements Processor {
17+
18+
public enum CheckNullOperation implements Function<Object, Boolean> {
19+
20+
IS_NULL(Objects::isNull, "IS NULL"),
21+
IS_NOT_NULL(Objects::nonNull, "IS NOT NULL");
22+
23+
private final Function<Object, Boolean> process;
24+
private final String symbol;
25+
26+
CheckNullOperation(Function<Object, Boolean> process, String symbol) {
27+
this.process = process;
28+
this.symbol = symbol;
29+
}
30+
31+
public String symbol() {
32+
return symbol;
33+
}
34+
35+
@Override
36+
public String toString() {
37+
return symbol;
38+
}
39+
40+
@Override
41+
public Boolean apply(Object o) {
42+
return process.apply(o);
43+
}
44+
}
45+
46+
public static final String NAME = "nckn";
47+
48+
private final CheckNullOperation operation;
49+
50+
CheckNullProcessor(CheckNullOperation operation) {
51+
this.operation = operation;
52+
}
53+
54+
public CheckNullProcessor(StreamInput in) throws IOException {
55+
this(in.readEnum(CheckNullOperation.class));
56+
}
57+
58+
@Override
59+
public String getWriteableName() {
60+
return NAME;
61+
}
62+
63+
@Override
64+
public void writeTo(StreamOutput out) throws IOException {
65+
out.writeEnum(operation);
66+
}
67+
68+
@Override
69+
public Object process(Object input) {
70+
return operation.apply(input);
71+
}
72+
73+
@Override
74+
public boolean equals(Object o) {
75+
if (this == o) {
76+
return true;
77+
}
78+
if (o == null || getClass() != o.getClass()) {
79+
return false;
80+
}
81+
CheckNullProcessor that = (CheckNullProcessor) o;
82+
return operation == that.operation;
83+
}
84+
85+
@Override
86+
public int hashCode() {
87+
return Objects.hash(operation);
88+
}
89+
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/IsNotNull.java renamed to x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/IsNotNull.java

+12-5
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
* or more contributor license agreements. Licensed under the Elastic License;
44
* you may not use this file except in compliance with the Elastic License.
55
*/
6-
package org.elasticsearch.xpack.sql.expression.predicate;
6+
package org.elasticsearch.xpack.sql.expression.predicate.nulls;
77

88
import org.elasticsearch.xpack.sql.expression.Expression;
99
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
1010
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
1111
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
12+
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
13+
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation;
1214
import org.elasticsearch.xpack.sql.tree.Location;
1315
import org.elasticsearch.xpack.sql.tree.NodeInfo;
1416
import org.elasticsearch.xpack.sql.type.DataType;
1517
import org.elasticsearch.xpack.sql.type.DataTypes;
1618

17-
public class IsNotNull extends UnaryScalarFunction {
19+
public class IsNotNull extends UnaryScalarFunction implements Negatable<UnaryScalarFunction> {
1820

1921
public IsNotNull(Location location, Expression field) {
2022
super(location, field);
@@ -37,12 +39,12 @@ public Object fold() {
3739

3840
@Override
3941
protected Processor makeProcessor() {
40-
return IsNotNullProcessor.INSTANCE;
42+
return new CheckNullProcessor(CheckNullOperation.IS_NOT_NULL);
4143
}
4244

4345
@Override
4446
public String processScript(String script) {
45-
return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".notNull(" + script + ")");
47+
return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".isNotNull(" + script + ")");
4648
}
4749

4850
@Override
@@ -54,4 +56,9 @@ public boolean nullable() {
5456
public DataType dataType() {
5557
return DataType.BOOLEAN;
5658
}
57-
}
59+
60+
@Override
61+
public UnaryScalarFunction negate() {
62+
return new IsNull(location(), field());
63+
}
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.sql.expression.predicate.nulls;
7+
8+
import org.elasticsearch.xpack.sql.expression.Expression;
9+
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
10+
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
11+
import org.elasticsearch.xpack.sql.expression.gen.script.Scripts;
12+
import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
13+
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor.CheckNullOperation;
14+
import org.elasticsearch.xpack.sql.tree.Location;
15+
import org.elasticsearch.xpack.sql.tree.NodeInfo;
16+
import org.elasticsearch.xpack.sql.type.DataType;
17+
import org.elasticsearch.xpack.sql.type.DataTypes;
18+
19+
public class IsNull extends UnaryScalarFunction implements Negatable<UnaryScalarFunction> {
20+
21+
public IsNull(Location location, Expression field) {
22+
super(location, field);
23+
}
24+
25+
@Override
26+
protected NodeInfo<IsNull> info() {
27+
return NodeInfo.create(this, IsNull::new, field());
28+
}
29+
30+
@Override
31+
protected IsNull replaceChild(Expression newChild) {
32+
return new IsNull(location(), newChild);
33+
}
34+
35+
@Override
36+
public Object fold() {
37+
return field().fold() == null || DataTypes.isNull(field().dataType());
38+
}
39+
40+
@Override
41+
protected Processor makeProcessor() {
42+
return new CheckNullProcessor(CheckNullOperation.IS_NULL);
43+
}
44+
45+
@Override
46+
public String processScript(String script) {
47+
return Scripts.formatTemplate(Scripts.SQL_SCRIPTS + ".isNull(" + script + ")");
48+
}
49+
50+
@Override
51+
public boolean nullable() {
52+
return false;
53+
}
54+
55+
@Override
56+
public DataType dataType() {
57+
return DataType.BOOLEAN;
58+
}
59+
60+
@Override
61+
public UnaryScalarFunction negate() {
62+
return new IsNotNull(location(), field());
63+
}
64+
}

0 commit comments

Comments
 (0)