You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by hu...@apache.org on 2022/07/28 09:23:23 UTC

[doris] branch master updated: [enhancement](Nereids)enable explain query for nereids planner (#11210)

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

huajianlan 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 951320256b [enhancement](Nereids)enable explain query for nereids planner (#11210)
951320256b is described below

commit 951320256b418c12e6c4de880ed4f1d70c2e1e30
Author: morrySnow <10...@users.noreply.github.com>
AuthorDate: Thu Jul 28 17:23:17 2022 +0800

    [enhancement](Nereids)enable explain query for nereids planner (#11210)
    
    Support explain syntax. And generate explain tree string by nereids' planner.
---
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |   2 +
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |   4 +
 .../org/apache/doris/nereids/NereidsPlanner.java   |   5 ++
 .../glue/translator/PhysicalPlanTranslator.java    |   3 +-
 .../doris/nereids/parser/LogicalPlanBuilder.java   |  16 ++++
 .../apache/doris/nereids/parser/NereidsParser.java |  28 ++++--
 .../org/apache/doris/nereids/pattern/Pattern.java  |   7 --
 .../doris/nereids/trees/AbstractTreeNode.java      |   8 +-
 .../org/apache/doris/nereids/trees/TreeNode.java   |   6 --
 .../doris/nereids/trees/plans/AbstractPlan.java    |   6 ++
 .../org/apache/doris/nereids/trees/plans/Plan.java |   3 +
 .../nereids/trees/plans/commands/Command.java      | 100 +++++++++++++++++++++
 .../trees/plans/commands/ExplainCommand.java       |  52 +++++++++++
 .../doris/nereids/parser/NereidsParserTest.java    |  58 ++++++++++++
 14 files changed, 269 insertions(+), 29 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 21ff03c484..c7bb9083e9 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
@@ -191,6 +191,7 @@ FUNCTION: 'FUNCTION';
 FUNCTIONS: 'FUNCTIONS';
 GLOBAL: 'GLOBAL';
 GRANT: 'GRANT';
+GRAPH: 'GRAPH';
 GROUP: 'GROUP';
 GROUPING: 'GROUPING';
 HAVING: 'HAVING';
@@ -358,6 +359,7 @@ USE: 'USE';
 USER: 'USER';
 USING: 'USING';
 VALUES: 'VALUES';
+VERBOSE: 'VERBOSE';
 VERSION: 'VERSION';
 VIEW: 'VIEW';
 VIEWS: 'VIEWS';
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 64fa6c8752..6fab3a9b0c 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
@@ -50,6 +50,8 @@ singleStatement
 
 statement
     : query                                                            #statementDefault
+    | (EXPLAIN | DESC | DESCRIBE) level=(VERBOSE | GRAPH)?
+        query                                                          #explain
     ;
 
 //  -----------------Query-----------------
@@ -626,6 +628,7 @@ nonReserved
     | FUNCTIONS
     | GLOBAL
     | GRANT
+    | GRAPH
     | GROUP
     | GROUPING
     | HAVING
@@ -779,6 +782,7 @@ nonReserved
     | USE
     | USER
     | VALUES
+    | VERBOSE
     | VERSION
     | VIEW
     | VIEWS
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 625ec84097..3ccb0615d1 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
@@ -177,4 +177,9 @@ public class NereidsPlanner extends Planner {
     public DescriptorTable getDescTable() {
         return descTable;
     }
+
+    @Override
+    public void appendTupleInfo(StringBuilder str) {
+        str.append(descTable.getExplainString());
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
index b55ff0277e..139cf360e3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
@@ -117,7 +117,7 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor<PlanFragment, Pla
         if (physicalPlan.getType() == PlanType.PHYSICAL_PROJECT) {
             PhysicalProject<Plan> physicalProject = (PhysicalProject<Plan>) physicalPlan;
             List<Expr> outputExprs = physicalProject.getProjects().stream()
-                    .map(e -> ExpressionTranslator.translate((Expression) e, context))
+                    .map(e -> ExpressionTranslator.translate(e, context))
                     .collect(Collectors.toList());
             rootFragment.setOutputExprs(outputExprs);
         } else {
@@ -329,7 +329,6 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor<PlanFragment, Pla
             childSortNode.setLimit(limit + offset);
         }
         childSortNode.setOffset(0);
-        context.addPlanFragment(mergeFragment);
         return mergeFragment;
     }
 
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 03d77bb6a1..b16f1a6c0f 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
@@ -28,6 +28,7 @@ import org.apache.doris.nereids.DorisParser.ColumnReferenceContext;
 import org.apache.doris.nereids.DorisParser.ComparisonContext;
 import org.apache.doris.nereids.DorisParser.DereferenceContext;
 import org.apache.doris.nereids.DorisParser.ExistContext;
+import org.apache.doris.nereids.DorisParser.ExplainContext;
 import org.apache.doris.nereids.DorisParser.FromClauseContext;
 import org.apache.doris.nereids.DorisParser.IdentifierListContext;
 import org.apache.doris.nereids.DorisParser.IdentifierSeqContext;
@@ -103,6 +104,9 @@ import org.apache.doris.nereids.trees.expressions.Subtract;
 import org.apache.doris.nereids.trees.expressions.TimestampArithmetic;
 import org.apache.doris.nereids.trees.expressions.WhenClause;
 import org.apache.doris.nereids.trees.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.commands.Command;
+import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
+import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@@ -121,6 +125,7 @@ import org.antlr.v4.runtime.tree.TerminalNode;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
@@ -163,6 +168,17 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
     /* ********************************************************************************************
      * Plan parsing
      * ******************************************************************************************** */
+
+    @Override
+    public Command visitExplain(ExplainContext ctx) {
+        LogicalPlan logicalPlan = plan(ctx.query());
+        ExplainLevel explainLevel = ExplainLevel.NORMAL;
+        if (ctx.level != null) {
+            explainLevel = ExplainLevel.valueOf(ctx.level.getText().toUpperCase(Locale.ROOT));
+        }
+        return new ExplainCommand(explainLevel, logicalPlan);
+    }
+
     @Override
     public LogicalPlan visitQuery(QueryContext ctx) {
         return ParserUtils.withOrigin(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 9a190fe9bf..e1077d13c3 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
@@ -17,11 +17,14 @@
 
 package org.apache.doris.nereids.parser;
 
+import org.apache.doris.analysis.ExplainOptions;
 import org.apache.doris.analysis.StatementBase;
 import org.apache.doris.nereids.DorisLexer;
 import org.apache.doris.nereids.DorisParser;
 import org.apache.doris.nereids.glue.LogicalPlanAdapter;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
+import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 
 import org.antlr.v4.runtime.CharStreams;
@@ -46,14 +49,25 @@ public class NereidsParser {
      * a single packet.
      * https://dev.mysql.com/doc/internals/en/com-set-option.html
      */
-    public List<StatementBase> parseSQL(String originStr) throws Exception {
-        List<LogicalPlan> logicalPlanList = parseMultiple(originStr);
-        List<StatementBase> statementBaseList = new ArrayList<>();
-        for (LogicalPlan logicalPlan : logicalPlanList) {
-            LogicalPlanAdapter logicalPlanAdapter = new LogicalPlanAdapter(logicalPlan);
-            statementBaseList.add(logicalPlanAdapter);
+    public List<StatementBase> parseSQL(String originStr) {
+        List<LogicalPlan> logicalPlans = parseMultiple(originStr);
+        List<StatementBase> statementBases = new ArrayList<>();
+        for (LogicalPlan logicalPlan : logicalPlans) {
+            // TODO: this is a trick to support explain. Since we do not support any other command in a short time.
+            //     It is acceptable. In the future, we need to refactor this.
+            if (logicalPlan instanceof ExplainCommand) {
+                ExplainCommand explainCommand = (ExplainCommand) logicalPlan;
+                LogicalPlan innerPlan = explainCommand.getLogicalPlan();
+                LogicalPlanAdapter logicalPlanAdapter = new LogicalPlanAdapter(innerPlan);
+                logicalPlanAdapter.setIsExplain(new ExplainOptions(
+                        explainCommand.getLevel() == ExplainLevel.VERBOSE,
+                        explainCommand.getLevel() == ExplainLevel.GRAPH));
+                statementBases.add(logicalPlanAdapter);
+            } else {
+                statementBases.add(new LogicalPlanAdapter(logicalPlan));
+            }
         }
-        return statementBaseList;
+        return statementBases;
     }
 
     /**
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
index fe0f1cb909..31c2713aa3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
@@ -17,7 +17,6 @@
 
 package org.apache.doris.nereids.pattern;
 
-import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.trees.AbstractTreeNode;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
@@ -26,7 +25,6 @@ import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.function.Predicate;
 
 /**
@@ -176,11 +174,6 @@ public class Pattern<TYPE extends Plan>
         return new Pattern(patternType, planType, predicates, children.toArray(new Pattern[0]));
     }
 
-    @Override
-    public Optional<GroupExpression> getGroupExpression() {
-        return Optional.empty();
-    }
-
     public boolean hasMultiChild() {
         return !children.isEmpty() && children.get(children.size() - 1).isMulti();
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java
index 70eeee0e88..73a934cc45 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/AbstractTreeNode.java
@@ -23,7 +23,6 @@ import org.apache.doris.nereids.memo.GroupExpression;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -38,7 +37,7 @@ public abstract class AbstractTreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>>
     protected final List<NODE_TYPE> children;
     // TODO: Maybe we should use a GroupPlan to avoid TreeNode hold the GroupExpression.
     // https://github.com/apache/doris/pull/9807#discussion_r884829067
-    protected final Optional<GroupExpression> groupExpression;
+
 
     public AbstractTreeNode(NODE_TYPE... children) {
         this(Optional.empty(), children);
@@ -52,12 +51,7 @@ public abstract class AbstractTreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>>
      */
     public AbstractTreeNode(Optional<GroupExpression> groupExpression, NODE_TYPE... children) {
         this.children = ImmutableList.copyOf(children);
-        this.groupExpression = Objects.requireNonNull(groupExpression, "groupExpression can not be null");
-    }
 
-    @Override
-    public Optional<GroupExpression> getGroupExpression() {
-        return groupExpression;
     }
 
     @Override
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
index 93d9e97522..29b509c884 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
@@ -17,12 +17,9 @@
 
 package org.apache.doris.nereids.trees;
 
-import org.apache.doris.nereids.memo.GroupExpression;
-
 import com.alibaba.google.common.collect.ImmutableList;
 
 import java.util.List;
-import java.util.Optional;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
@@ -34,9 +31,6 @@ import java.util.function.Predicate;
  */
 public interface TreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>> {
 
-    // cache GroupExpression for fast exit from Memo.copyIn.
-    Optional<GroupExpression> getGroupExpression();
-
     List<NODE_TYPE> children();
 
     NODE_TYPE child(int index);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
index 431fb9c281..c058e959c7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
@@ -38,6 +38,7 @@ public abstract class AbstractPlan extends AbstractTreeNode<Plan> implements Pla
     protected long limit = -1;
 
     protected final PlanType type;
+    protected final Optional<GroupExpression> groupExpression;
     protected final LogicalProperties logicalProperties;
 
     public AbstractPlan(PlanType type, Plan... children) {
@@ -53,6 +54,7 @@ public abstract class AbstractPlan extends AbstractTreeNode<Plan> implements Pla
                         Optional<LogicalProperties> optLogicalProperties, Plan... children) {
         super(groupExpression, children);
         this.type = Objects.requireNonNull(type, "type can not be null");
+        this.groupExpression = Objects.requireNonNull(groupExpression, "groupExpression can not be null");
         LogicalProperties logicalProperties = optLogicalProperties.orElseGet(() -> computeLogicalProperties(children));
         this.logicalProperties = Objects.requireNonNull(logicalProperties, "logicalProperties can not be null");
     }
@@ -62,6 +64,10 @@ public abstract class AbstractPlan extends AbstractTreeNode<Plan> implements Pla
         return type;
     }
 
+    public Optional<GroupExpression> getGroupExpression() {
+        return groupExpression;
+    }
+
     /**
      * Get tree like string describing query plan.
      *
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
index fd2e72c02d..ece8624164 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
@@ -34,6 +34,9 @@ public interface Plan extends TreeNode<Plan> {
 
     PlanType getType();
 
+    // cache GroupExpression for fast exit from Memo.copyIn.
+    Optional<GroupExpression> getGroupExpression();
+
     default <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         throw new RuntimeException("accept() is not implemented by plan " + this.getClass().getSimpleName());
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/Command.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/Command.java
new file mode 100644
index 0000000000..3f50ca688b
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/Command.java
@@ -0,0 +1,100 @@
+// 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.commands;
+
+import org.apache.doris.nereids.memo.GroupExpression;
+import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * All DDL and DML commands' super class.
+ */
+public interface Command extends LogicalPlan {
+
+    @Override
+    default Optional<GroupExpression> getGroupExpression() {
+        throw new RuntimeException("Command do not implement getGroupExpression");
+    }
+
+    @Override
+    default List<Plan> children() {
+        throw new RuntimeException("Command do not implement children");
+    }
+
+    @Override
+    default Plan child(int index) {
+        throw new RuntimeException("Command do not implement child");
+    }
+
+    @Override
+    default int arity() {
+        throw new RuntimeException("Command do not implement arity");
+    }
+
+    @Override
+    default Plan withChildren(List<Plan> children) {
+        throw new RuntimeException("Command do not implement withChildren");
+    }
+
+    @Override
+    default PlanType getType() {
+        throw new RuntimeException("Command do not implement getType");
+    }
+
+    @Override
+    default List<Expression> getExpressions() {
+        throw new RuntimeException("Command do not implement getExpressions");
+    }
+
+    @Override
+    default LogicalProperties getLogicalProperties() {
+        throw new RuntimeException("Command do not implement getLogicalProperties");
+    }
+
+    @Override
+    default List<Slot> getOutput() {
+        throw new RuntimeException("Command do not implement getOutput");
+    }
+
+    @Override
+    default String treeString() {
+        throw new RuntimeException("Command do not implement treeString");
+    }
+
+    @Override
+    default Plan withGroupExpression(Optional<GroupExpression> groupExpression) {
+        throw new RuntimeException("Command do not implement withGroupExpression");
+    }
+
+    @Override
+    default Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) {
+        throw new RuntimeException("Command do not implement withLogicalProperties");
+    }
+
+    @Override
+    default long getLimit() {
+        throw new RuntimeException("Command do not implement getLimit");
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExplainCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExplainCommand.java
new file mode 100644
index 0000000000..80980fcb4d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExplainCommand.java
@@ -0,0 +1,52 @@
+// 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.commands;
+
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+
+/**
+ * explain command.
+ */
+public class ExplainCommand implements Command {
+
+    /**
+     * explain level.
+     */
+    public enum ExplainLevel {
+        NORMAL,
+        VERBOSE,
+        GRAPH,
+        ;
+    }
+
+    private final ExplainLevel level;
+    private final LogicalPlan logicalPlan;
+
+    public ExplainCommand(ExplainLevel level, LogicalPlan logicalPlan) {
+        this.level = level;
+        this.logicalPlan = logicalPlan;
+    }
+
+    public ExplainLevel getLevel() {
+        return level;
+    }
+
+    public LogicalPlan getLogicalPlan() {
+        return logicalPlan;
+    }
+}
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 08fbc07b38..ef20960897 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
@@ -17,8 +17,13 @@
 
 package org.apache.doris.nereids.parser;
 
+import org.apache.doris.analysis.ExplainOptions;
+import org.apache.doris.analysis.StatementBase;
 import org.apache.doris.nereids.exceptions.ParseException;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
 import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.commands.ExplainCommand;
+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;
 
@@ -70,4 +75,57 @@ public class NereidsParserTest {
         LogicalProject<Plan> logicalProject = (LogicalProject) logicalPlan;
         Assertions.assertEquals("AD`D", logicalProject.getProjects().get(0).getName());
     }
+
+    @Test
+    public void testExplainNormal() {
+        String sql = "explain select `AD``D` from t1 where a = 1";
+        NereidsParser nereidsParser = new NereidsParser();
+        LogicalPlan logicalPlan = nereidsParser.parseSingle(sql);
+        Assertions.assertTrue(logicalPlan instanceof ExplainCommand);
+        ExplainCommand explainCommand = (ExplainCommand) logicalPlan;
+        ExplainLevel explainLevel = explainCommand.getLevel();
+        Assertions.assertEquals(ExplainLevel.NORMAL, explainLevel);
+        logicalPlan = explainCommand.getLogicalPlan();
+        LogicalProject<Plan> logicalProject = (LogicalProject) logicalPlan;
+        Assertions.assertEquals("AD`D", logicalProject.getProjects().get(0).getName());
+    }
+
+    @Test
+    public void testExplainVerbose() {
+        String sql = "explain verbose select `AD``D` from t1 where a = 1";
+        NereidsParser nereidsParser = new NereidsParser();
+        LogicalPlan logicalPlan = nereidsParser.parseSingle(sql);
+        ExplainCommand explainCommand = (ExplainCommand) logicalPlan;
+        ExplainLevel explainLevel = explainCommand.getLevel();
+        Assertions.assertEquals(ExplainLevel.VERBOSE, explainLevel);
+    }
+
+    @Test
+    public void testExplainGraph() {
+        String sql = "explain graph select `AD``D` from t1 where a = 1";
+        NereidsParser nereidsParser = new NereidsParser();
+        LogicalPlan logicalPlan = nereidsParser.parseSingle(sql);
+        ExplainCommand explainCommand = (ExplainCommand) logicalPlan;
+        ExplainLevel explainLevel = explainCommand.getLevel();
+        Assertions.assertEquals(ExplainLevel.GRAPH, explainLevel);
+    }
+
+    @Test
+    public void testParseSQL() {
+        String sql = "select `AD``D` from t1 where a = 1;explain graph select `AD``D` from t1 where a = 1;";
+        NereidsParser nereidsParser = new NereidsParser();
+        List<StatementBase> statementBases = nereidsParser.parseSQL(sql);
+        Assertions.assertEquals(2, statementBases.size());
+        Assertions.assertTrue(statementBases.get(0) instanceof LogicalPlanAdapter);
+        Assertions.assertTrue(statementBases.get(1) instanceof LogicalPlanAdapter);
+        LogicalPlan logicalPlan0 = ((LogicalPlanAdapter) statementBases.get(0)).getLogicalPlan();
+        LogicalPlan logicalPlan1 = ((LogicalPlanAdapter) statementBases.get(1)).getLogicalPlan();
+        Assertions.assertTrue(logicalPlan0 instanceof LogicalProject);
+        Assertions.assertTrue(logicalPlan1 instanceof LogicalProject);
+        Assertions.assertNull(statementBases.get(0).getExplainOptions());
+        Assertions.assertNotNull(statementBases.get(1).getExplainOptions());
+        ExplainOptions explainOptions = statementBases.get(1).getExplainOptions();
+        Assertions.assertTrue(explainOptions.isGraph());
+        Assertions.assertFalse(explainOptions.isVerbose());
+    }
 }


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