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 @@ -185,15 +185,12 @@ private int getFieldIndex(String colName) {


public static SlotRef convertDorisExprToSlotRef(Expr expr) {
SlotRef slotRef = null;
// Stripping CAST can prune matching rows, e.g. CAST('05' AS INT) = 5 is not '05' = '5'.
// Keep casted columns in the original Doris conjuncts to preserve value and null semantics.
if (expr instanceof SlotRef) {
slotRef = (SlotRef) expr;
} else if (expr instanceof CastExpr) {
if (expr.getChild(0) instanceof SlotRef) {
slotRef = (SlotRef) expr.getChild(0);
}
return (SlotRef) expr;
}
return slotRef;
return null;
}

public LiteralExpr convertDorisExprToLiteralExpr(Expr expr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.doris.planner;

import org.apache.doris.analysis.CastExpr;
import org.apache.doris.analysis.Expr;
import org.apache.doris.common.FeConstants;
import org.apache.doris.datasource.paimon.source.PaimonPredicateConverter;
Expand All @@ -29,10 +30,14 @@
import org.apache.paimon.predicate.Or;
import org.apache.paimon.predicate.Predicate;
import org.apache.paimon.types.DataField;
import org.apache.paimon.types.DecimalType;
import org.apache.paimon.types.IntType;
import org.apache.paimon.types.RowType;
import org.apache.paimon.types.VarCharType;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.List;

Expand All @@ -46,6 +51,57 @@ protected void runBeforeAll() throws Exception {
String tbl1 = "create table db1.tbl1(" + "k1 int," + " k2 int," + " v1 int)" + " distributed by hash(k1)"
+ " properties('replication_num' = '1');";
createTables(tbl1);
createTables("create table db1.cast_predicates (id int, code string, amount decimal(10, 2))"
+ " distributed by hash(id) properties('replication_num' = '1')");
}

@ParameterizedTest
@ValueSource(strings = {"cast(code as int) = 5", "5 = cast(code as int)", "cast(code as int) > 5",
"cast(code as int) in (5, 6)", "cast(code as int) not in (5, 6)",
"cast(code as int) is null", "cast(code as int) is not null",
"cast(code as int) = 5 or id = 1"})
public void rejectStringToIntegerCast(String predicate) throws Exception {
List<Expr> conjuncts = planCastPredicate(predicate);
Assertions.assertTrue(conjuncts.stream().anyMatch(expr -> expr.contains(CastExpr.class)), predicate);
List<Expr> remaining = Expr.cloneList(conjuncts);
Assertions.assertTrue(castPredicateConverter().convertToPaimonExpr(conjuncts).isEmpty(), predicate);
Assertions.assertEquals(remaining, conjuncts);
}

@Test
public void rejectDecimalScaleCast() throws Exception {
List<Expr> conjuncts = planCastPredicate("cast(amount as decimal(10, 1)) = 1.2");
Assertions.assertTrue(conjuncts.stream().anyMatch(expr -> expr.contains(CastExpr.class)));
Assertions.assertTrue(castPredicateConverter().convertToPaimonExpr(conjuncts).isEmpty());
}

@Test
public void retainIndependentUncastPredicates() throws Exception {
List<Expr> conjuncts = planCastPredicate("cast(code as int) = 5 and id = 1");
List<Expr> remaining = Expr.cloneList(conjuncts);
List<Predicate> predicates = castPredicateConverter().convertToPaimonExpr(conjuncts);
Assertions.assertEquals(1, predicates.size());
Assertions.assertEquals("id", ((LeafPredicate) predicates.get(0)).fieldName());
Assertions.assertEquals(remaining, conjuncts);

for (String predicate : Lists.newArrayList("code = '5'", "id > 1", "id in (1, 2)")) {
Assertions.assertEquals(1, castPredicateConverter().convertToPaimonExpr(planCastPredicate(predicate)).size(),
predicate);
}
}

private List<Expr> planCastPredicate(String predicate) throws Exception {
StmtExecutor executor = new StmtExecutor(connectContext,
"select * from db1.cast_predicates where " + predicate);
executor.execute();
return executor.planner().getScanNodes().get(0).getConjuncts();
}

private PaimonPredicateConverter castPredicateConverter() {
return new PaimonPredicateConverter(new RowType(Lists.newArrayList(
new DataField(0, "id", new IntType()),
new DataField(1, "code", new VarCharType()),
new DataField(2, "amount", new DecimalType(10, 2)))));
}

@Test
Expand Down
Loading