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


Reply via email to