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

yongzao pushed a commit to branch rename-user-sql
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 359f70550ea888e463a08e4f54b0a7bd66879bd7
Author: Yongzao <[email protected]>
AuthorDate: Sun Sep 28 16:23:30 2025 +0800

    commit 4 cp
---
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |  7 ++-
 .../consensus/request/ConfigPhysicalPlanType.java  |  4 +-
 .../consensus/request/write/auth/AuthorPlan.java   | 13 ++++-
 .../request/write/auth/AuthorRelationalPlan.java   | 12 ++++-
 .../request/write/auth/AuthorTreePlan.java         | 12 ++++-
 .../persistence/auth/AuthorPlanExecutor.java       |  7 +++
 .../persistence/executor/ConfigPlanExecutor.java   |  2 +
 .../thrift/ConfigNodeRPCServiceProcessor.java      | 58 +++++++++++++---------
 .../plan/relational/type/AuthorRType.java          |  4 +-
 .../db/queryengine/plan/statement/AuthorType.java  |  6 +++
 .../plan/statement/sys/AuthorStatement.java        |  1 +
 .../commons/auth/authorizer/BasicAuthorizer.java   |  5 ++
 .../iotdb/commons/auth/authorizer/IAuthorizer.java |  9 ++++
 .../commons/auth/authorizer/OpenIdAuthorizer.java  |  5 ++
 .../iotdb/commons/auth/user/BasicUserManager.java  | 21 ++++++++
 .../db/relational/grammar/sql/RelationalSql.g4     |  5 ++
 .../src/main/thrift/confignode.thrift              |  2 +
 17 files changed, 141 insertions(+), 32 deletions(-)

diff --git 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 3095adba3f6..8d75981f41a 100644
--- 
a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ 
b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -81,7 +81,7 @@ dmlStatement
     ;
 
 dclStatement
-    : createUser | createRole | alterUser | grantUser | grantRole | 
grantRoleToUser
+    : createUser | createRole | alterUser | renameUser | grantUser | grantRole 
| grantRoleToUser
     | revokeUser |  revokeRole | revokeRoleFromUser | dropUser | dropRole
     | listUser | listRole | listPrivilegesUser | listPrivilegesRole
     ;
@@ -1059,6 +1059,11 @@ alterUser
     : ALTER USER userName=usernameWithRoot SET PASSWORD password=STRING_LITERAL
     ;
 
+// Rename user
+renameUser
+    : ALTER USER username=usernameWithRoot RENAME TO newUsername=identifier
+    ;
+
 // Grant User Privileges
 grantUser
     : GRANT privileges ON prefixPath (COMMA prefixPath)* TO USER 
userName=identifier (grantOpt)?
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
index f174352e411..dee820d825d 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
@@ -319,11 +319,13 @@ public enum ConfigPhysicalPlanType {
 
   ShowSubscription((short) 2000),
 
+  // Authority version after and equal 2.0
   DropUserV2((short) 2100),
   UpdateUserV2((short) 2101),
-
   RUpdateUserV2((short) 2102),
   RDropUserV2((short) 2103),
+  RenameUser((short) 2104),
+  RRenameUser((short) 2105),
 
   EnableSeparationOfAdminPowers((short) 2200),
 
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorPlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorPlan.java
index a0090e19af6..ba39e8871d3 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorPlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorPlan.java
@@ -33,6 +33,7 @@ public abstract class AuthorPlan extends 
ConfigPhysicalReadPlan {
   protected boolean grantOpt;
   protected int maxSessionPerUser;
   protected int minSessionPerUser;
+  protected String newUsername = "";
 
   // Used for read plans or some write plans whose type name ends with 'V2'
   protected long executedByUserId;
@@ -122,6 +123,10 @@ public abstract class AuthorPlan extends 
ConfigPhysicalReadPlan {
     this.userName = userName;
   }
 
+  public String getNewUsername() {
+    return newUsername;
+  }
+
   public long getExecutedByUserId() {
     return executedByUserId;
   }
@@ -144,12 +149,14 @@ public abstract class AuthorPlan extends 
ConfigPhysicalReadPlan {
         && Objects.equals(roleName, that.roleName)
         && Objects.equals(password, that.password)
         && Objects.equals(newPassword, that.newPassword)
-        && grantOpt == that.grantOpt;
+        && grantOpt == that.grantOpt
+        && Objects.equals(newUsername, that.newUsername);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(super.getType(), userName, roleName, password, 
newPassword, grantOpt);
+    return Objects.hash(
+        super.getType(), userName, roleName, password, newPassword, grantOpt, 
newUsername);
   }
 
   @Override
@@ -162,6 +169,8 @@ public abstract class AuthorPlan extends 
ConfigPhysicalReadPlan {
         + roleName
         + ", grant option:"
         + grantOpt
+        + ", new username:"
+        + newUsername
         + "]";
   }
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorRelationalPlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorRelationalPlan.java
index 93459018653..c418aa70b4e 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorRelationalPlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorRelationalPlan.java
@@ -85,7 +85,7 @@ public class AuthorRelationalPlan extends AuthorPlan {
         permissions,
         grantOpt,
         password,
-        0);
+        0, "");
   }
 
   public AuthorRelationalPlan(
@@ -97,13 +97,15 @@ public class AuthorRelationalPlan extends AuthorPlan {
       final Set<Integer> permissions,
       final boolean grantOpt,
       final String password,
-      final long executedByUserId) {
+      final long executedByUserId,
+      final String newUsername) {
     super(authorType, userName, roleName, password, "", grantOpt, -1, -1);
 
     this.databaseName = databaseName;
     this.tableName = tableName;
     this.permissions = permissions;
     this.executedByUserId = executedByUserId;
+    this.newUsername = newUsername;
   }
 
   public AuthorRelationalPlan(
@@ -196,6 +198,9 @@ public class AuthorRelationalPlan extends AuthorPlan {
       BasicStructureSerDeUtil.write(maxSessionPerUser, stream);
       BasicStructureSerDeUtil.write(minSessionPerUser, stream);
     }
+    if (authorType == ConfigPhysicalPlanType.RRenameUser) {
+      BasicStructureSerDeUtil.write(newUsername, stream);
+    }
     if (authorType == ConfigPhysicalPlanType.RDropUserV2
         || authorType == ConfigPhysicalPlanType.RUpdateUserV2) {
       BasicStructureSerDeUtil.write(executedByUserId, stream);
@@ -221,6 +226,9 @@ public class AuthorRelationalPlan extends AuthorPlan {
       maxSessionPerUser = buffer.getInt();
       minSessionPerUser = buffer.getInt();
     }
+    if (authorType == ConfigPhysicalPlanType.RRenameUser) {
+      newUsername = BasicStructureSerDeUtil.readString(buffer);
+    }
     if (authorType == ConfigPhysicalPlanType.RDropUserV2
         || authorType == ConfigPhysicalPlanType.RUpdateUserV2) {
       executedByUserId = buffer.getLong();
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorTreePlan.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorTreePlan.java
index 146faea75be..4df7aa89658 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorTreePlan.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/auth/AuthorTreePlan.java
@@ -108,7 +108,7 @@ public class AuthorTreePlan extends AuthorPlan {
         permissions,
         grantOpt,
         nodeNameList,
-        0);
+        0, "");
   }
 
   public AuthorTreePlan(
@@ -120,11 +120,13 @@ public class AuthorTreePlan extends AuthorPlan {
       final Set<Integer> permissions,
       final boolean grantOpt,
       final List<PartialPath> nodeNameList,
-      final long executedByUserId) {
+      final long executedByUserId,
+      final String newUsername) {
     super(authorType, userName, roleName, password, newPassword, grantOpt, -1, 
-1);
     this.permissions = permissions;
     this.nodeNameList = nodeNameList;
     this.executedByUserId = executedByUserId;
+    this.newUsername = newUsername;
   }
 
   public Set<Integer> getPermissions() {
@@ -193,6 +195,9 @@ public class AuthorTreePlan extends AuthorPlan {
       BasicStructureSerDeUtil.write(maxSessionPerUser, stream);
       BasicStructureSerDeUtil.write(minSessionPerUser, stream);
     }
+    if (authorType == ConfigPhysicalPlanType.RenameUser) {
+      BasicStructureSerDeUtil.write(newUsername, stream);
+    }
     if (authorType == ConfigPhysicalPlanType.DropUserV2
         || authorType == ConfigPhysicalPlanType.UpdateUserV2) {
       BasicStructureSerDeUtil.write(executedByUserId, stream);
@@ -225,6 +230,9 @@ public class AuthorTreePlan extends AuthorPlan {
       maxSessionPerUser = buffer.getInt();
       minSessionPerUser = buffer.getInt();
     }
+    if (authorType == ConfigPhysicalPlanType.RenameUser) {
+      newUsername = BasicStructureSerDeUtil.readString(buffer);
+    }
     if (authorType == ConfigPhysicalPlanType.DropUserV2
         || authorType == ConfigPhysicalPlanType.UpdateUserV2) {
       executedByUserId = buffer.getLong();
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
index 69bb5779abc..dd271090396 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
@@ -123,12 +123,16 @@ public class AuthorPlanExecutor implements 
IAuthorPlanExecutor {
     Set<Integer> permissions = authorPlan.getPermissions();
     boolean grantOpt = authorPlan.getGrantOpt();
     List<PartialPath> nodeNameList = authorPlan.getNodeNameList();
+    String newUsername = authorPlan.getNewUsername();
     try {
       switch (authorType) {
         case UpdateUser:
         case UpdateUserV2:
           authorizer.updateUserPassword(userName, newPassword);
           break;
+        case RenameUser:
+          authorizer.renameUser(userName, newUsername);
+          break;
         case CreateUser:
           authorizer.createUser(userName, password);
           break;
@@ -241,6 +245,9 @@ public class AuthorPlanExecutor implements 
IAuthorPlanExecutor {
         case RUpdateUserV2:
           authorizer.updateUserPassword(userName, authorPlan.getPassword());
           break;
+          case RRenameUser:
+            authorizer.renameUser(userName, roleName);
+            break;
         case RDropRole:
           authorizer.deleteRole(roleName);
           break;
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
index 41d459a9c3b..aa3504ac6d6 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
@@ -483,6 +483,7 @@ public class ConfigPlanExecutor {
       case RevokeRoleDep:
       case RevokeRoleFromUserDep:
       case UpdateUserDep:
+      case RenameUser:
       case RCreateRole:
       case RCreateUser:
       case RDropUser:
@@ -514,6 +515,7 @@ public class ConfigPlanExecutor {
       case RRevokeRoleSysPri:
       case RRevokeRoleTBPriv:
       case RRevokeUserRole:
+      case RRenameUser:
         return authorInfo.authorNonQuery((AuthorPlan) physicalPlan);
       case ApplyConfigNode:
         return nodeInfo.applyConfigNode((ApplyConfigNodePlan) physicalPlan);
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index 8b206558080..3d577bcdb1a 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -635,16 +635,20 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
     if (req.getAuthorType() < 0 || req.getAuthorType() >= 
AuthorType.values().length) {
       throw new IndexOutOfBoundsException("Invalid Author Type ordinal");
     }
-    ConfigPhysicalPlanType configPhysicalPlanType =
-        ConfigPhysicalPlanType.values()[
-            req.getAuthorType() + ConfigPhysicalPlanType.CreateUser.ordinal()];
-    switch (configPhysicalPlanType) {
-      case UpdateUser:
-        configPhysicalPlanType = ConfigPhysicalPlanType.UpdateUserV2;
-        break;
-      case DropUser:
-        configPhysicalPlanType = ConfigPhysicalPlanType.DropUserV2;
-        break;
+    ConfigPhysicalPlanType configPhysicalPlanType;
+    if (req.getAuthorType() == AuthorType.RENAME_USER.ordinal()) {
+      configPhysicalPlanType = ConfigPhysicalPlanType.RenameUser;
+    } else {configPhysicalPlanType
+      =ConfigPhysicalPlanType.values()[
+          req.getAuthorType() + ConfigPhysicalPlanType.CreateUser.ordinal()];
+      switch (configPhysicalPlanType) {
+        case UpdateUser:
+          configPhysicalPlanType = ConfigPhysicalPlanType.UpdateUserV2;
+          break;
+        case DropUser:
+          configPhysicalPlanType = ConfigPhysicalPlanType.DropUserV2;
+          break;
+      }
     }
     return configManager.operatePermission(
         new AuthorTreePlan(
@@ -656,7 +660,8 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
             req.getPermissions(),
             req.isGrantOpt(),
             
AuthUtils.deserializePartialPathList(ByteBuffer.wrap(req.getNodeNameList())),
-            req.getExecutedByUserID()));
+            req.getExecutedByUserID(),
+            req.getNewUsername()));
   }
 
   @Override
@@ -677,7 +682,7 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
                     req.getPermissions(),
                     req.isGrantOpt(),
                     
AuthUtils.deserializePartialPathList(ByteBuffer.wrap(req.getNodeNameList())),
-                    req.getExecutedByUserID()));
+                    req.getExecutedByUserID(), req.getNewUsername()));
     final TAuthorizerResp resp = new TAuthorizerResp(dataSet.getStatus());
     resp.setMemberInfo(dataSet.getMemberList());
     resp.setPermissionInfo(dataSet.getPermissionInfoResp());
@@ -691,16 +696,22 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
     if (req.getAuthorType() < 0 || req.getAuthorType() >= 
AuthorRType.values().length) {
       throw new IndexOutOfBoundsException("Invalid Author Type ordinal");
     }
-    ConfigPhysicalPlanType configPhysicalPlanType =
-        ConfigPhysicalPlanType.values()[
-            req.getAuthorType() + 
ConfigPhysicalPlanType.RCreateUser.ordinal()];
-    switch (configPhysicalPlanType) {
-      case RUpdateUser:
-        configPhysicalPlanType = ConfigPhysicalPlanType.RUpdateUserV2;
-        break;
-      case RDropUser:
-        configPhysicalPlanType = ConfigPhysicalPlanType.RDropUserV2;
-        break;
+    ConfigPhysicalPlanType configPhysicalPlanType;
+    if (req.getAuthorType() == AuthorRType.RENAME_USER.ordinal()) {
+      configPhysicalPlanType = ConfigPhysicalPlanType.RRenameUser;
+    } else {
+      configPhysicalPlanType
+    =
+      ConfigPhysicalPlanType.values()[
+          req.getAuthorType() + ConfigPhysicalPlanType.RCreateUser.ordinal()];
+      switch (configPhysicalPlanType) {
+        case RUpdateUser:
+          configPhysicalPlanType = ConfigPhysicalPlanType.RUpdateUserV2;
+          break;
+        case RDropUser:
+          configPhysicalPlanType = ConfigPhysicalPlanType.RDropUserV2;
+          break;
+      }
     }
     return configManager.operatePermission(
         new AuthorRelationalPlan(
@@ -712,7 +723,8 @@ public class ConfigNodeRPCServiceProcessor implements 
IConfigNodeRPCService.Ifac
             req.getPermissions(),
             req.isGrantOpt(),
             req.getPassword(),
-            req.getExecutedByUserID()));
+            req.getExecutedByUserID(),
+            req.getNewUsername()));
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/type/AuthorRType.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/type/AuthorRType.java
index 1cac0e1bacb..8bbff6a718c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/type/AuthorRType.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/type/AuthorRType.java
@@ -49,5 +49,7 @@ public enum AuthorRType {
   LIST_USER,
   LIST_ROLE,
   LIST_USER_PRIV,
-  LIST_ROLE_PRIV
+  LIST_ROLE_PRIV,
+  // Remind to renew the convert codes in ConfigNodeRPCServiceProcessor
+  RENAME_USER,
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/AuthorType.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/AuthorType.java
index 07ba1ecf795..3e3ad61fcd7 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/AuthorType.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/AuthorType.java
@@ -35,6 +35,8 @@ public enum AuthorType {
   LIST_ROLE,
   LIST_USER_PRIVILEGE,
   LIST_ROLE_PRIVILEGE,
+  // Remind to renew the convert codes in ConfigNodeRPCServiceProcessor
+  RENAME_USER,
   ;
 
   /**
@@ -75,6 +77,8 @@ public enum AuthorType {
         return LIST_USER_PRIVILEGE;
       case 14:
         return LIST_ROLE_PRIVILEGE;
+      case 15:
+        return RENAME_USER;
       default:
         return null;
     }
@@ -117,6 +121,8 @@ public enum AuthorType {
         return 13;
       case LIST_ROLE_PRIVILEGE:
         return 14;
+      case RENAME_USER:
+        return 15;
       default:
         return -1;
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
index 09336734c48..cbbbcd38698 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
@@ -48,6 +48,7 @@ public class AuthorStatement extends Statement implements 
IConfigStatement {
   private List<PartialPath> nodeNameList;
   private boolean grantOpt;
   private long executedByUserId;
+  private String newUsername;
 
   /**
    * Constructor with AuthorType.
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
index de800b2be56..ac86ae8d9fc 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java
@@ -318,6 +318,11 @@ public abstract class BasicAuthorizer implements 
IAuthorizer, IService {
     }
   }
 
+  @Override
+  public void renameUser(String username, String newUsername) throws 
AuthException {
+    userManager.renameUser(username, newUsername);
+  }
+
   private void forceUpdateUserPassword(String userName, String newPassword) 
throws AuthException {
     if (!userManager.updateUserPassword(userName, newPassword, true)) {
       throw new AuthException(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
index 52b8ad4e0f4..2745318b69d 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/IAuthorizer.java
@@ -167,6 +167,15 @@ public interface IAuthorizer extends SnapshotProcessor {
    */
   void updateUserPassword(String userName, String newPassword) throws 
AuthException;
 
+  /**
+   * Rename the specified user.
+   *
+   * @param username The original name of the specified user.
+   * @param newUsername The new name to be specified.
+   * @throws AuthException If the original name does not exist or the new name 
is already existed.
+   */
+  void renameUser(String username, String newUsername) throws AuthException;
+
   /**
    * Check if the user have the privilege or grant option on the target.
    *
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
index 38199adf98f..e1f73260dc3 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/OpenIdAuthorizer.java
@@ -262,4 +262,9 @@ public class OpenIdAuthorizer extends BasicAuthorizer {
   public void updateUserPassword(String userName, String newPassword) {
     throwUnsupportedOperationException();
   }
+
+  @Override
+  public void renameUser(String username, String newUsername) {
+    throwUnsupportedOperationException();
+  }
 }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
index 0d67aa21b76..c335896c6d2 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/user/BasicUserManager.java
@@ -229,6 +229,27 @@ public abstract class BasicUserManager extends 
BasicRoleManager {
     }
   }
 
+  public void renameUser(String username, String newUsername) throws 
AuthException {
+    User user = this.getEntity(username);
+    if (user == null) {
+      throw new AuthException(
+          getEntityNotExistErrorCode(), String.format(getNoSuchEntityError(), 
username));
+    }
+    User tmpUser = this.getEntity(newUsername);
+    if (tmpUser != null) {
+      throw new AuthException(
+          TSStatusCode.USER_ALREADY_EXIST, String.format("Cannot rename user 
%s to %s, because the target username is already existed.",
+          username, newUsername
+      ));
+    }
+    lock.writeLock(username);
+    try {
+      entityMap.get(username).setName(newUsername);
+    } finally {
+      lock.writeUnlock(username);
+    }
+  }
+
   public void grantRoleToUser(String roleName, String username) throws 
AuthException {
     lock.writeLock(username);
     try {
diff --git 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index 38a461c93f6..24a652fbd12 100644
--- 
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++ 
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -157,6 +157,7 @@ statement
     | grantUserRoleStatement
     | revokeUserRoleStatement
     | alterUserStatement
+    | renameUserStatement
     | listUserPrivilegeStatement
     | listRolePrivilegeStatement
     | listUserStatement
@@ -708,6 +709,10 @@ alterUserStatement
     : ALTER USER userName=identifier SET PASSWORD password=string
     ;
 
+renameUserStatement
+    : ALTER USER username=identifier RENAME TO newUsername=identifier
+    ;
+
 grantUserRoleStatement
     : GRANT ROLE roleName=identifier TO userName=identifier
     ;
diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift 
b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
index 8f755f08b0c..8627ddf1770 100644
--- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift
@@ -353,6 +353,7 @@ struct TAuthorizerReq {
   7: required bool grantOpt
   8: required binary nodeNameList
   9: required i64 executedByUserID
+  10: required string newUsername
 }
 
 struct TAuthorizerRelationalReq {
@@ -365,6 +366,7 @@ struct TAuthorizerRelationalReq {
    7: required set<i32> permissions
    8: required bool grantOpt
    9: required i64 executedByUserID
+   10: required string newUsername
 }
 
 struct TAuthorizerResp {

Reply via email to