Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -209,19 +209,15 @@ private Optional<Expression> simplify(Session session, Case caseExpression)

private static Optional<Expression> simplify(Match caseExpression)
{
Optional<Expression> defaultValue = Optional.of(caseExpression.defaultValue());

if (caseExpression.operand() instanceof Constant literal && literal.value() == null) {
return defaultValue;
}
Expression defaultValue = caseExpression.defaultValue();

List<Expression> results = caseExpression.clauses().stream()
.map(MatchClause::result)
.collect(toImmutableList());
if (results.stream().allMatch(result -> result.equals(TRUE)) && defaultValue.get().equals(TRUE)) {
if (results.stream().allMatch(result -> result.equals(TRUE)) && defaultValue.equals(TRUE)) {
return Optional.of(TRUE);
}
if (results.stream().allMatch(SimplifyFilterPredicate::isNotTrue) && isNotTrue(defaultValue.get())) {
if (results.stream().allMatch(SimplifyFilterPredicate::isNotTrue) && isNotTrue(defaultValue)) {
return Optional.of(FALSE);
}
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.trino.sql.ir.Expression;
import io.trino.sql.ir.IrExpressions;
import io.trino.sql.ir.IsNull;
import io.trino.sql.ir.Lambda;
import io.trino.sql.ir.Logical;
import io.trino.sql.ir.Match;
import io.trino.sql.ir.MatchClause;
Expand All @@ -42,6 +43,7 @@
import static io.trino.sql.ir.Booleans.TRUE;
import static io.trino.sql.ir.ComparisonOperator.EQUAL;
import static io.trino.sql.ir.ComparisonOperator.GREATER_THAN;
import static io.trino.sql.ir.ComparisonOperator.IDENTICAL;
import static io.trino.sql.ir.ComparisonOperator.LESS_THAN;
import static io.trino.sql.ir.IrExpressions.ifExpression;
import static io.trino.sql.ir.Logical.Operator.AND;
Expand Down Expand Up @@ -402,6 +404,25 @@ public void testSimplifySearchedCaseExpression()
.doesNotFire();
}

@Test
public void testNullOperandCanMatch()
{
Symbol operand = new Symbol(INTEGER, "operand");
Lambda predicate = new Lambda(ImmutableList.of(operand), comparison(IDENTICAL, operand.toSymbolReference(), new Reference(INTEGER, "a")));

tester().assertThat(new SimplifyFilterPredicate(FUNCTIONS.getMetadata()))
.on(p -> p.filter(
new Match(new Constant(INTEGER, null), ImmutableList.of(new MatchClause(predicate, TRUE)), FALSE),
p.values(p.symbol("a", INTEGER))))
.doesNotFire();

tester().assertThat(new SimplifyFilterPredicate(FUNCTIONS.getMetadata()))
.on(p -> p.filter(
new Match(new Constant(INTEGER, null), ImmutableList.of(new MatchClause(predicate, FALSE)), TRUE),
p.values(p.symbol("a", INTEGER))))
.doesNotFire();
}

@Test
public void testSimplifySimpleCaseExpression()
{
Expand All @@ -416,7 +437,7 @@ public void testSimplifySimpleCaseExpression()
p.values(p.symbol("a"), p.symbol("b"))))
.doesNotFire();

// comparison with null returns null - no WHEN branch matches, return default value
// Null operands are evaluated by the IR optimizer using the clause predicates.
tester().assertThat(new SimplifyFilterPredicate(FUNCTIONS.getMetadata()))
.on(p -> p.filter(
new Match(
Expand All @@ -426,12 +447,8 @@ public void testSimplifySimpleCaseExpression()
equalityClause(new Reference(BOOLEAN, "a"), FALSE)),
new Reference(BOOLEAN, "b")),
p.values(p.symbol("a"), p.symbol("b"))))
.matches(
filter(
new Reference(BOOLEAN, "b"),
values("a", "b")));
.doesNotFire();

// comparison with null returns null - no WHEN branch matches, the result is default null, simplified to FALSE
tester().assertThat(new SimplifyFilterPredicate(FUNCTIONS.getMetadata()))
.on(p -> p.filter(
new Match(
Expand All @@ -441,10 +458,7 @@ public void testSimplifySimpleCaseExpression()
equalityClause(new Reference(BOOLEAN, "a"), FALSE)),
NULL_BOOLEAN),
p.values(p.symbol("a"))))
.matches(
filter(
FALSE,
values("a")));
.doesNotFire();

// all results true
tester().assertThat(new SimplifyFilterPredicate(FUNCTIONS.getMetadata()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,57 @@ WHEN IS NOT DISTINCT FROM CAST(NULL AS integer) THEN 1
.matches("VALUES 1, 2, 1");
}

@Test
public void testNullOperandInFilter()
{
assertThat(assertions.query(
"""
SELECT x
FROM UNNEST(ARRAY[NULL, 1]) t(x)
WHERE CASE CAST(NULL AS integer) WHEN IS NOT DISTINCT FROM x THEN true ELSE false END
"""))
.matches("VALUES CAST(NULL AS integer)");
}

@Test
public void testNullOperandInFilterWithTrueDefault()
{
assertThat(assertions.query(
"""
SELECT x
FROM UNNEST(ARRAY[NULL, 1]) t(x)
WHERE CASE CAST(NULL AS integer) WHEN IS NOT DISTINCT FROM x THEN false ELSE true END
"""))
.matches("VALUES 1");
}

@Test
public void testNullOperandControls()
{
assertThat(assertions.query(
"""
SELECT x, CASE CAST(NULL AS integer) WHEN IS NOT DISTINCT FROM x THEN true ELSE false END
FROM UNNEST(ARRAY[NULL, 1]) t(x)
"""))
.matches("VALUES (CAST(NULL AS integer), true), (1, false)");

assertThat(assertions.query(
"""
SELECT x
FROM UNNEST(ARRAY[NULL, 1]) t(x)
WHERE CASE WHEN CAST(NULL AS integer) IS NOT DISTINCT FROM x THEN true ELSE false END
"""))
.matches("VALUES CAST(NULL AS integer)");

assertThat(assertions.query(
"""
SELECT x
FROM UNNEST(ARRAY[NULL, 1]) t(x)
WHERE CASE CAST(NULL AS integer) WHEN x THEN false ELSE true END
"""))
.matches("VALUES CAST(NULL AS integer), 1");
}

@Test
public void testTypeReconciliation()
{
Expand Down
Loading