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 095bf84b822 [Enhancement] (nereids) implement alterUserCommand in nereids (#48428) 095bf84b822 is described below commit 095bf84b822cc231dc22d5317df49f459d897b05 Author: yaoxiao <yx136264...@163.com> AuthorDate: Thu Apr 17 14:54:57 2025 +0800 [Enhancement] (nereids) implement alterUserCommand in nereids (#48428) Issue Number: #42798 --- .../antlr4/org/apache/doris/nereids/DorisParser.g4 | 6 +- .../AlterUserOpType.java} | 31 ++----- .../org/apache/doris/analysis/AlterUserStmt.java | 25 ++---- .../org/apache/doris/mysql/privilege/Auth.java | 15 +++- .../doris/nereids/parser/LogicalPlanBuilder.java | 46 ++++------ .../apache/doris/nereids/parser/ParserUtils.java | 14 ++++ .../apache/doris/nereids/trees/plans/PlanType.java | 4 +- .../trees/plans/commands/AlterUserCommand.java | 60 +++++++++++++ .../trees/plans/commands/info/AlterUserInfo.java} | 98 ++++++---------------- .../trees/plans/visitor/CommandVisitor.java | 5 ++ .../doris/persist/AlterUserOperationLog.java | 11 ++- .../trees/plans/commands/AlterUserCommandTest.java | 91 ++++++++++++++++++++ .../ddl/alter/test_alter_user_nereids.groovy | 37 +++----- 13 files changed, 263 insertions(+), 180 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 959f0cf0d43..d2c3dbbf36f 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 @@ -252,6 +252,8 @@ supportedAlterStatement QUOTA (quota=identifier | INTEGER_VALUE) #alterDatabaseSetQuota | ALTER SYSTEM RENAME COMPUTE GROUP name=identifier newName=identifier #alterSystemRenameComputeGroup | ALTER REPOSITORY name=identifier properties=propertyClause? #alterRepository + | ALTER USER (IF EXISTS)? grantUserIdentify + passwordOption (COMMENT STRING_LITERAL)? #alterUser ; supportedDropStatement @@ -638,8 +640,8 @@ unsupportedAlterStatement SET LEFT_PAREN propertyItemList RIGHT_PAREN #alterColocateGroup | ALTER ROUTINE LOAD FOR name=multipartIdentifier properties=propertyClause? (FROM type=identifier LEFT_PAREN propertyItemList RIGHT_PAREN)? #alterRoutineLoad - | ALTER USER (IF EXISTS)? grantUserIdentify - passwordOption (COMMENT STRING_LITERAL)? #alterUser + | ALTER STORAGE POLICY name=identifierOrText + properties=propertyClause #alterStoragePlicy ; alterSystemClause diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java b/fe/fe-core/src/main/java/org/apache/doris/alter/AlterUserOpType.java similarity index 52% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java copy to fe/fe-core/src/main/java/org/apache/doris/alter/AlterUserOpType.java index 0afc7ddce15..4b694c38ef9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/alter/AlterUserOpType.java @@ -15,29 +15,14 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.parser; +package org.apache.doris.alter; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.misc.Interval; -import java.util.function.Supplier; - -/** - * Utils for parser. - */ -public class ParserUtils { - public static <T> T withOrigin(ParserRuleContext ctx, Supplier<T> f) { - return f.get(); - } - - public static String command(ParserRuleContext ctx) { - CharStream stream = ctx.getStart().getInputStream(); - return stream.getText(Interval.of(0, stream.size() - 1)); - } - - public static Origin position(Token token) { - return new Origin(token.getLine(), token.getCharPositionInLine()); - } +public enum AlterUserOpType { + SET_PASSWORD, + SET_ROLE, + SET_PASSWORD_POLICY, + LOCK_ACCOUNT, + UNLOCK_ACCOUNT, + MODIFY_COMMENT } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java index aa5c69c29ac..cc340182970 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java @@ -17,6 +17,7 @@ package org.apache.doris.analysis; +import org.apache.doris.alter.AlterUserOpType; import org.apache.doris.catalog.Env; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.AnalysisException; @@ -48,17 +49,7 @@ public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { private String comment; - // Only support doing one of these operation at one time. - public enum OpType { - SET_PASSWORD, - SET_ROLE, - SET_PASSWORD_POLICY, - LOCK_ACCOUNT, - UNLOCK_ACCOUNT, - MODIFY_COMMENT - } - - private Set<OpType> ops = Sets.newHashSet(); + private Set<AlterUserOpType> ops = Sets.newHashSet(); public AlterUserStmt(boolean ifExist, UserDesc userDesc, String role, PasswordOptions passwordOptions, String comment) { @@ -92,7 +83,7 @@ public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { return passwordOptions; } - public OpType getOpType() { + public AlterUserOpType getOpType() { Preconditions.checkState(ops.size() == 1); return ops.iterator().next(); } @@ -108,27 +99,27 @@ public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { userDesc.getPassVar().analyze(); if (userDesc.hasPassword()) { - ops.add(OpType.SET_PASSWORD); + ops.add(AlterUserOpType.SET_PASSWORD); } if (!Strings.isNullOrEmpty(role)) { - ops.add(OpType.SET_ROLE); + ops.add(AlterUserOpType.SET_ROLE); } // may be set comment to "", so not use `Strings.isNullOrEmpty` if (comment != null) { - ops.add(OpType.MODIFY_COMMENT); + ops.add(AlterUserOpType.MODIFY_COMMENT); } passwordOptions.analyze(); if (passwordOptions.getAccountUnlocked() == FailedLoginPolicy.LOCK_ACCOUNT) { throw new AnalysisException("Not support lock account now"); } else if (passwordOptions.getAccountUnlocked() == FailedLoginPolicy.UNLOCK_ACCOUNT) { - ops.add(OpType.UNLOCK_ACCOUNT); + ops.add(AlterUserOpType.UNLOCK_ACCOUNT); } else if (passwordOptions.getExpirePolicySecond() != PasswordOptions.UNSET || passwordOptions.getHistoryPolicy() != PasswordOptions.UNSET || passwordOptions.getPasswordLockSecond() != PasswordOptions.UNSET || passwordOptions.getLoginAttempts() != PasswordOptions.UNSET) { - ops.add(OpType.SET_PASSWORD_POLICY); + ops.add(AlterUserOpType.SET_PASSWORD_POLICY); } if (ops.size() != 1) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java index cd8a682c4bc..aba0f9571f9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java @@ -17,9 +17,9 @@ package org.apache.doris.mysql.privilege; +import org.apache.doris.alter.AlterUserOpType; import org.apache.doris.analysis.AlterRoleStmt; import org.apache.doris.analysis.AlterUserStmt; -import org.apache.doris.analysis.AlterUserStmt.OpType; import org.apache.doris.analysis.CreateRoleStmt; import org.apache.doris.analysis.CreateUserStmt; import org.apache.doris.analysis.DropRoleStmt; @@ -62,6 +62,7 @@ import org.apache.doris.mysql.MysqlPassword; import org.apache.doris.mysql.authenticate.AuthenticateType; import org.apache.doris.mysql.authenticate.ldap.LdapManager; import org.apache.doris.mysql.authenticate.ldap.LdapUserInfo; +import org.apache.doris.nereids.trees.plans.commands.info.AlterUserInfo; import org.apache.doris.nereids.trees.plans.commands.info.CreateUserInfo; import org.apache.doris.persist.AlterUserOperationLog; import org.apache.doris.persist.LdapInfo; @@ -1863,6 +1864,11 @@ public class Auth implements Writable { stmt.getPasswordOptions(), stmt.getComment(), false); } + public void alterUser(AlterUserInfo info) throws DdlException { + alterUserInternal(info.isIfExist(), info.getOpType(), info.getUserIdent(), info.getPassword(), + null, info.getPasswordOptions(), info.getComment(), false); + } + public void replayAlterUser(AlterUserOperationLog log) { try { alterUserInternal(true, log.getOp(), log.getUserIdent(), log.getPassword(), log.getRole(), @@ -1872,8 +1878,9 @@ public class Auth implements Writable { } } - private void alterUserInternal(boolean ifExists, OpType opType, UserIdentity userIdent, byte[] password, - String role, PasswordOptions passwordOptions, String comment, boolean isReplay) throws DdlException { + private void alterUserInternal(boolean ifExists, AlterUserOpType opType, UserIdentity userIdent, byte[] password, + String role, PasswordOptions passwordOptions, String comment, + boolean isReplay) throws DdlException { writeLock(); try { if (!doesUserExist(userIdent)) { @@ -1901,7 +1908,7 @@ public class Auth implements Writable { default: throw new DdlException("Unknown alter user operation type: " + opType.name()); } - if (opType != OpType.SET_PASSWORD && !isReplay) { + if (opType != AlterUserOpType.SET_PASSWORD && !isReplay) { // For SET_PASSWORD: // the edit log is wrote in "setPasswordInternal" AlterUserOperationLog log = new AlterUserOperationLog(opType, userIdent, password, role, 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 67fa8eafdb6..65f6ce755f4 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 @@ -544,6 +544,7 @@ import org.apache.doris.nereids.trees.plans.commands.AlterSystemCommand; import org.apache.doris.nereids.trees.plans.commands.AlterSystemRenameComputeGroupCommand; import org.apache.doris.nereids.trees.plans.commands.AlterTableCommand; import org.apache.doris.nereids.trees.plans.commands.AlterTableStatsCommand; +import org.apache.doris.nereids.trees.plans.commands.AlterUserCommand; import org.apache.doris.nereids.trees.plans.commands.AlterViewCommand; import org.apache.doris.nereids.trees.plans.commands.AlterWorkloadGroupCommand; import org.apache.doris.nereids.trees.plans.commands.AlterWorkloadPolicyCommand; @@ -728,6 +729,7 @@ import org.apache.doris.nereids.trees.plans.commands.info.AlterMTMVReplaceInfo; import org.apache.doris.nereids.trees.plans.commands.info.AlterMultiPartitionOp; import org.apache.doris.nereids.trees.plans.commands.info.AlterSystemOp; import org.apache.doris.nereids.trees.plans.commands.info.AlterTableOp; +import org.apache.doris.nereids.trees.plans.commands.info.AlterUserInfo; import org.apache.doris.nereids.trees.plans.commands.info.AlterViewInfo; import org.apache.doris.nereids.trees.plans.commands.info.BuildIndexOp; import org.apache.doris.nereids.trees.plans.commands.info.BulkLoadDataDesc; @@ -6384,6 +6386,16 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { return new DescribeCommand(tableValuedFunctionRef); } + @Override + public LogicalPlan visitAlterUser(DorisParser.AlterUserContext ctx) { + boolean ifExist = ctx.EXISTS() != null; + UserDesc userDesc = visitGrantUserIdentify(ctx.grantUserIdentify()); + PasswordOptions passwordOptions = visitPasswordOption(ctx.passwordOption()); + String comment = ctx.STRING_LITERAL() != null ? stripQuotes(ctx.STRING_LITERAL().getText()) : null; + AlterUserInfo alterUserInfo = new AlterUserInfo(ifExist, userDesc, passwordOptions, comment); + return new AlterUserCommand(alterUserInfo); + } + @Override public LogicalPlan visitShowTableStats(DorisParser.ShowTableStatsContext ctx) { if (ctx.tableId != null) { @@ -6517,9 +6529,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { return new KillAnalyzeJobCommand(jobId); } - /** - * PasswordOption - */ + @Override public PasswordOptions visitPasswordOption(DorisParser.PasswordOptionContext ctx) { int historyPolicy = PasswordOptions.UNSET; long expirePolicySecond = PasswordOptions.UNSET; @@ -6540,7 +6550,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { expirePolicySecond = 0; } else if (ctx.expireValue != null) { long value = Long.parseLong(ctx.expireValue.getText()); - expirePolicySecond = getSecond(value, ctx.expireTimeUnit.getText()); + expirePolicySecond = ParserUtils.getSecond(value, ctx.expireTimeUnit.getText()); } if (ctx.reuseValue != null) { @@ -6555,7 +6565,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { passwordLockSecond = -1; } else if (ctx.lockValue != null) { long value = Long.parseLong(ctx.lockValue.getText()); - passwordLockSecond = getSecond(value, ctx.lockTimeUint.getText()); + passwordLockSecond = ParserUtils.getSecond(value, ctx.lockTimeUint.getText()); } if (ctx.ACCOUNT_LOCK() != null) { @@ -6572,26 +6582,10 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { accountUnlocked); } - private long getSecond(long value, String s) { - long ans = 0; - - switch (s) { - case "DAY": - ans = value * 24 * 60 * 60; - break; - case "HOUR": - ans = value * 60 * 60; - break; - default: - ans = value; - } - return ans; - } - @Override public LogicalPlan visitCreateUser(CreateUserContext ctx) { String comment = visitCommentSpec(ctx.commentSpec()); - PasswordOptions passwordOptions = (PasswordOptions) ctx.passwordOption().accept(this); + PasswordOptions passwordOptions = visitPasswordOption(ctx.passwordOption()); UserDesc userDesc = (UserDesc) ctx.grantUserIdentify().accept(this); String role = null; @@ -6610,16 +6604,12 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { @Override public UserDesc visitGrantUserIdentify(DorisParser.GrantUserIdentifyContext ctx) { - UserIdentity userIdentity = (UserIdentity) ctx.userIdentify().accept(this); - + UserIdentity userIdentity = visitUserIdentify(ctx.userIdentify()); if (ctx.IDENTIFIED() == null) { return new UserDesc(userIdentity); } - String password = stripQuotes(ctx.STRING_LITERAL().getText()); - boolean isPlain = !(ctx.PASSWORD() != null); - + boolean isPlain = ctx.PASSWORD() == null; return new UserDesc(userIdentity, new PassVar(password, isPlain)); } } - diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java index 0afc7ddce15..c829fe01c35 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java @@ -40,4 +40,18 @@ public class ParserUtils { public static Origin position(Token token) { return new Origin(token.getLine(), token.getCharPositionInLine()); } + + /** + * getSecond + */ + public static long getSecond(long value, String s) { + switch (s) { + case "DAY": + return value * 24 * 60 * 60; + case "HOUR": + return value * 60 * 60; + default: + return value; + } + } } 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 96db0af6fd4..3bfe92a2b72 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 @@ -313,6 +313,9 @@ public enum PlanType { DROP_TABLE_COMMAND, ANALYZE_DATABASE, ANALYZE_TABLE, + ALTER_SYSTEM, + ALTER_SYSTEM_RENAME_COMPUTE_GROUP, + ALTER_USER_COMMAND, ALTER_SYSTEM_ADD_BACKEND, ALTER_SYSTEM_DROP_BACKEND, ALTER_SYSTEM_DECOMMISSION_BACKEND, @@ -326,7 +329,6 @@ public enum PlanType { ALTER_SYSTEM_SET_LOAD_ERRORS_HU, ALTER_SYSTEM_MODIFY_BACKEND, ALTER_SYSTEM_MODIFY_FRONTEND_OR_BACKEND_HOSTNAME, - ALTER_SYSTEM_RENAME_COMPUTE_GROUP, SHOW_TABLE_STATS_COMMAND, DROP_STATS_COMMAND, DROP_CACHED_STATS_COMMAND, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java new file mode 100644 index 00000000000..e1bde5ac549 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java @@ -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. + +package org.apache.doris.nereids.trees.plans.commands; + +import org.apache.doris.analysis.StmtType; +import org.apache.doris.catalog.Env; +import org.apache.doris.common.UserException; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.commands.info.AlterUserInfo; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.StmtExecutor; + +/** + * AlterUserCommand + */ +public class AlterUserCommand extends AlterCommand { + + private final AlterUserInfo alterUserInfo; + + public AlterUserCommand(AlterUserInfo alterUserInfo) { + super(PlanType.ALTER_USER_COMMAND); + this.alterUserInfo = alterUserInfo; + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitAlterUserCommand(this, context); + } + + @Override + public void doRun(ConnectContext ctx, StmtExecutor executor) throws Exception { + validate(); + Env.getCurrentEnv().getAuth().alterUser(alterUserInfo); + } + + public void validate() throws UserException { + alterUserInfo.validate(); + } + + @Override + public StmtType stmtType() { + return StmtType.ALTER; + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java similarity index 57% copy from fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java index aa5c69c29ac..40c1ef7d781 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AlterUserStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterUserInfo.java @@ -15,8 +15,12 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.analysis; +package org.apache.doris.nereids.trees.plans.commands.info; +import org.apache.doris.alter.AlterUserOpType; +import org.apache.doris.analysis.PasswordOptions; +import org.apache.doris.analysis.UserDesc; +import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.Env; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.AnalysisException; @@ -24,47 +28,28 @@ import org.apache.doris.common.ErrorCode; import org.apache.doris.common.ErrorReport; import org.apache.doris.common.UserException; import org.apache.doris.mysql.privilege.Auth; -import org.apache.doris.mysql.privilege.PasswordPolicy.FailedLoginPolicy; +import org.apache.doris.mysql.privilege.PasswordPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import com.google.common.base.Preconditions; -import com.google.common.base.Strings; import com.google.common.collect.Sets; import java.util.Set; -// ALTER USER user@host [IDENTIFIED BY "password"] [DEFAULT ROLE role] [password_options] -// password_options: -// PASSWORD_HISTORY -// ACCOUNT_LOCK[ACCOUNT_UNLOCK] -// FAILED_LOGIN_ATTEMPTS -// PASSWORD_LOCK_TIME -public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { +/** + * AlterUserInfo + */ +public class AlterUserInfo { private boolean ifExist; private UserDesc userDesc; - private String role; private PasswordOptions passwordOptions; - private String comment; + private Set<AlterUserOpType> ops = Sets.newHashSet(); - // Only support doing one of these operation at one time. - public enum OpType { - SET_PASSWORD, - SET_ROLE, - SET_PASSWORD_POLICY, - LOCK_ACCOUNT, - UNLOCK_ACCOUNT, - MODIFY_COMMENT - } - - private Set<OpType> ops = Sets.newHashSet(); - - public AlterUserStmt(boolean ifExist, UserDesc userDesc, String role, PasswordOptions passwordOptions, - String comment) { + public AlterUserInfo(boolean ifExist, UserDesc userDesc, PasswordOptions passwordOptions, String comment) { this.ifExist = ifExist; this.userDesc = userDesc; - this.role = role; this.passwordOptions = passwordOptions; this.comment = comment; } @@ -84,15 +69,11 @@ public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { return null; } - public String getRole() { - return role; - } - public PasswordOptions getPasswordOptions() { return passwordOptions; } - public OpType getOpType() { + public AlterUserOpType getOpType() { Preconditions.checkState(ops.size() == 1); return ops.iterator().next(); } @@ -101,38 +82,36 @@ public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { return comment; } - @Override - public void analyze(Analyzer analyzer) throws UserException { - super.analyze(analyzer); + /** + * validate + */ + public void validate() throws UserException { userDesc.getUserIdent().analyze(); userDesc.getPassVar().analyze(); if (userDesc.hasPassword()) { - ops.add(OpType.SET_PASSWORD); - } - - if (!Strings.isNullOrEmpty(role)) { - ops.add(OpType.SET_ROLE); + ops.add(AlterUserOpType.SET_PASSWORD); } // may be set comment to "", so not use `Strings.isNullOrEmpty` if (comment != null) { - ops.add(OpType.MODIFY_COMMENT); + ops.add(AlterUserOpType.MODIFY_COMMENT); } passwordOptions.analyze(); - if (passwordOptions.getAccountUnlocked() == FailedLoginPolicy.LOCK_ACCOUNT) { + if (passwordOptions.getAccountUnlocked() == PasswordPolicy.FailedLoginPolicy.LOCK_ACCOUNT) { throw new AnalysisException("Not support lock account now"); - } else if (passwordOptions.getAccountUnlocked() == FailedLoginPolicy.UNLOCK_ACCOUNT) { - ops.add(OpType.UNLOCK_ACCOUNT); + } else if (passwordOptions.getAccountUnlocked() == PasswordPolicy.FailedLoginPolicy.UNLOCK_ACCOUNT) { + ops.add(AlterUserOpType.UNLOCK_ACCOUNT); } else if (passwordOptions.getExpirePolicySecond() != PasswordOptions.UNSET || passwordOptions.getHistoryPolicy() != PasswordOptions.UNSET || passwordOptions.getPasswordLockSecond() != PasswordOptions.UNSET || passwordOptions.getLoginAttempts() != PasswordOptions.UNSET) { - ops.add(OpType.SET_PASSWORD_POLICY); + ops.add(AlterUserOpType.SET_PASSWORD_POLICY); } if (ops.size() != 1) { - throw new AnalysisException("Only support doing one type of operation at one time"); + throw new org.apache.doris.common.AnalysisException("Only support doing one type of operation at one time," + + "actual number of type is " + ops.size()); } if (userDesc.getUserIdent().getQualifiedUser().equals(Auth.ROOT_USER) @@ -145,31 +124,4 @@ public class AlterUserStmt extends DdlStmt implements NotFallbackInParser { ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT"); } } - - @Override - public String toSql() { - StringBuilder sb = new StringBuilder(); - sb.append("ALTER USER ").append(userDesc.getUserIdent()); - if (!Strings.isNullOrEmpty(userDesc.getPassVar().getText())) { - if (userDesc.getPassVar().isPlain()) { - sb.append(" IDENTIFIED BY '").append("*XXX").append("'"); - } else { - sb.append(" IDENTIFIED BY PASSWORD '").append(userDesc.getPassVar().getText()).append("'"); - } - } - - if (!Strings.isNullOrEmpty(role)) { - sb.append(" DEFAULT ROLE '").append(role).append("'"); - } - if (passwordOptions != null) { - sb.append(passwordOptions.toSql()); - } - - return sb.toString(); - } - - @Override - public StmtType stmtType() { - return StmtType.ALTER; - } } 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 c60ae160429..429228c2a54 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 @@ -36,6 +36,7 @@ import org.apache.doris.nereids.trees.plans.commands.AlterSqlBlockRuleCommand; import org.apache.doris.nereids.trees.plans.commands.AlterStoragePolicyCommand; import org.apache.doris.nereids.trees.plans.commands.AlterTableCommand; import org.apache.doris.nereids.trees.plans.commands.AlterTableStatsCommand; +import org.apache.doris.nereids.trees.plans.commands.AlterUserCommand; import org.apache.doris.nereids.trees.plans.commands.AlterViewCommand; import org.apache.doris.nereids.trees.plans.commands.AlterWorkloadGroupCommand; import org.apache.doris.nereids.trees.plans.commands.AlterWorkloadPolicyCommand; @@ -896,6 +897,10 @@ public interface CommandVisitor<R, C> { return visitCommand(describeCommand, context); } + default R visitAlterUserCommand(AlterUserCommand alterUserCommand, C context) { + return visitCommand(alterUserCommand, context); + } + default R visitShowTableStatusCommand(ShowTableStatusCommand showTableStatusCommand, C context) { return visitCommand(showTableStatusCommand, context); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/AlterUserOperationLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/AlterUserOperationLog.java index 472cda7874e..90580c012f7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/persist/AlterUserOperationLog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/persist/AlterUserOperationLog.java @@ -17,8 +17,7 @@ package org.apache.doris.persist; -import org.apache.doris.analysis.AlterUserStmt; -import org.apache.doris.analysis.AlterUserStmt.OpType; +import org.apache.doris.alter.AlterUserOpType; import org.apache.doris.analysis.PasswordOptions; import org.apache.doris.analysis.UserIdentity; import org.apache.doris.common.io.Text; @@ -41,13 +40,13 @@ public class AlterUserOperationLog implements Writable { @SerializedName(value = "passwordOptions") private PasswordOptions passwordOptions; @SerializedName(value = "op") - private AlterUserStmt.OpType op; + private AlterUserOpType op; @SerializedName(value = "comment") private String comment; - public AlterUserOperationLog(OpType opType, UserIdentity userIdent, byte[] password, - String role, PasswordOptions passwordOptions, String comment) { + public AlterUserOperationLog(AlterUserOpType opType, UserIdentity userIdent, byte[] password, + String role, PasswordOptions passwordOptions, String comment) { this.op = opType; this.userIdent = userIdent; this.password = password; @@ -56,7 +55,7 @@ public class AlterUserOperationLog implements Writable { this.comment = comment; } - public OpType getOp() { + public AlterUserOpType getOp() { return op; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommandTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommandTest.java new file mode 100644 index 00000000000..1d3c51ef70c --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommandTest.java @@ -0,0 +1,91 @@ +// 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.PassVar; +import org.apache.doris.analysis.PasswordOptions; +import org.apache.doris.analysis.UserDesc; +import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.catalog.Env; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.mysql.privilege.AccessControllerManager; +import org.apache.doris.mysql.privilege.Auth; +import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.nereids.trees.plans.commands.info.AlterUserInfo; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.utframe.TestWithFeService; + +import mockit.Expectations; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +public class AlterUserCommandTest extends TestWithFeService { + private ConnectContext connectContext; + private Env env; + private AccessControllerManager accessControllerManager; + private UserDesc userDesc; + + private void runBefore() throws IOException { + connectContext = createDefaultCtx(); + env = Env.getCurrentEnv(); + accessControllerManager = env.getAccessManager(); + } + + @Test + public void testValidateNormal() throws Exception { + runBefore(); + new Expectations() { + { + connectContext.isSkipAuth(); + minTimes = 0; + result = true; + + accessControllerManager.checkGlobalPriv(connectContext, PrivPredicate.GRANT); + minTimes = 0; + result = true; + } + }; + // init + UserIdentity userIdentity = new UserIdentity(Auth.ROOT_USER, "%"); + connectContext.setQualifiedUser("root"); + PassVar passVar = new PassVar("", true); + userDesc = new UserDesc(userIdentity, passVar); + PasswordOptions passwordOptions = PasswordOptions.UNSET_OPTION; + AlterUserInfo alterUserInfo = new AlterUserInfo(true, userDesc, passwordOptions, null); + AlterUserCommand alterUserCommand = new AlterUserCommand(alterUserInfo); + Assertions.assertDoesNotThrow(() -> alterUserCommand.validate()); + + //test ops.size() > 1 + AlterUserInfo alterUserInfo02 = new AlterUserInfo(true, userDesc, passwordOptions, "alterUserInfo02"); + AlterUserCommand alterUserCommand02 = new AlterUserCommand(alterUserInfo02); + Assertions.assertThrows(AnalysisException.class, () -> alterUserCommand02.validate(), + "Only support doing one type of operation at one time,actual number of type is 2"); + + //testUser to modify root user + connectContext.setQualifiedUser("testUser"); + Assertions.assertThrows(AnalysisException.class, () -> alterUserCommand.validate(), "Only root user can modify root user"); + + //test PasswordOptions + PasswordOptions passwordOptions02 = new PasswordOptions(PasswordOptions.UNSET, PasswordOptions.UNSET, PasswordOptions.UNSET, PasswordOptions.UNSET, PasswordOptions.UNSET, -1); + AlterUserInfo alterUserInfo03 = new AlterUserInfo(true, userDesc, passwordOptions02, null); + AlterUserCommand alterUserCommand03 = new AlterUserCommand(alterUserInfo03); + Assertions.assertThrows(AnalysisException.class, () -> alterUserCommand03.validate(), "Not support lock account now"); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java b/regression-test/suites/nereids_p0/ddl/alter/test_alter_user_nereids.groovy similarity index 52% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java copy to regression-test/suites/nereids_p0/ddl/alter/test_alter_user_nereids.groovy index 0afc7ddce15..f2d24bbed4e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java +++ b/regression-test/suites/nereids_p0/ddl/alter/test_alter_user_nereids.groovy @@ -15,29 +15,14 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.parser; - -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.misc.Interval; - -import java.util.function.Supplier; - -/** - * Utils for parser. - */ -public class ParserUtils { - public static <T> T withOrigin(ParserRuleContext ctx, Supplier<T> f) { - return f.get(); - } - - public static String command(ParserRuleContext ctx) { - CharStream stream = ctx.getStart().getInputStream(); - return stream.getText(Interval.of(0, stream.size() - 1)); - } - - public static Origin position(Token token) { - return new Origin(token.getLine(), token.getCharPositionInLine()); - } -} +suite("test_alter_user_nereids") { + sql "SET enable_nereids_planner=true;" + sql "SET enable_fallback_to_original_planner=false;" + + sql """CREATE USER 'fjytf';""" + + sql """ALTER USER fjytf@'%' IDENTIFIED BY "12345";""" + sql """ALTER USER fjytf@'%' FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 1 DAY;""" + sql """ALTER USER fjytf@'%' ACCOUNT_UNLOCK;""" + sql """ALTER USER fjytf@'%' COMMENT "this is my first user";""" +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org