SQL: Implement NULLIF(expr1, expr2) function (#35826)
NULLIF returns null if the 2 expressions are equal or the expr1 otherwise. Closes: #35818
This commit is contained in:
parent
51d2e986c5
commit
410f570d5f
|
@ -155,3 +155,38 @@ include-tagged::{sql-specs}/docs.csv-spec[nvlReturnFirst]
|
|||
----
|
||||
include-tagged::{sql-specs}/docs.csv-spec[nvlReturnSecond]
|
||||
----
|
||||
|
||||
|
||||
[[sql-functions-conditional-nullif]]
|
||||
==== `NULLIF`
|
||||
|
||||
.Synopsis
|
||||
[source, sql]
|
||||
----
|
||||
NULLIF ( expression<1>, expression<2> )
|
||||
----
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> 1st expression
|
||||
|
||||
<2> 2nd expression
|
||||
|
||||
|
||||
*Output*: `null` if the 2 expressions are equal, otherwise the 1st expression.
|
||||
|
||||
.Description
|
||||
|
||||
Returns `null` when the two input expressions are equal and
|
||||
if not, it returns the 1st expression.
|
||||
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
----
|
||||
include-tagged::{sql-specs}/docs.csv-spec[nullIfReturnFirst]
|
||||
----
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
----
|
||||
include-tagged::{sql-specs}/docs.csv-spec[nullIfReturnNull]
|
||||
----
|
||||
|
|
|
@ -23,6 +23,7 @@ COALESCE |CONDITIONAL
|
|||
IFNULL |CONDITIONAL
|
||||
ISNULL |CONDITIONAL
|
||||
NVL |CONDITIONAL
|
||||
NULLIF |CONDITIONAL
|
||||
DAY |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
|
|
|
@ -200,6 +200,7 @@ COALESCE |CONDITIONAL
|
|||
IFNULL |CONDITIONAL
|
||||
ISNULL |CONDITIONAL
|
||||
NVL |CONDITIONAL
|
||||
NULLIF |CONDITIONAL
|
||||
DAY |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
|
@ -1597,3 +1598,24 @@ SELECT NVL(null, 'search') AS "nvl";
|
|||
search
|
||||
// end::nvlReturnSecond
|
||||
;
|
||||
|
||||
|
||||
nullIfReturnFirst
|
||||
// tag::nullIfReturnFirst
|
||||
SELECT NULLIF('elastic', 'search') AS "nullif";
|
||||
nullif
|
||||
---------------
|
||||
elastic
|
||||
// end::nullIfReturnFirst
|
||||
;
|
||||
|
||||
|
||||
nullIfReturnNull
|
||||
// tag::nullIfReturnNull
|
||||
SELECT NULLIF('elastic', 'elastic') AS "nullif";
|
||||
|
||||
nullif:s
|
||||
---------------
|
||||
null
|
||||
// end::nullIfReturnNull
|
||||
;
|
||||
|
|
|
@ -12,4 +12,13 @@ coalesceWhere
|
|||
SELECT COALESCE(null, ABS(emp_no) + 1, 123) AS c FROM test_emp WHERE COALESCE(null, ABS(emp_no) + 1, 123, 321) > 100 ORDER BY emp_no NULLS FIRST LIMIT 5;
|
||||
|
||||
ifNullField
|
||||
SELECT IFNULL(null, ABS(emp_no) + 1) AS c FROM test_emp ORDER BY emp_no LIMIT 5;
|
||||
SELECT IFNULL(null, ABS(emp_no) + 1) AS "ifnull" FROM test_emp ORDER BY emp_no LIMIT 5;
|
||||
|
||||
nullIfField
|
||||
SELECT NULLIF(emp_no - 2 + 3, ABS(emp_no) + 1) AS "nullif1", NULLIF(emp_no + 1, emp_no - 1) as "nullif2" FROM test_emp ORDER BY emp_no LIMIT 5;
|
||||
|
||||
nullIfWhere
|
||||
SELECT NULLIF(10002, ABS(emp_no) + 1) AS c, emp_no FROM test_emp WHERE NULLIF(10003, ABS(emp_no) + 1) IS NOT NULL ORDER BY emp_no NULLS FIRST LIMIT 5;
|
||||
|
||||
nullIfHaving
|
||||
SELECT NULLIF(10030, ABS(MAX(emp_no)) + 1) AS nif FROM test_emp GROUP BY languages HAVING nif IS NOT NULL ORDER BY languages;
|
||||
|
|
|
@ -83,7 +83,8 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.Space;
|
|||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Substring;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.UCase;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.Coalesce;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IFNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IfNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIf;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Mod;
|
||||
import org.elasticsearch.xpack.sql.parser.ParsingException;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
|
@ -93,11 +94,13 @@ import org.elasticsearch.xpack.sql.util.StringUtils;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -108,6 +111,15 @@ import static java.util.Collections.unmodifiableList;
|
|||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class FunctionRegistry {
|
||||
|
||||
private static final Set<String> EXCLUDE_FROM_NAME_NORMALIZATION = new HashSet<>();
|
||||
|
||||
static {
|
||||
EXCLUDE_FROM_NAME_NORMALIZATION.add(IfNull.class.getSimpleName());
|
||||
EXCLUDE_FROM_NAME_NORMALIZATION.add(NullIf.class.getSimpleName());
|
||||
}
|
||||
|
||||
|
||||
// list of functions grouped by type of functions (aggregate, statistics, math etc) and ordered alphabetically inside each group
|
||||
// a single function will have one entry for itself with its name associated to its instance and, also, one entry for each alias
|
||||
// it has with the alias name associated to the FunctionDefinition instance
|
||||
|
@ -146,7 +158,8 @@ public class FunctionRegistry {
|
|||
// Scalar functions
|
||||
// conditional
|
||||
addToMap(def(Coalesce.class, Coalesce::new));
|
||||
addToMap(def(IFNull.class, IFNull::new, "ISNULL", "NVL"));
|
||||
addToMap(def(IfNull.class, IfNull::new, "ISNULL", "NVL"));
|
||||
addToMap(def(NullIf.class, NullIf::new));
|
||||
// Date
|
||||
addToMap(def(DayName.class, DayName::new, "DAYNAME"),
|
||||
def(DayOfMonth.class, DayOfMonth::new, "DAYOFMONTH", "DAY", "DOM"),
|
||||
|
@ -485,7 +498,11 @@ public class FunctionRegistry {
|
|||
}
|
||||
|
||||
private static String normalize(String name) {
|
||||
// translate CamelCase to camel_case
|
||||
if (EXCLUDE_FROM_NAME_NORMALIZATION.contains(name)) {
|
||||
return name.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
// translate CamelCase to CAMEL_CASE
|
||||
return StringUtils.camelCaseToUnderscore(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.elasticsearch.xpack.sql.expression.gen.processor.ConstantProcessor;
|
|||
import org.elasticsearch.xpack.sql.expression.gen.processor.HitExtractorProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.CoalesceProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIfProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.BinaryLogicProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.NotProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.nulls.CheckNullProcessor;
|
||||
|
@ -61,6 +62,7 @@ public final class Processors {
|
|||
// null
|
||||
entries.add(new Entry(Processor.class, CheckNullProcessor.NAME, CheckNullProcessor::new));
|
||||
entries.add(new Entry(Processor.class, CoalesceProcessor.NAME, CoalesceProcessor::new));
|
||||
entries.add(new Entry(Processor.class, NullIfProcessor.NAME, NullIfProcessor::new));
|
||||
|
||||
// arithmetic
|
||||
entries.add(new Entry(Processor.class, BinaryArithmeticProcessor.NAME, BinaryArithmeticProcessor::new));
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.SubstringFu
|
|||
import org.elasticsearch.xpack.sql.expression.literal.IntervalDayTime;
|
||||
import org.elasticsearch.xpack.sql.expression.literal.IntervalYearMonth;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.CoalesceProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIfProcessor;
|
||||
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.nulls.CheckNullProcessor.CheckNullOperation;
|
||||
|
@ -142,6 +143,10 @@ public final class InternalSqlScriptUtils {
|
|||
return CoalesceProcessor.apply(expressions);
|
||||
}
|
||||
|
||||
public static Object nullif(Object left, Object right) {
|
||||
return NullIfProcessor.apply(left, right);
|
||||
}
|
||||
|
||||
//
|
||||
// Regex
|
||||
//
|
||||
|
|
|
@ -15,22 +15,20 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* Variant of {@link Coalesce} with two args used by MySQL and ODBC.
|
||||
*
|
||||
* Name is `IFNull` to avoid having it registered as `IF_NULL` instead of `IFNULL`.
|
||||
*/
|
||||
public class IFNull extends Coalesce {
|
||||
public class IfNull extends Coalesce {
|
||||
|
||||
public IFNull(Location location, Expression first, Expression second) {
|
||||
public IfNull(Location location, Expression first, Expression second) {
|
||||
super(location, Arrays.asList(first, second));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression replaceChildren(List<Expression> newChildren) {
|
||||
return new IFNull(location(), newChildren.get(0), newChildren.get(1));
|
||||
return new IfNull(location(), newChildren.get(0), newChildren.get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<IFNull> info() {
|
||||
return NodeInfo.create(this, IFNull::new, children().get(0), children().get(1));
|
||||
protected NodeInfo<IfNull> info() {
|
||||
return NodeInfo.create(this, IfNull::new, children().get(0), children().get(1));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.conditional;
|
||||
|
||||
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.script.ParamsBuilder;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
/**
|
||||
* Accepts 2 arguments of any data type and returns null if they are equal,
|
||||
* and the 1st argument otherwise.
|
||||
*/
|
||||
public class NullIf extends ConditionalFunction {
|
||||
|
||||
private DataType dataType;
|
||||
|
||||
public NullIf(Location location, Expression left, Expression right) {
|
||||
super(location, Arrays.asList(left, right));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<? extends NullIf> info() {
|
||||
return NodeInfo.create(this, NullIf::new, children().get(0), children().get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression replaceChildren(List<Expression> newChildren) {
|
||||
return new NullIf(location(), newChildren.get(0), newChildren.get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeResolution resolveType() {
|
||||
dataType = children().get(0).dataType();
|
||||
return TypeResolution.TYPE_RESOLVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean foldable() {
|
||||
return Expressions.foldable(children());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nullable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fold() {
|
||||
return NullIfProcessor.apply(children().get(0).fold(), children().get(1).fold());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate asScript() {
|
||||
ScriptTemplate left = asScript(children().get(0));
|
||||
ScriptTemplate right = asScript(children().get(1));
|
||||
String template = "{sql}.nullif(" + left.template() + "," + right.template() + ")";
|
||||
ParamsBuilder params = paramsBuilder();
|
||||
params.script(left.params());
|
||||
params.script(right.params());
|
||||
|
||||
return new ScriptTemplate(template, params.build(), dataType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pipe makePipe() {
|
||||
return new NullIfPipe(location(), this,
|
||||
Expressions.pipe(children().get(0)), Expressions.pipe(children().get(1)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.conditional;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.BinaryPipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
|
||||
public class NullIfPipe extends BinaryPipe {
|
||||
|
||||
public NullIfPipe(Location location, Expression expression, Pipe left, Pipe right) {
|
||||
super(location, expression, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BinaryPipe replaceChildren(Pipe left, Pipe right) {
|
||||
return new NullIfPipe(location(), expression(), left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<NullIfPipe> info() {
|
||||
return NodeInfo.create(this, NullIfPipe::new, expression(), children().get(0), children().get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Processor asProcessor() {
|
||||
return new NullIfProcessor(left().asProcessor(), right().asProcessor());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.conditional;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.BinaryComparisonProcessor.BinaryComparisonOperation.EQ;
|
||||
|
||||
public class NullIfProcessor implements Processor {
|
||||
|
||||
public static final String NAME = "nni";
|
||||
|
||||
private final Processor leftProcessor;
|
||||
private final Processor rightProcessor;
|
||||
|
||||
|
||||
public NullIfProcessor(Processor leftProcessor, Processor rightProcessor) {
|
||||
this.leftProcessor = leftProcessor;
|
||||
this.rightProcessor = rightProcessor;
|
||||
}
|
||||
|
||||
public NullIfProcessor(StreamInput in) throws IOException {
|
||||
leftProcessor = in.readNamedWriteable(Processor.class);
|
||||
rightProcessor = in.readNamedWriteable(Processor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeNamedWriteable(leftProcessor);
|
||||
out.writeNamedWriteable(rightProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object process(Object input) {
|
||||
Object leftValue = leftProcessor.process(input);
|
||||
Object rightValue = rightProcessor.process(input);
|
||||
return apply(leftValue, rightValue);
|
||||
}
|
||||
|
||||
public static Object apply(Object leftValue, Object rightValue) {
|
||||
if (EQ.apply(leftValue, rightValue) == Boolean.TRUE) {
|
||||
return null;
|
||||
}
|
||||
return leftValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
NullIfProcessor that = (NullIfProcessor) o;
|
||||
return Objects.equals(leftProcessor, that.leftProcessor) &&
|
||||
Objects.equals(rightProcessor, that.rightProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(leftProcessor, rightProcessor);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ import org.elasticsearch.xpack.sql.expression.predicate.Negatable;
|
|||
import org.elasticsearch.xpack.sql.expression.predicate.Predicates;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.Range;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.Coalesce;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIf;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
|
@ -1172,6 +1173,9 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||
return Literal.of(in, null);
|
||||
}
|
||||
|
||||
} else if (e instanceof NullIf) {
|
||||
return e;
|
||||
|
||||
} else if (e.nullable() && Expressions.anyMatch(e.children(), Expressions::isNull)) {
|
||||
return Literal.of(e, null);
|
||||
}
|
||||
|
@ -1229,6 +1233,7 @@ public class Optimizer extends RuleExecutor<LogicalPlan> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static class BooleanSimplification extends OptimizerExpressionRule {
|
||||
|
||||
BooleanSimplification() {
|
||||
|
|
|
@ -46,6 +46,7 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS
|
|||
# Null
|
||||
#
|
||||
Object coalesce(java.util.List)
|
||||
Object nullif(Object, Object)
|
||||
|
||||
#
|
||||
# Regex
|
||||
|
|
|
@ -37,7 +37,8 @@ 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.Range;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.Coalesce;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IFNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IfNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.NullIf;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.And;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Not;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.logical.Or;
|
||||
|
@ -450,21 +451,27 @@ public class OptimizerTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testSimplifyIfNullNulls() {
|
||||
Expression e = new SimplifyCoalesce().rule(new IFNull(EMPTY, Literal.NULL, Literal.NULL));
|
||||
Expression e = new SimplifyCoalesce().rule(new IfNull(EMPTY, Literal.NULL, Literal.NULL));
|
||||
assertEquals(Coalesce.class, e.getClass());
|
||||
assertEquals(0, e.children().size());
|
||||
}
|
||||
|
||||
public void testSimplifyIfNullWithNullAndValue() {
|
||||
Expression e = new SimplifyCoalesce().rule(new IFNull(EMPTY, Literal.NULL, ONE));
|
||||
Expression e = new SimplifyCoalesce().rule(new IfNull(EMPTY, Literal.NULL, ONE));
|
||||
assertEquals(1, e.children().size());
|
||||
assertEquals(ONE, e.children().get(0));
|
||||
|
||||
e = new SimplifyCoalesce().rule(new IFNull(EMPTY, ONE, Literal.NULL));
|
||||
e = new SimplifyCoalesce().rule(new IfNull(EMPTY, ONE, Literal.NULL));
|
||||
assertEquals(1, e.children().size());
|
||||
assertEquals(ONE, e.children().get(0));
|
||||
}
|
||||
|
||||
public void testFoldNullNotAppliedOnNullIf() {
|
||||
Expression orig = new NullIf(EMPTY, ONE, Literal.NULL);
|
||||
Expression f = new FoldNull().rule(orig);
|
||||
assertEquals(orig, f);
|
||||
}
|
||||
|
||||
//
|
||||
// Logical simplifications
|
||||
//
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.elasticsearch.xpack.sql.expression.gen.pipeline.BinaryPipesTests;
|
|||
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.ConstantProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IFNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.conditional.IfNull;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.In;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.fulltext.FullTextPredicate;
|
||||
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InPipe;
|
||||
|
@ -88,7 +88,7 @@ import static org.mockito.Mockito.mock;
|
|||
public class NodeSubclassTests<T extends B, B extends Node<B>> extends ESTestCase {
|
||||
|
||||
private static final List<Class<? extends Node<?>>> CLASSES_WITH_MIN_TWO_CHILDREN = Arrays.asList(
|
||||
IFNull.class, In.class, InPipe.class, Percentile.class, Percentiles.class, PercentileRanks.class);
|
||||
IfNull.class, In.class, InPipe.class, Percentile.class, Percentiles.class, PercentileRanks.class);
|
||||
|
||||
private final Class<T> subclass;
|
||||
|
||||
|
|
Loading…
Reference in New Issue