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 9f2756f61ce [feat](Nereids) support nereids hint position detaction 
(#39113)
9f2756f61ce is described below

commit 9f2756f61cef5725e024f37ee8c4ff0aa4ff2321
Author: LiBinfeng <46676950+libinfeng...@users.noreply.github.com>
AuthorDate: Thu Aug 15 15:11:12 2024 +0800

    [feat](Nereids) support nereids hint position detaction (#39113)
    
    When use hint in wrong position or use unsupport hint,
    use channel(2) to filter it out
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |  18 +++
 .../doris/nereids/parser/LogicalPlanBuilder.java   | 126 ++++++++++++---------
 .../parser/LogicalPlanBuilderForCreateView.java    |   5 +
 .../parser/LogicalPlanBuilderForSyncMv.java        |   5 +
 .../apache/doris/nereids/parser/NereidsParser.java |  37 +++++-
 .../parser/plsql/PLSqlLogicalPlanBuilder.java      |   4 +
 .../doris/nereids/parser/NereidsParserTest.java    |   8 --
 regression-test/data/nereids_p0/hint/test_hint.out |  78 +++++++++++++
 .../data/nereids_p0/hint/test_leading.out          |   4 +-
 .../suites/nereids_p0/hint/test_hint.groovy        |  61 ++++++++++
 .../suites/nereids_p0/hint/test_leading.groovy     |   2 +-
 11 files changed, 280 insertions(+), 68 deletions(-)

diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index 5ed655c212a..b4a4c7ddefe 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -72,6 +72,19 @@ lexer grammar DorisLexer;
   public void markUnclosedComment() {
     has_unclosed_bracketed_comment = true;
   }
+
+  // This variable will hold the external state
+  private boolean channel2;
+
+  // Method to set the external state
+  public void setChannel2(boolean value) {
+      this.channel2 = value;
+  }
+
+  // Method to decide the channel based on external state
+  private boolean isChannel2() {
+      return this.channel2;
+  }
 }
 
 SEMICOLON: ';';
@@ -686,6 +699,11 @@ BRACKETED_COMMENT
     : '/*' {!isHint()}? ( BRACKETED_COMMENT | . )*? ('*/' | 
{markUnclosedComment();} EOF) -> channel(HIDDEN)
     ;
 
+HINT_WITH_CHANNEL
+    : {isChannel2()}? HINT_START .*? HINT_END -> channel(2)
+    ;
+
+
 FROM_DUAL
     : 'FROM' WS+ 'DUAL' -> channel(HIDDEN);
 
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 de23ba16e82..104acf7fe4c 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
@@ -514,6 +514,12 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return pos1.getCharPositionInLine() - pos2.getCharPositionInLine();
     });
 
+    private final Map<Integer, ParserRuleContext> selectHintMap;
+
+    public LogicalPlanBuilder(Map<Integer, ParserRuleContext> selectHintMap) {
+        this.selectHintMap = selectHintMap;
+    }
+
     @SuppressWarnings("unchecked")
     protected <T> T typedVisit(ParseTree ctx) {
         return (T) ctx.accept(this);
@@ -1352,7 +1358,16 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
                     Optional.ofNullable(ctx.aggClause()),
                     Optional.ofNullable(ctx.havingClause()));
             selectPlan = withQueryOrganization(selectPlan, 
ctx.queryOrganization());
-            return withSelectHint(selectPlan, selectCtx.selectHint());
+            if ((selectHintMap == null) || selectHintMap.isEmpty()) {
+                return selectPlan;
+            }
+            List<ParserRuleContext> selectHintContexts = Lists.newArrayList();
+            for (Integer key : selectHintMap.keySet()) {
+                if (key > selectCtx.getStart().getStopIndex() && key < 
selectCtx.getStop().getStartIndex()) {
+                    selectHintContexts.add(selectHintMap.get(key));
+                }
+            }
+            return withSelectHint(selectPlan, selectHintContexts);
         });
     }
 
@@ -3110,67 +3125,70 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return last;
     }
 
-    private LogicalPlan withSelectHint(LogicalPlan logicalPlan, 
SelectHintContext hintContext) {
-        if (hintContext == null) {
+    private LogicalPlan withSelectHint(LogicalPlan logicalPlan, 
List<ParserRuleContext> hintContexts) {
+        if (hintContexts.isEmpty()) {
             return logicalPlan;
         }
         Map<String, SelectHint> hints = Maps.newLinkedHashMap();
-        for (HintStatementContext hintStatement : hintContext.hintStatements) {
-            String hintName = 
hintStatement.hintName.getText().toLowerCase(Locale.ROOT);
-            switch (hintName) {
-                case "set_var":
-                    Map<String, Optional<String>> parameters = 
Maps.newLinkedHashMap();
-                    for (HintAssignmentContext kv : hintStatement.parameters) {
-                        if (kv.key != null) {
-                            String parameterName = 
visitIdentifierOrText(kv.key);
-                            Optional<String> value = Optional.empty();
-                            if (kv.constantValue != null) {
-                                Literal literal = (Literal) 
visit(kv.constantValue);
-                                value = 
Optional.ofNullable(literal.toLegacyLiteral().getStringValue());
-                            } else if (kv.identifierValue != null) {
-                                // maybe we should throw exception when the 
identifierValue is quoted identifier
-                                value = 
Optional.ofNullable(kv.identifierValue.getText());
+        for (ParserRuleContext hintContext : hintContexts) {
+            SelectHintContext selectHintContext = (SelectHintContext) 
hintContext;
+            for (HintStatementContext hintStatement : 
selectHintContext.hintStatements) {
+                String hintName = 
hintStatement.hintName.getText().toLowerCase(Locale.ROOT);
+                switch (hintName) {
+                    case "set_var":
+                        Map<String, Optional<String>> parameters = 
Maps.newLinkedHashMap();
+                        for (HintAssignmentContext kv : 
hintStatement.parameters) {
+                            if (kv.key != null) {
+                                String parameterName = 
visitIdentifierOrText(kv.key);
+                                Optional<String> value = Optional.empty();
+                                if (kv.constantValue != null) {
+                                    Literal literal = (Literal) 
visit(kv.constantValue);
+                                    value = 
Optional.ofNullable(literal.toLegacyLiteral().getStringValue());
+                                } else if (kv.identifierValue != null) {
+                                    // maybe we should throw exception when 
the identifierValue is quoted identifier
+                                    value = 
Optional.ofNullable(kv.identifierValue.getText());
+                                }
+                                parameters.put(parameterName, value);
                             }
-                            parameters.put(parameterName, value);
                         }
-                    }
-                    hints.put(hintName, new SelectHintSetVar(hintName, 
parameters));
-                    break;
-                case "leading":
-                    List<String> leadingParameters = new ArrayList<String>();
-                    for (HintAssignmentContext kv : hintStatement.parameters) {
-                        if (kv.key != null) {
-                            String parameterName = 
visitIdentifierOrText(kv.key);
-                            leadingParameters.add(parameterName);
+                        hints.put(hintName, new SelectHintSetVar(hintName, 
parameters));
+                        break;
+                    case "leading":
+                        List<String> leadingParameters = new 
ArrayList<String>();
+                        for (HintAssignmentContext kv : 
hintStatement.parameters) {
+                            if (kv.key != null) {
+                                String parameterName = 
visitIdentifierOrText(kv.key);
+                                leadingParameters.add(parameterName);
+                            }
                         }
-                    }
-                    hints.put(hintName, new SelectHintLeading(hintName, 
leadingParameters));
-                    break;
-                case "ordered":
-                    hints.put(hintName, new SelectHintOrdered(hintName));
-                    break;
-                case "use_cbo_rule":
-                    List<String> useRuleParameters = new ArrayList<String>();
-                    for (HintAssignmentContext kv : hintStatement.parameters) {
-                        if (kv.key != null) {
-                            String parameterName = 
visitIdentifierOrText(kv.key);
-                            useRuleParameters.add(parameterName);
+                        hints.put(hintName, new SelectHintLeading(hintName, 
leadingParameters));
+                        break;
+                    case "ordered":
+                        hints.put(hintName, new SelectHintOrdered(hintName));
+                        break;
+                    case "use_cbo_rule":
+                        List<String> useRuleParameters = new 
ArrayList<String>();
+                        for (HintAssignmentContext kv : 
hintStatement.parameters) {
+                            if (kv.key != null) {
+                                String parameterName = 
visitIdentifierOrText(kv.key);
+                                useRuleParameters.add(parameterName);
+                            }
                         }
-                    }
-                    hints.put(hintName, new SelectHintUseCboRule(hintName, 
useRuleParameters, false));
-                    break;
-                case "no_use_cbo_rule":
-                    List<String> noUseRuleParameters = new ArrayList<String>();
-                    for (HintAssignmentContext kv : hintStatement.parameters) {
-                        String parameterName = visitIdentifierOrText(kv.key);
-                        if (kv.key != null) {
-                            noUseRuleParameters.add(parameterName);
+                        hints.put(hintName, new SelectHintUseCboRule(hintName, 
useRuleParameters, false));
+                        break;
+                    case "no_use_cbo_rule":
+                        List<String> noUseRuleParameters = new 
ArrayList<String>();
+                        for (HintAssignmentContext kv : 
hintStatement.parameters) {
+                            String parameterName = 
visitIdentifierOrText(kv.key);
+                            if (kv.key != null) {
+                                noUseRuleParameters.add(parameterName);
+                            }
                         }
-                    }
-                    hints.put(hintName, new SelectHintUseCboRule(hintName, 
noUseRuleParameters, true));
-                    break;
-                default:
-                    break;
+                        hints.put(hintName, new SelectHintUseCboRule(hintName, 
noUseRuleParameters, true));
+                        break;
+                    default:
+                        break;
+                }
             }
         }
         return new LogicalSelectHint<>(hints, logicalPlan);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForCreateView.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForCreateView.java
index 3989a8f8988..12c206dc084 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForCreateView.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForCreateView.java
@@ -52,10 +52,15 @@ import org.apache.doris.qe.ConnectContext;
 import com.google.common.collect.ImmutableList;
 import org.antlr.v4.runtime.ParserRuleContext;
 
+import java.util.Map;
 import java.util.Optional;
 
 /**LogicalPlanBuilderForCreateView*/
 public class LogicalPlanBuilderForCreateView extends LogicalPlanBuilder {
+    public LogicalPlanBuilderForCreateView(Map<Integer, ParserRuleContext> 
selectHintMap) {
+        super(selectHintMap);
+    }
+
     @Override
     protected LogicalPlan withGenerate(LogicalPlan plan, LateralViewContext 
ctx) {
         ConnectContext.get().getStatementContext().addIndexInSqlToString(
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForSyncMv.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForSyncMv.java
index 4cdf33f9ff7..840b9fdacc3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForSyncMv.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForSyncMv.java
@@ -37,6 +37,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.util.PlanUtils;
 
 import com.google.common.collect.ImmutableList;
+import org.antlr.v4.runtime.ParserRuleContext;
 
 import java.util.List;
 import java.util.Map;
@@ -49,6 +50,10 @@ import java.util.TreeMap;
 public class LogicalPlanBuilderForSyncMv extends LogicalPlanBuilder {
     private Optional<String> querySql;
 
+    public LogicalPlanBuilderForSyncMv(Map<Integer, ParserRuleContext> 
selectHintMap) {
+        super(selectHintMap);
+    }
+
     @Override
     public Expression 
visitFunctionCallExpression(DorisParser.FunctionCallExpressionContext ctx) {
         Expression expression = super.visitFunctionCallExpression(ctx);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
index 0cfea1e8eb7..3ba1e0e5431 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
@@ -36,6 +36,7 @@ import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.SessionVariable;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.ParserRuleContext;
@@ -273,26 +274,56 @@ public class NereidsParser {
                         Function<DorisParser, ParserRuleContext> 
parseFunction) {
         ParserRuleContext tree = toAst(sql, parseFunction);
         LogicalPlanBuilder realLogicalPlanBuilder = logicalPlanBuilder == null
-                    ? new LogicalPlanBuilder() : logicalPlanBuilder;
+                    ? new LogicalPlanBuilder(getHintMap(sql, 
DorisParser::selectHint)) : logicalPlanBuilder;
         return (T) realLogicalPlanBuilder.visit(tree);
     }
 
     public LogicalPlan parseForCreateView(String sql) {
         ParserRuleContext tree = toAst(sql, DorisParser::singleStatement);
-        LogicalPlanBuilder realLogicalPlanBuilder = new 
LogicalPlanBuilderForCreateView();
+        LogicalPlanBuilder realLogicalPlanBuilder = new 
LogicalPlanBuilderForCreateView(
+                getHintMap(sql, DorisParser::selectHint));
         return (LogicalPlan) realLogicalPlanBuilder.visit(tree);
     }
 
     public Optional<String> parseForSyncMv(String sql) {
         ParserRuleContext tree = toAst(sql, DorisParser::singleStatement);
-        LogicalPlanBuilderForSyncMv logicalPlanBuilderForSyncMv = new 
LogicalPlanBuilderForSyncMv();
+        LogicalPlanBuilderForSyncMv logicalPlanBuilderForSyncMv = new 
LogicalPlanBuilderForSyncMv(
+                getHintMap(sql, DorisParser::selectHint));
         logicalPlanBuilderForSyncMv.visit(tree);
         return logicalPlanBuilderForSyncMv.getQuerySql();
     }
 
+    /** get hint map */
+    public static Map<Integer, ParserRuleContext> getHintMap(String sql,
+                                                             
Function<DorisParser, ParserRuleContext> parseFunction) {
+        // parse hint first round
+        DorisLexer hintLexer = new DorisLexer(new 
CaseInsensitiveStream(CharStreams.fromString(sql)));
+        hintLexer.setChannel2(true);
+        CommonTokenStream hintTokenStream = new CommonTokenStream(hintLexer);
+
+        Map<Integer, ParserRuleContext> selectHintMap = Maps.newHashMap();
+
+        Token hintToken = hintTokenStream.getTokenSource().nextToken();
+        while (hintToken != null && hintToken.getType() != DorisLexer.EOF) {
+            int tokenType = hintToken.getType();
+            if (tokenType == DorisLexer.HINT_WITH_CHANNEL) {
+                String hintSql = sql.substring(hintToken.getStartIndex(), 
hintToken.getStopIndex() + 1);
+                DorisLexer newHintLexer = new DorisLexer(new 
CaseInsensitiveStream(CharStreams.fromString(hintSql)));
+                newHintLexer.setChannel2(false);
+                CommonTokenStream newHintTokenStream = new 
CommonTokenStream(newHintLexer);
+                DorisParser hintParser = new DorisParser(newHintTokenStream);
+                ParserRuleContext hintContext = 
parseFunction.apply(hintParser);
+                selectHintMap.put(hintToken.getStartIndex(), hintContext);
+            }
+            hintToken = hintTokenStream.getTokenSource().nextToken();
+        }
+        return selectHintMap;
+    }
+
     /** toAst */
     public static ParserRuleContext toAst(String sql, Function<DorisParser, 
ParserRuleContext> parseFunction) {
         DorisLexer lexer = new DorisLexer(new 
CaseInsensitiveStream(CharStreams.fromString(sql)));
+        lexer.setChannel2(true);
         CommonTokenStream tokenStream = new CommonTokenStream(lexer);
         DorisParser parser = new DorisParser(tokenStream);
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/plsql/PLSqlLogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/plsql/PLSqlLogicalPlanBuilder.java
index 5841c451dd1..8825f5abd93 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/plsql/PLSqlLogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/plsql/PLSqlLogicalPlanBuilder.java
@@ -36,6 +36,10 @@ import java.util.List;
  */
 public class PLSqlLogicalPlanBuilder extends LogicalPlanBuilder {
 
+    public PLSqlLogicalPlanBuilder() {
+        super(null);
+    }
+
     public List<String> visitMultipartIdentifier(MultipartIdentifierContext 
ctx) {
         return ctx.parts.stream()
                 .map(RuleContext::getText)
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 f838b300649..0907fec8f28 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
@@ -352,16 +352,10 @@ public class NereidsParserTest extends ParserTestBase {
         parsePlan("select * from t1 join [broadcast] t2 on t1.keyy=t2.keyy")
                 .matches(logicalJoin().when(j -> 
j.getDistributeHint().distributeType == DistributeType.BROADCAST_RIGHT));
 
-        parsePlan("select * from t1 join /*+ broadcast   */ t2 on 
t1.keyy=t2.keyy")
-                .matches(logicalJoin().when(j -> 
j.getDistributeHint().distributeType == DistributeType.BROADCAST_RIGHT));
-
         // invalid hint position
         parsePlan("select * from [shuffle] t1 join t2 on t1.keyy=t2.keyy")
                 .assertThrowsExactly(ParseException.class);
 
-        parsePlan("select * from /*+ shuffle */ t1 join t2 on t1.keyy=t2.keyy")
-                .assertThrowsExactly(ParseException.class);
-
         // invalid hint content
         parsePlan("select * from t1 join [bucket] t2 on t1.keyy=t2.keyy")
                 .assertThrowsExactly(ParseException.class)
@@ -372,8 +366,6 @@ public class NereidsParserTest extends ParserTestBase {
                         + "----------------------^^^");
 
         // invalid multiple hints
-        parsePlan("select * from t1 join /*+ shuffle , broadcast */ t2 on 
t1.keyy=t2.keyy")
-                .assertThrowsExactly(ParseException.class);
 
         parsePlan("select * from t1 join [shuffle,broadcast] t2 on 
t1.keyy=t2.keyy")
                 .assertThrowsExactly(ParseException.class);
diff --git a/regression-test/data/nereids_p0/hint/test_hint.out 
b/regression-test/data/nereids_p0/hint/test_hint.out
new file mode 100644
index 00000000000..66a218b09fe
--- /dev/null
+++ b/regression-test/data/nereids_p0/hint/test_hint.out
@@ -0,0 +1,78 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !select1_1 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------hashJoin[INNER_JOIN broadcast] hashCondition=((t1.c1 = t2.c2)) 
otherCondition=()
+----------PhysicalOlapScan[t2]
+----------PhysicalOlapScan[t1]
+
+Hint log:
+Used: leading(t2 broadcast t1 ) 
+UnUsed:
+SyntaxError:
+
+-- !select1_2 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------PhysicalStorageLayerAggregate[t1]
+
+-- !select1_3 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------PhysicalStorageLayerAggregate[t1]
+
+-- !select1_4 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------PhysicalStorageLayerAggregate[t1]
+
+-- !select1_5 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------hashJoin[INNER_JOIN broadcast] hashCondition=((t1.c1 = t2.c2)) 
otherCondition=()
+----------PhysicalOlapScan[t2]
+----------PhysicalOlapScan[t1]
+
+Hint log:
+Used: leading(t2 broadcast t1 ) 
+UnUsed:
+SyntaxError:
+
+-- !select1_6 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------hashJoin[INNER_JOIN broadcast] hashCondition=((t1.c1 = t2.c2)) 
otherCondition=()
+----------PhysicalOlapScan[t2]
+----------PhysicalOlapScan[t1]
+
+Hint log:
+Used: leading(t2 broadcast t1 ) 
+UnUsed:
+SyntaxError:
+
+-- !select1_7 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------PhysicalStorageLayerAggregate[t1]
+
+-- !select1_8 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------PhysicalStorageLayerAggregate[t1]
+
diff --git a/regression-test/data/nereids_p0/hint/test_leading.out 
b/regression-test/data/nereids_p0/hint/test_leading.out
index 45de5151904..7d397578838 100644
--- a/regression-test/data/nereids_p0/hint/test_leading.out
+++ b/regression-test/data/nereids_p0/hint/test_leading.out
@@ -2493,8 +2493,8 @@ PhysicalResultSink
 ----------PhysicalOlapScan[t3]
 
 Hint log:
-Used: leading(t1 broadcast t2 t3 ) 
-UnUsed: 
+Used: leading(t1 broadcast t2 broadcast t3 ) 
+UnUsed:
 SyntaxError:
 
 -- !select95_4 --
diff --git a/regression-test/suites/nereids_p0/hint/test_hint.groovy 
b/regression-test/suites/nereids_p0/hint/test_hint.groovy
new file mode 100644
index 00000000000..d279b7c1a1d
--- /dev/null
+++ b/regression-test/suites/nereids_p0/hint/test_hint.groovy
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+suite("test_hint") {
+    // create database and tables
+    sql 'DROP DATABASE IF EXISTS test_hint'
+    sql 'CREATE DATABASE IF NOT EXISTS test_hint'
+    sql 'use test_hint'
+
+    // setting planner to nereids
+    sql 'set exec_mem_limit=21G'
+    sql 'set be_number_for_test=1'
+    sql 'set parallel_pipeline_task_num=1'
+    sql "set disable_nereids_rules=PRUNE_EMPTY_PARTITION"
+    sql 'set enable_nereids_planner=true'
+    sql 'set enable_nereids_distribute_planner=false'
+    sql "set ignore_shape_nodes='PhysicalProject'"
+    sql 'set enable_fallback_to_original_planner=false'
+    sql 'set runtime_filter_mode=OFF'
+
+    // create tables
+    sql """drop table if exists t1;"""
+    sql """drop table if exists t2;"""
+
+    sql """create table t1 (c1 int, c11 int) distributed by hash(c1) buckets 3 
properties('replication_num' = '1');"""
+    sql """create table t2 (c2 int, c22 int) distributed by hash(c2) buckets 3 
properties('replication_num' = '1');"""
+
+// test hint positions, remove join in order to make sure shape stable when no 
use hint
+    qt_select1_1 """explain shape plan select /*+ leading(t2 broadcast t1) */ 
count(*) from t1 join t2 on c1 = c2;"""
+
+    qt_select1_2 """explain shape plan /*+ leading(t2 broadcast t1) */ select 
count(*) from t1;"""
+
+    qt_select1_3 """explain shape plan select /*+DBP: ROUTE={GROUP_ID(zjaq)}*/ 
count(*) from t1;"""
+
+    qt_select1_4 """explain shape plan/*+DBP: ROUTE={GROUP_ID(zjaq)}*/ select 
count(*) from t1;"""
+
+    qt_select1_5 """explain shape plan /*+ leading(t2 broadcast t1) */ select 
/*+ leading(t2 broadcast t1) */ count(*) from t1 join t2 on c1 = c2;"""
+
+    qt_select1_6 """explain shape plan/*+DBP: ROUTE={GROUP_ID(zjaq)}*/ select 
/*+ leading(t2 broadcast t1) */ count(*) from t1 join t2 on c1 = c2;"""
+
+    qt_select1_7 """explain shape plan /*+ leading(t2 broadcast t1) */ select 
/*+DBP: ROUTE={GROUP_ID(zjaq)}*/ count(*) from t1;"""
+
+    qt_select1_8 """explain shape plan /*+DBP: ROUTE={GROUP_ID(zjaq)}*/ select 
/*+DBP: ROUTE={GROUP_ID(zjaq)}*/ count(*) from t1;"""
+
+}
diff --git a/regression-test/suites/nereids_p0/hint/test_leading.groovy 
b/regression-test/suites/nereids_p0/hint/test_leading.groovy
index 4a873afbf73..0013eb4e63c 100644
--- a/regression-test/suites/nereids_p0/hint/test_leading.groovy
+++ b/regression-test/suites/nereids_p0/hint/test_leading.groovy
@@ -1001,7 +1001,7 @@ suite("test_leading") {
     qt_select94_2 """explain shape plan select /*+ leading(t2 shuffle {t3 t1}) 
*/ count(*) from t1 join t2 on c1 = c2 join t3 on c2 = c3;"""
 
     // outer join
-    qt_select95_1 """explain shape plan select /*+ leading(t1 broadcast t2 t3) 
*/ count(*) from t1 left outer join t2 on c1 = c2 join t3 on c2 = c3;"""
+    qt_select95_1 """explain shape plan select /*+ leading(t1 broadcast t2 
broadcast t3) */ count(*) from t1 left outer join t2 on c1 = c2 join t3 on c2 = 
c3;"""
     explain {
         sql """shape plan select /*+ leading(t1 broadcast {t2 t3}) */ count(*) 
from t1 left outer join t2 on c1 = c2 join t3 on c2 = c3;"""
         contains("UnUsed: leading(t1 broadcast { t2 t3 })")


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to