结论:用DBMS_RLS.ADD_POLICY绑定返回WHERE条件的函数可实现透明行级过滤,但需确保参数正确、函数合法、权限直授且策略启用。

直接说结论:用 DBMS_RLS.ADD_POLICY 绑定一个返回 WHERE 条件的函数到目标表,就能实现行级过滤。它不是视图、不改应用 SQL,对用户完全透明——但函数逻辑写错、权限没配全、或忘记启用策略,都会导致策略“看似生效实则失效”。
dbms_rls.add_policy 参数必须填对,尤其 Function_Schema 和 Object_Schema
常见错误是把策略函数放在当前用户下,却在 ADD_POLICY 里填了其他 Schema 名。比如函数 fn_getpolicy 是在用户 niegc 下创建的,那 Function_Schema 就必须写 'NIEGC',不能写成当前登录用户名或空字符串。
-
Object_Schema是目标表所在的 Schema,比如'KGIS',不是当前连接用户 -
Policy_Function只能是函数名,不能带 Schema 前缀(如不能写'niegc.fn_getpolicy') -
Statement_Types如果只填'SELECT',那 INSERT/UPDATE/DELETE 就不受控;若要控制 DML,必须显式列出并设Update_Check => TRUE -
Enable => TRUE必须显式指定,否则策略创建成功但实际不生效
策略函数必须返回合法 WHERE 片段,且不能依赖会话外变量
函数返回值会被 Oracle 自动拼进 SQL 的 WHERE 子句,所以内容必须是纯条件表达式,不能含 SELECT、FROM 或分号。更关键的是:函数体内不能硬编码用户名,得用 SYS_CONTEXT('USERENV', 'SESSION_USER') 动态获取当前用户。
- 错误写法:
RETURN 'owner = ''T01''';—— 所有用户都看到 T01 的数据 - 正确写法:
RETURN 'owner = SYS_CONTEXT(''USERENV'', ''SESSION_USER'')'; - 如果业务规则更复杂(比如按部门 ID 过滤),建议先建
APPLICATION CONTEXT并在登录时设置属性,再在函数里读取,避免每次查询都查用户表 - 函数必须
GRANT EXECUTE给策略所作用的 Schema 所有者(通常是表 owner),否则策略启用时报ORA-28113: policy predicate has error
启用后查不到数据?先确认策略是否真在生效路径上
策略只对直查基表生效,对同义词、视图、DBLINK 远程表默认不触发。即使你建了 PUBLIC SYNONYM xx_test,用户查 SELECT * FROM xx_test 时,策略仍按底层表 Schema 判断是否启用。
- 用
SELECT * FROM DBA_POLICIES WHERE OBJECT_NAME = 'XX_TEST';确认策略状态为ENABLED - 用
SELECT * FROM SESSION_CONTEXT;检查上下文是否已设好(如果策略函数依赖它) - 用
EXPLAIN PLAN FOR SELECT * FROM xx_test;+SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);查看执行计划里是否出现了策略注入的 filter 条件 - 切到目标用户(如
t01/t01)后直接查表,不要通过 DBA 用户或 sysdba 查——策略对非目标用户不生效
最易被忽略的一点:策略函数里调用的任何对象(比如查找部门映射的表),该函数所有者必须有对应 SELECT 权限,且权限不能来自角色——必须是直接授予的,否则运行时报 ORA-00942: table or view does not exist 却找不到原因。


















