SQL: Fix issue with DataType for CASE with NULL (#46173)

Previously, if the DataType of all the WHEN conditions of a CASE
statement is NULL, then it was set to NULL even if the ELSE clause
has a non-NULL data type, e.g.:
```
CASE WHEN a = 1 THEN NULL
           WHEN a = 5 THEN NULL
ELSE 'foo'
```

Fixes: #46032
(cherry picked from commit 8c1012efbbd3a300afd0dfb9b18250f15ea753f9)
This commit is contained in:
Marios Trivyzas 2019-09-02 11:16:04 +03:00
parent 5747badaa8
commit 3bee647e5b
No known key found for this signature in database
GPG Key ID: 8817B46B0CF36A3F
2 changed files with 41 additions and 0 deletions

View File

@ -58,6 +58,7 @@ public class Case extends ConditionalFunction {
for (IfConditional conditional : conditions) { for (IfConditional conditional : conditions) {
dataType = DataTypeConversion.commonType(dataType, conditional.dataType()); dataType = DataTypeConversion.commonType(dataType, conditional.dataType());
} }
dataType = DataTypeConversion.commonType(dataType, elseResult.dataType());
} }
} }
return dataType; return dataType;

View File

@ -6,19 +6,23 @@
package org.elasticsearch.xpack.sql.expression.predicate.conditional; package org.elasticsearch.xpack.sql.expression.predicate.conditional;
import org.elasticsearch.xpack.sql.expression.Expression; import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.Literal;
import org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils; import org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils;
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Equals;
import org.elasticsearch.xpack.sql.tree.AbstractNodeTestCase; import org.elasticsearch.xpack.sql.tree.AbstractNodeTestCase;
import org.elasticsearch.xpack.sql.tree.NodeSubclassTests; import org.elasticsearch.xpack.sql.tree.NodeSubclassTests;
import org.elasticsearch.xpack.sql.tree.Source; import org.elasticsearch.xpack.sql.tree.Source;
import org.elasticsearch.xpack.sql.tree.SourceTests; import org.elasticsearch.xpack.sql.tree.SourceTests;
import org.elasticsearch.xpack.sql.type.DataType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import static org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils.randomIntLiteral; import static org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils.randomIntLiteral;
import static org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils.randomStringLiteral; import static org.elasticsearch.xpack.sql.expression.function.scalar.FunctionTestUtils.randomStringLiteral;
import static org.elasticsearch.xpack.sql.tree.Source.EMPTY;
import static org.elasticsearch.xpack.sql.tree.SourceTests.randomSource; import static org.elasticsearch.xpack.sql.tree.SourceTests.randomSource;
/** /**
@ -77,6 +81,42 @@ public class CaseTests extends AbstractNodeTestCase<Case, Expression> {
assertEquals(new Case(c.source(), newChildren), c.replaceChildren(newChildren)); assertEquals(new Case(c.source(), newChildren), c.replaceChildren(newChildren));
} }
public void testDataTypes() {
// CASE WHEN 1 = 1 THEN NULL
// ELSE 'default'
// END
Case c = new Case(EMPTY, Arrays.asList(
new IfConditional(EMPTY, new Equals(EMPTY, Literal.of(EMPTY, 1), Literal.of(EMPTY, 1)), Literal.NULL),
Literal.of(EMPTY, "default")));
assertEquals(DataType.KEYWORD, c.dataType());
// CASE WHEN 1 = 1 THEN 'foo'
// ELSE NULL
// END
c = new Case(EMPTY, Arrays.asList(
new IfConditional(EMPTY, new Equals(EMPTY, Literal.of(EMPTY, 1), Literal.of(EMPTY, 1)), Literal.of(EMPTY, "foo")),
Literal.NULL));
assertEquals(DataType.KEYWORD, c.dataType());
// CASE WHEN 1 = 1 THEN NULL
// ELSE NULL
// END
c = new Case(EMPTY, Arrays.asList(
new IfConditional(EMPTY, new Equals(EMPTY, Literal.of(EMPTY, 1), Literal.of(EMPTY, 1)), Literal.NULL),
Literal.NULL));
assertEquals(DataType.NULL, c.dataType());
// CASE WHEN 1 = 1 THEN NULL
// WHEN 2 = 2 THEN 'foo'
// ELSE NULL
// END
c = new Case(EMPTY, Arrays.asList(
new IfConditional(EMPTY, new Equals(EMPTY, Literal.of(EMPTY, 1), Literal.of(EMPTY, 1)), Literal.NULL),
new IfConditional(EMPTY, new Equals(EMPTY, Literal.of(EMPTY, 2), Literal.of(EMPTY, 2)), Literal.of(EMPTY, "foo")),
Literal.NULL));
assertEquals(DataType.KEYWORD, c.dataType());
}
private List<Expression> mutateChildren(Case c) { private List<Expression> mutateChildren(Case c) {
boolean removeConditional = randomBoolean(); boolean removeConditional = randomBoolean();
List<Expression> expressions = new ArrayList<>(c.children().size()); List<Expression> expressions = new ArrayList<>(c.children().size());