This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch dev-1.0.1 in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
commit eefe8ceab074fcdf509db56b4cc43e037c65ccab Author: Jiading Guo <zing...@gmail.com> AuthorDate: Fri Apr 8 09:08:08 2022 +0800 [improvement](account) support to account management sql (#8849) Add [IF EXISTS] support to following statements: - CREATE [IF NOT EXISTS] USER - CREATE [IF NOT EXISTS] ROLE - DROP [IF EXISTS] USER - DROP [IF EXISTS] ROLE --- .../Account Management/CREATE ROLE.md | 14 +-- .../Account Management/CREATE USER.md | 26 ++-- .../sql-statements/Account Management/DROP ROLE.md | 16 +-- .../sql-statements/Account Management/DROP USER.md | 6 +- fe/fe-core/src/main/cup/sql_parser.cup | 12 +- .../org/apache/doris/analysis/CreateRoleStmt.java | 10 ++ .../org/apache/doris/analysis/DropRoleStmt.java | 10 ++ .../org/apache/doris/analysis/DropUserStmt.java | 11 ++ .../java/org/apache/doris/catalog/Catalog.java | 2 +- .../org/apache/doris/mysql/privilege/PaloAuth.java | 67 ++++++---- .../org/apache/doris/mysql/privilege/AuthTest.java | 140 ++++++++++++++++++++- 11 files changed, 254 insertions(+), 60 deletions(-) diff --git a/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE ROLE.md b/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE ROLE.md index 6b430a2037..f8f4879d1c 100644 --- a/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE ROLE.md +++ b/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE ROLE.md @@ -5,7 +5,7 @@ } --- -<!-- +<!-- 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 @@ -27,19 +27,19 @@ under the License. # CREATE ROLE ## description 该语句用户创建一个角色 - + 语法: - CREATE ROLE role1; - + CREATE ROLE [IF NOT EXISTS] role1; + 该语句创建一个无权限的角色,可以后续通过 GRANT 命令赋予该角色权限。 ## example 1. 创建一个角色 - + CREATE ROLE role1; - + ## keyword CREATE, ROLE - + diff --git a/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE USER.md b/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE USER.md index 2222e987ef..7acb73e05d 100644 --- a/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE USER.md +++ b/docs/zh-CN/sql-reference/sql-statements/Account Management/CREATE USER.md @@ -5,7 +5,7 @@ } --- -<!-- +<!-- 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 @@ -28,40 +28,40 @@ under the License. ## description Syntax: - - CREATE USER user_identity [IDENTIFIED BY 'password'] [DEFAULT ROLE 'role_name'] + + CREATE USER [IF NOT EXISTS] user_identity [IDENTIFIED BY 'password'] [DEFAULT ROLE 'role_name'] user_identity: 'user_name'@'host' - + CREATE USER 命令用于创建一个 Doris 用户。在 Doris 中,一个 user_identity 唯一标识一个用户。user_identity 由两部分组成,user_name 和 host,其中 username 为用户名。host 标识用户端连接所在的主机地址。host 部分可以使用 % 进行模糊匹配。如果不指定 host,默认为 '%',即表示该用户可以从任意 host 连接到 Doris。 - + host 部分也可指定为 domain,语法为:'user_name'@['domain'],即使用中括号包围,则 Doris 会认为这个是一个 domain,并尝试解析其 ip 地址。目前仅支持百度内部的 BNS 解析。 - + 如果指定了角色(ROLE),则会自动将该角色所拥有的权限赋予新创建的这个用户。如果不指定,则该用户默认没有任何权限。指定的 ROLE 必须已经存在。 ## example 1. 创建一个无密码用户(不指定 host,则等价于 jack@'%') - + CREATE USER 'jack'; 2. 创建一个有密码用户,允许从 '172.10.1.10' 登陆 - + CREATE USER jack@'172.10.1.10' IDENTIFIED BY '123456'; 3. 为了避免传递明文,用例2也可以使用下面的方式来创建 - + CREATE USER jack@'172.10.1.10' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9'; - + 后面加密的内容可以通过PASSWORD()获得到,例如: - + SELECT PASSWORD('123456'); 4. 创建一个允许从 '192.168' 子网登陆的用户,同时指定其角色为 example_role - + CREATE USER 'jack'@'192.168.%' DEFAULT ROLE 'example_role'; - + 5. 创建一个允许从域名 'example_domain' 登陆的用户 CREATE USER 'jack'@['example_domain'] IDENTIFIED BY '12345'; diff --git a/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP ROLE.md b/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP ROLE.md index ee0cc980bc..d9cf9fca17 100644 --- a/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP ROLE.md +++ b/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP ROLE.md @@ -5,7 +5,7 @@ } --- -<!-- +<!-- 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 @@ -27,18 +27,18 @@ under the License. # DROP ROLE ## description 该语句用户删除一个角色 - + 语法: - DROP ROLE role1; - + DROP ROLE [IF EXISTS] role1; + 删除一个角色,不会影响之前属于该角色的用户的权限。仅相当于将该角色与用户解耦。用户已经从该角色中获取到的权限,不会改变。 - + ## example 1. 删除一个角色 - + DROP ROLE role1; - + ## keyword - DROP, ROLE + DROP, ROLE diff --git a/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP USER.md b/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP USER.md index dbdebd164a..43e7fc8b12 100644 --- a/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP USER.md +++ b/docs/zh-CN/sql-reference/sql-statements/Account Management/DROP USER.md @@ -5,7 +5,7 @@ } --- -<!-- +<!-- 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 @@ -29,7 +29,7 @@ under the License. Syntax: - DROP USER 'user_identity' + DROP USER [IF EXISTS] 'user_identity' `user_identity`: @@ -41,7 +41,7 @@ Syntax: ## example 1. 删除用户 jack@'192.%' - + DROP USER 'jack'@'192.%' ## keyword diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index 529022f94a..3078d8f068 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -1309,9 +1309,9 @@ create_stmt ::= {: RESULT = new CreateRepositoryStmt(isReadOnly, repoName, storage); :} - | KW_CREATE KW_ROLE ident:role + | KW_CREATE KW_ROLE opt_if_not_exists:ifNotExists ident:role {: - RESULT = new CreateRoleStmt(role); + RESULT = new CreateRoleStmt(ifNotExists, role); :} | KW_CREATE KW_FILE STRING_LITERAL:fileName opt_db:db KW_PROPERTIES LPAREN key_value_map:properties RPAREN {: @@ -2009,9 +2009,9 @@ drop_stmt ::= RESULT = new DropTableStmt(ifExists, name, force); :} /* User */ - | KW_DROP KW_USER user_identity:userId + | KW_DROP KW_USER opt_if_exists:ifExists user_identity:userId {: - RESULT = new DropUserStmt(userId); + RESULT = new DropUserStmt(ifExists, userId); :} /* View */ | KW_DROP KW_VIEW opt_if_exists:ifExists table_name:name @@ -2022,9 +2022,9 @@ drop_stmt ::= {: RESULT = new DropRepositoryStmt(repoName); :} - | KW_DROP KW_ROLE ident:role + | KW_DROP KW_ROLE opt_if_exists:ifExists ident:role {: - RESULT = new DropRoleStmt(role); + RESULT = new DropRoleStmt(ifExists, role); :} | KW_DROP KW_FILE STRING_LITERAL:fileName opt_db:dbName KW_PROPERTIES LPAREN key_value_map:properties RPAREN {: diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateRoleStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateRoleStmt.java index a35e10eb5b..d93632127e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateRoleStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateRoleStmt.java @@ -28,12 +28,22 @@ import org.apache.doris.qe.ConnectContext; public class CreateRoleStmt extends DdlStmt { + private boolean ifNotExists; private String role; public CreateRoleStmt(String role) { this.role = role; } + public CreateRoleStmt(boolean ifNotExists, String role) { + this.ifNotExists = ifNotExists; + this.role = role; + } + + public boolean isSetIfNotExists() { + return ifNotExists; + } + public String getQualifiedRole() { return role; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropRoleStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropRoleStmt.java index 2852b0a2f1..522aebf4bf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropRoleStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropRoleStmt.java @@ -28,12 +28,22 @@ import org.apache.doris.qe.ConnectContext; public class DropRoleStmt extends DdlStmt { + private boolean ifExists; private String role; public DropRoleStmt(String role) { this.role = role; } + public DropRoleStmt(boolean ifExists, String role) { + this.ifExists = ifExists; + this.role = role; + } + + public boolean isSetIfExists() { + return ifExists; + } + public String getQualifiedRole() { return role; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropUserStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropUserStmt.java index d7c5402eae..9c8453e23d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DropUserStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DropUserStmt.java @@ -29,12 +29,23 @@ import org.apache.doris.qe.ConnectContext; // drop user cmy <==> drop user cmy@'%' // drop user cmy@'192.168.1.%' public class DropUserStmt extends DdlStmt { + + private boolean ifExists; private UserIdentity userIdent; public DropUserStmt(UserIdentity userIdent) { this.userIdent = userIdent; } + public DropUserStmt(boolean ifExists, UserIdentity userIdent) { + this.ifExists = ifExists; + this.userIdent = userIdent; + } + + public boolean isSetIfExists() { + return ifExists; + } + public UserIdentity getUserIdentity() { return userIdent; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java index f115f4e63c..f3e187065a 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java @@ -6104,7 +6104,7 @@ public class Catalog { idToDb.remove(infoSchemaDb.getId()); } - public void replayDropCluster(ClusterInfo info) { + public void replayDropCluster(ClusterInfo info) throws DdlException { tryLock(true); try { unprotectDropCluster(info, true/* is replay */); diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java index 27fc99289f..ec072bfdec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/PaloAuth.java @@ -554,12 +554,12 @@ public class PaloAuth implements Writable { // create user public void createUser(CreateUserStmt stmt) throws DdlException { - createUserInternal(stmt.getUserIdent(), stmt.getQualifiedRole(), stmt.getPassword(), false); + createUserInternal(stmt.getUserIdent(), stmt.getQualifiedRole(), stmt.getPassword(), stmt.isIfNotExist(), false); } public void replayCreateUser(PrivInfo privInfo) { try { - createUserInternal(privInfo.getUserIdent(), privInfo.getRole(), privInfo.getPasswd(), true); + createUserInternal(privInfo.getUserIdent(), privInfo.getRole(), privInfo.getPasswd(), false, true); } catch (DdlException e) { LOG.error("should not happen", e); } @@ -568,12 +568,12 @@ public class PaloAuth implements Writable { /* * Do following steps: * 1. Check does specified role exist. If not, throw exception. - * 2. Check does user already exist. If yes, throw exception. + * 2. Check does user already exist. If yes && ignoreIfExists, just return. Otherwise, throw exception. * 3. set password for specified user. * 4. grant privs of role to user, if role is specified. */ private void createUserInternal(UserIdentity userIdent, String roleName, byte[] password, - boolean isReplay) throws DdlException { + boolean ignoreIfExists, boolean isReplay) throws DdlException { writeLock(); try { // 1. check if role exist @@ -584,9 +584,13 @@ public class PaloAuth implements Writable { throw new DdlException("Role: " + roleName + " does not exist"); } } - + // 2. check if user already exist if (userPrivTable.doesUserExist(userIdent)) { + if (ignoreIfExists) { + LOG.debug("user exists, ignored to create user: {}, is replay: {}", userIdent, isReplay); + return; + } throw new DdlException("User " + userIdent + " already exist"); } @@ -646,22 +650,33 @@ public class PaloAuth implements Writable { // drop user public void dropUser(DropUserStmt stmt) throws DdlException { - dropUserInternal(stmt.getUserIdentity(), false); + dropUserInternal(stmt.getUserIdentity(), stmt.isSetIfExists(), false); } - public void replayDropUser(UserIdentity userIdent) { - dropUserInternal(userIdent, true); + public void replayDropUser(UserIdentity userIdent) throws DdlException { + dropUserInternal(userIdent, false, true); } - public void replayOldDropUser(String userName) { + public void replayOldDropUser(String userName) throws DdlException { UserIdentity userIdentity = new UserIdentity(userName, "%"); userIdentity.setIsAnalyzed(); - dropUserInternal(userIdentity, true /* is replay */); + dropUserInternal(userIdentity, false /* ignore if non exists */, true /* is replay */); } - private void dropUserInternal(UserIdentity userIdent, boolean isReplay) { + private void dropUserInternal(UserIdentity userIdent, boolean ignoreIfNonExists, boolean isReplay) throws DdlException { writeLock(); try { + // check if user exists + if (!doesUserExist(userIdent)) { + if (ignoreIfNonExists) { + LOG.info("user non exists, ignored to drop user: {}, is replay: {}", + userIdent.getQualifiedUser(), isReplay); + return; + } + throw new DdlException(String.format("User `%s`@`%s` does not exist.", + userIdent.getQualifiedUser(), userIdent.getHost())); + } + // we don't check if user exists userPrivTable.dropUser(userIdent); dbPrivTable.dropUser(userIdent); @@ -1047,21 +1062,26 @@ public class PaloAuth implements Writable { // create role public void createRole(CreateRoleStmt stmt) throws DdlException { - createRoleInternal(stmt.getQualifiedRole(), false); + createRoleInternal(stmt.getQualifiedRole(), stmt.isSetIfNotExists(), false); } public void replayCreateRole(PrivInfo info) { try { - createRoleInternal(info.getRole(), true); + createRoleInternal(info.getRole(), false, true); } catch (DdlException e) { LOG.error("should not happened", e); } } - private void createRoleInternal(String role, boolean isReplay) throws DdlException { + private void createRoleInternal(String role, boolean ignoreIfExists, boolean isReplay) throws DdlException { PaloRole emptyPrivsRole = new PaloRole(role); writeLock(); try { + if (ignoreIfExists && roleManager.getRole(role) != null) { + LOG.info("role exists, ignored to create role: {}, is replay: {}", role, isReplay); + return; + } + roleManager.addRole(emptyPrivsRole, true /* err on exist */); if (!isReplay) { @@ -1076,20 +1096,25 @@ public class PaloAuth implements Writable { // drop role public void dropRole(DropRoleStmt stmt) throws DdlException { - dropRoleInternal(stmt.getQualifiedRole(), false); + dropRoleInternal(stmt.getQualifiedRole(), stmt.isSetIfExists(), false); } public void replayDropRole(PrivInfo info) { try { - dropRoleInternal(info.getRole(), true); + dropRoleInternal(info.getRole(), false, true); } catch (DdlException e) { LOG.error("should not happened", e); } } - private void dropRoleInternal(String role, boolean isReplay) throws DdlException { + private void dropRoleInternal(String role, boolean ignoreIfNonExists, boolean isReplay) throws DdlException { writeLock(); try { + if (ignoreIfNonExists && roleManager.getRole(role) == null) { + LOG.info("role non exists, ignored to drop role: {}, is replay: {}", role, isReplay); + return; + } + roleManager.dropRole(role, true /* err on non exist */); if (!isReplay) { @@ -1429,13 +1454,13 @@ public class PaloAuth implements Writable { } } - public void dropUserOfCluster(String clusterName, boolean isReplay) { + public void dropUserOfCluster(String clusterName, boolean isReplay) throws DdlException { writeLock(); try { Set<UserIdentity> allUserIdents = getAllUserIdents(true); for (UserIdentity userIdent : allUserIdents) { if (userIdent.getQualifiedUser().startsWith(clusterName)) { - dropUserInternal(userIdent, isReplay); + dropUserInternal(userIdent, false, isReplay); } } } finally { @@ -1478,10 +1503,10 @@ public class PaloAuth implements Writable { try { UserIdentity rootUser = new UserIdentity(ROOT_USER, "%"); rootUser.setIsAnalyzed(); - createUserInternal(rootUser, PaloRole.OPERATOR_ROLE, new byte[0], true /* is replay */); + createUserInternal(rootUser, PaloRole.OPERATOR_ROLE, new byte[0], false /* ignore if exists */, true /* is replay */); UserIdentity adminUser = new UserIdentity(ADMIN_USER, "%"); adminUser.setIsAnalyzed(); - createUserInternal(adminUser, PaloRole.ADMIN_ROLE, new byte[0], true /* is replay */); + createUserInternal(adminUser, PaloRole.ADMIN_ROLE, new byte[0], false /* ignore if exists */, true /* is replay */); } catch (DdlException e) { LOG.error("should not happened", e); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java index f05a341a3d..91182dc4cf 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/AuthTest.java @@ -161,6 +161,43 @@ public class AuthTest { Assert.fail(); } + // 1.1 create cmy@% again with IF NOT EXISTS + userIdentity = new UserIdentity("cmy", "%"); + userDesc = new UserDesc(userIdentity, "54321", true); + createUserStmt = new CreateUserStmt(true, userDesc, null); + try { + createUserStmt.analyze(analyzer); + } catch (UserException e) { + e.printStackTrace(); + Assert.fail(); + } + + try { + auth.createUser(createUserStmt); + } catch (DdlException e) { + Assert.fail(); + } + + // 1.2 create cmy@% again without IF NOT EXISTS + userIdentity = new UserIdentity("cmy", "%"); + userDesc = new UserDesc(userIdentity, "54321", true); + createUserStmt = new CreateUserStmt(false, userDesc, null); + try { + createUserStmt.analyze(analyzer); + } catch (UserException e) { + e.printStackTrace(); + Assert.fail(); + } + + boolean hasException = false; + try { + auth.createUser(createUserStmt); + } catch (DdlException e) { + e.printStackTrace(); + hasException = true; + } + Assert.assertTrue(hasException); + // 2. check if cmy from specified ip can access to palo List<UserIdentity> currentUser = Lists.newArrayList(); Assert.assertTrue(auth.checkPlainPassword(SystemInfoService.DEFAULT_CLUSTER + ":cmy", "192.168.0.1", "12345", @@ -205,7 +242,7 @@ public class AuthTest { Assert.fail(); } - boolean hasException = false; + hasException = false; try { auth.createUser(createUserStmt); } catch (DdlException e) { @@ -769,6 +806,40 @@ public class AuthTest { Assert.fail(); } + // 24.1 create role again with IF NOT EXISTS + roleStmt = new CreateRoleStmt(true, "role1"); + try { + roleStmt.analyze(analyzer); + } catch (UserException e1) { + e1.printStackTrace(); + Assert.fail(); + } + + try { + auth.createRole(roleStmt); + } catch (DdlException e1) { + e1.printStackTrace(); + Assert.fail(); + } + + // 24.2 create role again without IF NOT EXISTS + roleStmt = new CreateRoleStmt(false, "role1"); + try { + roleStmt.analyze(analyzer); + } catch (UserException e1) { + e1.printStackTrace(); + Assert.fail(); + } + + hasException = false; + try { + auth.createRole(roleStmt); + } catch (DdlException e1) { + e1.printStackTrace(); + hasException = true; + } + Assert.assertTrue(hasException); + // 25. grant auth to non exist role, will create this new role privileges = Lists.newArrayList(AccessPrivilege.DROP_PRIV, AccessPrivilege.SELECT_PRIV); grantStmt = new GrantStmt(null, "role2", new TablePattern("*", "*"), privileges); @@ -917,6 +988,40 @@ public class AuthTest { Assert.assertFalse(auth.checkDbPriv(currentUser2.get(0), SystemInfoService.DEFAULT_CLUSTER + ":db4", PrivPredicate.DROP)); + // 31.1 drop role again with IF EXISTS + dropRoleStmt = new DropRoleStmt(true, "role1"); + try { + dropRoleStmt.analyze(analyzer); + } catch (UserException e) { + e.printStackTrace(); + Assert.fail(); + } + + try { + auth.dropRole(dropRoleStmt); + } catch (DdlException e) { + e.printStackTrace(); + Assert.fail(); + } + + // 31.2 drop role again without IF EXISTS + dropRoleStmt = new DropRoleStmt(false, "role1"); + try { + dropRoleStmt.analyze(analyzer); + } catch (UserException e) { + e.printStackTrace(); + Assert.fail(); + } + + hasException = false; + try { + auth.dropRole(dropRoleStmt); + } catch (DdlException e) { + e.printStackTrace(); + hasException = true; + } + Assert.assertTrue(hasException); + // 32. drop user cmy@"%" DropUserStmt dropUserStmt = new DropUserStmt(new UserIdentity("cmy", "%")); try { @@ -936,6 +1041,39 @@ public class AuthTest { Assert.assertTrue(auth.checkPlainPassword(SystemInfoService.DEFAULT_CLUSTER + ":zhangsan", "192.168.0.1", "12345", null)); + // 32.1 drop user cmy@"%" again with IF EXISTS + dropUserStmt = new DropUserStmt(true, new UserIdentity("cmy", "%")); + try { + dropUserStmt.analyze(analyzer); + } catch (UserException e) { + e.printStackTrace(); + Assert.fail(); + } + + try { + auth.dropUser(dropUserStmt); + } catch (DdlException e) { + Assert.fail(); + } + + // 32.2 drop user cmy@"%" again without IF EXISTS + dropUserStmt = new DropUserStmt(false, new UserIdentity("cmy", "%")); + try { + dropUserStmt.analyze(analyzer); + } catch (UserException e) { + e.printStackTrace(); + Assert.fail(); + } + + hasException = false; + try { + auth.dropUser(dropUserStmt); + } catch (DdlException e) { + e.printStackTrace(); + hasException = true; + } + Assert.assertTrue(hasException); + // 33. drop user zhangsan@"192.%" dropUserStmt = new DropUserStmt(new UserIdentity("zhangsan", "192.%")); try { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org