This is an automated email from the ASF dual-hosted git repository. morrysnow pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new c0b39de61c [Feature](Nereids) Support join hint (#13601) c0b39de61c is described below commit c0b39de61c7fa93a89c463c9f5159703b8a2c82a Author: Shuo Wang <wangshuo...@gmail.com> AuthorDate: Wed Dec 21 21:09:13 2022 +0800 [Feature](Nereids) Support join hint (#13601) Support join hint for nereids planner. Hints for broadcast and shuffle are supported by this PR. --- .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 8 +- .../org/apache/doris/nereids/NereidsPlanner.java | 20 +++ .../doris/nereids/parser/LogicalPlanBuilder.java | 29 +++- .../nereids/properties/RequestPropertyDeriver.java | 48 +++++-- .../doris/nereids/rules/analysis/BindFunction.java | 1 + .../nereids/rules/analysis/BindSlotReference.java | 4 +- .../rules/exploration/join/InnerJoinLAsscom.java | 6 +- .../exploration/join/InnerJoinLAsscomProject.java | 6 +- .../exploration/join/InnerJoinLeftAssociate.java | 6 +- .../exploration/join/InnerJoinRightAssociate.java | 6 +- .../rules/exploration/join/JoinCommute.java | 3 + .../rules/exploration/join/JoinExchange.java | 8 +- .../rules/exploration/join/OuterJoinLAsscom.java | 6 +- .../exploration/join/OuterJoinLAsscomProject.java | 6 +- .../join/SemiJoinLogicalJoinTranspose.java | 13 +- .../join/SemiJoinLogicalJoinTransposeProject.java | 10 +- .../join/SemiJoinSemiJoinTranspose.java | 5 +- .../join/SemiJoinSemiJoinTransposeProject.java | 6 +- .../expression/rewrite/ExpressionRewrite.java | 2 +- .../implementation/LogicalJoinToHashJoin.java | 1 + .../rules/rewrite/logical/ExistsApplyToJoin.java | 3 + .../rewrite/logical/FindHashConditionForJoin.java | 1 + .../rules/rewrite/logical/InApplyToJoin.java | 3 + .../rewrite/logical/PushFilterInsideJoin.java | 2 +- .../rewrite/logical/PushdownFilterThroughJoin.java | 1 + .../logical/PushdownJoinOtherCondition.java | 2 +- .../nereids/rules/rewrite/logical/ReorderJoin.java | 36 +++-- .../rules/rewrite/logical/ScalarApplyToJoin.java | 2 + .../apache/doris/nereids/trees/plans/JoinHint.java | 72 ++++++++++ .../doris/nereids/trees/plans/algebra/Join.java | 26 ++++ .../nereids/trees/plans/logical/LogicalJoin.java | 106 ++++++++++----- .../trees/plans/physical/AbstractPhysicalJoin.java | 37 +++++- .../trees/plans/physical/PhysicalHashJoin.java | 56 +++++--- .../plans/physical/PhysicalNestedLoopJoin.java | 41 ++++-- .../org/apache/doris/nereids/JoinHintTest.java | 148 +++++++++++++++++++++ .../doris/nereids/parser/NereidsParserTest.java | 44 ++++++ .../properties/ChildOutputPropertyDeriverTest.java | 11 +- .../properties/RequestPropertyDeriverTest.java | 10 +- .../logical/FindHashConditionForJoinTest.java | 3 +- .../logical/PushdownJoinOtherConditionTest.java | 8 +- .../doris/nereids/trees/plans/PlanEqualsTest.java | 6 +- .../doris/nereids/util/ExceptionChecker.java | 2 +- .../doris/nereids/util/LogicalPlanBuilder.java | 3 +- ...{GroupMatchingUtils.java => MatchingUtils.java} | 30 ++++- .../org/apache/doris/nereids/util/PlanChecker.java | 15 ++- .../doris/nereids/util/PlanParseChecker.java | 2 +- .../account_p0/test_nereids_authentication.groovy | 12 +- 47 files changed, 723 insertions(+), 153 deletions(-) diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index fc226c46bc..e17a593648 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -128,7 +128,13 @@ relation ; joinRelation - : (joinType) JOIN right=relationPrimary joinCriteria? + : (joinType) JOIN joinHint? right=relationPrimary joinCriteria? + ; + +// Just like `opt_plan_hints` in legacy CUP parser. +joinHint + : LEFT_BRACKET identifier RIGHT_BRACKET #bracketStyleHint + | HINT_START identifier HINT_END #commentStyleHint ; aggClause diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java index 03847cc6e8..06b0a05d29 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java @@ -354,4 +354,24 @@ public class NereidsPlanner extends Planner { ExplainLevel explainLevel = explainOptions.getExplainLevel(); return explainLevel == null ? ExplainLevel.NONE : explainLevel; } + + @VisibleForTesting + public Plan getParsedPlan() { + return parsedPlan; + } + + @VisibleForTesting + public Plan getAnalyzedPlan() { + return analyzedPlan; + } + + @VisibleForTesting + public Plan getRewrittenPlan() { + return rewrittenPlan; + } + + @VisibleForTesting + public Plan getOptimizedPlan() { + return optimizedPlan; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 5510cb493c..a7f5fd915c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -27,7 +27,9 @@ import org.apache.doris.nereids.DorisParser.AliasedRelationContext; import org.apache.doris.nereids.DorisParser.ArithmeticBinaryContext; import org.apache.doris.nereids.DorisParser.ArithmeticUnaryContext; import org.apache.doris.nereids.DorisParser.BooleanLiteralContext; +import org.apache.doris.nereids.DorisParser.BracketStyleHintContext; import org.apache.doris.nereids.DorisParser.ColumnReferenceContext; +import org.apache.doris.nereids.DorisParser.CommentStyleHintContext; import org.apache.doris.nereids.DorisParser.ComparisonContext; import org.apache.doris.nereids.DorisParser.CreateRowPolicyContext; import org.apache.doris.nereids.DorisParser.CteContext; @@ -168,6 +170,7 @@ import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.algebra.Aggregate; @@ -976,6 +979,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { JoinType.CROSS_JOIN, ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, + JoinHint.NONE, left, right); left = withJoinRelations(left, relation); @@ -1219,10 +1223,23 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { } } + JoinHint joinHint = Optional.ofNullable(join.joinHint()).map(hintCtx -> { + String hint = typedVisit(join.joinHint()); + if (JoinHint.JoinHintType.SHUFFLE.toString().equalsIgnoreCase(hint)) { + return JoinHint.SHUFFLE_RIGHT; + } else if (JoinHint.JoinHintType.BROADCAST.toString().equalsIgnoreCase(hint)) { + return JoinHint.BROADCAST_RIGHT; + } else { + throw new ParseException("Invalid join hint: " + hint, hintCtx); + } + }).orElse(JoinHint.NONE); + last = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition.map(ExpressionUtils::extractConjunction) .orElse(ExpressionUtils.EMPTY_CONDITION), - last, plan(join.relationPrimary())); + joinHint, + last, + plan(join.relationPrimary())); } return last; } @@ -1252,6 +1269,16 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { return new LogicalSelectHint<>(hints, logicalPlan); } + @Override + public String visitBracketStyleHint(BracketStyleHintContext ctx) { + return ctx.identifier().getText(); + } + + @Override + public Object visitCommentStyleHint(CommentStyleHintContext ctx) { + return ctx.identifier().getText(); + } + private LogicalPlan withProjection(LogicalPlan input, SelectColumnClauseContext selectCtx, Optional<AggClauseContext> aggCtx) { return ParserUtils.withOrigin(selectCtx, () -> { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java index 1b8f29fa91..99c5c197bc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java @@ -27,6 +27,7 @@ import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.physical.PhysicalAssertNumRows; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; @@ -107,24 +108,43 @@ public class RequestPropertyDeriver extends PlanVisitor<Void, PlanContext> { @Override public Void visitPhysicalHashJoin(PhysicalHashJoin<? extends Plan, ? extends Plan> hashJoin, PlanContext context) { - // for shuffle join - if (JoinUtils.couldShuffle(hashJoin)) { - Pair<List<ExprId>, List<ExprId>> onClauseUsedSlots = JoinUtils.getOnClauseUsedSlots(hashJoin); - // shuffle join - addRequestPropertyToChildren( - PhysicalProperties.createHash( - new DistributionSpecHash(onClauseUsedSlots.first, ShuffleType.JOIN)), - PhysicalProperties.createHash( - new DistributionSpecHash(onClauseUsedSlots.second, ShuffleType.JOIN))); - } - // for broadcast join - if (JoinUtils.couldBroadcast(hashJoin)) { - addRequestPropertyToChildren(PhysicalProperties.ANY, PhysicalProperties.REPLICATED); - } + JoinHint hint = hashJoin.getHint(); + switch (hint) { + case BROADCAST_RIGHT: + addBroadcastJoinRequestProperty(); + break; + case SHUFFLE_RIGHT: + addShuffleJoinRequestProperty(hashJoin); + break; + case NONE: + default: + // for shuffle join + if (JoinUtils.couldShuffle(hashJoin)) { + addShuffleJoinRequestProperty(hashJoin); + } + // for broadcast join + if (JoinUtils.couldBroadcast(hashJoin)) { + addRequestPropertyToChildren(PhysicalProperties.ANY, PhysicalProperties.REPLICATED); + } + } return null; } + private void addBroadcastJoinRequestProperty() { + addRequestPropertyToChildren(PhysicalProperties.ANY, PhysicalProperties.REPLICATED); + } + + private void addShuffleJoinRequestProperty(PhysicalHashJoin<? extends Plan, ? extends Plan> hashJoin) { + Pair<List<ExprId>, List<ExprId>> onClauseUsedSlots = JoinUtils.getOnClauseUsedSlots(hashJoin); + // shuffle join + addRequestPropertyToChildren( + PhysicalProperties.createHash( + new DistributionSpecHash(onClauseUsedSlots.first, ShuffleType.JOIN)), + PhysicalProperties.createHash( + new DistributionSpecHash(onClauseUsedSlots.second, ShuffleType.JOIN))); + } + @Override public Void visitPhysicalNestedLoopJoin( PhysicalNestedLoopJoin<? extends Plan, ? extends Plan> nestedLoopJoin, PlanContext context) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java index 5935c76032..61e46c7f68 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java @@ -130,6 +130,7 @@ public class BindFunction implements AnalysisRuleFactory { List<Expression> hashConjuncts = bind(join.getHashJoinConjuncts(), ctx.connectContext.getEnv()); List<Expression> otherConjuncts = bind(join.getOtherJoinConjuncts(), ctx.connectContext.getEnv()); return new LogicalJoin<>(join.getJoinType(), hashConjuncts, otherConjuncts, + join.getHint(), join.left(), join.right()); }) ), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java index b434737224..12f107c369 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java @@ -133,7 +133,7 @@ public class BindSlotReference implements AnalysisRuleFactory { .map(expr -> bind(expr, join.children(), join, ctx.cascadesContext)) .collect(Collectors.toList()); return new LogicalJoin<>(join.getJoinType(), - hashJoinConjuncts, cond, join.left(), join.right()); + hashJoinConjuncts, cond, join.getHint(), join.left(), join.right()); }) ), RuleType.BINDING_USING_JOIN_SLOT.build( @@ -154,7 +154,7 @@ public class BindSlotReference implements AnalysisRuleFactory { hashEqExpr.add(new EqualTo(leftSlots.get(i), rightSlots.get(i))); } return new LogicalJoin(JoinType.INNER_JOIN, hashEqExpr, - join.getOtherJoinConjuncts(), join.left(), join.right()); + join.getOtherJoinConjuncts(), join.getHint(), join.left(), join.right()); }) ), RuleType.BINDING_AGGREGATE_SLOT.build( diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscom.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscom.java index 1910ee78d0..37984db597 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscom.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscom.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -52,6 +53,7 @@ public class InnerJoinLAsscom extends OneExplorationRuleFactory { public Rule build() { return innerLogicalJoin(innerLogicalJoin(), group()) .when(topJoin -> checkReorder(topJoin, topJoin.left())) + .whenNot(join -> join.hasJoinHint() || join.left().hasJoinHint()) .then(topJoin -> { LogicalJoin<GroupPlan, GroupPlan> bottomJoin = topJoin.left(); GroupPlan a = bottomJoin.left(); @@ -76,13 +78,13 @@ public class InnerJoinLAsscom extends OneExplorationRuleFactory { List<Expression> newBottomOtherConjuncts = splitOtherConjunts.get(false); LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(JoinType.INNER_JOIN, - newBottomHashConjuncts, newBottomOtherConjuncts, + newBottomHashConjuncts, newBottomOtherConjuncts, JoinHint.NONE, a, c, bottomJoin.getJoinReorderContext()); newBottomJoin.getJoinReorderContext().setHasLAsscom(false); newBottomJoin.getJoinReorderContext().setHasCommute(false); LogicalJoin<LogicalJoin<GroupPlan, GroupPlan>, GroupPlan> newTopJoin = new LogicalJoin<>( - JoinType.INNER_JOIN, newTopHashConjuncts, newTopOtherConjuncts, + JoinType.INNER_JOIN, newTopHashConjuncts, newTopOtherConjuncts, JoinHint.NONE, newBottomJoin, b, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasLAsscom(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java index 21b28acfa4..67488a0a16 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java @@ -27,6 +27,7 @@ import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.util.ExpressionUtils; @@ -62,6 +63,7 @@ public class InnerJoinLAsscomProject extends OneExplorationRuleFactory { public Rule build() { return innerLogicalJoin(logicalProject(innerLogicalJoin()), group()) .when(topJoin -> InnerJoinLAsscom.checkReorder(topJoin, topJoin.left().child())) + .whenNot(join -> join.hasJoinHint() || join.left().child().hasJoinHint()) .then(topJoin -> { /* ********** init ********** */ @@ -151,7 +153,7 @@ public class InnerJoinLAsscomProject extends OneExplorationRuleFactory { /* ********** new Plan ********** */ LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(topJoin.getJoinType(), - newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, + newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, JoinHint.NONE, a, c, bottomJoin.getJoinReorderContext()); newBottomJoin.getJoinReorderContext().setHasLAsscom(false); newBottomJoin.getJoinReorderContext().setHasCommute(false); @@ -168,7 +170,7 @@ public class InnerJoinLAsscomProject extends OneExplorationRuleFactory { } LogicalJoin<Plan, Plan> newTopJoin = new LogicalJoin<>(bottomJoin.getJoinType(), - newTopHashJoinConjuncts, newTopOtherJoinConjuncts, + newTopHashJoinConjuncts, newTopOtherJoinConjuncts, JoinHint.NONE, left, right, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasLAsscom(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociate.java index 118fc2aa3c..8fb969daa6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociate.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -53,6 +54,7 @@ public class InnerJoinLeftAssociate extends OneExplorationRuleFactory { public Rule build() { return innerLogicalJoin(group(), innerLogicalJoin()) .when(InnerJoinLeftAssociate::checkReorder) + .whenNot(join -> join.hasJoinHint() || join.right().hasJoinHint()) .then(topJoin -> { LogicalJoin<GroupPlan, GroupPlan> bottomJoin = topJoin.right(); GroupPlan a = topJoin.left(); @@ -89,7 +91,7 @@ public class InnerJoinLeftAssociate extends OneExplorationRuleFactory { // new join. LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(JoinType.INNER_JOIN, - newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, + newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, JoinHint.NONE, a, b, bottomJoin.getJoinReorderContext()); newBottomJoin.getJoinReorderContext().setHasCommute(false); newBottomJoin.getJoinReorderContext().setHasRightAssociate(false); @@ -97,7 +99,7 @@ public class InnerJoinLeftAssociate extends OneExplorationRuleFactory { newBottomJoin.getJoinReorderContext().setHasExchange(false); LogicalJoin<LogicalJoin<GroupPlan, GroupPlan>, GroupPlan> newTopJoin = new LogicalJoin<>( - JoinType.INNER_JOIN, newTopHashJoinConjuncts, newTopOtherJoinConjuncts, + JoinType.INNER_JOIN, newTopHashJoinConjuncts, newTopOtherJoinConjuncts, JoinHint.NONE, newBottomJoin, c, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasLeftAssociate(true); newTopJoin.getJoinReorderContext().setHasCommute(false); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociate.java index caa16258b2..ded9e6bb98 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociate.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -52,6 +53,7 @@ public class InnerJoinRightAssociate extends OneExplorationRuleFactory { public Rule build() { return innerLogicalJoin(innerLogicalJoin(), group()) .when(InnerJoinRightAssociate::checkReorder) + .whenNot(join -> join.hasJoinHint() || join.left().hasJoinHint()) .then(topJoin -> { LogicalJoin<GroupPlan, GroupPlan> bottomJoin = topJoin.left(); GroupPlan a = bottomJoin.left(); @@ -87,7 +89,7 @@ public class InnerJoinRightAssociate extends OneExplorationRuleFactory { List<Expression> newTopOtherJoinConjuncts = otherConjunctsSplit.get(false); LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(JoinType.INNER_JOIN, - newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, + newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, JoinHint.NONE, b, c, bottomJoin.getJoinReorderContext()); newBottomJoin.getJoinReorderContext().setHasCommute(false); newBottomJoin.getJoinReorderContext().setHasRightAssociate(false); @@ -95,7 +97,7 @@ public class InnerJoinRightAssociate extends OneExplorationRuleFactory { newBottomJoin.getJoinReorderContext().setHasExchange(false); LogicalJoin<GroupPlan, LogicalJoin<GroupPlan, GroupPlan>> newTopJoin = new LogicalJoin<>( - JoinType.INNER_JOIN, newTopHashJoinConjuncts, newTopOtherJoinConjuncts, + JoinType.INNER_JOIN, newTopHashJoinConjuncts, newTopOtherJoinConjuncts, JoinHint.NONE, a, newBottomJoin, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasRightAssociate(true); newTopJoin.getJoinReorderContext().setHasCommute(false); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinCommute.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinCommute.java index 6705c74fbc..0dfa60dd05 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinCommute.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinCommute.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import java.util.List; @@ -45,11 +46,13 @@ public class JoinCommute extends OneExplorationRuleFactory { public Rule build() { return logicalJoin() .when(join -> check(swapType, join)) + .whenNot(LogicalJoin::hasJoinHint) .then(join -> { LogicalJoin<GroupPlan, GroupPlan> newJoin = new LogicalJoin<>( join.getJoinType().swap(), join.getHashJoinConjuncts(), join.getOtherJoinConjuncts(), + JoinHint.NONE, join.right(), join.left(), join.getJoinReorderContext()); newJoin.getJoinReorderContext().setHasCommute(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinExchange.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinExchange.java index f2b221dc27..0ae9e30030 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinExchange.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinExchange.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -53,6 +54,7 @@ public class JoinExchange extends OneExplorationRuleFactory { public Rule build() { return innerLogicalJoin(innerLogicalJoin(), innerLogicalJoin()) .when(JoinExchange::checkReorder) + .whenNot(join -> join.hasJoinHint() || join.left().hasJoinHint() || join.right().hasJoinHint()) .then(topJoin -> { LogicalJoin<GroupPlan, GroupPlan> leftJoin = topJoin.left(); LogicalJoin<GroupPlan, GroupPlan> rightJoin = topJoin.right(); @@ -83,7 +85,7 @@ public class JoinExchange extends OneExplorationRuleFactory { return null; } LogicalJoin<GroupPlan, GroupPlan> newLeftJoin = new LogicalJoin<>(JoinType.INNER_JOIN, - newLeftJoinHashJoinConjuncts, newLeftJoinOtherJoinConjuncts, + newLeftJoinHashJoinConjuncts, newLeftJoinOtherJoinConjuncts, JoinHint.NONE, a, c, leftJoin.getJoinReorderContext()); newLeftJoin.getJoinReorderContext().setHasCommute(false); newLeftJoin.getJoinReorderContext().setHasLeftAssociate(false); @@ -91,7 +93,7 @@ public class JoinExchange extends OneExplorationRuleFactory { newLeftJoin.getJoinReorderContext().setHasExchange(false); LogicalJoin<GroupPlan, GroupPlan> newRightJoin = new LogicalJoin<>(JoinType.INNER_JOIN, - newRightJoinHashJoinConjuncts, newRightJoinOtherJoinConjuncts, + newRightJoinHashJoinConjuncts, newRightJoinOtherJoinConjuncts, JoinHint.NONE, b, d, rightJoin.getJoinReorderContext()); newRightJoin.getJoinReorderContext().setHasCommute(false); newRightJoin.getJoinReorderContext().setHasLeftAssociate(false); @@ -100,7 +102,7 @@ public class JoinExchange extends OneExplorationRuleFactory { LogicalJoin<LogicalJoin<GroupPlan, GroupPlan>, LogicalJoin<GroupPlan, GroupPlan>> newTopJoin = new LogicalJoin<>(JoinType.INNER_JOIN, - newTopJoinHashJoinConjuncts, newTopJoinOtherJoinConjuncts, + newTopJoinHashJoinConjuncts, newTopJoinOtherJoinConjuncts, JoinHint.NONE, newLeftJoin, newRightJoin, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasExchange(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscom.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscom.java index 348d8d0dd7..0abdc66dae 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscom.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscom.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -62,6 +63,7 @@ public class OuterJoinLAsscom extends OneExplorationRuleFactory { .when(join -> VALID_TYPE_PAIR_SET.contains(Pair.of(join.left().getJoinType(), join.getJoinType()))) .when(topJoin -> checkReorder(topJoin, topJoin.left())) .when(topJoin -> checkCondition(topJoin, topJoin.left().right().getOutputSet())) + .whenNot(join -> join.hasJoinHint() || join.left().hasJoinHint()) .then(topJoin -> { LogicalJoin<GroupPlan, GroupPlan> bottomJoin = topJoin.left(); GroupPlan a = bottomJoin.left(); @@ -69,14 +71,14 @@ public class OuterJoinLAsscom extends OneExplorationRuleFactory { GroupPlan c = topJoin.right(); LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(topJoin.getJoinType(), - topJoin.getHashJoinConjuncts(), topJoin.getOtherJoinConjuncts(), + topJoin.getHashJoinConjuncts(), topJoin.getOtherJoinConjuncts(), JoinHint.NONE, a, c, bottomJoin.getJoinReorderContext()); newBottomJoin.getJoinReorderContext().setHasLAsscom(false); newBottomJoin.getJoinReorderContext().setHasCommute(false); LogicalJoin<LogicalJoin<GroupPlan, GroupPlan>, GroupPlan> newTopJoin = new LogicalJoin<>( bottomJoin.getJoinType(), - bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), + bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), JoinHint.NONE, newBottomJoin, b, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasLAsscom(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java index 239aeaf489..a1187f1098 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java @@ -28,6 +28,7 @@ import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.util.JoinUtils; @@ -64,6 +65,7 @@ public class OuterJoinLAsscomProject extends OneExplorationRuleFactory { .when(join -> OuterJoinLAsscom.VALID_TYPE_PAIR_SET.contains( Pair.of(join.left().child().getJoinType(), join.getJoinType()))) .when(topJoin -> OuterJoinLAsscom.checkReorder(topJoin, topJoin.left().child())) + .whenNot(join -> join.hasJoinHint() || join.left().child().hasJoinHint()) .then(topJoin -> { /* ********** init ********** */ @@ -168,7 +170,7 @@ public class OuterJoinLAsscomProject extends OneExplorationRuleFactory { /* ********** new Plan ********** */ LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(topJoin.getJoinType(), - newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, + newBottomHashJoinConjuncts, newBottomOtherJoinConjuncts, JoinHint.NONE, a, c, bottomJoin.getJoinReorderContext()); newBottomJoin.getJoinReorderContext().setHasLAsscom(false); newBottomJoin.getJoinReorderContext().setHasCommute(false); @@ -185,7 +187,7 @@ public class OuterJoinLAsscomProject extends OneExplorationRuleFactory { } LogicalJoin<Plan, Plan> newTopJoin = new LogicalJoin<>(bottomJoin.getJoinType(), - newTopHashJoinConjuncts, newTopOtherJoinConjuncts, + newTopHashJoinConjuncts, newTopOtherJoinConjuncts, JoinHint.NONE, left, right, topJoin.getJoinReorderContext()); newTopJoin.getJoinReorderContext().setHasLAsscom(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTranspose.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTranspose.java index 4a12d5d836..be0508336a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTranspose.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTranspose.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.util.ExpressionUtils; @@ -57,6 +58,7 @@ public class SemiJoinLogicalJoinTranspose extends OneExplorationRuleFactory { || topJoin.getJoinType() == JoinType.LEFT_ANTI_JOIN) .whenNot(topJoin -> topJoin.left().getJoinType().isSemiOrAntiJoin()) .when(this::conditionChecker) + .whenNot(topJoin -> topJoin.hasJoinHint() || topJoin.left().hasJoinHint()) .then(topSemiJoin -> { LogicalJoin<GroupPlan, GroupPlan> bottomJoin = topSemiJoin.left(); GroupPlan a = bottomJoin.left(); @@ -82,9 +84,10 @@ public class SemiJoinLogicalJoinTranspose extends OneExplorationRuleFactory { */ LogicalJoin<GroupPlan, GroupPlan> newBottomSemiJoin = new LogicalJoin<>( topSemiJoin.getJoinType(), - topSemiJoin.getHashJoinConjuncts(), topSemiJoin.getOtherJoinConjuncts(), a, c); + topSemiJoin.getHashJoinConjuncts(), topSemiJoin.getOtherJoinConjuncts(), JoinHint.NONE, + a, c); return new LogicalJoin<>(bottomJoin.getJoinType(), bottomJoin.getHashJoinConjuncts(), - bottomJoin.getOtherJoinConjuncts(), newBottomSemiJoin, b); + bottomJoin.getOtherJoinConjuncts(), JoinHint.NONE, newBottomSemiJoin, b); } else { /* * topSemiJoin newTopJoin @@ -95,9 +98,11 @@ public class SemiJoinLogicalJoinTranspose extends OneExplorationRuleFactory { */ LogicalJoin<GroupPlan, GroupPlan> newBottomSemiJoin = new LogicalJoin<>( topSemiJoin.getJoinType(), - topSemiJoin.getHashJoinConjuncts(), topSemiJoin.getOtherJoinConjuncts(), b, c); + topSemiJoin.getHashJoinConjuncts(), topSemiJoin.getOtherJoinConjuncts(), + JoinHint.NONE, + b, c); return new LogicalJoin<>(bottomJoin.getJoinType(), bottomJoin.getHashJoinConjuncts(), - bottomJoin.getOtherJoinConjuncts(), a, newBottomSemiJoin); + bottomJoin.getOtherJoinConjuncts(), JoinHint.NONE, a, newBottomSemiJoin); } }).toRule(RuleType.LOGICAL_SEMI_JOIN_LOGICAL_JOIN_TRANSPOSE); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTransposeProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTransposeProject.java index f16a1c2818..3546abfa07 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTransposeProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinLogicalJoinTransposeProject.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -58,6 +59,7 @@ public class SemiJoinLogicalJoinTransposeProject extends OneExplorationRuleFacto .when(topJoin -> topJoin.getJoinType() == JoinType.LEFT_SEMI_JOIN || topJoin.getJoinType() == JoinType.LEFT_ANTI_JOIN) .whenNot(topJoin -> topJoin.left().child().getJoinType().isSemiOrAntiJoin()) + .whenNot(join -> join.hasJoinHint() || join.left().child().hasJoinHint()) .when(this::conditionChecker) .then(topSemiJoin -> { LogicalProject<LogicalJoin<GroupPlan, GroupPlan>> project = topSemiJoin.left(); @@ -88,10 +90,10 @@ public class SemiJoinLogicalJoinTransposeProject extends OneExplorationRuleFacto */ LogicalJoin<GroupPlan, GroupPlan> newBottomSemiJoin = new LogicalJoin<>( topSemiJoin.getJoinType(), topSemiJoin.getHashJoinConjuncts(), - topSemiJoin.getOtherJoinConjuncts(), a, c); + topSemiJoin.getOtherJoinConjuncts(), JoinHint.NONE, a, c); LogicalJoin<Plan, Plan> newTopJoin = new LogicalJoin<>(bottomJoin.getJoinType(), - bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), + bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), JoinHint.NONE, newBottomSemiJoin, b); return new LogicalProject<>(new ArrayList<>(topSemiJoin.getOutput()), newTopJoin); @@ -107,10 +109,10 @@ public class SemiJoinLogicalJoinTransposeProject extends OneExplorationRuleFacto */ LogicalJoin<GroupPlan, GroupPlan> newBottomSemiJoin = new LogicalJoin<>( topSemiJoin.getJoinType(), topSemiJoin.getHashJoinConjuncts(), - topSemiJoin.getOtherJoinConjuncts(), b, c); + topSemiJoin.getOtherJoinConjuncts(), JoinHint.NONE, b, c); LogicalJoin<Plan, Plan> newTopJoin = new LogicalJoin<>(bottomJoin.getJoinType(), - bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), + bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), JoinHint.NONE, a, newBottomSemiJoin); return new LogicalProject<>(new ArrayList<>(topSemiJoin.getOutput()), newTopJoin); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTranspose.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTranspose.java index 61f86f6314..78bc186501 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTranspose.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTranspose.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -56,6 +57,7 @@ public class SemiJoinSemiJoinTranspose extends OneExplorationRuleFactory { public Rule build() { return logicalJoin(logicalJoin(), group()) .when(this::typeChecker) + .whenNot(join -> join.hasJoinHint() || join.left().hasJoinHint()) .then(topJoin -> { LogicalJoin<GroupPlan, GroupPlan> bottomJoin = topJoin.left(); GroupPlan a = bottomJoin.left(); @@ -63,10 +65,11 @@ public class SemiJoinSemiJoinTranspose extends OneExplorationRuleFactory { GroupPlan c = topJoin.right(); LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new LogicalJoin<>(topJoin.getJoinType(), - topJoin.getHashJoinConjuncts(), topJoin.getOtherJoinConjuncts(), a, c); + topJoin.getHashJoinConjuncts(), topJoin.getOtherJoinConjuncts(), JoinHint.NONE, a, c); LogicalJoin<LogicalJoin<GroupPlan, GroupPlan>, GroupPlan> newTopJoin = new LogicalJoin<>( bottomJoin.getJoinType(), bottomJoin.getHashJoinConjuncts(), bottomJoin.getOtherJoinConjuncts(), + JoinHint.NONE, newBottomJoin, b); return newTopJoin; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java index 79b7eb2909..448cef7221 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory; import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; @@ -52,6 +53,7 @@ public class SemiJoinSemiJoinTransposeProject extends OneExplorationRuleFactory return logicalJoin(logicalProject(logicalJoin()), group()) .when(this::typeChecker) .when(topSemi -> InnerJoinLAsscom.checkReorder(topSemi, topSemi.left().child())) + .whenNot(join -> join.hasJoinHint() || join.left().child().hasJoinHint()) .then(topSemi -> { LogicalJoin<GroupPlan, GroupPlan> bottomSemi = topSemi.left().child(); LogicalProject abProject = topSemi.left(); @@ -72,14 +74,14 @@ public class SemiJoinSemiJoinTransposeProject extends OneExplorationRuleFactory } ); LogicalJoin newBottomSemi = new LogicalJoin(topSemi.getJoinType(), topSemi.getHashJoinConjuncts(), - topSemi.getOtherJoinConjuncts(), a, c, + topSemi.getOtherJoinConjuncts(), JoinHint.NONE, a, c, bottomSemi.getJoinReorderContext()); newBottomSemi.getJoinReorderContext().setHasCommute(false); newBottomSemi.getJoinReorderContext().setHasLAsscom(false); LogicalProject acProject = new LogicalProject(acProjects.stream().collect(Collectors.toList()), newBottomSemi); LogicalJoin newTopSemi = new LogicalJoin(bottomSemi.getJoinType(), - bottomSemi.getHashJoinConjuncts(), bottomSemi.getOtherJoinConjuncts(), + bottomSemi.getHashJoinConjuncts(), bottomSemi.getOtherJoinConjuncts(), JoinHint.NONE, acProject, b, topSemi.getJoinReorderContext()); newTopSemi.getJoinReorderContext().setHasLAsscom(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java index 4eb6913caf..fdf73c69d7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java @@ -157,7 +157,7 @@ public class ExpressionRewrite implements RewriteRuleFactory { return join; } return new LogicalJoin<>(join.getJoinType(), rewriteHashJoinConjuncts, - rewriteOtherJoinConjuncts, join.left(), join.right()); + rewriteOtherJoinConjuncts, join.getHint(), join.left(), join.right()); }).toRule(RuleType.REWRITE_JOIN_EXPRESSION); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java index 161ebe52b7..8657bb4801 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java @@ -34,6 +34,7 @@ public class LogicalJoinToHashJoin extends OneImplementationRuleFactory { join.getJoinType(), join.getHashJoinConjuncts(), join.getOtherJoinConjuncts(), + join.getHint(), join.getLogicalProperties(), join.left(), join.right()) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ExistsApplyToJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ExistsApplyToJoin.java index 2dd33b524b..e54949c952 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ExistsApplyToJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ExistsApplyToJoin.java @@ -26,6 +26,7 @@ import org.apache.doris.nereids.trees.expressions.Exists; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.functions.agg.Count; import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; @@ -94,12 +95,14 @@ public class ExistsApplyToJoin extends OneRewriteRuleFactory { correlationFilter .map(ExpressionUtils::extractConjunction) .orElse(ExpressionUtils.EMPTY_CONDITION), + JoinHint.NONE, (LogicalPlan) apply.left(), (LogicalPlan) apply.right()); } else { return new LogicalJoin<>(JoinType.LEFT_SEMI_JOIN, ExpressionUtils.EMPTY_CONDITION, correlationFilter .map(ExpressionUtils::extractConjunction) .orElse(ExpressionUtils.EMPTY_CONDITION), + JoinHint.NONE, (LogicalPlan) apply.left(), (LogicalPlan) apply.right()); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoin.java index 96a8f71510..6ee7546cf0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoin.java @@ -69,6 +69,7 @@ public class FindHashConditionForJoin extends OneRewriteRuleFactory { return new LogicalJoin<>(joinType, combinedHashJoinConjuncts, remainedNonHashJoinConjuncts, + join.getHint(), join.left(), join.right()); }).toRule(RuleType.FIND_HASH_CONDITION_FOR_JOIN); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/InApplyToJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/InApplyToJoin.java index 8daab33f46..ba89fe1f0e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/InApplyToJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/InApplyToJoin.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.InSubquery; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.logical.LogicalApply; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -54,10 +55,12 @@ public class InApplyToJoin extends OneRewriteRuleFactory { if (((InSubquery) apply.getSubqueryExpr()).isNot()) { return new LogicalJoin<>(JoinType.LEFT_ANTI_JOIN, Lists.newArrayList(), ExpressionUtils.extractConjunction(predicate), + JoinHint.NONE, apply.left(), apply.right()); } else { return new LogicalJoin<>(JoinType.LEFT_SEMI_JOIN, Lists.newArrayList(), ExpressionUtils.extractConjunction(predicate), + JoinHint.NONE, apply.left(), apply.right()); } }).toRule(RuleType.IN_APPLY_TO_JOIN); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushFilterInsideJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushFilterInsideJoin.java index eeb1699f3f..da7af4c205 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushFilterInsideJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushFilterInsideJoin.java @@ -44,7 +44,7 @@ public class PushFilterInsideJoin extends OneRewriteRuleFactory { LogicalJoin<GroupPlan, GroupPlan> join = filter.child(); otherConditions.addAll(join.getOtherJoinConjuncts()); return new LogicalJoin<>(join.getJoinType(), join.getHashJoinConjuncts(), - otherConditions, join.left(), join.right()); + otherConditions, join.getHint(), join.left(), join.right()); }).toRule(RuleType.PUSH_FILTER_INSIDE_JOIN); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughJoin.java index 4d2fa019e2..1bdc6087ec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughJoin.java @@ -137,6 +137,7 @@ public class PushdownFilterThroughJoin extends OneRewriteRuleFactory { new LogicalJoin<>(join.getJoinType(), join.getHashJoinConjuncts(), joinConditions, + join.getHint(), PlanUtils.filterOrSelf(leftPredicates, join.left()), PlanUtils.filterOrSelf(rightPredicates, join.right()))); }).toRule(RuleType.PUSHDOWN_FILTER_THROUGH_JOIN); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherCondition.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherCondition.java index 3d6c3b3143..cbe3eebe17 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherCondition.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherCondition.java @@ -85,7 +85,7 @@ public class PushdownJoinOtherCondition extends OneRewriteRuleFactory { Plan right = PlanUtils.filterOrSelf(rightConjuncts, join.right()); return new LogicalJoin<>(join.getJoinType(), join.getHashJoinConjuncts(), - remainingOther, left, right); + remainingOther, join.getHint(), left, right); }).toRule(RuleType.PUSHDOWN_JOIN_OTHER_CONDITION); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ReorderJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ReorderJoin.java index 122f73e463..cfd5b2ca1c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ReorderJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ReorderJoin.java @@ -24,6 +24,8 @@ import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; +import org.apache.doris.nereids.trees.plans.JoinHint.JoinHintType; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; @@ -36,6 +38,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import java.util.ArrayList; import java.util.HashSet; @@ -70,10 +73,11 @@ public class ReorderJoin extends OneRewriteRuleFactory { return logicalFilter(subTree(LogicalJoin.class, LogicalFilter.class)).thenApply(ctx -> { LogicalFilter<Plan> filter = ctx.root; - Plan plan = joinToMultiJoin(filter); + Map<Plan, JoinHintType> planToHintType = Maps.newHashMap(); + Plan plan = joinToMultiJoin(filter, planToHintType); Preconditions.checkState(plan instanceof MultiJoin); MultiJoin multiJoin = (MultiJoin) plan; - Plan after = multiJoinToJoin(multiJoin); + Plan after = multiJoinToJoin(multiJoin, planToHintType); return after; }).toRule(RuleType.REORDER_JOIN); } @@ -83,7 +87,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { * {@link LogicalJoin} or {@link LogicalFilter}--{@link LogicalJoin} * --> {@link MultiJoin} */ - public Plan joinToMultiJoin(Plan plan) { + public Plan joinToMultiJoin(Plan plan, Map<Plan, JoinHintType> planToHintType) { // subtree can't specify the end of Pattern. so end can be GroupPlan or Filter if (plan instanceof GroupPlan || (plan instanceof LogicalFilter && plan.child(0) instanceof GroupPlan)) { @@ -113,8 +117,10 @@ public class ReorderJoin extends OneRewriteRuleFactory { } // recursively convert children. - Plan left = joinToMultiJoin(join.left()); - Plan right = joinToMultiJoin(join.right()); + planToHintType.put(join.left(), join.getLeftHint()); + Plan left = joinToMultiJoin(join.left(), planToHintType); + planToHintType.put(join.right(), join.getRightHint()); + Plan right = joinToMultiJoin(join.right(), planToHintType); boolean changeLeft = join.getJoinType().isRightJoin() || join.getJoinType().isFullOuterJoin(); @@ -197,7 +203,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { * A B C D F ──► A B C │ D F ──► MJ(FOJ MJ(A,B,C) MJ(D,F)) * </pre> */ - public Plan multiJoinToJoin(MultiJoin multiJoin) { + public Plan multiJoinToJoin(MultiJoin multiJoin, Map<Plan, JoinHintType> planToHintType) { if (multiJoin.arity() == 1) { return PlanUtils.filterOrSelf(multiJoin.getJoinFilter(), multiJoin.child(0)); } @@ -207,7 +213,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { for (Plan child : multiJoin.children()) { if (child instanceof MultiJoin) { MultiJoin childMultiJoin = (MultiJoin) child; - builder.add(multiJoinToJoin(childMultiJoin)); + builder.add(multiJoinToJoin(childMultiJoin, planToHintType)); } else { builder.add(child); } @@ -232,7 +238,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { multiJoinHandleChildren.children().subList(0, multiJoinHandleChildren.arity() - 1), pushedFilter, JoinType.INNER_JOIN, - ExpressionUtils.EMPTY_CONDITION)); + ExpressionUtils.EMPTY_CONDITION), planToHintType); } else if (multiJoinHandleChildren.getJoinType().isRightJoin()) { left = multiJoinHandleChildren.child(0); Set<Slot> leftOutputSet = left.getOutputSet(); @@ -246,13 +252,13 @@ public class ReorderJoin extends OneRewriteRuleFactory { multiJoinHandleChildren.children().subList(1, multiJoinHandleChildren.arity()), pushedFilter, JoinType.INNER_JOIN, - ExpressionUtils.EMPTY_CONDITION)); + ExpressionUtils.EMPTY_CONDITION), planToHintType); } else { remainingFilter = multiJoin.getJoinFilter(); Preconditions.checkState(multiJoinHandleChildren.arity() == 2); List<Plan> children = multiJoinHandleChildren.children().stream().map(child -> { if (child instanceof MultiJoin) { - return multiJoinToJoin((MultiJoin) child); + return multiJoinToJoin((MultiJoin) child, planToHintType); } else { return child; } @@ -264,6 +270,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { return PlanUtils.filterOrSelf(remainingFilter, new LogicalJoin<>( multiJoinHandleChildren.getJoinType(), ExpressionUtils.EMPTY_CONDITION, multiJoinHandleChildren.getNotInnerJoinConditions(), + JoinHint.fromRightPlanHintType(planToHintType.getOrDefault(right, JoinHintType.NONE)), left, right)); } @@ -276,7 +283,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { while (usedPlansIndex.size() != multiJoinHandleChildren.children().size()) { LogicalJoin<? extends Plan, ? extends Plan> join = findInnerJoin(left, multiJoinHandleChildren.children(), - joinFilter, usedPlansIndex); + joinFilter, usedPlansIndex, planToHintType); join.getHashJoinConjuncts().forEach(joinFilter::remove); join.getOtherJoinConjuncts().forEach(joinFilter::remove); @@ -306,7 +313,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { * @return InnerJoin or CrossJoin{left, last of [candidates]} */ private LogicalJoin<? extends Plan, ? extends Plan> findInnerJoin(Plan left, List<Plan> candidates, - Set<Expression> joinFilter, Set<Integer> usedPlansIndex) { + Set<Expression> joinFilter, Set<Integer> usedPlansIndex, Map<Plan, JoinHintType> planToHintType) { List<Expression> otherJoinConditions = Lists.newArrayList(); Set<Slot> leftOutputSet = left.getOutputSet(); for (int i = 0; i < candidates.size(); i++) { @@ -335,6 +342,7 @@ public class ReorderJoin extends OneRewriteRuleFactory { usedPlansIndex.add(i); return new LogicalJoin<>(JoinType.INNER_JOIN, hashJoinConditions, otherJoinConditions, + JoinHint.fromRightPlanHintType(planToHintType.getOrDefault(candidate, JoinHintType.NONE)), left, candidate); } } @@ -345,10 +353,12 @@ public class ReorderJoin extends OneRewriteRuleFactory { continue; } usedPlansIndex.add(i); + Plan right = candidates.get(i); return new LogicalJoin<>(JoinType.CROSS_JOIN, ExpressionUtils.EMPTY_CONDITION, otherJoinConditions, - left, candidates.get(i)); + JoinHint.fromRightPlanHintType(planToHintType.getOrDefault(right, JoinHintType.NONE)), + left, right); } throw new RuntimeException("findInnerJoin: can't reach here"); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ScalarApplyToJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ScalarApplyToJoin.java index f77ca4ac07..141f2e4203 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ScalarApplyToJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/ScalarApplyToJoin.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; import org.apache.doris.nereids.trees.expressions.AssertNumRowsElement; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalApply; @@ -67,6 +68,7 @@ public class ScalarApplyToJoin extends OneRewriteRuleFactory { correlationFilter .map(ExpressionUtils::extractConjunction) .orElse(ExpressionUtils.EMPTY_CONDITION), + JoinHint.NONE, (LogicalPlan) apply.left(), (LogicalPlan) apply.right()); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/JoinHint.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/JoinHint.java new file mode 100644 index 0000000000..37e246f1a6 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/JoinHint.java @@ -0,0 +1,72 @@ +// 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.nereids.trees.plans; + +/** + * Hints for join. + * <p> + * Hints for the right child of join are supported currently. + * Left input and right input of join could have different hints for further extension. + */ +public enum JoinHint { + NONE(JoinHintType.NONE, JoinHintType.NONE), + BROADCAST_RIGHT(JoinHintType.NONE, JoinHintType.BROADCAST), + SHUFFLE_RIGHT(JoinHintType.NONE, JoinHintType.SHUFFLE); + + /** + * Join hint type for single join input plan. + */ + public enum JoinHintType { + // No join hint. + NONE, + // Shuffle join hint. + SHUFFLE, + // Broadcast join hint. + BROADCAST, + } + + private final JoinHintType leftHint; + private final JoinHintType rightHint; + + JoinHint(JoinHintType leftHint, JoinHintType rightHint) { + this.leftHint = leftHint; + this.rightHint = rightHint; + } + + public JoinHintType getLeftHint() { + return leftHint; + } + + public JoinHintType getRightHint() { + return rightHint; + } + + /** + * Create join hint from join right child's join hint type. + */ + public static JoinHint fromRightPlanHintType(JoinHintType hintType) { + switch (hintType) { + case SHUFFLE: + return SHUFFLE_RIGHT; + case BROADCAST: + return BROADCAST_RIGHT; + default: + return NONE; + } + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java index 6bf8810344..6de43e7db3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java @@ -18,6 +18,8 @@ package org.apache.doris.nereids.trees.plans.algebra; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.JoinHint; +import org.apache.doris.nereids.trees.plans.JoinHint.JoinHintType; import org.apache.doris.nereids.trees.plans.JoinType; import java.util.List; @@ -35,10 +37,34 @@ public interface Join { Optional<Expression> getOnClauseCondition(); + JoinHint getHint(); + + default boolean hasJoinHint() { + return getHint() != JoinHint.NONE; + } + /** * The join plan has join condition or not. */ default boolean hasJoinCondition() { return !getHashJoinConjuncts().isEmpty() || !getOtherJoinConjuncts().isEmpty(); } + + default JoinHintType getLeftHint() { + return JoinHintType.NONE; + } + + /** + * Get the hint type of join's right child. + */ + default JoinHintType getRightHint() { + switch (getHint()) { + case SHUFFLE_RIGHT: + return JoinHintType.SHUFFLE; + case BROADCAST_RIGHT: + return JoinHintType.BROADCAST; + default: + return JoinHintType.NONE; + } + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java index 638973d2aa..db9ed1816b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.rules.exploration.join.JoinReorderContext; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; @@ -33,6 +34,7 @@ import org.apache.doris.nereids.util.Utils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Lists; import java.util.List; import java.util.Objects; @@ -47,6 +49,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends private final JoinType joinType; private final ImmutableList<Expression> otherJoinConjuncts; private final ImmutableList<Expression> hashJoinConjuncts; + private final JoinHint hint; // Use for top-to-down join reorder private final JoinReorderContext joinReorderContext = new JoinReorderContext(); @@ -57,40 +60,62 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends * @param joinType logical type for join */ public LogicalJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { - this(joinType, ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, Optional.empty(), - Optional.empty(), leftChild, rightChild); + this(joinType, ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, + Optional.empty(), Optional.empty(), leftChild, rightChild); } public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { - this(joinType, hashJoinConjuncts, ExpressionUtils.EMPTY_CONDITION, Optional.empty(), Optional.empty(), - leftChild, rightChild); + this(joinType, hashJoinConjuncts, ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, Optional.empty(), + Optional.empty(), leftChild, rightChild); } - public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, + public LogicalJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { this(joinType, hashJoinConjuncts, - otherJoinConjuncts, Optional.empty(), Optional.empty(), leftChild, rightChild); + otherJoinConjuncts, hint, Optional.empty(), Optional.empty(), leftChild, rightChild); } - public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, LEFT_CHILD_TYPE leftChild, - RIGHT_CHILD_TYPE rightChild, JoinReorderContext joinReorderContext) { - this(joinType, hashJoinConjuncts, ExpressionUtils.EMPTY_CONDITION, + public LogicalJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + JoinHint hint, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild, + JoinReorderContext joinReorderContext) { + this(joinType, hashJoinConjuncts, ExpressionUtils.EMPTY_CONDITION, hint, Optional.empty(), Optional.empty(), leftChild, rightChild); this.joinReorderContext.copyFrom(joinReorderContext); } - public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild, JoinReorderContext joinReorderContext) { - this(joinType, hashJoinConjuncts, otherJoinConjuncts, + public LogicalJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild, + JoinReorderContext joinReorderContext) { + this(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, Optional.empty(), Optional.empty(), leftChild, rightChild); this.joinReorderContext.copyFrom(joinReorderContext); } - public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties, - LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild, JoinReorderContext joinReorderContext) { - this(joinType, hashJoinConjuncts, otherJoinConjuncts, groupExpression, logicalProperties, leftChild, + public LogicalJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild, + JoinReorderContext joinReorderContext) { + this(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, groupExpression, logicalProperties, leftChild, rightChild); this.joinReorderContext.copyFrom(joinReorderContext); } @@ -100,13 +125,20 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends * * @param joinType logical type for join */ - public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties, - LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { + public LogicalJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild) { super(PlanType.LOGICAL_JOIN, groupExpression, logicalProperties, leftChild, rightChild); this.joinType = Objects.requireNonNull(joinType, "joinType can not be null"); this.hashJoinConjuncts = ImmutableList.copyOf(hashJoinConjuncts); this.otherJoinConjuncts = ImmutableList.copyOf(otherJoinConjuncts); + this.hint = Objects.requireNonNull(hint, "hint can not be null"); } public List<Expression> getOtherJoinConjuncts() { @@ -126,6 +158,10 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends return joinType; } + public JoinHint getHint() { + return hint; + } + @Override public List<Slot> computeOutput() { @@ -167,11 +203,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends @Override public String toString() { - return Utils.toSqlString("LogicalJoin", + List<Object> args = Lists.newArrayList( "type", joinType, "hashJoinConjuncts", hashJoinConjuncts, - "otherJoinConjuncts", otherJoinConjuncts - ); + "otherJoinConjuncts", otherJoinConjuncts); + if (hint != JoinHint.NONE) { + args.add("hint"); + args.add(hint); + } + return Utils.toSqlString("LogicalJoin", args.toArray()); } // TODO: @@ -190,7 +230,8 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends // TODO: why use containsAll? && that.getHashJoinConjuncts().containsAll(hashJoinConjuncts) && hashJoinConjuncts.containsAll(that.getHashJoinConjuncts()) - && Objects.equals(otherJoinConjuncts, that.otherJoinConjuncts); + && Objects.equals(otherJoinConjuncts, that.otherJoinConjuncts) + && hint.equals(that.hint); } @Override @@ -218,19 +259,19 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends @Override public LogicalBinary<Plan, Plan> withChildren(List<Plan> children) { Preconditions.checkArgument(children.size() == 2); - return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, children.get(0), children.get(1), - joinReorderContext); + return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, children.get(0), + children.get(1), joinReorderContext); } @Override public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { - return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, groupExpression, + return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, groupExpression, Optional.of(getLogicalProperties()), left(), right(), joinReorderContext); } @Override public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { - return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, + return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, Optional.empty(), logicalProperties, left(), right(), joinReorderContext); } @@ -246,21 +287,22 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends public LogicalJoin withHashJoinConjuncts(List<Expression> hashJoinConjuncts) { return new LogicalJoin<>( - joinType, hashJoinConjuncts, this.otherJoinConjuncts, left(), right(), joinReorderContext); + joinType, hashJoinConjuncts, this.otherJoinConjuncts, hint, left(), right(), joinReorderContext); } public LogicalJoin withhashJoinConjunctsAndChildren(List<Expression> hashJoinConjuncts, List<Plan> children) { Preconditions.checkArgument(children.size() == 2); - return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, children.get(0), children.get(1), - joinReorderContext); + return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, children.get(0), + children.get(1), joinReorderContext); } public LogicalJoin withJoinType(JoinType joinType) { - return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, left(), right(), joinReorderContext); + return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, left(), right(), + joinReorderContext); } public LogicalJoin withOtherJoinConjuncts(List<Expression> otherJoinConjuncts) { - return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, left(), right(), + return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, left(), right(), joinReorderContext); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java index ccb9a68e6b..293670eb53 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.memo.GroupExpression; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.properties.PhysicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; @@ -49,30 +50,46 @@ public abstract class AbstractPhysicalJoin< protected final ImmutableList<Expression> otherJoinConjuncts; protected boolean shouldTranslateOutput = true; + protected final JoinHint hint; /** * Constructor of PhysicalJoin. */ - public AbstractPhysicalJoin(PlanType type, JoinType joinType, List<Expression> hashJoinConjuncts, - List<Expression> otherJoinConjuncts, Optional<GroupExpression> groupExpression, + public AbstractPhysicalJoin( + PlanType type, + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { super(type, groupExpression, logicalProperties, leftChild, rightChild); this.joinType = Objects.requireNonNull(joinType, "joinType can not be null"); this.hashJoinConjuncts = ImmutableList.copyOf(hashJoinConjuncts); this.otherJoinConjuncts = ImmutableList.copyOf(otherJoinConjuncts); + this.hint = Objects.requireNonNull(hint, "hint can not be null"); } /** * Constructor of PhysicalJoin. */ - public AbstractPhysicalJoin(PlanType type, JoinType joinType, List<Expression> hashJoinConjuncts, - List<Expression> otherJoinConjuncts, Optional<GroupExpression> groupExpression, - LogicalProperties logicalProperties, PhysicalProperties physicalProperties, - StatsDeriveResult statsDeriveResult, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { + public AbstractPhysicalJoin( + PlanType type, + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, + PhysicalProperties physicalProperties, + StatsDeriveResult statsDeriveResult, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild) { super(type, groupExpression, logicalProperties, physicalProperties, statsDeriveResult, leftChild, rightChild); this.joinType = Objects.requireNonNull(joinType, "joinType can not be null"); this.hashJoinConjuncts = ImmutableList.copyOf(hashJoinConjuncts); this.otherJoinConjuncts = ImmutableList.copyOf(otherJoinConjuncts); + this.hint = hint; } public List<Expression> getHashJoinConjuncts() { @@ -118,7 +135,8 @@ public abstract class AbstractPhysicalJoin< AbstractPhysicalJoin<?, ?> that = (AbstractPhysicalJoin<?, ?>) o; return joinType == that.joinType && hashJoinConjuncts.equals(that.hashJoinConjuncts) - && otherJoinConjuncts.equals(that.otherJoinConjuncts); + && otherJoinConjuncts.equals(that.otherJoinConjuncts) + && hint.equals(that.hint); } @Override @@ -134,4 +152,9 @@ public abstract class AbstractPhysicalJoin< public Optional<Expression> getOnClauseCondition() { return ExpressionUtils.optionalAnd(hashJoinConjuncts, otherJoinConjuncts); } + + @Override + public JoinHint getHint() { + return hint; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java index cfc7cdbfe8..81f6814685 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.memo.GroupExpression; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.properties.PhysicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; @@ -45,10 +46,15 @@ public class PhysicalHashJoin< // TODO: What's purpose? it's alway empty. private final List<Expression> filterConjuncts = Lists.newArrayList(); - public PhysicalHashJoin(JoinType joinType, List<Expression> hashJoinConjuncts, - List<Expression> otherJoinConjuncts, LogicalProperties logicalProperties, - LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { - this(joinType, hashJoinConjuncts, otherJoinConjuncts, Optional.empty(), logicalProperties, leftChild, + public PhysicalHashJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + LogicalProperties logicalProperties, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild) { + this(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, Optional.empty(), logicalProperties, leftChild, rightChild); } @@ -58,10 +64,15 @@ public class PhysicalHashJoin< * @param joinType Which join type, left semi join, inner join... * @param hashJoinConjuncts conjunct list could use for build hash table in hash join */ - public PhysicalHashJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties, + public PhysicalHashJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { - super(PlanType.PHYSICAL_HASH_JOIN, joinType, hashJoinConjuncts, otherJoinConjuncts, + super(PlanType.PHYSICAL_HASH_JOIN, joinType, hashJoinConjuncts, otherJoinConjuncts, hint, groupExpression, logicalProperties, leftChild, rightChild); } @@ -71,11 +82,18 @@ public class PhysicalHashJoin< * @param joinType Which join type, left semi join, inner join... * @param hashJoinConjuncts conjunct list could use for build hash table in hash join */ - public PhysicalHashJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties, - PhysicalProperties physicalProperties, StatsDeriveResult statsDeriveResult, LEFT_CHILD_TYPE leftChild, + public PhysicalHashJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + JoinHint hint, + Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, + PhysicalProperties physicalProperties, + StatsDeriveResult statsDeriveResult, + LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { - super(PlanType.PHYSICAL_HASH_JOIN, joinType, hashJoinConjuncts, otherJoinConjuncts, + super(PlanType.PHYSICAL_HASH_JOIN, joinType, hashJoinConjuncts, otherJoinConjuncts, hint, groupExpression, logicalProperties, physicalProperties, statsDeriveResult, leftChild, rightChild); } @@ -86,38 +104,42 @@ public class PhysicalHashJoin< @Override public String toString() { - return Utils.toSqlString("PhysicalHashJoin", - "type", joinType, + List<Object> args = Lists.newArrayList("type", joinType, "hashJoinCondition", hashJoinConjuncts, "otherJoinCondition", otherJoinConjuncts, "stats", statsDeriveResult); + if (hint != JoinHint.NONE) { + args.add("hint"); + args.add(hint); + } + return Utils.toSqlString("PhysicalHashJoin", args.toArray()); } @Override public PhysicalHashJoin<Plan, Plan> withChildren(List<Plan> children) { Preconditions.checkArgument(children.size() == 2); - return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, + return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, getLogicalProperties(), children.get(0), children.get(1)); } @Override public PhysicalHashJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> withGroupExpression( Optional<GroupExpression> groupExpression) { - return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, + return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, groupExpression, getLogicalProperties(), left(), right()); } @Override public PhysicalHashJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> withLogicalProperties( Optional<LogicalProperties> logicalProperties) { - return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, + return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, Optional.empty(), logicalProperties.get(), left(), right()); } @Override public PhysicalHashJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> withPhysicalPropertiesAndStats( PhysicalProperties physicalProperties, StatsDeriveResult statsDeriveResult) { - return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, + return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, Optional.empty(), getLogicalProperties(), physicalProperties, statsDeriveResult, left(), right()); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java index e9b54e65b8..525f40ebe7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.memo.GroupExpression; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.properties.PhysicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; @@ -41,11 +42,15 @@ public class PhysicalNestedLoopJoin< RIGHT_CHILD_TYPE extends Plan> extends AbstractPhysicalJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> { - public PhysicalNestedLoopJoin(JoinType joinType, - List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { - this(joinType, hashJoinConjuncts, otherJoinConjuncts, - Optional.empty(), logicalProperties, leftChild, rightChild); + public PhysicalNestedLoopJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + LogicalProperties logicalProperties, + LEFT_CHILD_TYPE leftChild, + RIGHT_CHILD_TYPE rightChild) { + this(joinType, hashJoinConjuncts, otherJoinConjuncts, Optional.empty(), logicalProperties, leftChild, + rightChild); } /** @@ -54,11 +59,16 @@ public class PhysicalNestedLoopJoin< * @param joinType Which join type, left semi join, inner join... * @param hashJoinConjuncts conjunct list could use for build hash table in hash join */ - public PhysicalNestedLoopJoin(JoinType joinType, - List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, - Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties, + public PhysicalNestedLoopJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { super(PlanType.PHYSICAL_NESTED_LOOP_JOIN, joinType, hashJoinConjuncts, otherJoinConjuncts, + // nested loop join ignores join hints. + JoinHint.NONE, groupExpression, logicalProperties, leftChild, rightChild); } @@ -68,12 +78,19 @@ public class PhysicalNestedLoopJoin< * @param joinType Which join type, left semi join, inner join... * @param hashJoinConjuncts conjunct list could use for build hash table in hash join */ - public PhysicalNestedLoopJoin(JoinType joinType, List<Expression> hashJoinConjuncts, - List<Expression> otherJoinConjuncts, Optional<GroupExpression> groupExpression, - LogicalProperties logicalProperties, PhysicalProperties physicalProperties, - StatsDeriveResult statsDeriveResult, LEFT_CHILD_TYPE leftChild, + public PhysicalNestedLoopJoin( + JoinType joinType, + List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, + Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, + PhysicalProperties physicalProperties, + StatsDeriveResult statsDeriveResult, + LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { super(PlanType.PHYSICAL_NESTED_LOOP_JOIN, joinType, hashJoinConjuncts, otherJoinConjuncts, + // nested loop join ignores join hints. + JoinHint.NONE, groupExpression, logicalProperties, physicalProperties, statsDeriveResult, leftChild, rightChild); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/JoinHintTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/JoinHintTest.java new file mode 100644 index 0000000000..76b2cf6dd0 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/JoinHintTest.java @@ -0,0 +1,148 @@ +// 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.nereids; + +import org.apache.doris.nereids.properties.DistributionSpec; +import org.apache.doris.nereids.properties.DistributionSpecHash; +import org.apache.doris.nereids.properties.DistributionSpecHash.ShuffleType; +import org.apache.doris.nereids.trees.plans.JoinHint; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.util.MatchingUtils; +import org.apache.doris.nereids.util.PatternMatchSupported; +import org.apache.doris.nereids.util.PlanChecker; +import org.apache.doris.planner.HashJoinNode; +import org.apache.doris.planner.HashJoinNode.DistributionMode; +import org.apache.doris.planner.PlanFragment; +import org.apache.doris.planner.PlanNode; +import org.apache.doris.utframe.TestWithFeService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +class JoinHintTest extends TestWithFeService implements PatternMatchSupported { + + @Override + protected void runBeforeAll() throws Exception { + createDatabase("test"); + useDatabase("test"); + + createTable("CREATE TABLE `t1` (\n" + + " `a` int(11) NULL,\n" + + " `b` int(11) NULL,\n" + + " `c` int(11) NULL\n" + + ") ENGINE=OLAP\n" + + "DUPLICATE KEY(`a`, `b`, `c`)\n" + + "COMMENT 'OLAP'\n" + + "DISTRIBUTED BY HASH(`b`) BUCKETS 3\n" + + "PROPERTIES (\n" + + "\"replication_allocation\" = \"tag.location.default: 1\",\n" + + "\"in_memory\" = \"false\",\n" + + "\"storage_format\" = \"V2\",\n" + + "\"disable_auto_compaction\" = \"false\"\n" + + ");"); + + createTable("CREATE TABLE `t2` (\n" + + " `x` int(11) NULL,\n" + + " `y` int(11) NULL,\n" + + " `z` int(11) NULL\n" + + ") ENGINE=OLAP\n" + + "DUPLICATE KEY(`x`, `y`, `z`)\n" + + "COMMENT 'OLAP'\n" + + "DISTRIBUTED BY HASH(`y`) BUCKETS 3\n" + + "PROPERTIES (\n" + + "\"replication_allocation\" = \"tag.location.default: 1\",\n" + + "\"in_memory\" = \"false\",\n" + + "\"storage_format\" = \"V2\",\n" + + "\"disable_auto_compaction\" = \"false\"\n" + + ");"); + + createTable("CREATE TABLE `t3` (\n" + + " `x` int(11) NULL,\n" + + " `y` int(11) NULL,\n" + + " `z` int(11) NULL\n" + + ") ENGINE=OLAP\n" + + "DUPLICATE KEY(`x`, `y`, `z`)\n" + + "COMMENT 'OLAP'\n" + + "DISTRIBUTED BY HASH(`y`) BUCKETS 3\n" + + "PROPERTIES (\n" + + "\"replication_allocation\" = \"tag.location.default: 1\",\n" + + "\"in_memory\" = \"false\",\n" + + "\"storage_format\" = \"V2\",\n" + + "\"disable_auto_compaction\" = \"false\"\n" + + ");"); + } + + @Test + public void testBroadcastJoinHint() { + PlanChecker.from(connectContext).checkPlannerResult( + "select * from t1 join [broadcast] t2 on t1.a=t2.x", + planner -> checkPlannerResult(planner, DistributionMode.BROADCAST) + ); + } + + @Test + public void testShuffleJoinHint() { + PlanChecker.from(connectContext).checkPlannerResult( + "select * from t1 join [shuffle] t2 on t1.a=t2.x", + planner -> checkPlannerResult(planner, DistributionMode.PARTITIONED) + ); + } + + @Test + public void testHintWithReorderCrossJoin() throws Exception { + String sql = "select t1.a , t2.x, t.x from " + + "t1 join [shuffle] t2, (select x from t3) t where t1.a=t.x and t2.x=t.x"; + PlanChecker.from(connectContext).checkExplain(sql, planner -> { + Plan plan = planner.getOptimizedPlan(); + MatchingUtils.assertMatches(plan, + physicalDistribute( + physicalProject( + physicalHashJoin( + physicalHashJoin(), + physicalDistribute().when(dis -> { + DistributionSpec spec = dis.getDistributionSpec(); + Assertions.assertTrue(spec instanceof DistributionSpecHash); + DistributionSpecHash hashSpec = (DistributionSpecHash) spec; + Assertions.assertEquals(ShuffleType.ENFORCED, + hashSpec.getShuffleType()); + return true; + }) + ).when(join -> join.getHint() == JoinHint.SHUFFLE_RIGHT) + ) + ) + ); + }); + } + + private void checkPlannerResult(NereidsPlanner planner, DistributionMode mode) { + List<PlanFragment> fragments = planner.getFragments(); + Set<HashJoinNode> hashJoins = new HashSet<>(); + for (PlanFragment fragment : fragments) { + PlanNode plan = fragment.getPlanRoot(); + plan.collect(HashJoinNode.class, hashJoins); + } + + Assertions.assertEquals(1, hashJoins.size()); + HashJoinNode join = hashJoins.iterator().next(); + Assertions.assertEquals(mode, join.getDistributionMode()); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java index d11a82d3c3..f4d4222da8 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.StatementContext; import org.apache.doris.nereids.exceptions.ParseException; import org.apache.doris.nereids.glue.LogicalPlanAdapter; import org.apache.doris.nereids.trees.expressions.literal.DecimalLiteral; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; @@ -255,4 +256,47 @@ public class NereidsParserTest extends ParserTestBase { LogicalPlan logicalPlan1 = nereidsParser1.parseSingle(union1); System.out.println(logicalPlan1.treeString()); } + + @Test + public void testJoinHint() { + // no hint + parsePlan("select * from t1 join t2 on t1.key=t2.key") + .matches(logicalJoin().when(j -> j.getHint() == JoinHint.NONE)); + + // valid hint + parsePlan("select * from t1 join [shuffle] t2 on t1.key=t2.key") + .matches(logicalJoin().when(j -> j.getHint() == JoinHint.SHUFFLE_RIGHT)); + + parsePlan("select * from t1 join [ shuffle ] t2 on t1.key=t2.key") + .matches(logicalJoin().when(j -> j.getHint() == JoinHint.SHUFFLE_RIGHT)); + + parsePlan("select * from t1 join [broadcast] t2 on t1.key=t2.key") + .matches(logicalJoin().when(j -> j.getHint() == JoinHint.BROADCAST_RIGHT)); + + parsePlan("select * from t1 join /*+ broadcast */ t2 on t1.key=t2.key") + .matches(logicalJoin().when(j -> j.getHint() == JoinHint.BROADCAST_RIGHT)); + + // invalid hint position + parsePlan("select * from [shuffle] t1 join t2 on t1.key=t2.key") + .assertThrowsExactly(ParseException.class); + + parsePlan("select * from /*+ shuffle */ t1 join t2 on t1.key=t2.key") + .assertThrowsExactly(ParseException.class); + + // invalid hint content + parsePlan("select * from t1 join [bucket] t2 on t1.key=t2.key") + .assertThrowsExactly(ParseException.class) + .assertMessageContains("Invalid join hint: bucket(line 1, pos 22)\n" + + "\n" + + "== SQL ==\n" + + "select * from t1 join [bucket] t2 on t1.key=t2.key\n" + + "----------------------^^^"); + + // invalid multiple hints + parsePlan("select * from t1 join /*+ shuffle , broadcast */ t2 on t1.key=t2.key") + .assertThrowsExactly(ParseException.class); + + parsePlan("select * from t1 join [shuffle,broadcast] t2 on t1.key=t2.key") + .assertThrowsExactly(ParseException.class); + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java index 0810b5ed0a..a1bcda875b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java @@ -31,6 +31,7 @@ import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateParam; import org.apache.doris.nereids.trees.plans.AggMode; import org.apache.doris.nereids.trees.plans.AggPhase; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalJoin; @@ -112,7 +113,8 @@ public class ChildOutputPropertyDeriverTest { }; PhysicalHashJoin<GroupPlan, GroupPlan> join = new PhysicalHashJoin<>(JoinType.RIGHT_OUTER_JOIN, - ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, + groupPlan, groupPlan); GroupExpression groupExpression = new GroupExpression(join); PhysicalProperties left = new PhysicalProperties( @@ -161,7 +163,7 @@ public class ChildOutputPropertyDeriverTest { new SlotReference(new ExprId(0), "left", IntegerType.INSTANCE, false, Collections.emptyList()), new SlotReference(new ExprId(2), "right", IntegerType.INSTANCE, false, Collections.emptyList()))), - ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, groupPlan, groupPlan); GroupExpression groupExpression = new GroupExpression(join); Map<ExprId, Integer> leftMap = Maps.newHashMap(); @@ -207,7 +209,7 @@ public class ChildOutputPropertyDeriverTest { new SlotReference(new ExprId(0), "left", IntegerType.INSTANCE, false, Collections.emptyList()), new SlotReference(new ExprId(2), "right", IntegerType.INSTANCE, false, Collections.emptyList()))), - ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, groupPlan, groupPlan); GroupExpression groupExpression = new GroupExpression(join); Map<ExprId, Integer> leftMap = Maps.newHashMap(); @@ -244,7 +246,8 @@ public class ChildOutputPropertyDeriverTest { @Test public void testNestedLoopJoin() { PhysicalNestedLoopJoin<GroupPlan, GroupPlan> join = new PhysicalNestedLoopJoin<>(JoinType.CROSS_JOIN, - ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, + groupPlan); GroupExpression groupExpression = new GroupExpression(join); Map<ExprId, Integer> leftMap = Maps.newHashMap(); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/RequestPropertyDeriverTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/RequestPropertyDeriverTest.java index 9e007f8bea..2639dcfa18 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/RequestPropertyDeriverTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/RequestPropertyDeriverTest.java @@ -28,6 +28,7 @@ import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateParam; import org.apache.doris.nereids.trees.plans.AggMode; import org.apache.doris.nereids.trees.plans.AggPhase; import org.apache.doris.nereids.trees.plans.GroupPlan; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalJoin; @@ -78,7 +79,8 @@ public class RequestPropertyDeriverTest { @Test public void testNestedLoopJoin() { PhysicalNestedLoopJoin<GroupPlan, GroupPlan> join = new PhysicalNestedLoopJoin<>(JoinType.CROSS_JOIN, - ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, + groupPlan); GroupExpression groupExpression = new GroupExpression(join); RequestPropertyDeriver requestPropertyDeriver = new RequestPropertyDeriver(jobContext); @@ -101,7 +103,8 @@ public class RequestPropertyDeriverTest { }; PhysicalHashJoin<GroupPlan, GroupPlan> join = new PhysicalHashJoin<>(JoinType.RIGHT_OUTER_JOIN, - ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, + groupPlan, groupPlan); GroupExpression groupExpression = new GroupExpression(join); RequestPropertyDeriver requestPropertyDeriver = new RequestPropertyDeriver(jobContext); @@ -127,7 +130,8 @@ public class RequestPropertyDeriverTest { }; PhysicalHashJoin<GroupPlan, GroupPlan> join = new PhysicalHashJoin<>(JoinType.INNER_JOIN, - ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, logicalProperties, groupPlan, groupPlan); + ExpressionUtils.EMPTY_CONDITION, ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, + groupPlan, groupPlan); GroupExpression groupExpression = new GroupExpression(join); RequestPropertyDeriver requestPropertyDeriver = new RequestPropertyDeriver(jobContext); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoinTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoinTest.java index 88f5e0570f..42d34f2cd0 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoinTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/FindHashConditionForJoinTest.java @@ -26,6 +26,7 @@ import org.apache.doris.nereids.trees.expressions.LessThan; import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -74,7 +75,7 @@ class FindHashConditionForJoinTest { Expression less = new LessThan(scoreId, studentId); List<Expression> expr = ImmutableList.of(eq1, eq2, eq3, or, less); LogicalJoin join = new LogicalJoin<>(JoinType.INNER_JOIN, new ArrayList<>(), - expr, student, score); + expr, JoinHint.NONE, student, score); CascadesContext context = MemoTestUtils.createCascadesContext(join); List<Rule> rules = Lists.newArrayList(new FindHashConditionForJoin().build()); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherConditionTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherConditionTest.java index 387edc747c..9b7d20b84a 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherConditionTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownJoinOtherConditionTest.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.memo.Memo; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.GreaterThan; import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; @@ -83,7 +84,7 @@ public class PushdownJoinOtherConditionTest { right = rStudent; } - Plan join = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition, left, right); + Plan join = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition, JoinHint.NONE, left, right); Plan root = new LogicalProject<>(Lists.newArrayList(), join); Memo memo = rewrite(root); @@ -123,7 +124,8 @@ public class PushdownJoinOtherConditionTest { Expression rightSide = new GreaterThan(rScore.getOutput().get(2), Literal.of(60)); List<Expression> condition = ImmutableList.of(leftSide, rightSide); - Plan join = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition, rStudent, rScore); + Plan join = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition, JoinHint.NONE, rStudent, + rScore); Plan root = new LogicalProject<>(Lists.newArrayList(), join); Memo memo = rewrite(root); @@ -165,7 +167,7 @@ public class PushdownJoinOtherConditionTest { right = rStudent; } - Plan join = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition, left, right); + Plan join = new LogicalJoin<>(joinType, ExpressionUtils.EMPTY_CONDITION, condition, JoinHint.NONE, left, right); Plan root = new LogicalProject<>(Lists.newArrayList(), join); Memo memo = rewrite(root); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java index c91cffabf9..f084777bf7 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java @@ -227,20 +227,20 @@ public class PlanEqualsTest { Lists.newArrayList(new EqualTo( new SlotReference(new ExprId(0), "a", BigIntType.INSTANCE, true, Lists.newArrayList()), new SlotReference(new ExprId(1), "b", BigIntType.INSTANCE, true, Lists.newArrayList()))), - ExpressionUtils.EMPTY_CONDITION, logicalProperties, left, right); + ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, left, right); PhysicalHashJoin<Plan, Plan> expected = new PhysicalHashJoin<>(JoinType.INNER_JOIN, Lists.newArrayList(new EqualTo( new SlotReference(new ExprId(0), "a", BigIntType.INSTANCE, true, Lists.newArrayList()), new SlotReference(new ExprId(1), "b", BigIntType.INSTANCE, true, Lists.newArrayList()))), - ExpressionUtils.EMPTY_CONDITION, logicalProperties, left, right); + ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, left, right); Assertions.assertEquals(expected, actual); PhysicalHashJoin<Plan, Plan> unexpected = new PhysicalHashJoin<>(JoinType.INNER_JOIN, Lists.newArrayList(new EqualTo( new SlotReference(new ExprId(2), "a", BigIntType.INSTANCE, false, Lists.newArrayList()), new SlotReference(new ExprId(3), "b", BigIntType.INSTANCE, true, Lists.newArrayList()))), - ExpressionUtils.EMPTY_CONDITION, logicalProperties, left, right); + ExpressionUtils.EMPTY_CONDITION, JoinHint.NONE, logicalProperties, left, right); Assertions.assertNotEquals(unexpected, actual); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExceptionChecker.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExceptionChecker.java index ebea43fee5..0ae5615e78 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExceptionChecker.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/ExceptionChecker.java @@ -37,7 +37,7 @@ public class ExceptionChecker { } public ExceptionChecker assertMessageContains(String context) { - Assertions.assertTrue(exception.getMessage().contains(context)); + Assertions.assertTrue(exception.getMessage().contains(context), exception.getMessage()); return this; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java index fb9f9a7b49..2a8aa72952 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.plans.JoinHint; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; @@ -104,7 +105,7 @@ public class LogicalPlanBuilder { public LogicalPlanBuilder hashJoinUsing(LogicalPlan right, JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjucts) { LogicalJoin<LogicalPlan, LogicalPlan> join = new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjucts, - this.plan, right); + JoinHint.NONE, this.plan, right); return from(join); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/GroupMatchingUtils.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/MatchingUtils.java similarity index 61% rename from fe/fe-core/src/test/java/org/apache/doris/nereids/util/GroupMatchingUtils.java rename to fe/fe-core/src/test/java/org/apache/doris/nereids/util/MatchingUtils.java index 15861f724e..bc5bb1d78d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/GroupMatchingUtils.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/MatchingUtils.java @@ -19,11 +19,39 @@ package org.apache.doris.nereids.util; import org.apache.doris.nereids.memo.Group; import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.memo.Memo; import org.apache.doris.nereids.pattern.GroupExpressionMatching; import org.apache.doris.nereids.pattern.Pattern; +import org.apache.doris.nereids.pattern.PatternDescriptor; import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; +import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan; -public class GroupMatchingUtils { +import com.google.common.base.Supplier; +import org.junit.jupiter.api.Assertions; + +public class MatchingUtils { + + public static void assertMatches(Plan plan, PatternDescriptor<? extends Plan> patternDesc) { + Memo memo = new Memo(plan); + if (plan instanceof PhysicalPlan) { + assertMatches(memo, () -> new GroupExpressionMatching(patternDesc.pattern, + memo.getRoot().getPhysicalExpressions().get(0)).iterator().hasNext()); + } else if (plan instanceof LogicalPlan) { + assertMatches(memo, () -> new GroupExpressionMatching(patternDesc.pattern, + memo.getRoot().getLogicalExpression()).iterator().hasNext()); + } else { + throw new IllegalStateException("Input plan should be LogicalPlan or PhysicalPlan, but meet " + plan); + } + } + + private static void assertMatches(Memo memo, Supplier<Boolean> asserter) { + Assertions.assertTrue(asserter.get(), + () -> "pattern not match, plan :\n" + + memo.getRoot().getLogicalExpression().getPlan().treeString() + + "\n" + ); + } public static boolean topDownFindMatching(Group group, Pattern<? extends Plan> pattern) { for (GroupExpression logicalExpr : group.getLogicalExpressions()) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java index 87754d1642..362ca94f42 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanChecker.java @@ -17,6 +17,7 @@ package org.apache.doris.nereids.util; +import org.apache.doris.analysis.ExplainOptions; import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.NereidsPlanner; import org.apache.doris.nereids.StatementContext; @@ -41,6 +42,7 @@ import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan; @@ -345,7 +347,7 @@ public class PlanChecker { public PlanChecker matches(PatternDescriptor<? extends Plan> patternDesc) { Memo memo = cascadesContext.getMemo(); - assertMatches(memo, () -> GroupMatchingUtils.topDownFindMatching(memo.getRoot(), patternDesc.pattern)); + assertMatches(memo, () -> MatchingUtils.topDownFindMatching(memo.getRoot(), patternDesc.pattern)); return this; } @@ -414,6 +416,17 @@ public class PlanChecker { return this; } + public PlanChecker checkExplain(String sql, Consumer<NereidsPlanner> consumer) { + LogicalPlan parsed = new NereidsParser().parseSingle(sql); + NereidsPlanner nereidsPlanner = new NereidsPlanner( + new StatementContext(connectContext, new OriginStatement(sql, 0))); + LogicalPlanAdapter adapter = LogicalPlanAdapter.of(parsed); + adapter.setIsExplain(new ExplainOptions(ExplainLevel.ALL_PLAN)); + nereidsPlanner.plan(adapter); + consumer.accept(nereidsPlanner); + return this; + } + public PlanChecker checkPlannerResult(String sql, Consumer<NereidsPlanner> consumer) { LogicalPlan parsed = new NereidsParser().parseSingle(sql); NereidsPlanner nereidsPlanner = new NereidsPlanner( diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanParseChecker.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanParseChecker.java index 55032a2864..1e3484ae40 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanParseChecker.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanParseChecker.java @@ -35,7 +35,7 @@ public class PlanParseChecker extends ParseChecker { } public PlanParseChecker matches(PatternDescriptor<? extends Plan> patternDesc) { - assertMatches(() -> GroupMatchingUtils.topDownFindMatching( + assertMatches(() -> MatchingUtils.topDownFindMatching( new Memo(parsedSupplier.get()).getRoot(), patternDesc.pattern)); return this; } diff --git a/regression-test/suites/account_p0/test_nereids_authentication.groovy b/regression-test/suites/account_p0/test_nereids_authentication.groovy index 6a2a980401..bd9449cf53 100644 --- a/regression-test/suites/account_p0/test_nereids_authentication.groovy +++ b/regression-test/suites/account_p0/test_nereids_authentication.groovy @@ -41,17 +41,17 @@ suite("test_nereids_authentication", "query") { def user='nereids_user' try_sql "DROP USER ${user}" - sql "CREATE USER ${user} IDENTIFIED BY '123456'" + sql "CREATE USER ${user} IDENTIFIED BY 'Doris_123456'" sql "GRANT SELECT_PRIV ON internal.${dbName}.${tableName1} TO ${user}" def tokens = context.config.jdbcUrl.split('/') def url=tokens[0] + "//" + tokens[2] + "/" + dbName + "?" - def result = connect(user=user, password='123456', url=url) { + def result = connect(user=user, password='Doris_123456', url=url) { sql "SELECT * FROM ${tableName1}" } assertEquals(result.size(), 0) - connect(user=user, password='123456', url=url) { + connect(user=user, password='Doris_123456', url=url) { try { sql "SELECT * FROM ${tableName2}" fail() @@ -61,7 +61,7 @@ suite("test_nereids_authentication", "query") { } } - connect(user=user, password='123456', url=url) { + connect(user=user, password='Doris_123456', url=url) { try { sql "SELECT * FROM ${tableName1}, ${tableName2} WHERE ${tableName1}.`key` = ${tableName2}.`key`" fail() @@ -72,11 +72,11 @@ suite("test_nereids_authentication", "query") { } sql "GRANT SELECT_PRIV ON internal.${dbName}.${tableName2} TO ${user}" - connect(user=user, password='123456', url=url) { + connect(user=user, password='Doris_123456', url=url) { sql "SELECT * FROM ${tableName2}" } assertEquals(result.size(), 0) - connect(user=user, password='123456', url=url) { + connect(user=user, password='Doris_123456', url=url) { sql "SELECT * FROM ${tableName1}, ${tableName2} WHERE ${tableName1}.`key` = ${tableName2}.`key`" } assertEquals(result.size(), 0) --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org