From f1880d32d9d2255e1edd4ea3b73376292944f542 Mon Sep 17 00:00:00 2001 From: minghong Date: Wed, 16 Aug 2023 17:22:44 +0800 Subject: [PATCH] [fix](nereids)bind slot failed because of "default_cluster" #23008 slot bind failed for following querys: select tpch.lineitem.* from lineitem select tpch.lineitem.l_partkey from lineitem the unbound slot is tpch.lineitem.l_partkey, but the bounded slot is default_cluster:tpch.lineitem.l_partkey. They are not matched. we need to ignore default_cluster: when compare dbName --- .../nereids/rules/analysis/SlotBinder.java | 27 ++++++++++++++----- .../functions/ExpressionTrait.java | 2 +- .../expressions/functions/scalar/Random.java | 3 +++ .../apache/doris/analysis/SelectStmtTest.java | 8 +++--- .../except/test_bound_exception.groovy | 2 +- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java index 94c4b4f07dfdb6..dfa2528793e9e8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SlotBinder.java @@ -17,6 +17,7 @@ package org.apache.doris.nereids.rules.analysis; +import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.util.Util; import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.analyzer.Scope; @@ -178,7 +179,7 @@ private BoundStar bindQualifiedStar(List qualifierStar, List bound case 1: // bound slot is `table`.`column` return false; case 2:// bound slot is `db`.`table`.`column` - return qualifierStar.get(0).equalsIgnoreCase(boundSlotQualifier.get(0)) + return compareDbNameIgnoreClusterName(qualifierStar.get(0), boundSlotQualifier.get(0)) && qualifierStar.get(1).equalsIgnoreCase(boundSlotQualifier.get(1)); default: throw new AnalysisException("Not supported qualifier: " @@ -193,6 +194,18 @@ private BoundStar bindQualifiedStar(List qualifierStar, List bound return new BoundStar(slots); } + private boolean compareDbNameIgnoreClusterName(String unBoundDbName, String boundedDbName) { + if (unBoundDbName.equalsIgnoreCase(boundedDbName)) { + return true; + } + // boundedDbName example + int idx = boundedDbName.indexOf(ClusterNamespace.CLUSTER_DELIMITER); + if (idx > -1) { + return unBoundDbName.equalsIgnoreCase(boundedDbName.substring(idx + 1)); + } + return false; + } + private List bindSlot(UnboundSlot unboundSlot, List boundSlots) { return boundSlots.stream().distinct().filter(boundSlot -> { List nameParts = unboundSlot.getNameParts(); @@ -205,14 +218,14 @@ private List bindSlot(UnboundSlot unboundSlot, List boundSlots) { return nameParts.get(0).equalsIgnoreCase(boundSlot.getName()); } if (namePartsSize == 2) { - String qualifierDbName = boundSlot.getQualifier().get(qualifierSize - 1); - return qualifierDbName.equalsIgnoreCase(nameParts.get(0)) + String qualifierTableName = boundSlot.getQualifier().get(qualifierSize - 1); + return qualifierTableName.equalsIgnoreCase(nameParts.get(0)) && boundSlot.getName().equalsIgnoreCase(nameParts.get(1)); } else if (nameParts.size() == 3) { - String qualifierDbName = boundSlot.getQualifier().get(qualifierSize - 1); - String qualifierClusterName = boundSlot.getQualifier().get(qualifierSize - 2); - return qualifierClusterName.equalsIgnoreCase(nameParts.get(0)) - && qualifierDbName.equalsIgnoreCase(nameParts.get(1)) + String qualifierTableName = boundSlot.getQualifier().get(qualifierSize - 1); + String qualifierDbName = boundSlot.getQualifier().get(qualifierSize - 2); + return compareDbNameIgnoreClusterName(nameParts.get(0), qualifierDbName) + && qualifierTableName.equalsIgnoreCase(nameParts.get(1)) && boundSlot.getName().equalsIgnoreCase(nameParts.get(2)); } //TODO: handle name parts more than three. diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java index f76e242dbb6238..2d76c78f4cc06c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ExpressionTrait.java @@ -66,7 +66,7 @@ default DataType getArgumentType(int index) { } default DataType getDataType() throws UnboundException { - throw new UnboundException("dataType"); + throw new UnboundException(toSql() + ".getDataType()"); } default String toSql() throws UnboundException { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java index 04b669d843b51a..1ee251c305dac5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.functions.Nondeterministic; +import org.apache.doris.nereids.trees.expressions.literal.Literal; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.BigIntType; import org.apache.doris.nereids.types.DoubleType; @@ -53,6 +54,8 @@ public Random() { */ public Random(Expression arg) { super("random", arg); + // align with original planner behavior, refer to: org/apache/doris/analysis/Expr.getBuiltinFunction() + Preconditions.checkState(arg instanceof Literal, "The param of rand function must be literal"); } /** diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java index a63326c0fba481..4b8835c1bb0c0d 100755 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java @@ -508,14 +508,12 @@ public void testImplicitConvertSupport() throws Exception { @Test public void testDeleteSign() throws Exception { - String sql1 = "SELECT * FROM db1.table1 LEFT ANTI JOIN db1.table2 ON db1.table1.siteid = db1.table2.siteid;"; + String sql1 = "SELECT /*+ SET_VAR(enable_nereids_planner=true, ENABLE_FALLBACK_TO_ORIGINAL_PLANNER=false) */ * FROM db1.table1 LEFT ANTI JOIN db1.table2 ON db1.table1.siteid = db1.table2.siteid;"; String explain = dorisAssert.query(sql1).explainQuery(); Assert.assertTrue(explain - .contains("PREDICATES: `default_cluster:db1`.`table1`.`__DORIS_DELETE_SIGN__` = 0")); - Assert.assertTrue(explain - .contains("PREDICATES: `default_cluster:db1`.`table2`.`__DORIS_DELETE_SIGN__` = 0")); + .contains("PREDICATES: __DORIS_DELETE_SIGN__ = 0")); Assert.assertFalse(explain.contains("other predicates:")); - String sql2 = "SELECT * FROM db1.table1 JOIN db1.table2 ON db1.table1.siteid = db1.table2.siteid;"; + String sql2 = "SELECT /*+ SET_VAR(enable_nereids_planner=false) */ * FROM db1.table1 JOIN db1.table2 ON db1.table1.siteid = db1.table2.siteid;"; explain = dorisAssert.query(sql2).explainQuery(); Assert.assertTrue(explain .contains("PREDICATES: `default_cluster:db1`.`table1`.`__DORIS_DELETE_SIGN__` = 0")); diff --git a/regression-test/suites/nereids_p0/except/test_bound_exception.groovy b/regression-test/suites/nereids_p0/except/test_bound_exception.groovy index 95479f009de28d..02b29b65170669 100644 --- a/regression-test/suites/nereids_p0/except/test_bound_exception.groovy +++ b/regression-test/suites/nereids_p0/except/test_bound_exception.groovy @@ -50,6 +50,6 @@ suite("test_bound_exception") { } test { sql "SELECT id FROM ${tbName} WHERE id123 = 123 ORDER BY id" - exception "errCode = 2, detailMessage = Unexpected exception: Invalid call to dataType on unbound object" + exception "errCode = 2, detailMessage = Unexpected exception: Invalid call to id123.getDataType() on unbound object" } }