Skip to content

Commit

Permalink
implement alterUserCommand in nereids
Browse files Browse the repository at this point in the history
  • Loading branch information
yx-keith committed Feb 27, 2025
1 parent 4a2b55d commit 2899bb7
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ supportedAlterStatement
SET LEFT_PAREN propertyItemList RIGHT_PAREN #modifyBackendClause
| ALTER SYSTEM MODIFY (FRONTEND | BACKEND) hostPort=STRING_LITERAL
HOSTNAME hostName=STRING_LITERAL #modifyFrontendOrBackendHostNameClause
| ALTER USER (IF EXISTS)? grantUserIdentify
passwordOption (COMMENT STRING_LITERAL)? #alterUser
;

supportedDropStatement
Expand Down Expand Up @@ -648,8 +650,6 @@ unsupportedAlterStatement
(FROM type=identifier LEFT_PAREN propertyItemList RIGHT_PAREN)? #alterRoutineLoad
| ALTER STORAGE POLICY name=identifierOrText
properties=propertyClause #alterStoragePlicy
| ALTER USER (IF EXISTS)? grantUserIdentify
passwordOption (COMMENT STRING_LITERAL)? #alterUser
;

alterSystemClause
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public enum AlterOpType {
MODIFY_TABLE_COMMENT,
MODIFY_COLUMN_COMMENT,
MODIFY_ENGINE,
SET_PASSWORD,
SET_ROLE,
SET_PASSWORD_POLICY,
LOCK_ACCOUNT,
UNLOCK_ACCOUNT,
MODIFY_COMMENT,
INVALID_OP; // INVALID_OP must be the last one

// true means 2 operations have no conflict.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.doris.analysis;

import org.apache.doris.alter.AlterOpType;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
Expand Down Expand Up @@ -46,17 +47,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<AlterOpType> ops = Sets.newHashSet();

public AlterUserStmt(boolean ifExist, UserDesc userDesc, String role, PasswordOptions passwordOptions,
String comment) {
Expand Down Expand Up @@ -90,7 +81,7 @@ public PasswordOptions getPasswordOptions() {
return passwordOptions;
}

public OpType getOpType() {
public AlterOpType getOpType() {
Preconditions.checkState(ops.size() == 1);
return ops.iterator().next();
}
Expand All @@ -106,27 +97,27 @@ public void analyze(Analyzer analyzer) throws UserException {
userDesc.getPassVar().analyze();

if (userDesc.hasPassword()) {
ops.add(OpType.SET_PASSWORD);
ops.add(AlterOpType.SET_PASSWORD);
}

if (!Strings.isNullOrEmpty(role)) {
ops.add(OpType.SET_ROLE);
ops.add(AlterOpType.SET_ROLE);
}

// may be set comment to "", so not use `Strings.isNullOrEmpty`
if (comment != null) {
ops.add(OpType.MODIFY_COMMENT);
ops.add(AlterOpType.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(AlterOpType.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(AlterOpType.SET_PASSWORD_POLICY);
}

if (ops.size() != 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

package org.apache.doris.mysql.privilege;

import org.apache.doris.alter.AlterOpType;
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;
Expand Down Expand Up @@ -62,6 +62,7 @@
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.persist.AlterUserOperationLog;
import org.apache.doris.persist.LdapInfo;
import org.apache.doris.persist.PrivInfo;
Expand Down Expand Up @@ -1839,6 +1840,11 @@ public void alterUser(AlterUserStmt stmt) throws DdlException {
stmt.getPasswordOptions(), stmt.getComment(), false);
}

public void alterUser(AlterUserInfo info) throws DdlException {
alterUserInternal(info.isIfExist(), info.getOpType(), info.getUserIdent(), info.getPassword(),
AlterOpType.SET_ROLE.toString(), info.getPasswordOptions(), info.getComment(), false);
}

public void replayAlterUser(AlterUserOperationLog log) {
try {
alterUserInternal(true, log.getOp(), log.getUserIdent(), log.getPassword(), log.getRole(),
Expand All @@ -1848,8 +1854,9 @@ public void replayAlterUser(AlterUserOperationLog log) {
}
}

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, AlterOpType opType, UserIdentity userIdent, byte[] password,
String role, PasswordOptions passwordOptions, String comment,
boolean isReplay) throws DdlException {
writeLock();
try {
if (!doesUserExist(userIdent)) {
Expand Down Expand Up @@ -1877,7 +1884,7 @@ private void alterUserInternal(boolean ifExists, OpType opType, UserIdentity use
default:
throw new DdlException("Unknown alter user operation type: " + opType.name());
}
if (opType != OpType.SET_PASSWORD && !isReplay) {
if (opType != AlterOpType.SET_PASSWORD && !isReplay) {
// For SET_PASSWORD:
// the edit log is wrote in "setPasswordInternal"
AlterUserOperationLog log = new AlterUserOperationLog(opType, userIdent, password, role,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
import org.apache.doris.analysis.EncryptKeyName;
import org.apache.doris.analysis.FunctionName;
import org.apache.doris.analysis.PassVar;
import org.apache.doris.analysis.PasswordOptions;
import org.apache.doris.analysis.SetType;
import org.apache.doris.analysis.StorageBackend;
import org.apache.doris.analysis.TableName;
import org.apache.doris.analysis.TableScanParams;
import org.apache.doris.analysis.TableSnapshot;
import org.apache.doris.analysis.TableValuedFunctionRef;
import org.apache.doris.analysis.UserDesc;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.AggregateType;
import org.apache.doris.catalog.BuiltinAggregateFunctions;
Expand Down Expand Up @@ -524,6 +526,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.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;
Expand Down Expand Up @@ -677,6 +680,7 @@
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;
Expand Down Expand Up @@ -6002,5 +6006,84 @@ public LogicalPlan visitDescribeTableValuedFunction(DorisParser.DescribeTableVal
}
return new DescribeCommand(tableValuedFunctionRef);
}

@Override
public UserDesc visitGrantUserIdentify(DorisParser.GrantUserIdentifyContext ctx) {
UserIdentity userIdentity = (UserIdentity) visit(ctx.userIdentify());
if (ctx.IDENTIFIED() == null) {
return new UserDesc(userIdentity);
}
String password = stripQuotes(ctx.STRING_LITERAL().getText());
boolean isPlain = ctx.PASSWORD() == null;
return new UserDesc(userIdentity, new PassVar(password, isPlain));
}

@Override
public PasswordOptions visitPasswordOption(DorisParser.PasswordOptionContext ctx) {
long expirePolicySecond = -2;
int historyPolicy = -2;
int reusePolicy = -2;
int loginAttempts = -2;
long passwordLockSecond = -2;
int accountUnlocked = -2;

if (ctx.expireDefault != null) {
expirePolicySecond = -1;
} else if (ctx.expireNever != null) {
expirePolicySecond = 0;
} else if (ctx.expireValue != null) {
long value = Long.parseLong(ctx.expireValue.getText());
expirePolicySecond = ParserUtils.convertSecond(value, ctx.expireTimeUnit.getText());
}

if (ctx.historyDefault != null) {
historyPolicy = -1;
} else if (ctx.historyValue != null) {
historyPolicy = Integer.parseInt(ctx.historyValue.getText());
}

if (ctx.reuseValue != null) {
reusePolicy = Integer.parseInt(ctx.reuseValue.getText());
}

if (ctx.attemptsValue != null) {
loginAttempts = Integer.parseInt(ctx.attemptsValue.getText());
}

if (ctx.lockUnbounded != null) {
passwordLockSecond = -1;
} else if (ctx.lockValue != null) {
long value = Long.parseLong(ctx.lockValue.getText());
passwordLockSecond = ParserUtils.convertSecond(value, ctx.lockTimeUint.getText());
}

if (ctx.ACCOUNT_LOCK() != null) {
accountUnlocked = -1;
} else if (ctx.ACCOUNT_UNLOCK() != null) {
accountUnlocked = 1;
}

if (expirePolicySecond == -2 && historyPolicy == -2 && reusePolicy == -2
&& loginAttempts == -2 && passwordLockSecond == -2 && accountUnlocked == -2) {
return PasswordOptions.UNSET_OPTION;
}

return new PasswordOptions(expirePolicySecond,
historyPolicy,
reusePolicy,
loginAttempts,
passwordLockSecond,
accountUnlocked);
}

@Override
public LogicalPlan visitAlterUser(DorisParser.AlterUserContext ctx) {
boolean ifExist = ctx.EXISTS() != null;
UserDesc userDesc = (UserDesc) visit(ctx.grantUserIdentify());
PasswordOptions passwordOptions = (PasswordOptions) visit(ctx.passwordOption());
String comment = ctx.STRING_LITERAL().getText();
AlterUserInfo alterUserInfo = new AlterUserInfo(ifExist, userDesc, passwordOptions, comment);
return new AlterUserCommand(alterUserInfo);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,18 @@ public static String command(ParserRuleContext ctx) {
public static Origin position(Token token) {
return new Origin(token.getLine(), token.getCharPositionInLine());
}

/**
* convertSecond
*/
public static long convertSecond(long value, String s) {
switch (s) {
case "DAY":
return value * 24 * 60 * 60;
case "HOUR":
return value * 60 * 60;
default:
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,5 +293,6 @@ public enum PlanType {
ANALYZE_DATABASE,
ANALYZE_TABLE,
ALTER_SYSTEM,
ALTER_SYSTEM_RENAME_COMPUTE_GROUP
ALTER_SYSTEM_RENAME_COMPUTE_GROUP,
ALTER_USER_COMMAND
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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.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 {
alterUserInfo.validate();
Env.getCurrentEnv().getAuth().alterUser(alterUserInfo);
}

@Override
public StmtType stmtType() {
return StmtType.ALTER;
}
}
Loading

0 comments on commit 2899bb7

Please sign in to comment.