From ce8cdb071a3256df711d627b9e3654f4677074a2 Mon Sep 17 00:00:00 2001 From: HappenLee Date: Fri, 22 Jan 2021 16:38:38 +0800 Subject: [PATCH] [Bug] Fix bug of outer join cause error result. issue:5284 --- .../apache/doris/planner/HashJoinNode.java | 30 +++++++++++++++++++ .../apache/doris/planner/QueryPlanTest.java | 21 +++++++++++++ 2 files changed, 51 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/HashJoinNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/HashJoinNode.java index f080a83a747035..e847bfe5f1a1b5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/HashJoinNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/HashJoinNode.java @@ -26,6 +26,7 @@ import org.apache.doris.analysis.SlotId; import org.apache.doris.analysis.SlotRef; import org.apache.doris.analysis.TableRef; +import org.apache.doris.analysis.TupleId; import org.apache.doris.catalog.ColumnStats; import org.apache.doris.common.UserException; import org.apache.doris.thrift.TEqJoinCondition; @@ -41,6 +42,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -139,6 +141,10 @@ public void init(Analyzer analyzer) throws UserException { // Set smap to the combined children's smaps and apply that to all conjuncts_. createDefaultSmap(analyzer); + // outSmap replace in outer join may cause NULL be replace by literal + // so need replace the outsmap in nullableTupleID + replaceOutputSmapForOuterJoin(); + computeStats(analyzer); //assignedConjuncts = analyzr.getAssignedConjuncts(); @@ -151,6 +157,30 @@ public void init(Analyzer analyzer) throws UserException { Expr.substituteList(otherJoinConjuncts, combinedChildSmap, analyzer, false); } + private void replaceOutputSmapForOuterJoin() { + if (joinOp.isOuterJoin()) { + List lhs = new ArrayList<>(); + List rhs = new ArrayList<>(); + + for (int i = 0; i < outputSmap.size(); i++) { + Expr expr = outputSmap.getLhs().get(i); + boolean isInNullableTuple = false; + for (TupleId tupleId : nullableTupleIds) { + if (expr.isBound(tupleId)) { + isInNullableTuple = true; + break; + } + } + + if (!isInNullableTuple) { + lhs.add(outputSmap.getLhs().get(i)); + rhs.add(outputSmap.getRhs().get(i)); + } + } + outputSmap = new ExprSubstitutionMap(lhs, rhs); + } + } + @Override public void computeStats(Analyzer analyzer) { super.computeStats(analyzer); diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java index 92e766487911f9..09289085dea58f 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -1400,6 +1400,27 @@ public void testIntDateTime() throws Exception { explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); Assert.assertTrue(explainString.contains("PREDICATES: `date` IN ('2020-10-30 00:00:00')")); } + + @Test + public void testOutJoinSmapReplace() throws Exception { + connectContext.setDatabase("default_cluster:test"); + //valid date + String sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a right outer JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)"; + String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`a`.`aid` | 4")); + + sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a left outer JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("OUTPUT EXPRS:3 | `b`.`bid`")); + + sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a full outer JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`a`.`aid` | `b`.`bid`")); + + sql = "SELECT a.aid, b.bid FROM (SELECT 3 AS aid) a JOIN (SELECT 4 AS bid) b ON (a.aid=b.bid)"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "EXPLAIN " + sql); + Assert.assertTrue(explainString.contains("OUTPUT EXPRS:3 | 4")); + } }