You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by GitBox <gi...@apache.org> on 2022/05/07 09:40:18 UTC

[GitHub] [incubator-doris] morningman commented on a diff in pull request #9206: [feature]: support row policy filter

morningman commented on code in PR #9206:
URL: https://github.com/apache/incubator-doris/pull/9206#discussion_r867326814


##########
docs/zh-CN/sql-manual/sql-reference/Data-Definition-Statements/Create/CREATE-POLICY.md:
##########
@@ -0,0 +1,84 @@
+---
+{
+    "title": "CREATE-POLICY",
+    "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+## CREATE-POLICY
+
+### Name
+
+CREATE POLICY
+
+### Description
+
+创建安全策略,explain 可以查看改写后的 SQL。
+
+#### 行安全策略
+语法:
+
+```sql
+CREATE ROW POLICY test_row_policy_1 ON test.table1 
+AS {RESTRICTIVE|PERMISSIVE} TO root USING (id in (1, 2));
+```
+
+参数说明:
+
+- filterType:RESTRICTIVE 将一组策略通过 AND 连接, PERMISSIVE 将一组策略通过 OR 连接
+- 配置多个策略首先合并 RESTRICTIVE 的策略,再添加 PERMISSIVE 的策略

Review Comment:
   添加一个说明:RESTRICTIVE 和 PERMISSIVE 之间是通过and连接的



##########
docs/zh-CN/sql-manual/sql-reference/Data-Definition-Statements/Create/CREATE-POLICY.md:
##########
@@ -0,0 +1,84 @@
+---
+{
+    "title": "CREATE-POLICY",
+    "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+## CREATE-POLICY
+
+### Name
+
+CREATE POLICY
+
+### Description
+
+创建安全策略,explain 可以查看改写后的 SQL。
+
+#### 行安全策略
+语法:
+
+```sql
+CREATE ROW POLICY test_row_policy_1 ON test.table1 
+AS {RESTRICTIVE|PERMISSIVE} TO root USING (id in (1, 2));
+```
+
+参数说明:
+
+- filterType:RESTRICTIVE 将一组策略通过 AND 连接, PERMISSIVE 将一组策略通过 OR 连接
+- 配置多个策略首先合并 RESTRICTIVE 的策略,再添加 PERMISSIVE 的策略
+
+### Example
+
+1. 创建一组行安全策略
+
+   ```sql
+   CREATE ROW POLICY test_row_policy_1 ON test.table1 
+   AS RESTRICTIVE TO root USING (c1 = 'a');
+   ```
+   ```sql
+   CREATE ROW POLICY test_row_policy_2 ON test.table1 
+   AS RESTRICTIVE TO root USING (c2 = 'b');
+   ```
+   ```sql
+   CREATE ROW POLICY test_row_policy_3 ON test.table1 
+   AS PERMISSIVE TO root USING (c3 = 'c');
+   ```
+   ```sql
+   CREATE ROW POLICY test_row_policy_3 ON test.table1 

Review Comment:
   I think we should not allow to create policy for `root` and `admin` user



##########
docs/zh-CN/sql-manual/sql-reference/Data-Definition-Statements/Create/CREATE-POLICY.md:
##########
@@ -0,0 +1,84 @@
+---
+{
+    "title": "CREATE-POLICY",
+    "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+## CREATE-POLICY
+
+### Name
+
+CREATE POLICY
+
+### Description
+
+创建安全策略,explain 可以查看改写后的 SQL。
+
+#### 行安全策略
+语法:
+
+```sql
+CREATE ROW POLICY test_row_policy_1 ON test.table1 
+AS {RESTRICTIVE|PERMISSIVE} TO root USING (id in (1, 2));
+```
+
+参数说明:
+
+- filterType:RESTRICTIVE 将一组策略通过 AND 连接, PERMISSIVE 将一组策略通过 OR 连接
+- 配置多个策略首先合并 RESTRICTIVE 的策略,再添加 PERMISSIVE 的策略
+
+### Example
+
+1. 创建一组行安全策略
+
+   ```sql
+   CREATE ROW POLICY test_row_policy_1 ON test.table1 
+   AS RESTRICTIVE TO root USING (c1 = 'a');
+   ```
+   ```sql
+   CREATE ROW POLICY test_row_policy_2 ON test.table1 
+   AS RESTRICTIVE TO root USING (c2 = 'b');
+   ```
+   ```sql
+   CREATE ROW POLICY test_row_policy_3 ON test.table1 
+   AS PERMISSIVE TO root USING (c3 = 'c');
+   ```
+   ```sql
+   CREATE ROW POLICY test_row_policy_3 ON test.table1 
+   AS PERMISSIVE TO root USING (c4 = 'd');
+   ```
+
+   当我们执行对 table1 的查询时被改写后的 sql 为
+
+   ```sql
+   select * from (select * from table1 where c1 = 'a' and c2 = 'b' or c3 = 'c' or c4 = 'd')
+   ```
+
+### Keywords
+
+```text

Review Comment:
   remove ```text



##########
fe/fe-core/src/main/java/org/apache/doris/analysis/StmtRewriter.java:
##########
@@ -1141,5 +1147,49 @@ private static Expr createJoinConjunct(Expr exprWithSubquery, InlineViewRef inli
         smap.put(subquery, subquerySubstitute);
         return exprWithSubquery.substitute(smap, analyzer, false);
     }
+    
+    public static void rewriteByPolicy(StatementBase statementBase, Analyzer analyzer) throws UserException {
+        Catalog currentCatalog = Catalog.getCurrentCatalog();
+        if (!(statementBase instanceof SelectStmt)) {
+            return;
+        }
+        SelectStmt selectStmt = (SelectStmt) statementBase;
+        for (int i = 0; i < selectStmt.fromClause_.size(); i++) {
+            TableRef tableRef = selectStmt.fromClause_.get(i);
+            if (tableRef instanceof InlineViewRef) {
+                InlineViewRef viewRef = (InlineViewRef) tableRef;
+                rewriteByPolicy(viewRef.getQueryStmt(), analyzer);
+            }
+            // has been rewrite
+            if (tableRef instanceof InlineViewRef) {
+                continue;

Review Comment:
   Why not move this `continue` to to above `if (tableRef instanceof InlineViewRef) {`?



##########
fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java:
##########
@@ -0,0 +1,285 @@
+// 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.policy;
+
+import org.apache.doris.analysis.CompoundPredicate;
+import org.apache.doris.analysis.CreatePolicyStmt;
+import org.apache.doris.analysis.DropPolicyStmt;
+import org.apache.doris.analysis.ShowPolicyStmt;
+import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.DdlException;
+import org.apache.doris.common.UserException;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.ShowResultSet;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.commons.lang.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.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+public class PolicyMgr implements Writable {
+    private static final Logger LOG = LogManager.getLogger(PolicyMgr.class);
+
+    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+
+    @SerializedName(value = "dbIdToPolicyMap")
+    private Map<Long, List<Policy>> dbIdToPolicyMap = Maps.newConcurrentMap();
+
+    /**
+     * cache merge policy for match
+     * key:dbId:tableId-type-user
+     **/
+    private Map<Long, Map<String, Policy>> dbIdToMergePolicyMap = Maps.newConcurrentMap();
+
+    private void writeLock() {
+        lock.writeLock().lock();
+    }
+
+    private void writeUnlock() {
+        lock.writeLock().unlock();
+    }
+
+    private void readLock() {
+        lock.readLock().lock();
+    }
+
+    private void readUnlock() {
+        lock.readLock().unlock();
+    }
+
+    public void createPolicy(CreatePolicyStmt stmt) throws UserException {
+        writeLock();
+        try {
+            Policy policy = Policy.fromCreateStmt(stmt);
+            if (existPolicy(policy.getDbId(), policy.getTableId(), policy.getType(), policy.getPolicyName(), policy.getUser())) {
+                if (stmt.isIfNotExists()) {
+                    return;
+                }
+                throw new DdlException("the policy " + policy.getPolicyName() + " already create");
+            }
+            unprotectedAdd(policy);
+            Catalog.getCurrentCatalog().getEditLog().logCreatePolicy(policy);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    public void dropPolicy(DropPolicyStmt stmt) throws DdlException {
+        writeLock();
+        try {
+            DropPolicyLog policy = DropPolicyLog.fromDropStmt(stmt);

Review Comment:
   Move this outside the lock



##########
fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java:
##########
@@ -0,0 +1,285 @@
+// 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.policy;
+
+import org.apache.doris.analysis.CompoundPredicate;
+import org.apache.doris.analysis.CreatePolicyStmt;
+import org.apache.doris.analysis.DropPolicyStmt;
+import org.apache.doris.analysis.ShowPolicyStmt;
+import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.DdlException;
+import org.apache.doris.common.UserException;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.ShowResultSet;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.commons.lang.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.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+public class PolicyMgr implements Writable {
+    private static final Logger LOG = LogManager.getLogger(PolicyMgr.class);
+
+    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+
+    @SerializedName(value = "dbIdToPolicyMap")
+    private Map<Long, List<Policy>> dbIdToPolicyMap = Maps.newConcurrentMap();
+
+    /**
+     * cache merge policy for match
+     * key:dbId:tableId-type-user
+     **/
+    private Map<Long, Map<String, Policy>> dbIdToMergePolicyMap = Maps.newConcurrentMap();
+
+    private void writeLock() {
+        lock.writeLock().lock();
+    }
+
+    private void writeUnlock() {
+        lock.writeLock().unlock();
+    }
+
+    private void readLock() {
+        lock.readLock().lock();
+    }
+
+    private void readUnlock() {
+        lock.readLock().unlock();
+    }
+
+    public void createPolicy(CreatePolicyStmt stmt) throws UserException {
+        writeLock();
+        try {
+            Policy policy = Policy.fromCreateStmt(stmt);
+            if (existPolicy(policy.getDbId(), policy.getTableId(), policy.getType(), policy.getPolicyName(), policy.getUser())) {
+                if (stmt.isIfNotExists()) {
+                    return;
+                }
+                throw new DdlException("the policy " + policy.getPolicyName() + " already create");
+            }
+            unprotectedAdd(policy);
+            Catalog.getCurrentCatalog().getEditLog().logCreatePolicy(policy);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    public void dropPolicy(DropPolicyStmt stmt) throws DdlException {
+        writeLock();
+        try {
+            DropPolicyLog policy = DropPolicyLog.fromDropStmt(stmt);
+            if (!existPolicy(policy.getDbId(), policy.getTableId(), policy.getType(), policy.getPolicyName(), policy.getUser())) {
+                if (stmt.isIfExists()) {
+                    return;
+                }
+                throw new DdlException("the policy " + policy.getPolicyName() + " not exist");
+            }
+            unprotectedDrop(policy);
+            Catalog.getCurrentCatalog().getEditLog().logDropPolicy(policy);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    private boolean existPolicy(long dbId, long tableId, String type, String policyName, UserIdentity user) {
+        List<Policy> policies = getDbPolicies(dbId);
+        return policies.stream().anyMatch(policy -> matchPolicy(policy, tableId, type, policyName, user));
+    }
+
+    public List<Policy> getDbPolicies(long dbId) {
+        if (dbIdToPolicyMap == null) {
+            return new ArrayList<>();
+        }
+        return dbIdToPolicyMap.getOrDefault(dbId, new ArrayList<>());
+    }
+
+    public List<Policy> getDbUserPolicies(long dbId, String user) {
+        if (dbIdToPolicyMap == null) {
+            return new ArrayList<>();
+        }
+        return dbIdToPolicyMap.getOrDefault(dbId, new ArrayList<>()).stream().filter(p -> p.getUser().getQualifiedUser().equals(user)).collect(Collectors.toList());
+    }
+
+    public void replayCreate(Policy policy) {
+        unprotectedAdd(policy);
+        LOG.info("replay create policy: {}", policy);
+    }
+
+    public void unprotectedAdd(Policy policy) {
+        if (policy == null) {
+            return;
+        }
+        long dbId = policy.getDbId();
+        List<Policy> dbPolicies = getDbPolicies(dbId);
+        dbPolicies.add(policy);
+        dbIdToPolicyMap.put(dbId, dbPolicies);
+        updateMergePolicyMap(dbId);
+    }
+
+    public void replayDrop(DropPolicyLog log) {
+        unprotectedDrop(log);
+        LOG.info("replay drop policy log: {}", log);
+    }
+
+    public void unprotectedDrop(DropPolicyLog log) {
+        long dbId = log.getDbId();
+        List<Policy> policies = getDbPolicies(dbId);
+        policies.removeIf(p -> matchPolicy(p, log.getTableId(), log.getType(), log.getPolicyName(), log.getUser()));
+        dbIdToPolicyMap.put(dbId, policies);
+        updateMergePolicyMap(dbId);
+    }
+
+    private boolean matchPolicy(Policy policy, long tableId, String type, String policyName, UserIdentity user) {
+        return policy.getTableId() == tableId
+            && StringUtils.equals(policy.getType(), type)
+            && StringUtils.equals(policy.getPolicyName(), policyName)
+            && (user == null || StringUtils.equals(policy.getUser().getQualifiedUser(), user.getQualifiedUser()));
+    }
+
+    public Policy getMatchRowPolicy(long dbId, long tableId, String user) {
+        readLock();
+        try {
+            if (!dbIdToMergePolicyMap.containsKey(dbId)) {
+                return null;
+            }
+            String key = Joiner.on("-").join(tableId, Policy.ROW_POLICY, user);
+            if (!dbIdToMergePolicyMap.get(dbId).containsKey(key)) {
+                return null;
+            }
+            return dbIdToMergePolicyMap.get(dbId).get(key);
+        } finally {
+            readUnlock();
+        }
+    }
+    
+    public ShowResultSet showPolicy(ShowPolicyStmt showStmt) throws AnalysisException {
+        List<List<String>> rows = Lists.newArrayList();
+        List<Policy> policies;
+        long currentDbId = ConnectContext.get().getCurrentDbId();
+        if (showStmt.getUser() == null) {
+            policies = Catalog.getCurrentCatalog().getPolicyMgr().getDbPolicies(currentDbId);
+        } else {
+            policies = Catalog.getCurrentCatalog().getPolicyMgr().getDbUserPolicies(currentDbId, showStmt.getUser().getQualifiedUser());
+        }
+        for (Policy policy : policies) {
+            if (policy.getWherePredicate() == null) {
+                continue;
+            }
+            rows.add(policy.getShowInfo());
+        }
+        return new ShowResultSet(showStmt.getMetaData(), rows);
+    }
+
+    private void updateAllMergePolicyMap() {
+        dbIdToPolicyMap.forEach((dbId, policy) -> updateMergePolicyMap(dbId));
+    }
+
+    /**
+     * The merge policy cache needs to be regenerated after the update
+     **/
+    private void updateMergePolicyMap(long dbId) {
+        readLock();
+        try {
+            if (!dbIdToPolicyMap.containsKey(dbId)) {
+                return;
+            }
+            List<Policy> policies = dbIdToPolicyMap.get(dbId);
+            Map<String, Policy> andMap = new HashMap<>();
+            Map<String, Policy> orMap = new HashMap<>();
+            for (Policy policy : policies) {
+                if (policy.getWherePredicate() == null) {
+                    Policy.parseOriginStmt(policy);
+                }
+                // read from json, need set isAnalyzed
+                policy.getUser().setIsAnalyzed();
+                String key = Joiner.on("-").join(policy.getTableId(), policy.getType(), policy.getUser().getQualifiedUser());
+                // merge wherePredicate
+                if (CompoundPredicate.Operator.AND.equals(policy.getFilterType().getOp())) {
+                    Policy frontPolicy = andMap.get(key);
+                    if (frontPolicy == null) {
+                        andMap.put(key, policy.clone());
+                    } else {
+                        frontPolicy.setWherePredicate(new CompoundPredicate(CompoundPredicate.Operator.AND, frontPolicy.getWherePredicate(), policy.getWherePredicate()));
+                        andMap.put(key, frontPolicy.clone());
+                    }
+                } else {
+                    Policy frontPolicy = orMap.get(key);
+                    if (frontPolicy == null) {
+                        orMap.put(key, policy.clone());
+                    } else {
+                        frontPolicy.setWherePredicate(new CompoundPredicate(CompoundPredicate.Operator.OR, frontPolicy.getWherePredicate(), policy.getWherePredicate()));
+                        orMap.put(key, frontPolicy.clone());
+                    }
+                }
+            }
+            Map<String, Policy> mergeMap = new HashMap<>();
+            Set<String> policyKeys = new HashSet<>();
+            policyKeys.addAll(andMap.keySet());
+            policyKeys.addAll(orMap.keySet());
+            policyKeys.forEach(key -> {
+                if (andMap.containsKey(key) && orMap.containsKey(key)) {
+                    Policy mergePolicy = andMap.get(key).clone();
+                    mergePolicy.setWherePredicate(new CompoundPredicate(CompoundPredicate.Operator.OR, mergePolicy.getWherePredicate(), orMap.get(key).getWherePredicate()));

Review Comment:
   I think here we should use `AND`



##########
fe/fe-common/src/main/java/org/apache/doris/common/FeMetaVersion.java:
##########
@@ -36,8 +36,10 @@ public final class FeMetaVersion {
     public static final int VERSION_107 = 107;
     // add storage_cold_medium and remote_storage_resource_name in DataProperty
     public static final int VERSION_108 = 108;
+    // add policy

Review Comment:
   ```suggestion
       // add row policy
   ```



##########
fe/fe-core/src/main/cup/sql_parser.cup:
##########
@@ -2546,6 +2560,14 @@ show_stmt ::=
     {:
         RESULT = new ShowSqlBlockRuleStmt(null);
     :}
+    | KW_SHOW KW_ROW KW_POLICY KW_FOR user_identity:user
+    {:
+        RESULT = new ShowPolicyStmt("ROW", user);

Review Comment:
   Better using an Enum to replace raw string "ROW"



##########
fe/fe-core/src/main/java/org/apache/doris/analysis/UserIdentity.java:
##########
@@ -226,9 +245,7 @@ public String toString() {
     @Override
     public void write(DataOutput out) throws IOException {
         Preconditions.checkState(isAnalyzed);
-        Text.writeString(out, user);
-        Text.writeString(out, host);
-        out.writeBoolean(isDomain);
+        Text.writeString(out, GsonUtils.GSON.toJson(this));
     }
 
     public void readFields(DataInput in) throws IOException {

Review Comment:
   make this to `private`, and add `@Derepcated`



##########
fe/fe-core/src/main/java/org/apache/doris/policy/PolicyMgr.java:
##########
@@ -0,0 +1,285 @@
+// 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.policy;
+
+import org.apache.doris.analysis.CompoundPredicate;
+import org.apache.doris.analysis.CreatePolicyStmt;
+import org.apache.doris.analysis.DropPolicyStmt;
+import org.apache.doris.analysis.ShowPolicyStmt;
+import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.DdlException;
+import org.apache.doris.common.UserException;
+import org.apache.doris.common.io.Text;
+import org.apache.doris.common.io.Writable;
+import org.apache.doris.persist.gson.GsonUtils;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.ShowResultSet;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.commons.lang.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.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
+
+public class PolicyMgr implements Writable {
+    private static final Logger LOG = LogManager.getLogger(PolicyMgr.class);
+
+    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+
+    @SerializedName(value = "dbIdToPolicyMap")
+    private Map<Long, List<Policy>> dbIdToPolicyMap = Maps.newConcurrentMap();
+
+    /**
+     * cache merge policy for match
+     * key:dbId:tableId-type-user
+     **/
+    private Map<Long, Map<String, Policy>> dbIdToMergePolicyMap = Maps.newConcurrentMap();
+
+    private void writeLock() {
+        lock.writeLock().lock();
+    }
+
+    private void writeUnlock() {
+        lock.writeLock().unlock();
+    }
+
+    private void readLock() {
+        lock.readLock().lock();
+    }
+
+    private void readUnlock() {
+        lock.readLock().unlock();
+    }
+
+    public void createPolicy(CreatePolicyStmt stmt) throws UserException {
+        writeLock();
+        try {
+            Policy policy = Policy.fromCreateStmt(stmt);

Review Comment:
   You can move this outside the lock



##########
docs/zh-CN/sql-manual/sql-reference/Data-Definition-Statements/Drop/DROP-POLICY.md:
##########
@@ -0,0 +1,66 @@
+---
+{
+    "title": "DROP-POLICY",
+    "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+## DROP-POLICY
+
+### Name
+
+DROP POLICY
+
+### Description
+
+删除安全策略
+
+#### 行安全策略
+
+语法:
+
+```sql
+DROP ROW POLICY test_row_policy_1 on table1 [FOR user];
+```
+
+### Example
+
+1. 删除 table1 的 test_row_policy_1
+
+   ```sql
+   DROP ROW POLICY test_row_policy_1 on table1
+   ```
+
+2. 删除 table1 作用于 root 的 test_row_policy_1 行安全策略
+
+   ```sql
+   DROP ROW POLICY test_row_policy_1 on table1 for root

Review Comment:
   Not for root



##########
docs/zh-CN/sql-manual/sql-reference/Data-Definition-Statements/Drop/DROP-POLICY.md:
##########
@@ -0,0 +1,66 @@
+---
+{
+    "title": "DROP-POLICY",
+    "language": "zh-CN"
+}
+---
+
+<!--
+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.
+-->
+
+## DROP-POLICY
+
+### Name
+
+DROP POLICY
+
+### Description
+
+删除安全策略
+
+#### 行安全策略
+
+语法:
+
+```sql
+DROP ROW POLICY test_row_policy_1 on table1 [FOR user];
+```
+
+### Example
+
+1. 删除 table1 的 test_row_policy_1
+
+   ```sql
+   DROP ROW POLICY test_row_policy_1 on table1
+   ```
+
+2. 删除 table1 作用于 root 的 test_row_policy_1 行安全策略
+
+   ```sql
+   DROP ROW POLICY test_row_policy_1 on table1 for root
+   ```
+
+### Keywords
+
+```text

Review Comment:
   remove ```text



##########
fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java:
##########
@@ -676,6 +677,17 @@ private void analyzeAndGenerateQueryPlan(TQueryOptions tQueryOptions) throws Use
                 parsedStmt = StmtRewriter.rewrite(analyzer, parsedStmt);
                 reAnalyze = true;
             }
+            if (parsedStmt instanceof SelectStmt || parsedStmt instanceof SetOperationStmt) {

Review Comment:
   Need to consider `insert into select` stmt



-- 
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-unsubscribe@doris.apache.org

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


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