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 c3c0da05709..35bc87eabd7 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 @@ -66,7 +66,7 @@ public class Cast extends UnaryScalarFunction { if (from().isNull()) { return Nullability.TRUE; } - return field().nullable(); + return Nullability.UNKNOWN; } @Override diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/CheckNullProcessorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/CheckNullProcessorTests.java index 01b8ba80de2..4ed35e2f9ca 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/CheckNullProcessorTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/predicate/nulls/CheckNullProcessorTests.java @@ -9,15 +9,9 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.xpack.sql.expression.function.scalar.Processors; -import org.elasticsearch.xpack.sql.expression.gen.processor.ConstantProcessor; -import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; public class CheckNullProcessorTests extends AbstractWireSerializingTestCase { - private static final Processor FALSE = new ConstantProcessor(false); - private static final Processor TRUE = new ConstantProcessor(true); - private static final Processor NULL = new ConstantProcessor((Object) null); - public static CheckNullProcessor randomProcessor() { return new CheckNullProcessor(randomFrom(CheckNullProcessor.CheckNullOperation.values())); } diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java index c81b376c0a5..1f45d917dab 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/optimizer/OptimizerTests.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.sql.optimizer; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.sql.SqlIllegalArgumentException; import org.elasticsearch.xpack.sql.analysis.analyzer.Analyzer.PruneSubqueryAliases; import org.elasticsearch.xpack.sql.analysis.index.EsIndex; import org.elasticsearch.xpack.sql.expression.Alias; @@ -438,10 +439,46 @@ public class OptimizerTests extends ESTestCase { assertEquals(false, foldNull.rule(new IsNull(EMPTY, TRUE)).fold()); } + public void testNullFoldingIsNullWithCast() { + FoldNull foldNull = new FoldNull(); + + Cast cast = new Cast(EMPTY, L("foo"), DataType.DATE); + IsNull isNull = new IsNull(EMPTY, cast); + final IsNull isNullOpt = (IsNull) foldNull.rule(isNull); + assertEquals(isNull, isNullOpt); + + SqlIllegalArgumentException sqlIAE = + expectThrows(SqlIllegalArgumentException.class, () -> isNullOpt.asPipe().asProcessor().process(null)); + assertEquals("cannot cast [foo] to [date]: Text 'foo' could not be parsed at index 0", sqlIAE.getMessage()); + + isNull = new IsNull(EMPTY, new Cast(EMPTY, NULL, randomFrom(DataType.values()))); + assertTrue((Boolean) ((IsNull) foldNull.rule(isNull)).asPipe().asProcessor().process(null)); + } + public void testNullFoldingIsNotNull() { FoldNull foldNull = new FoldNull(); assertEquals(true, foldNull.rule(new IsNotNull(EMPTY, TRUE)).fold()); assertEquals(false, foldNull.rule(new IsNotNull(EMPTY, NULL)).fold()); + + Cast cast = new Cast(EMPTY, L("foo"), DataType.DATE); + IsNotNull isNotNull = new IsNotNull(EMPTY, cast); + assertEquals(isNotNull, foldNull.rule(isNotNull)); + } + + public void testNullFoldingIsNotNullWithCast() { + FoldNull foldNull = new FoldNull(); + + Cast cast = new Cast(EMPTY, L("foo"), DataType.DATE); + IsNotNull isNotNull = new IsNotNull(EMPTY, cast); + final IsNotNull isNotNullOpt = (IsNotNull) foldNull.rule(isNotNull); + assertEquals(isNotNull, isNotNullOpt); + + SqlIllegalArgumentException sqlIAE = + expectThrows(SqlIllegalArgumentException.class, () -> isNotNullOpt.asPipe().asProcessor().process(null)); + assertEquals("cannot cast [foo] to [date]: Text 'foo' could not be parsed at index 0", sqlIAE.getMessage()); + + isNotNull = new IsNotNull(EMPTY, new Cast(EMPTY, NULL, randomFrom(DataType.values()))); + assertFalse((Boolean) ((IsNotNull) foldNull.rule(isNotNull)).asPipe().asProcessor().process(null)); } public void testGenericNullableExpression() { @@ -461,6 +498,18 @@ public class OptimizerTests extends ESTestCase { assertNullLiteral(rule.rule(new RLike(EMPTY, NULL, "123"))); } + public void testNullFoldingOnCast() { + FoldNull foldNull = new FoldNull(); + + Cast cast = new Cast(EMPTY, NULL, randomFrom(DataType.values())); + assertEquals(Nullability.TRUE, cast.nullable()); + assertNull(foldNull.rule(cast).fold()); + + cast = new Cast(EMPTY, L("foo"), DataType.DATE); + assertEquals(Nullability.UNKNOWN, cast.nullable()); + assertEquals(cast, foldNull.rule(cast)); + } + public void testNullFoldingDoesNotApplyOnLogicalExpressions() { FoldNull rule = new FoldNull(); @@ -1684,4 +1733,4 @@ public class OptimizerTests extends ESTestCase { gt = (GreaterThan) and.left(); assertEquals(a, gt.left()); } -} \ No newline at end of file +}