[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:
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user