Skip to content
Merged
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 @@ -49,6 +49,7 @@
import org.apache.doris.nereids.trees.expressions.CaseWhen;
import org.apache.doris.nereids.trees.expressions.Cast;
import org.apache.doris.nereids.trees.expressions.ComparisonPredicate;
import org.apache.doris.nereids.trees.expressions.CompoundPredicate;
import org.apache.doris.nereids.trees.expressions.Divide;
import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.ExprId;
Expand Down Expand Up @@ -120,13 +121,19 @@

/** ExpressionAnalyzer */
public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext> {
// This rule only used in unit test
@VisibleForTesting
public static final AbstractExpressionRewriteRule FUNCTION_ANALYZER_RULE = new AbstractExpressionRewriteRule() {
@Override
public Expression rewrite(Expression expr, ExpressionRewriteContext ctx) {
return new ExpressionAnalyzer(
null, new Scope(ImmutableList.of()), null, false, false
).analyze(expr, ctx);
return new ExpressionAnalyzer(null, new Scope(ImmutableList.of()), null, false, false) {
@Override
protected Expression processCompoundNewChildren(CompoundPredicate cp, List<Expression> newChildren) {
// ExpressionUtils.and/ExpressionUtils.or will remove duplicate children, and simplify FALSE / TRUE.
// But we don't want to simplify them in unit test.
return cp.withChildren(newChildren);
}
}.analyze(expr, ctx);
}
};

Expand Down Expand Up @@ -594,7 +601,7 @@ public Expression visitOr(Or or, ExpressionRewriteContext context) {
newChildren.add(newChild);
}
if (hasNewChild) {
return ExpressionUtils.or(newChildren);
return processCompoundNewChildren(or, newChildren);
} else {
return or;
}
Expand All @@ -616,18 +623,26 @@ public Expression visitAnd(And and, ExpressionRewriteContext context) {
newChild = TypeCoercionUtils.castIfNotSameType(newChild, BooleanType.INSTANCE);
}

if (! child.equals(newChild)) {
if (!child.equals(newChild)) {
hasNewChild = true;
}
newChildren.add(newChild);
}
if (hasNewChild) {
return ExpressionUtils.and(newChildren);
return processCompoundNewChildren(and, newChildren);
} else {
return and;
}
}

protected Expression processCompoundNewChildren(CompoundPredicate cp, List<Expression> newChildren) {
if (cp instanceof And) {
return ExpressionUtils.and(newChildren);
} else {
return ExpressionUtils.or(newChildren);
}
}

@Override
public Expression visitNot(Not not, ExpressionRewriteContext context) {
// maybe is `not subquery`, we should bind it first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.doris.nereids.rules.expression.rules.DistinctPredicatesRule;
import org.apache.doris.nereids.rules.expression.rules.ExtractCommonFactorRule;
import org.apache.doris.nereids.rules.expression.rules.LikeToEqualRewrite;
import org.apache.doris.nereids.rules.expression.rules.NestedCaseWhenCondToLiteral;
import org.apache.doris.nereids.rules.expression.rules.NullSafeEqualToEqual;
import org.apache.doris.nereids.rules.expression.rules.ReplaceNullWithFalseForCond;
import org.apache.doris.nereids.rules.expression.rules.SimplifyComparisonPredicate;
Expand Down Expand Up @@ -59,6 +60,7 @@ public class ExpressionOptimization extends ExpressionRewrite {
DateFunctionRewrite.INSTANCE,
ArrayContainToArrayOverlap.INSTANCE,
ReplaceNullWithFalseForCond.INSTANCE,
NestedCaseWhenCondToLiteral.INSTANCE,
CaseWhenToIf.INSTANCE,
TopnToMax.INSTANCE,
NullSafeEqualToEqual.INSTANCE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public enum ExpressionRuleType {
LIKE_TO_EQUAL,
MERGE_DATE_TRUNC,
MEDIAN_CONVERT,
NESTED_CASE_WHEN_COND_TO_LITERAL,
NORMALIZE_BINARY_PREDICATES,
NULL_SAFE_EQUAL_TO_EQUAL,
REPLACE_NULL_WITH_FALSE_FOR_COND,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,13 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.codec.digest.DigestUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Predicate;

Expand Down Expand Up @@ -576,57 +577,64 @@ public Expression visitBinaryArithmetic(BinaryArithmetic binaryArithmetic, Expre
public Expression visitCaseWhen(CaseWhen caseWhen, ExpressionRewriteContext context) {
CaseWhen originCaseWhen = caseWhen;
caseWhen = rewriteChildren(caseWhen, context);
Expression newDefault = null;
boolean foundNewDefault = false;

List<WhenClause> whenClauses = new ArrayList<>();
final Expression oldDefault = caseWhen.getDefaultValue().orElse(null);
Expression newDefault = oldDefault;
ImmutableList.Builder<WhenClause> whenClausesBuilder
= ImmutableList.builderWithExpectedSize(caseWhen.getWhenClauses().size());
Set<Expression> uniqueOperands = Sets.newHashSet();
for (WhenClause whenClause : caseWhen.getWhenClauses()) {
Expression whenOperand = whenClause.getOperand();

if (!(whenOperand.isLiteral())) {
whenClauses.add(new WhenClause(whenOperand, whenClause.getResult()));
if (!whenOperand.isLiteral() && uniqueOperands.add(whenOperand)) {
whenClausesBuilder.add(new WhenClause(whenOperand, whenClause.getResult()));
} else if (BooleanLiteral.TRUE.equals(whenOperand)) {
foundNewDefault = true;
newDefault = whenClause.getResult();
break;
}
}

Expression defaultResult = null;
if (caseWhen.getDefaultValue().isPresent()) {
defaultResult = caseWhen.getDefaultValue().get();
}
if (foundNewDefault) {
defaultResult = newDefault;
List<WhenClause> newWhenClauses = whenClausesBuilder.build();
Expression realTypeCoercionDefault = newDefault != null ? newDefault : new NullLiteral(caseWhen.getDataType());
boolean allThenEqualsDefault = true;
for (WhenClause whenClause : newWhenClauses) {
if (!whenClause.getResult().equals(realTypeCoercionDefault)) {
allThenEqualsDefault = false;
break;
}
}
if (whenClauses.isEmpty()) {
return TypeCoercionUtils.ensureSameResultType(
originCaseWhen, defaultResult == null ? new NullLiteral(caseWhen.getDataType()) : defaultResult,
context
);
if (allThenEqualsDefault) {
return realTypeCoercionDefault;
}
if (defaultResult == null) {
if (caseWhen.getDataType().isNullType()) {
// if caseWhen's type is NULL_TYPE, means all possible return values are nulls
// it's safe to return null literal here
return new NullLiteral();
} else {
return TypeCoercionUtils.ensureSameResultType(originCaseWhen, new CaseWhen(whenClauses), context);
boolean hasNewChildren = newWhenClauses.size() != caseWhen.getWhenClauses().size()
|| newDefault != oldDefault;
if (newWhenClauses.size() == caseWhen.getWhenClauses().size()) {
for (int i = 0; i < newWhenClauses.size(); i++) {
if (newWhenClauses.get(i) != caseWhen.getWhenClauses().get(i)) {
hasNewChildren = true;
break;
}
}
}
return TypeCoercionUtils.ensureSameResultType(
originCaseWhen, new CaseWhen(whenClauses, defaultResult), context
);
if (hasNewChildren) {
caseWhen = newDefault == null
? new CaseWhen(newWhenClauses) : new CaseWhen(newWhenClauses, newDefault);
}
return TypeCoercionUtils.ensureSameResultType(originCaseWhen, caseWhen, context);
}

@Override
public Expression visitIf(If ifExpr, ExpressionRewriteContext context) {
If originIf = ifExpr;
ifExpr = rewriteChildren(ifExpr, context);
if (ifExpr.child(0) instanceof NullLiteral || ifExpr.child(0).equals(BooleanLiteral.FALSE)) {
return TypeCoercionUtils.ensureSameResultType(originIf, ifExpr.child(2), context);
} else if (ifExpr.child(0).equals(BooleanLiteral.TRUE)) {
return TypeCoercionUtils.ensureSameResultType(originIf, ifExpr.child(1), context);
Expression condition = ifExpr.getCondition();
Expression typeCoercionTrueValue
= TypeCoercionUtils.ensureSameResultType(originIf, ifExpr.getTrueValue(), context);
Expression typeCoercionFalseValue
= TypeCoercionUtils.ensureSameResultType(originIf, ifExpr.getFalseValue(), context);
if (condition.equals(BooleanLiteral.TRUE)) {
return typeCoercionTrueValue;
} else if (condition.equals(BooleanLiteral.FALSE) || condition.isNullLiteral()) {
return typeCoercionFalseValue;
} else if (typeCoercionTrueValue.equals(typeCoercionFalseValue)) {
return typeCoercionTrueValue;
}
return TypeCoercionUtils.ensureSameResultType(originIf, ifExpr, context);
}
Expand Down
Loading
Loading