[fix](planner) fix bugs in uncheckedCastChild (#15905)

1. `uncheckedCastChild` may generate redundant `CastExpr` like `cast( cast(XXX as Date) as Date)`
2. generate DateLiteral to replace cast(IntLiteral as Date)
This commit is contained in:
minghong
2023-01-19 15:51:08 +08:00
committed by GitHub
parent 21b78cb820
commit 74c0677d62
6 changed files with 90 additions and 21 deletions

View File

@ -283,6 +283,13 @@ public abstract class Type {
return isScalarType(PrimitiveType.DATETIMEV2);
}
public boolean isDateLike() {
return isScalarType(PrimitiveType.DATETIME)
|| isScalarType(PrimitiveType.DATETIMEV2)
|| isScalarType(PrimitiveType.DATE)
|| isScalarType(PrimitiveType.DATEV2);
}
public boolean isTimeV2() {
return isScalarType(PrimitiveType.TIMEV2);
}

View File

@ -1448,8 +1448,11 @@ public abstract class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl
public void uncheckedCastChild(Type targetType, int childIndex)
throws AnalysisException {
Expr child = getChild(childIndex);
Expr newChild = child.uncheckedCastTo(targetType);
setChild(childIndex, newChild);
//avoid to generate Expr like cast (cast(... as date) as date)
if (!child.getType().equals(targetType)) {
Expr newChild = child.uncheckedCastTo(targetType);
setChild(childIndex, newChild);
}
}
/**

View File

@ -294,28 +294,41 @@ public class IntLiteral extends LiteralExpr {
@Override
protected Expr uncheckedCastTo(Type targetType) throws AnalysisException {
if (!targetType.isNumericType()) {
return super.uncheckedCastTo(targetType);
}
if (targetType.isFixedPointType()) {
if (!targetType.isScalarType(PrimitiveType.LARGEINT)) {
if (!type.equals(targetType)) {
IntLiteral intLiteral = new IntLiteral(this);
intLiteral.setType(targetType);
return intLiteral;
if (targetType.isNumericType()) {
if (targetType.isFixedPointType()) {
if (!targetType.isScalarType(PrimitiveType.LARGEINT)) {
if (!type.equals(targetType)) {
IntLiteral intLiteral = new IntLiteral(this);
intLiteral.setType(targetType);
return intLiteral;
}
return this;
} else {
return new LargeIntLiteral(Long.toString(value));
}
return this;
} else {
return new LargeIntLiteral(Long.toString(value));
} else if (targetType.isFloatingPointType()) {
return new FloatLiteral(new Double(value), targetType);
} else if (targetType.isDecimalV2() || targetType.isDecimalV3()) {
DecimalLiteral res = new DecimalLiteral(new BigDecimal(value));
res.setType(targetType);
return res;
}
} else if (targetType.isFloatingPointType()) {
return new FloatLiteral(new Double(value), targetType);
} else if (targetType.isDecimalV2() || targetType.isDecimalV3()) {
DecimalLiteral res = new DecimalLiteral(new BigDecimal(value));
return this;
} else if (targetType.isDateLike()) {
try {
//int like 20200101 can be cast to date(2020,01,01)
DateLiteral res = new DateLiteral("" + value, targetType);
res.setType(targetType);
return res;
} catch (AnalysisException e) {
//invalid date format. leave it to BE to cast it as NULL
}
} else if (targetType.isStringType()) {
StringLiteral res = new StringLiteral("" + value);
res.setType(targetType);
return res;
}
return this;
return super.uncheckedCastTo(targetType);
}
@Override

View File

@ -32,6 +32,7 @@ import mockit.Injectable;
import mockit.Mocked;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@ -202,6 +203,15 @@ public class ExprTest {
Assert.assertFalse(Expr.equalSets(list1, list2));
}
@Test
public void testUncheckedCastChildAvoidDoubleCast() throws AnalysisException {
Expr cast = new CastExpr(Type.DATETIME, new IntLiteral(10000101));
FunctionCallExpr call = new FunctionCallExpr("leap", Lists.newArrayList(cast));
call.uncheckedCastChild(Type.DATETIME, 0);
//do not cast a castExpr
Assertions.assertTrue(call.getChild(0).getChild(0) instanceof IntLiteral);
}
@Test
public void testSrcSlotRef(@Injectable SlotDescriptor slotDescriptor) {
TableName tableName = new TableName(internalCtl, "db1", "table1");

View File

@ -202,9 +202,10 @@ public class InsertStmtTest {
FunctionCallExpr expr4 = (FunctionCallExpr) queryStmtSubstitute.getResultExprs().get(4);
Assert.assertEquals(expr4.getFnName().getFunction(), "to_bitmap");
List<Expr> slots = Lists.newArrayList();
expr4.collect(IntLiteral.class, slots);
expr4.collect(StringLiteral.class, slots);
Assert.assertEquals(1, slots.size());
Assert.assertEquals(queryStmtSubstitute.getResultExprs().get(0), slots.get(0));
Assert.assertEquals(queryStmtSubstitute.getResultExprs().get(0).getStringValue(),
slots.get(0).getStringValue());
Assert.assertTrue(queryStmtSubstitute.getResultExprs().get(5) instanceof FunctionCallExpr);
FunctionCallExpr expr5 = (FunctionCallExpr) queryStmtSubstitute.getResultExprs().get(5);

View File

@ -0,0 +1,35 @@
// 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.analysis;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class IntLiteralTest {
@Test
public void testUncheckedCastTo() throws AnalysisException {
IntLiteral intLiteral = new IntLiteral(20200101);
Expr expr = intLiteral.uncheckedCastTo(Type.DATETIME);
Assertions.assertTrue(expr instanceof DateLiteral);
expr = intLiteral.uncheckedCastTo(Type.STRING);
Assertions.assertTrue(expr instanceof StringLiteral);
}
}