morningman commented on a change in pull request #6192:
URL: https://github.com/apache/incubator-doris/pull/6192#discussion_r666983002



##########
File path: fe/fe-core/src/main/cup/sql_parser.cup
##########
@@ -692,6 +693,14 @@ stmt ::=
     {: RESULT = stmt; :}
     | uninstall_plugin_stmt : stmt
     {: RESULT = stmt; :}
+    | create_sql_block_rule_stmt : stmt
+    {: RESULT = stmt; :}
+    | alter_sql_block_rule_stmt : stmt
+    {: RESULT = stmt; :}
+    | drop_sql_block_rule_stmt : stmt
+    {: RESULT = stmt; :}
+    | show_sql_block_rule_stmt : stmt
+    {: RESULT = stmt; :}

Review comment:
       I think you can put these 4 stmts to `create_stmt`, `drop_stmt`, 
`alter_stmt` and `show_stmt`.

##########
File path: fe/fe-core/src/main/java/org/apache/doris/block/SqlBlockRule.java
##########
@@ -0,0 +1,111 @@
+// 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.block;
+
+import org.apache.doris.analysis.AlterSqlBlockRuleStmt;
+import org.apache.doris.analysis.CreateSqlBlockRuleStmt;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+
+import com.google.common.collect.Lists;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.List;
+
+public class SqlBlockRule implements Writable {
+
+    public static final String NAME_TYPE = "SQL BLOCK RULE NAME";
+
+    public static final String DEFAULT_USER = "default";
+
+    // the rule name, cluster unique
+    private String name;
+
+    // default stands for all users
+    private String user;
+
+    private String sql;
+
+    // whether to use the rule
+    private Boolean enable;
+
+    public SqlBlockRule(String name) {
+        this.name = name;
+    }
+
+    public SqlBlockRule(String name, String user, String sql,  Boolean enable) 
{
+        this.name = name;
+        this.user = user;
+        this.sql = sql;
+        this.enable = enable;
+    }
+
+    public static SqlBlockRule fromCreateStmt(CreateSqlBlockRuleStmt stmt) {
+        return new SqlBlockRule(stmt.getRuleName(), stmt.getUser(), 
stmt.getSql(), stmt.isEnable());
+    }
+
+    public static SqlBlockRule fromAlterStmt(AlterSqlBlockRuleStmt stmt) {
+        return new SqlBlockRule(stmt.getRuleName(), stmt.getUser(), 
stmt.getSql(), stmt.getEnable());
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public String getSql() {
+        return sql;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public void setSql(String sql) {
+        this.sql = sql;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public List<String> getShowInfo() {
+        return Lists.newArrayList(this.name, this.user, this.sql, 
String.valueOf(this.enable));
+    }
+
+    @Override
+    public void write(DataOutput out) throws IOException {
+        Text.writeString(out, name);

Review comment:
       Use GSON to serialize

##########
File path: 
fe/fe-core/src/main/java/org/apache/doris/analysis/AlterSqlBlockRuleStmt.java
##########
@@ -0,0 +1,84 @@
+// 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.analysis;
+
+import org.apache.doris.block.SqlBlockRule;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.UserException;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class AlterSqlBlockRuleStmt extends DdlStmt {
+
+    private final String ruleName;
+
+    private String user;
+
+    private String sql;
+
+    private Boolean enable;
+
+    private final Map<String, String> properties;
+
+    public AlterSqlBlockRuleStmt(String ruleName, Map<String, String> 
properties) {
+        this.ruleName = ruleName;
+        this.properties = properties;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+        super.analyze(analyzer);
+        // check properties
+        checkProperties(properties);
+    }
+
+    private void checkProperties(Map<String, String> properties) throws 
UserException {
+        this.user = properties.get(CreateSqlBlockRuleStmt.USER_PROPERTY);
+        // if not default, need check whether user exist
+        if (StringUtils.isNotEmpty(user) &&  
!SqlBlockRule.DEFAULT_USER.equals(user)) {
+            List<String> allUserIdents = 
Catalog.getCurrentCatalog().getAuth().getAllUserIdents(false).stream().map(UserIdentity::getUser).collect(Collectors.toList());
+            if (!allUserIdents.contains(user)) {
+                throw new AnalysisException(user + " is not exist");

Review comment:
       ```suggestion
                   throw new AnalysisException(user + " does not exist");
   ```

##########
File path: 
fe/fe-core/src/main/java/org/apache/doris/analysis/CreateSqlBlockRuleStmt.java
##########
@@ -0,0 +1,122 @@
+// 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.analysis;
+
+import org.apache.doris.block.SqlBlockRule;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.FeNameFormat;
+import org.apache.doris.common.UserException;
+import org.apache.doris.common.util.Util;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/*
+ Create sqlBlockRule statement
+
+ syntax:
+      CREATE SQL_BLOCK_RULE LOAD NAME PROPERTIES

Review comment:
       ```suggestion
         CREATE SQL_BLOCK_RULE `rule_name` PROPERTIES
   ```

##########
File path: 
fe/fe-core/src/main/java/org/apache/doris/analysis/AlterSqlBlockRuleStmt.java
##########
@@ -0,0 +1,84 @@
+// 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.analysis;
+
+import org.apache.doris.block.SqlBlockRule;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.UserException;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class AlterSqlBlockRuleStmt extends DdlStmt {
+
+    private final String ruleName;
+
+    private String user;
+
+    private String sql;
+
+    private Boolean enable;
+
+    private final Map<String, String> properties;
+
+    public AlterSqlBlockRuleStmt(String ruleName, Map<String, String> 
properties) {
+        this.ruleName = ruleName;
+        this.properties = properties;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+        super.analyze(analyzer);
+        // check properties
+        checkProperties(properties);
+    }
+
+    private void checkProperties(Map<String, String> properties) throws 
UserException {
+        this.user = properties.get(CreateSqlBlockRuleStmt.USER_PROPERTY);
+        // if not default, need check whether user exist
+        if (StringUtils.isNotEmpty(user) &&  
!SqlBlockRule.DEFAULT_USER.equals(user)) {
+            List<String> allUserIdents = 
Catalog.getCurrentCatalog().getAuth().getAllUserIdents(false).stream().map(UserIdentity::getUser).collect(Collectors.toList());

Review comment:
       Why not using `PaloAuth.doesUsernameExist()`?

##########
File path: fe/fe-core/src/main/java/org/apache/doris/block/SqlBlockRuleMgr.java
##########
@@ -0,0 +1,228 @@
+// 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.block;
+
+import org.apache.doris.analysis.AlterSqlBlockRuleStmt;
+import org.apache.doris.analysis.CreateSqlBlockRuleStmt;
+import org.apache.doris.analysis.DropSqlBlockRuleStmt;
+import org.apache.doris.analysis.ShowSqlBlockRuleStmt;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.DdlException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.UserException;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class SqlBlockRuleMgr implements Writable {
+    private static final Logger LOG = 
LogManager.getLogger(SqlBlockRuleMgr.class);
+
+    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+
+    private Map<String, List<SqlBlockRule>> userToSqlBlockRuleMap = 
Maps.newConcurrentMap();
+
+    private Map<String, SqlBlockRule> nameToSqlBlockRuleMap = 
Maps.newConcurrentMap();
+
+    private void writeLock() {
+        lock.writeLock().lock();
+    }
+
+    private void writeUnlock() {
+        lock.writeLock().unlock();
+    }
+
+    public boolean existRule(String name) {
+        return nameToSqlBlockRuleMap.containsKey(name);
+    }
+
+    public List<SqlBlockRule> get(ShowSqlBlockRuleStmt stmt) throws 
AnalysisException {
+        String ruleName = stmt.getRuleName();
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN");
+        }
+        if (StringUtils.isNotEmpty(ruleName)) {
+            if (nameToSqlBlockRuleMap.containsKey(ruleName)) {
+                SqlBlockRule sqlBlockRule = 
nameToSqlBlockRuleMap.get(ruleName);
+                return Lists.newArrayList(sqlBlockRule);
+            }
+            return Lists.newArrayList();
+        }
+        return Lists.newArrayList(nameToSqlBlockRuleMap.values());
+    }
+
+    public void createSqlBlockRule(CreateSqlBlockRuleStmt stmt) throws 
UserException {
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)
+                && 
!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
+                PrivPredicate.OPERATOR)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN/OPERATOR");
+        }
+        SqlBlockRule sqlBlockRule = SqlBlockRule.fromCreateStmt(stmt);
+        create(sqlBlockRule);
+    }
+
+    private void create(SqlBlockRule sqlBlockRule) throws DdlException {
+        writeLock();
+        try {
+            String ruleName = sqlBlockRule.getName();
+            if (existRule(ruleName)) {
+                throw new DdlException("the sql block rule " + ruleName + " 
already create");
+            }
+            
Catalog.getCurrentCatalog().getEditLog().logCreateSqlBlockRule(sqlBlockRule);

Review comment:
       call `unprotectedAdd(sqlBlockRule);` before calling 
`logCreateSqlBlockRule()`.
   And same as other 3 rule operations.

##########
File path: 
fe/fe-core/src/main/java/org/apache/doris/analysis/AlterSqlBlockRuleStmt.java
##########
@@ -0,0 +1,84 @@
+// 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.analysis;
+
+import org.apache.doris.block.SqlBlockRule;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.UserException;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class AlterSqlBlockRuleStmt extends DdlStmt {
+
+    private final String ruleName;
+
+    private String user;
+
+    private String sql;
+
+    private Boolean enable;
+
+    private final Map<String, String> properties;
+
+    public AlterSqlBlockRuleStmt(String ruleName, Map<String, String> 
properties) {
+        this.ruleName = ruleName;
+        this.properties = properties;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+        super.analyze(analyzer);
+        // check properties
+        checkProperties(properties);
+    }
+
+    private void checkProperties(Map<String, String> properties) throws 
UserException {
+        this.user = properties.get(CreateSqlBlockRuleStmt.USER_PROPERTY);
+        // if not default, need check whether user exist
+        if (StringUtils.isNotEmpty(user) &&  
!SqlBlockRule.DEFAULT_USER.equals(user)) {
+            List<String> allUserIdents = 
Catalog.getCurrentCatalog().getAuth().getAllUserIdents(false).stream().map(UserIdentity::getUser).collect(Collectors.toList());
+            if (!allUserIdents.contains(user)) {
+                throw new AnalysisException(user + " is not exist");
+            }
+        }
+        this.sql = properties.get(CreateSqlBlockRuleStmt.SQL_PROPERTY);

Review comment:
       The `CreateSqlBlockRuleStmt.SQL_PROPERTY` property may not be set? 
Should check it

##########
File path: 
fe/fe-core/src/main/java/org/apache/doris/analysis/AlterSqlBlockRuleStmt.java
##########
@@ -0,0 +1,84 @@
+// 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.analysis;
+
+import org.apache.doris.block.SqlBlockRule;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.UserException;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class AlterSqlBlockRuleStmt extends DdlStmt {
+
+    private final String ruleName;
+
+    private String user;
+
+    private String sql;
+
+    private Boolean enable;
+
+    private final Map<String, String> properties;
+
+    public AlterSqlBlockRuleStmt(String ruleName, Map<String, String> 
properties) {
+        this.ruleName = ruleName;
+        this.properties = properties;
+    }
+
+    @Override
+    public void analyze(Analyzer analyzer) throws UserException {
+        super.analyze(analyzer);
+        // check properties
+        checkProperties(properties);

Review comment:
       privilege check is always in `analyze` phase. 
   And I think only check `admin` priv is enough
   
   

##########
File path: fe/fe-core/src/main/java/org/apache/doris/block/SqlBlockRuleMgr.java
##########
@@ -0,0 +1,228 @@
+// 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.block;
+
+import org.apache.doris.analysis.AlterSqlBlockRuleStmt;
+import org.apache.doris.analysis.CreateSqlBlockRuleStmt;
+import org.apache.doris.analysis.DropSqlBlockRuleStmt;
+import org.apache.doris.analysis.ShowSqlBlockRuleStmt;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.DdlException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
+import org.apache.doris.common.UserException;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+import org.apache.doris.qe.ConnectContext;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class SqlBlockRuleMgr implements Writable {
+    private static final Logger LOG = 
LogManager.getLogger(SqlBlockRuleMgr.class);
+
+    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+
+    private Map<String, List<SqlBlockRule>> userToSqlBlockRuleMap = 
Maps.newConcurrentMap();
+
+    private Map<String, SqlBlockRule> nameToSqlBlockRuleMap = 
Maps.newConcurrentMap();
+
+    private void writeLock() {
+        lock.writeLock().lock();
+    }
+
+    private void writeUnlock() {
+        lock.writeLock().unlock();
+    }
+
+    public boolean existRule(String name) {
+        return nameToSqlBlockRuleMap.containsKey(name);
+    }
+
+    public List<SqlBlockRule> get(ShowSqlBlockRuleStmt stmt) throws 
AnalysisException {
+        String ruleName = stmt.getRuleName();
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN");
+        }
+        if (StringUtils.isNotEmpty(ruleName)) {
+            if (nameToSqlBlockRuleMap.containsKey(ruleName)) {
+                SqlBlockRule sqlBlockRule = 
nameToSqlBlockRuleMap.get(ruleName);
+                return Lists.newArrayList(sqlBlockRule);
+            }
+            return Lists.newArrayList();
+        }
+        return Lists.newArrayList(nameToSqlBlockRuleMap.values());
+    }
+
+    public void createSqlBlockRule(CreateSqlBlockRuleStmt stmt) throws 
UserException {
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)
+                && 
!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
+                PrivPredicate.OPERATOR)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN/OPERATOR");
+        }
+        SqlBlockRule sqlBlockRule = SqlBlockRule.fromCreateStmt(stmt);
+        create(sqlBlockRule);
+    }
+
+    private void create(SqlBlockRule sqlBlockRule) throws DdlException {
+        writeLock();
+        try {
+            String ruleName = sqlBlockRule.getName();
+            if (existRule(ruleName)) {
+                throw new DdlException("the sql block rule " + ruleName + " 
already create");
+            }
+            
Catalog.getCurrentCatalog().getEditLog().logCreateSqlBlockRule(sqlBlockRule);
+            unprotectedAdd(sqlBlockRule);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    public void replayCreate(SqlBlockRule sqlBlockRule) {
+        unprotectedAdd(sqlBlockRule);
+        LOG.info("replay create sql block rule: {}", sqlBlockRule);
+    }
+
+    public void alterSqlBlockRule(AlterSqlBlockRuleStmt stmt) throws 
UserException {
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)
+                && 
!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
+                PrivPredicate.OPERATOR)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN/OPERATOR");
+        }
+        SqlBlockRule sqlBlockRule = SqlBlockRule.fromAlterStmt(stmt);
+        alter(sqlBlockRule);
+    }
+
+    private void alter(SqlBlockRule sqlBlockRule) throws DdlException {
+        writeLock();
+        try {
+            String ruleName = sqlBlockRule.getName();
+            if (!existRule(ruleName)) {
+                throw new DdlException("the sql block rule " + ruleName + " 
not exist");
+            }
+            SqlBlockRule originRule = nameToSqlBlockRuleMap.get(ruleName);
+            if (StringUtils.isEmpty(sqlBlockRule.getUser())) {
+                sqlBlockRule.setUser(originRule.getUser());
+            }
+            if (StringUtils.isEmpty(sqlBlockRule.getSql())) {
+                sqlBlockRule.setSql(originRule.getSql());
+            }
+            if (sqlBlockRule.getEnable() == null) {
+                sqlBlockRule.setEnable(originRule.getEnable());
+            }
+            
Catalog.getCurrentCatalog().getEditLog().logAlterSqlBlockRule(sqlBlockRule);
+            unprotectedUpdate(sqlBlockRule);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    public void replayAlter(SqlBlockRule sqlBlockRule) {
+        unprotectedUpdate(sqlBlockRule);
+        LOG.info("replay alter sql block rule: {}", sqlBlockRule);
+    }
+
+    public void unprotectedUpdate(SqlBlockRule sqlBlockRule) {
+        nameToSqlBlockRuleMap.put(sqlBlockRule.getName(), sqlBlockRule);
+        List<SqlBlockRule> sqlBlockRules = 
userToSqlBlockRuleMap.getOrDefault(sqlBlockRule.getUser(), new ArrayList<>());
+        sqlBlockRules.removeIf(rule -> 
sqlBlockRule.getName().equals(rule.getName()));
+        sqlBlockRules.add(sqlBlockRule);
+        userToSqlBlockRuleMap.put(sqlBlockRule.getUser(), sqlBlockRules);
+    }
+
+    public void unprotectedAdd(SqlBlockRule sqlBlockRule) {
+        nameToSqlBlockRuleMap.put(sqlBlockRule.getName(), sqlBlockRule);
+        List<SqlBlockRule> sqlBlockRules = 
userToSqlBlockRuleMap.getOrDefault(sqlBlockRule.getUser(), new ArrayList<>());
+        sqlBlockRules.add(sqlBlockRule);
+        userToSqlBlockRuleMap.put(sqlBlockRule.getUser(), sqlBlockRules);
+    }
+
+    public void dropSqlBlockRule(DropSqlBlockRuleStmt stmt) throws 
UserException {
+        if 
(!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(), 
PrivPredicate.ADMIN)
+                && 
!Catalog.getCurrentCatalog().getAuth().checkGlobalPriv(ConnectContext.get(),
+                PrivPredicate.OPERATOR)) {
+            
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, 
"ADMIN/OPERATOR");
+        }
+        List<String> ruleNames = stmt.getRuleNames();
+        drop(ruleNames);
+    }
+
+    public void drop(List<String> ruleNames) throws DdlException {
+        writeLock();
+        try {
+            for (String ruleName : ruleNames) {
+                if (!existRule(ruleName)) {
+                    throw new DdlException("the sql block rule " + ruleName + 
" not exist");
+                }
+                SqlBlockRule sqlBlockRule = 
nameToSqlBlockRuleMap.get(ruleName);
+                if (sqlBlockRule == null) {
+                    continue;
+                }
+                
Catalog.getCurrentCatalog().getEditLog().logDropSqlBlockRule(sqlBlockRule);
+                unprotectedDrop(sqlBlockRule);
+            }
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    public void replayDrop(SqlBlockRule sqlBlockRule) {
+        unprotectedDrop(sqlBlockRule);
+        LOG.info("replay drop sql block rule: {}", sqlBlockRule);
+    }
+
+    public void unprotectedDrop(SqlBlockRule sqlBlockRule) {
+        nameToSqlBlockRuleMap.remove(sqlBlockRule.getName());
+        List<SqlBlockRule> sqlBlockRules = 
userToSqlBlockRuleMap.get(sqlBlockRule.getUser());
+        sqlBlockRules.removeIf(rule -> 
sqlBlockRule.getName().equals(rule.getName()));
+        userToSqlBlockRuleMap.put(sqlBlockRule.getUser(), sqlBlockRules);
+    }
+
+    public Map<String, List<SqlBlockRule>> getUserToSqlBlockRuleMap() {
+        return userToSqlBlockRuleMap;
+    }
+
+    @Override
+    public void write(DataOutput out) throws IOException {

Review comment:
       Use GSON serde.

##########
File path: fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
##########
@@ -298,6 +299,9 @@ public Long getValue() {
                 "total error rows of routine load");
         PALO_METRIC_REGISTER.addPaloMetrics(COUNTER_ROUTINE_LOAD_ERROR_ROWS);
 
+        COUNTER_HIT_SQL_BLOCK_RULE = new 
LongCounterMetric("counter_hit_sql_blacklist", MetricUnit.ROWS,

Review comment:
       ```suggestion
           COUNTER_HIT_SQL_BLOCK_RULE = new 
LongCounterMetric("counter_hit_sql_block_rule", MetricUnit.ROWS,
   ```

##########
File path: fe/fe-core/src/main/java/org/apache/doris/block/SqlBlockRule.java
##########
@@ -0,0 +1,111 @@
+// 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.block;

Review comment:
       The pacakge name can be `org.apache.doris.sqlblock`?

##########
File path: fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
##########
@@ -298,6 +299,9 @@ public Long getValue() {
                 "total error rows of routine load");
         PALO_METRIC_REGISTER.addPaloMetrics(COUNTER_ROUTINE_LOAD_ERROR_ROWS);
 
+        COUNTER_HIT_SQL_BLOCK_RULE = new 
LongCounterMetric("counter_hit_sql_blacklist", MetricUnit.ROWS,
+                "total hit sql blacklist query");

Review comment:
       ```suggestion
                   "total hit sql block rule query");
   ```

##########
File path: fe/fe-core/src/main/java/org/apache/doris/catalog/Catalog.java
##########
@@ -4894,6 +4912,10 @@ public RoutineLoadManager getRoutineLoadManager() {
         return routineLoadManager;
     }
 
+    public SqlBlockRuleMgr getSqlBlocklistMgr() {

Review comment:
       ```suggestion
       public SqlBlockRuleMgr getSqlBlockRuleMgr() {
   ```

##########
File path: fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java
##########
@@ -731,5 +733,18 @@ public void testUseFail(@Mocked UseStmt useStmt, @Mocked 
SqlParser parser) throw
 
         Assert.assertEquals(QueryState.MysqlStateType.ERR, 
state.getStateType());
     }
+
+    @Test(expected = AnalysisException.class)

Review comment:
       The unit test is too few...
   where is the create/alter/drop/show sql block rule unit test?

##########
File path: fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
##########
@@ -1169,5 +1178,33 @@ private void handleExportStmt() throws Exception {
     private List<PrimitiveType> exprToType(List<Expr> exprs) {
         return exprs.stream().map(e -> 
e.getType().getPrimitiveType()).collect(Collectors.toList());
     }
+
+    private void matchSql(QueryStmt queryStmt) throws AnalysisException {
+        Map<String, List<SqlBlockRule>> userToSqlBlockRuleMap = 
Catalog.getCurrentCatalog().getSqlBlocklistMgr().getUserToSqlBlockRuleMap();
+        // match default rule
+        String sql = queryStmt.getOrigStmt().originStmt;
+        List<SqlBlockRule> defaultRules = 
userToSqlBlockRuleMap.getOrDefault(SqlBlockRule.DEFAULT_USER, new 
ArrayList<>());
+        for (SqlBlockRule rule : defaultRules) {
+            matchSql(rule, sql);
+        }
+        // match user rule
+        String user = context.getUserIdentity().getUser();
+        List<SqlBlockRule> userRules = 
userToSqlBlockRuleMap.getOrDefault(user, new ArrayList<>());
+        for (SqlBlockRule rule : userRules) {
+            matchSql(rule, sql);
+        }
+    }
+
+    @VisibleForTesting
+    public static void matchSql(SqlBlockRule rule, String sql) throws 
AnalysisException {
+        if (rule.getEnable() != null && rule.getEnable()) {
+            String sqlPattern = rule.getSql();
+            Pattern pattern = Pattern.compile(sqlPattern);

Review comment:
       the pattern compilation should be done when the rule is created, so that 
we don't need to compile it every time.
   You should be aware that this rule checking logic is on the critical path of 
query, so performance is top level consideration.

##########
File path: fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
##########
@@ -1169,5 +1178,33 @@ private void handleExportStmt() throws Exception {
     private List<PrimitiveType> exprToType(List<Expr> exprs) {
         return exprs.stream().map(e -> 
e.getType().getPrimitiveType()).collect(Collectors.toList());
     }
+
+    private void matchSql(QueryStmt queryStmt) throws AnalysisException {
+        Map<String, List<SqlBlockRule>> userToSqlBlockRuleMap = 
Catalog.getCurrentCatalog().getSqlBlocklistMgr().getUserToSqlBlockRuleMap();

Review comment:
       If you get `userToSqlBlockRuleMap` out of the `SqlBlocklistMgr`, then no 
lock can protect it.
   So all check should be done inside the `SqlBlocklistMgr`

##########
File path: fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java
##########
@@ -804,6 +805,21 @@ public static void loadJournal(Catalog catalog, 
JournalEntity journal) {
                     catalog.getAlterInstance().replayReplaceTable(log);
                     break;
                 }
+                case OperationType.OP_CREATE_SQL_BLOCK_RULE: {

Review comment:
       I think you missed the `readFields()` method of `JournalEntity.java`




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to