[feature](Nereids) implicit cast StringLiteral to another side type of BinaryOperator if available (#13038)

for expression 5 > '1'. before this PR, we normalize it to '5' > '1'. After this PR, we normalize it to 5 > 1 to compatible with legacy planner.
This commit is contained in:
morrySnow
2022-09-28 21:34:25 +08:00
committed by GitHub
parent 820ec435ce
commit d53205076e
4 changed files with 137 additions and 1 deletions

View File

@ -19,6 +19,7 @@ package org.apache.doris.nereids.jobs.batch;
import org.apache.doris.nereids.CascadesContext;
import org.apache.doris.nereids.rules.expression.rewrite.ExpressionNormalization;
import org.apache.doris.nereids.rules.expression.rewrite.rules.CharacterLiteralTypeCoercion;
import org.apache.doris.nereids.rules.expression.rewrite.rules.TypeCoercion;
import com.google.common.collect.ImmutableList;
@ -35,7 +36,7 @@ public class TypeCoercionJob extends BatchRulesJob {
rulesJob.addAll(ImmutableList.of(
topDownBatch(ImmutableList.of(
new ExpressionNormalization(cascadesContext.getConnectContext(),
ImmutableList.of(TypeCoercion.INSTANCE)))
ImmutableList.of(CharacterLiteralTypeCoercion.INSTANCE, TypeCoercion.INSTANCE)))
)));
}
}

View File

@ -18,6 +18,7 @@
package org.apache.doris.nereids.rules.expression.rewrite;
import org.apache.doris.nereids.rules.expression.rewrite.rules.BetweenToCompoundRule;
import org.apache.doris.nereids.rules.expression.rewrite.rules.CharacterLiteralTypeCoercion;
import org.apache.doris.nereids.rules.expression.rewrite.rules.FoldConstantRule;
import org.apache.doris.nereids.rules.expression.rewrite.rules.InPredicateToEqualToRule;
import org.apache.doris.nereids.rules.expression.rewrite.rules.NormalizeBinaryPredicatesRule;
@ -41,6 +42,7 @@ public class ExpressionNormalization extends ExpressionRewrite {
InPredicateToEqualToRule.INSTANCE,
SimplifyNotExprRule.INSTANCE,
SimplifyCastRule.INSTANCE,
CharacterLiteralTypeCoercion.INSTANCE,
TypeCoercion.INSTANCE,
FoldConstantRule.INSTANCE
);

View File

@ -0,0 +1,129 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.expression.rewrite.rules;
import org.apache.doris.nereids.rules.expression.rewrite.AbstractExpressionRewriteRule;
import org.apache.doris.nereids.rules.expression.rewrite.ExpressionRewriteContext;
import org.apache.doris.nereids.trees.expressions.BinaryOperator;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
import org.apache.doris.nereids.trees.expressions.literal.CharLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DecimalLiteral;
import org.apache.doris.nereids.trees.expressions.literal.DoubleLiteral;
import org.apache.doris.nereids.trees.expressions.literal.FloatLiteral;
import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
import org.apache.doris.nereids.types.BooleanType;
import org.apache.doris.nereids.types.CharType;
import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DateTimeType;
import org.apache.doris.nereids.types.DateType;
import org.apache.doris.nereids.types.DecimalType;
import org.apache.doris.nereids.types.DoubleType;
import org.apache.doris.nereids.types.FloatType;
import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.VarcharType;
import org.apache.doris.nereids.types.coercion.IntegralType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Optional;
/**
* coercion character literal to another side
*/
public class CharacterLiteralTypeCoercion extends AbstractExpressionRewriteRule {
public static final CharacterLiteralTypeCoercion INSTANCE = new CharacterLiteralTypeCoercion();
@Override
public Expression visitBinaryOperator(BinaryOperator binaryOperator, ExpressionRewriteContext context) {
Expression left = rewrite(binaryOperator.left(), context);
Expression right = rewrite(binaryOperator.right(), context);
if (!(left instanceof Literal) && !(right instanceof Literal)) {
return binaryOperator.withChildren(left, right);
}
if (left instanceof Literal && right instanceof Literal) {
// process by constant folding
return binaryOperator.withChildren(left, right);
}
if (left instanceof Literal && ((Literal) left).isCharacterLiteral()) {
left = characterLiteralTypeCoercion(((Literal) left).getStringValue(), right.getDataType()).orElse(left);
}
if (right instanceof Literal && ((Literal) right).isCharacterLiteral()) {
right = characterLiteralTypeCoercion(((Literal) right).getStringValue(), left.getDataType()).orElse(right);
}
return binaryOperator.withChildren(left, right);
}
private Optional<Expression> characterLiteralTypeCoercion(String value, DataType dataType) {
Expression ret = null;
try {
if (dataType instanceof BooleanType) {
if ("true".equalsIgnoreCase(value)) {
ret = BooleanLiteral.TRUE;
}
if ("false".equalsIgnoreCase(value)) {
ret = BooleanLiteral.FALSE;
}
} else if (dataType instanceof IntegralType) {
BigInteger bigInt = new BigInteger(value);
if (BigInteger.valueOf(bigInt.byteValue()).equals(bigInt)) {
ret = new TinyIntLiteral(bigInt.byteValue());
} else if (BigInteger.valueOf(bigInt.shortValue()).equals(bigInt)) {
ret = new SmallIntLiteral(bigInt.shortValue());
} else if (BigInteger.valueOf(bigInt.intValue()).equals(bigInt)) {
ret = new IntegerLiteral(bigInt.intValue());
} else if (BigInteger.valueOf(bigInt.longValue()).equals(bigInt)) {
ret = new BigIntLiteral(bigInt.longValueExact());
} else {
ret = new LargeIntLiteral(bigInt);
}
} else if (dataType instanceof FloatType) {
ret = new FloatLiteral(Float.parseFloat(value));
} else if (dataType instanceof DoubleType) {
ret = new DoubleLiteral(Double.parseDouble(value));
} else if (dataType instanceof DecimalType) {
ret = new DecimalLiteral(new BigDecimal(value));
} else if (dataType instanceof CharType) {
ret = new CharLiteral(value, value.length());
} else if (dataType instanceof VarcharType) {
ret = new VarcharLiteral(value, value.length());
} else if (dataType instanceof StringType) {
ret = new StringLiteral(value);
} else if (dataType instanceof DateType) {
ret = new DateLiteral(value);
} else if (dataType instanceof DateTimeType) {
ret = new DateTimeLiteral(value);
}
} catch (Exception e) {
// ignore
}
return Optional.ofNullable(ret);
}
}

View File

@ -189,6 +189,10 @@ public abstract class Literal extends Expression implements LeafExpression {
throw new AnalysisException("no support cast!");
}
public boolean isCharacterLiteral() {
return this instanceof StringLiteral || this instanceof CharLiteral || this instanceof VarcharLiteral;
}
@Override
public boolean equals(Object o) {
if (this == o) {