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

starocean999 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 65077c90649 [Enhancement] (nereids)implement showClustersCommand in 
nereids (#49672)
65077c90649 is described below

commit 65077c90649f9653ed05dbd86cdea29b71e24f1e
Author: Sridhar R Manikarnike <sridhar.n...@gmail.com>
AuthorDate: Thu Apr 3 19:29:53 2025 +0530

    [Enhancement] (nereids)implement showClustersCommand in nereids (#49672)
    
    Issue Number: close #42780
---
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |   4 +-
 .../doris/nereids/parser/LogicalPlanBuilder.java   |   8 ++
 .../apache/doris/nereids/trees/plans/PlanType.java |   1 +
 .../trees/plans/commands/ShowClustersCommand.java  | 158 +++++++++++++++++++++
 .../trees/plans/visitor/CommandVisitor.java        |   5 +
 .../show/test_show_clusters_command.groovy         |  27 ++++
 6 files changed, 201 insertions(+), 2 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 359e4312147..7c7c5ca674e 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
@@ -330,7 +330,8 @@ supportedShowStatement
     | SHOW DATABASE databaseId=INTEGER_VALUE                                   
     #showDatabaseId
     | SHOW TABLE tableId=INTEGER_VALUE                                         
     #showTableId
     | SHOW TRASH (ON backend=STRING_LITERAL)?                                  
     #showTrash
-    | SHOW statementScope? STATUS                                       
#showStatus
+    | SHOW (CLUSTERS | (COMPUTE GROUPS))                                       
     #showClusters    
+    | SHOW statementScope? STATUS                                              
     #showStatus
     | SHOW WHITELIST                                                           
     #showWhitelist
     | SHOW TABLETS BELONG
         tabletIds+=INTEGER_VALUE (COMMA tabletIds+=INTEGER_VALUE)*             
     #showTabletsBelong
@@ -425,7 +426,6 @@ unsupportedShowStatement
             | (FROM tableName=multipartIdentifier (ALL VERBOSE?)?))?           
     #showQueryStats
     | SHOW BUILD INDEX ((FROM | IN) database=multipartIdentifier)?
         wildWhere? sortClause? limitClause?                                    
     #showBuildIndex
-    | SHOW (CLUSTERS | (COMPUTE GROUPS))                                       
     #showClusters
     | SHOW REPLICA STATUS FROM baseTableRef wildWhere?                         
     #showReplicaStatus
     | SHOW COPY ((FROM | IN) database=multipartIdentifier)?
         whereClause? sortClause? limitClause?                                  
     #showCopy
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 1177f5f1ed2..f21f70f3026 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
@@ -303,6 +303,7 @@ import 
org.apache.doris.nereids.DorisParser.ShowBackendsContext;
 import org.apache.doris.nereids.DorisParser.ShowBackupContext;
 import org.apache.doris.nereids.DorisParser.ShowBrokerContext;
 import org.apache.doris.nereids.DorisParser.ShowCharsetContext;
+import org.apache.doris.nereids.DorisParser.ShowClustersContext;
 import org.apache.doris.nereids.DorisParser.ShowCollationContext;
 import org.apache.doris.nereids.DorisParser.ShowColumnHistogramStatsContext;
 import org.apache.doris.nereids.DorisParser.ShowConfigContext;
@@ -622,6 +623,7 @@ import 
org.apache.doris.nereids.trees.plans.commands.ShowBackupCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowBrokerCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowCatalogCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowCharsetCommand;
+import org.apache.doris.nereids.trees.plans.commands.ShowClustersCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowCollationCommand;
 import 
org.apache.doris.nereids.trees.plans.commands.ShowColumnHistogramStatsCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowConfigCommand;
@@ -6397,6 +6399,12 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return new DropExpiredStatsCommand();
     }
 
+    @Override
+    public LogicalPlan visitShowClusters(ShowClustersContext ctx) {
+        boolean showComputeGroups = ctx.COMPUTE() != null;
+        return new ShowClustersCommand(showComputeGroups);
+    }
+
     @Override
     public LogicalPlan visitAlterTableStats(DorisParser.AlterTableStatsContext 
ctx) {
         TableNameInfo tableNameInfo = new 
TableNameInfo(visitMultipartIdentifier(ctx.name));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
index c850dfa26ef..1eebfcd236e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
@@ -228,6 +228,7 @@ public enum PlanType {
     SHOW_BROKER_COMMAND,
     SHOW_CATALOG_COMMAND,
     SHOW_CHARSET_COMMAND,
+    SHOW_CLUSTERS_COMMAND,
     SHOW_COLLATION_COMMAND,
     SHOW_COLUMN_HISTOGRAM,
     SHOW_CONFIG_COMMAND,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java
new file mode 100644
index 00000000000..27b1d20f1d2
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowClustersCommand.java
@@ -0,0 +1,158 @@
+// 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.analysis.CompoundPredicate.Operator;
+import org.apache.doris.analysis.ResourceTypeEnum;
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.cloud.qe.ComputeGroupException;
+import org.apache.doris.cloud.system.CloudSystemInfoService;
+import org.apache.doris.cluster.ClusterNamespace;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.mysql.privilege.Auth;
+import org.apache.doris.mysql.privilege.PrivBitSet;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.mysql.privilege.Privilege;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.ShowResultSet;
+import org.apache.doris.qe.ShowResultSetMetaData;
+import org.apache.doris.qe.StmtExecutor;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Represents the command for SHOW CLUSTERS.
+ */
+public class ShowClustersCommand extends ShowCommand {
+    public static final ImmutableList<String> CLUSTER_TITLE_NAMES = new 
ImmutableList.Builder<String>()
+            
.add("cluster").add("is_current").add("users").add("backend_num").build();
+
+    public static final ImmutableList<String> COMPUTE_GROUP_TITLE_NAMES = new 
ImmutableList.Builder<String>()
+            
.add("Name").add("IsCurrent").add("Users").add("BackendNum").build();
+
+    private static final Logger LOG = 
LogManager.getLogger(ShowClustersCommand.class);
+    private final boolean isComputeGroup;
+
+    public ShowClustersCommand(boolean isComputeGroup) {
+        super(PlanType.SHOW_CLUSTERS_COMMAND);
+        this.isComputeGroup = isComputeGroup;
+    }
+
+    private void validate(ConnectContext ctx) throws AnalysisException {
+        if (Config.isNotCloudMode()) {
+            // just user admin
+            if 
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get().getCurrentUserIdentity(),
+                        PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV, 
Privilege.NODE_PRIV), Operator.OR))) {
+                
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN");
+            }
+        }
+    }
+
+    @Override
+    public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) 
throws Exception {
+        validate(ctx);
+        final List<List<String>> rows = Lists.newArrayList();
+        if (!Config.isCloudMode()) {
+            ErrorReport.reportAnalysisException(ErrorCode.ERR_NOT_CLOUD_MODE);
+            return new ShowResultSet(getMetaData(), rows);
+        }
+
+        List<String> clusterNames = null;
+        clusterNames = ((CloudSystemInfoService) 
Env.getCurrentSystemInfo()).getCloudClusterNames();
+
+        final Set<String> clusterNameSet = Sets.newTreeSet();
+        clusterNameSet.addAll(clusterNames);
+
+        for (String clusterName : clusterNameSet) {
+            ArrayList<String> row = Lists.newArrayList(clusterName);
+            // current_used, users
+            if (!Env.getCurrentEnv().getAccessManager()
+                    
.checkCloudPriv(ConnectContext.get().getCurrentUserIdentity(), clusterName,
+                            PrivPredicate.USAGE, ResourceTypeEnum.CLUSTER)) {
+                continue;
+            }
+            String clusterNameFromCtx = "";
+            try {
+                clusterNameFromCtx = ctx.getCloudCluster();
+            } catch (ComputeGroupException e) {
+                LOG.warn("failed to get cluster name", e);
+            }
+            row.add(clusterName.equals(clusterNameFromCtx) ? "TRUE" : "FALSE");
+            List<String> users = 
Env.getCurrentEnv().getAuth().getCloudClusterUsers(clusterName);
+            // non-root do not display root information
+            if (!Auth.ROOT_USER.equals(ctx.getQualifiedUser())) {
+                users.remove(Auth.ROOT_USER);
+            }
+            // common user, not admin
+            if 
(!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ctx.getCurrentUserIdentity(),
+                    PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV), 
Operator.OR))) {
+                users.removeIf(user -> 
!user.equals(ClusterNamespace.getNameFromFullName(ctx.getQualifiedUser())));
+            }
+
+            String result = Joiner.on(", ").join(users);
+            row.add(result);
+            int backendNum = ((CloudSystemInfoService) 
Env.getCurrentEnv().getCurrentSystemInfo())
+                    .getBackendsByClusterName(clusterName).size();
+            row.add(String.valueOf(backendNum));
+            rows.add(row);
+        }
+
+        return new ShowResultSet(getMetaData(), rows);
+    }
+
+    @Override
+    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+        return visitor.visitShowClustersCommand(this, context);
+    }
+
+    /**
+     * getMetaData()
+     */
+    public ShowResultSetMetaData getMetaData() {
+        ShowResultSetMetaData.Builder builder = 
ShowResultSetMetaData.builder();
+
+        ImmutableList<String> titleNames = null;
+        if (isComputeGroup) {
+            titleNames = COMPUTE_GROUP_TITLE_NAMES;
+        } else {
+            titleNames = CLUSTER_TITLE_NAMES;
+        }
+
+        for (String title : titleNames) {
+            builder.addColumn(new Column(title, 
ScalarType.createVarchar(128)));
+        }
+        return builder.build();
+    }
+}
+
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
index c7c038a4f8c..d39297fdca2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/CommandVisitor.java
@@ -114,6 +114,7 @@ import 
org.apache.doris.nereids.trees.plans.commands.ShowBackupCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowBrokerCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowCatalogCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowCharsetCommand;
+import org.apache.doris.nereids.trees.plans.commands.ShowClustersCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowCollationCommand;
 import 
org.apache.doris.nereids.trees.plans.commands.ShowColumnHistogramStatsCommand;
 import org.apache.doris.nereids.trees.plans.commands.ShowConfigCommand;
@@ -826,6 +827,10 @@ public interface CommandVisitor<R, C> {
         return visitCommand(showConvertLSCCommand, context);
     }
 
+    default R visitShowClustersCommand(ShowClustersCommand 
showClustersCommand, C context) {
+        return visitCommand(showClustersCommand, context);
+    }
+
     default R visitSwitchCommand(SwitchCommand switchCommand, C context) {
         return visitCommand(switchCommand, context);
     }
diff --git 
a/regression-test/suites/nereids_p0/show/test_show_clusters_command.groovy 
b/regression-test/suites/nereids_p0/show/test_show_clusters_command.groovy
new file mode 100644
index 00000000000..a47e6f1b2b0
--- /dev/null
+++ b/regression-test/suites/nereids_p0/show/test_show_clusters_command.groovy
@@ -0,0 +1,27 @@
+// 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_show_clusters_command", "nereids_p0") {
+    if (!cloudMode)
+        return;
+
+    // SHOW CLUSTERS
+    checkNereidsExecute """SHOW CLUSTERS"""
+
+    // SHOW COMPUTE GROUPS
+    checkNereidsExecute """SHOW COMPUTE GROUPS"""
+}


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

Reply via email to