From 75fb7f1481824a5fafda90489d352e9c7bce71b1 Mon Sep 17 00:00:00 2001 From: Vallish Pai Date: Tue, 12 Nov 2024 09:15:29 +0530 Subject: [PATCH] [Enhancement] (nereids)implement showRolesCommand in nereids (#43118) Issue Number: close #42768 --- .../org/apache/doris/nereids/DorisParser.g4 | 3 +- .../nereids/parser/LogicalPlanBuilder.java | 7 ++ .../doris/nereids/trees/plans/PlanType.java | 1 + .../plans/commands/ShowRolesCommand.java | 87 +++++++++++++++++++ .../trees/plans/visitor/CommandVisitor.java | 5 ++ .../doris/regression/suite/Suite.groovy | 20 +++++ .../ddl/account/test_nereids_role.groovy | 67 ++++++++++++++ 7 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowRolesCommand.java create mode 100644 regression-test/suites/nereids_p0/ddl/account/test_nereids_role.groovy 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 e0d909d71464e1..73f8c48654fbb5 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 @@ -196,6 +196,7 @@ supportedShowStatement | SHOW VIEW (FROM |IN) tableName=multipartIdentifier ((FROM | IN) database=identifier)? #showView + | SHOW ROLES #showRoles ; unsupportedOtherStatement @@ -225,6 +226,7 @@ lockTable (READ (LOCAL)? | (LOW_PRIORITY)? WRITE) ; + unsupportedShowStatement : SHOW SQL_BLOCK_RULE (FOR ruleName=identifier)? #showSqlBlockRule | SHOW ROW POLICY (FOR (userIdentify | (ROLE role=identifier)))? #showRowPolicy @@ -299,7 +301,6 @@ unsupportedShowStatement | SHOW SNAPSHOT ON repo=identifier wildWhere? #showSnapshot | SHOW ALL? GRANTS #showGrants | SHOW GRANTS FOR userIdentify #showGrantsForUser - | SHOW ROLES #showRoles | SHOW PRIVILEGES #showPrivileges | SHOW FULL? BUILTIN? FUNCTIONS ((FROM | IN) database=multipartIdentifier)? wildWhere? #showFunctions 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 9f7b43aa8cb72d..f8e59c36130142 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 @@ -197,6 +197,7 @@ import org.apache.doris.nereids.DorisParser.ShowCreateMTMVContext; import org.apache.doris.nereids.DorisParser.ShowCreateProcedureContext; import org.apache.doris.nereids.DorisParser.ShowProcedureStatusContext; +import org.apache.doris.nereids.DorisParser.ShowRolesContext; import org.apache.doris.nereids.DorisParser.ShowVariablesContext; import org.apache.doris.nereids.DorisParser.ShowViewContext; import org.apache.doris.nereids.DorisParser.SimpleColumnDefContext; @@ -429,6 +430,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowRolesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowVariablesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowViewCommand; import org.apache.doris.nereids.trees.plans.commands.UnsetDefaultStorageVaultCommand; @@ -4053,4 +4055,9 @@ public ShowViewCommand visitShowView(ShowViewContext ctx) { } return new ShowViewCommand(databaseName, new TableNameInfo(tableNameParts)); } + + @Override + public LogicalPlan visitShowRoles(ShowRolesContext ctx) { + return new ShowRolesCommand(); + } } 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 573b81a7578e9b..dde7acedecdcec 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 @@ -176,6 +176,7 @@ public enum PlanType { PREPARED_COMMAND, EXECUTE_COMMAND, SHOW_CONFIG_COMMAND, + SHOW_ROLE_COMMAND, SHOW_VARIABLES_COMMAND, SHOW_AUTHORS_COMMAND, SHOW_VIEW_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowRolesCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowRolesCommand.java new file mode 100644 index 00000000000000..7cbb5f934cabba --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowRolesCommand.java @@ -0,0 +1,87 @@ +// 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.catalog.Column; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.ScalarType; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.mysql.privilege.PrivPredicate; +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 org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +/** + * show roles command + */ +public class ShowRolesCommand extends ShowCommand { + public static final Logger LOG = LogManager.getLogger(ShowRolesCommand.class); + private static final ShowResultSetMetaData META_DATA; + + static { + ShowResultSetMetaData.Builder builder = ShowResultSetMetaData.builder(); + + builder.addColumn(new Column("Name", ScalarType.createVarchar(100))); + builder.addColumn(new Column("Comment", ScalarType.createVarchar(100))); + builder.addColumn(new Column("Users", ScalarType.createVarchar(100))); + builder.addColumn(new Column("GlobalPrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("CatalogPrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("DatabasePrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("TablePrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("ResourcePrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("CloudClusterPrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("CloudStagePrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("StorageVaultPrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("WorkloadGroupPrivs", ScalarType.createVarchar(300))); + builder.addColumn(new Column("ComputeGroupPrivs", ScalarType.createVarchar(300))); + + META_DATA = builder.build(); + } + + /** + * constructor + */ + + public ShowRolesCommand() { + super(PlanType.SHOW_ROLE_COMMAND); + } + + @Override + public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.GRANT)) { + ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT"); + } + + List> infos = Env.getCurrentEnv().getAuth().getRoleInfo(); + return new ShowResultSet(META_DATA, infos); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitShowRolesCommand(this, context); + } +} 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 ab1ed7aecf452b..16e07e83589ee0 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 @@ -53,6 +53,7 @@ import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand; import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand; import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand; +import org.apache.doris.nereids.trees.plans.commands.ShowRolesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowVariablesCommand; import org.apache.doris.nereids.trees.plans.commands.ShowViewCommand; import org.apache.doris.nereids.trees.plans.commands.UnsetDefaultStorageVaultCommand; @@ -247,4 +248,8 @@ default R visitShowVariablesCommand(ShowVariablesCommand showVariablesCommand, C default R visitShowViewCommand(ShowViewCommand showViewCommand, C context) { return visitCommand(showViewCommand, context); } + + default R visitShowRolesCommand(ShowRolesCommand showRolesCommand, C context) { + return visitCommand(showRolesCommand, context); + } } diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy index d20517f15d5ff0..0d9ae067fecdc3 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/suite/Suite.groovy @@ -730,6 +730,26 @@ class Suite implements GroovyInterceptable { profileAction.run() } + String checkNereidsExecuteWithResult(String sqlString) { + String tag = UUID.randomUUID().toString(); + String result = null; + log.info("start check" + tag) + String finalSqlString = "--" + tag + "\n" + sqlString + ProfileAction profileAction = new ProfileAction(context, tag) + profileAction.run { + log.info("start profile run" + tag) + result = sql (finalSqlString) + } + profileAction.check { + profileString, exception -> + log.info("start profile check" + tag) + log.info(profileString) + Assertions.assertTrue(profileString.contains("- Is Nereids: Yes")) + } + profileAction.run() + return result; + } + void createMV(String sql) { (new CreateMVAction(context, sql)).run() } diff --git a/regression-test/suites/nereids_p0/ddl/account/test_nereids_role.groovy b/regression-test/suites/nereids_p0/ddl/account/test_nereids_role.groovy new file mode 100644 index 00000000000000..4e2cd4ca6375d2 --- /dev/null +++ b/regression-test/suites/nereids_p0/ddl/account/test_nereids_role.groovy @@ -0,0 +1,67 @@ +// 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. + +import org.junit.Assert; + +suite("test_nereids_role") { + def role= 'nereids_account_role_test' + def user = 'acount_role_user_test' + def dbName = 'nereids_account_role_test_db' + def pwd = 'C123_567p' + + try_sql("DROP ROLE ${role}") + try_sql("DROP USER ${user}") + sql """DROP DATABASE IF EXISTS ${dbName}""" + sql """CREATE DATABASE ${dbName}""" + + sql """CREATE ROLE ${role}""" + sql """GRANT SELECT_PRIV ON ${context.config.defaultDb} TO ROLE '${role}'""" + sql """GRANT SELECT_PRIV ON ${dbName} TO ROLE '${role}'""" + sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}' DEFAULT ROLE '${role}'""" + def result1 = connect(user=user, password="${pwd}", url=context.config.jdbcUrl) { + sql "show databases like '${dbName}'" + } + assertEquals(result1.size(), 1) + + sql """REVOKE SELECT_PRIV ON ${dbName} FROM ROLE '${role}'""" + def result2 = connect(user=user, password="${pwd}", url=context.config.jdbcUrl) { + sql "show databases like '${dbName}'" + } + assertEquals(result2.size(), 0) + + sql """DROP USER ${user}""" + sql """DROP ROLE ${role}""" + sql """DROP DATABASE ${dbName}""" + + // test comment + // create role with comment + sql """CREATE ROLE ${role} comment 'account_p0_nereids_account_role_test_comment_create'""" + def roles_create = checkNereidsExecuteWithResult("show roles;"); + logger.info("roles_create: " + roles_create.toString()) + assertTrue(roles_create.toString().contains("account_p0_nereids_account_role_test_comment_create")) + // alter role with comment + sql """ALTER ROLE ${role} comment 'account_p0_nereids_account_role_test_comment_alter'""" + def roles_alter = checkNereidsExecuteWithResult("show roles;"); + logger.info("roles_alter: " + roles_alter.toString()) + assertTrue(roles_alter.toString().contains("account_p0_nereids_account_role_test_comment_alter")) + // drop role + sql """DROP ROLE ${role}""" + def roles_drop = checkNereidsExecuteWithResult("show roles;"); + logger.info("roles_drop: " + roles_drop.toString()) + assertFalse(roles_drop.toString().contains("account_p0_nereids_account_role_test_comment_alter")) +} +