This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 9997911ec93 [feat](Nereids) support nereids hint position detaction 
(#39113) (#39417)
9997911ec93 is described below

commit 9997911ec9302e96432e4980e22c7460134eea9e
Author: LiBinfeng <46676950+libinfeng...@users.noreply.github.com>
AuthorDate: Sat Aug 24 23:59:54 2024 +0800

    [feat](Nereids) support nereids hint position detaction (#39113) (#39417)
    
    cherry-pick: #39113
    When use hint in wrong position or use unsupport hint, use channel(2) to
    filter it out
    
    ## Proposed changes
    
    Issue Number: close #xxx
    
    <!--Describe your changes.-->
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  | 20 +----
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  5 +-
 .../doris/nereids/parser/LogicalPlanBuilder.java   | 90 +++++++++++++---------
 .../parser/LogicalPlanBuilderForCreateView.java    |  5 ++
 .../apache/doris/nereids/parser/NereidsParser.java | 30 +++++++-
 .../parser/plsql/PLSqlLogicalPlanBuilder.java      |  4 +
 .../doris/nereids/parser/NereidsParserTest.java    |  8 --
 regression-test/data/nereids_p0/hint/test_hint.out | 81 +++++++++++++++++++
 .../data/nereids_p0/hint/test_leading.out          |  4 +-
 .../suites/nereids_p0/hint/test_hint.groovy        | 60 +++++++++++++++
 .../suites/nereids_p0/hint/test_leading.groovy     |  2 +-
 11 files changed, 242 insertions(+), 67 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 72542ba0874..3ed51ca8fbf 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
@@ -47,22 +47,6 @@ lexer grammar DorisLexer;
     }
   }
 
-  /**
-   * This method will be called when we see '/*' and try to match it as a 
bracketed comment.
-   * If the next character is '+', it should be parsed as hint later, and we 
cannot match
-   * it as a bracketed comment.
-   *
-   * Returns true if the next character is '+'.
-   */
-  public boolean isHint() {
-    int nextChar = _input.LA(1);
-    if (nextChar == '+') {
-      return true;
-    } else {
-      return false;
-    }
-  }
-
   /**
    * This method will be called when the character stream ends and try to find 
out the
    * unclosed bracketed comment.
@@ -599,6 +583,7 @@ COLON: ':';
 ARROW: '->';
 HINT_START: '/*+';
 HINT_END: '*/';
+COMMENT_START: '/*';
 ATSIGN: '@';
 DOUBLEATSIGN: '@@';
 
@@ -678,9 +663,10 @@ SIMPLE_COMMENT
     ;
 
 BRACKETED_COMMENT
-    : '/*' {!isHint()}? ( BRACKETED_COMMENT | . )*? ('*/' | 
{markUnclosedComment();} EOF) -> channel(HIDDEN)
+    : COMMENT_START ( BRACKETED_COMMENT | . )*? ('*/' | 
{markUnclosedComment();} EOF) -> channel(2)
     ;
 
+
 FROM_DUAL
     : 'FROM' WS+ 'DUAL' -> channel(HIDDEN);
 
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 33d04fb8550..d94a0f4f680 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
@@ -457,7 +457,7 @@ havingClause
     : HAVING booleanExpression
     ;
 
-selectHint: HINT_START hintStatements+=hintStatement (COMMA? 
hintStatements+=hintStatement)* HINT_END;
+selectHint: hintStatements+=hintStatement (COMMA? 
hintStatements+=hintStatement)* HINT_END;
 
 hintStatement
     : hintName=identifier (LEFT_PAREN parameters+=hintAssignment (COMMA? 
parameters+=hintAssignment)* RIGHT_PAREN)?
@@ -1065,6 +1065,7 @@ nonReserved
     | COLOCATE
     | COLUMNS
     | COMMENT
+    | COMMENT_START
     | COMMIT
     | COMMITTED
     | COMPACT
@@ -1147,6 +1148,8 @@ nonReserved
     | HASH
     | HDFS
     | HELP
+    | HINT_END
+    | HINT_START
     | HISTOGRAM
     | HLL_UNION
     | HOSTNAME
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 ad2aa783307..c4403a98bd0 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
@@ -499,6 +499,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);
@@ -1331,7 +1337,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);
         });
     }
 
@@ -3068,47 +3083,50 @@ 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;
-                default:
-                    break;
+                        hints.put(hintName, new SelectHintLeading(hintName, 
leadingParameters));
+                        break;
+                    case "ordered":
+                        hints.put(hintName, new SelectHintOrdered(hintName));
+                        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/NereidsParser.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
index 58854b1a293..edcbb76ad84 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,16 +274,41 @@ 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);
     }
 
+    /** 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)));
+        CommonTokenStream hintTokenStream = new CommonTokenStream(hintLexer);
+
+        Map<Integer, ParserRuleContext> selectHintMap = Maps.newHashMap();
+
+        Token hintToken = hintTokenStream.getTokenSource().nextToken();
+        while (hintToken != null && hintToken.getType() != DorisLexer.EOF) {
+            if (hintToken.getChannel() == 2 && 
sql.charAt(hintToken.getStartIndex() + 2) == '+') {
+                String hintSql = sql.substring(hintToken.getStartIndex() + 3, 
hintToken.getStopIndex() + 1);
+                DorisLexer newHintLexer = new DorisLexer(new 
CaseInsensitiveStream(CharStreams.fromString(hintSql)));
+                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)));
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 2bbcbc4290d..aa6ff756b20 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
@@ -351,16 +351,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)
@@ -371,8 +365,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..2145d4edae6
--- /dev/null
+++ b/regression-test/data/nereids_p0/hint/test_hint.out
@@ -0,0 +1,81 @@
+-- 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] hashCondition=((t1.c1 = t2.c2)) otherCondition=()
+----------PhysicalOlapScan[t2]
+----------PhysicalDistribute[DistributionSpecReplicated]
+------------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] hashCondition=((t1.c1 = t2.c2)) otherCondition=()
+----------PhysicalOlapScan[t2]
+----------PhysicalDistribute[DistributionSpecReplicated]
+------------PhysicalOlapScan[t1]
+
+Hint log:
+Used: leading(t2 broadcast t1 ) 
+UnUsed:
+SyntaxError:
+
+-- !select1_6 --
+PhysicalResultSink
+--hashAgg[GLOBAL]
+----PhysicalDistribute[DistributionSpecGather]
+------hashAgg[LOCAL]
+--------hashJoin[INNER_JOIN] hashCondition=((t1.c1 = t2.c2)) otherCondition=()
+----------PhysicalOlapScan[t2]
+----------PhysicalDistribute[DistributionSpecReplicated]
+------------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 470dc086812..07cc7c16284 100644
--- a/regression-test/data/nereids_p0/hint/test_leading.out
+++ b/regression-test/data/nereids_p0/hint/test_leading.out
@@ -2538,8 +2538,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..d847f17fe64
--- /dev/null
+++ b/regression-test/suites/nereids_p0/hint/test_hint.groovy
@@ -0,0 +1,60 @@
+/*
+ * 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 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 cbbff148c3a..ec7d568362e 100644
--- a/regression-test/suites/nereids_p0/hint/test_leading.groovy
+++ b/regression-test/suites/nereids_p0/hint/test_leading.groovy
@@ -1000,7 +1000,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