vpd策略函数必须返回合法where子句字符串;它动态拼接sql谓词,返回值直接追加到原始sql的where后,须为语法正确的varchar2字符串,不能是布尔值、数字或null,空字符串''导致全表可见。
策略函数必须返回合法where子句字符串
vpd不是开关式功能,它靠策略函数动态拼接sql谓词。函数返回值会直接追加到用户原始sql的where子句后,所以必须是语法正确的字符串片段,不能是布尔值、数字或空字符串。
- 返回
NULL或'1=1'表示无限制;返回空字符串''会导致全表可见 - 字段名要与基表定义完全一致:若表用双引号建为
"Emp",策略里也得写"emp_id",不能写emp_id - 字符串内含单引号需转义:想生成
username = 'XXF',代码中必须写'username = ''XXF''' - 避免在函数里调用
SYSDATE、DBMS_RANDOM等非确定性函数,否则可能触发ORA-20000或缓存失效
添加策略时参数必须严格匹配对象上下文
DBMS_RLS.ADD_POLICY稍有偏差,策略就静默失效——不会报错,但过滤不生效。
-
object_schema填的是表所在schema,不是当前登录用户。例如表在SCOTT下,即使你用HR执行,也要写'SCOTT' -
object_name区分大小写:建表时用了"Orders",这里就必须写'Orders'(带双引号),否则查不到对象 -
statement_types默认只对SELECT生效;如需控制UPDATE,必须显式写成'SELECT, UPDATE' - 重复执行
ADD_POLICY会报ORA-28102;修改前先用DBMS_RLS.DROP_POLICY清理旧策略
测试必须用普通业务用户,SYS/DBA默认豁免
Oracle明确规定VPD策略对SYS、SYSTEM及拥有DBA角色的用户不生效——这不是bug,是设计行为。
- 测试前务必用业务账号(如
SCOTT、HR)连接,不要用SYS AS SYSDBA - 如果发现“没过滤”,先查
SELECT * FROM SESSION_ROLES;确认是否意外拥有了DBA角色 - 策略函数中获取用户名要用
SYS_CONTEXT('USERENV', 'SESSION_USER'),别用CURRENT_USER——后者受角色影响,可能返回代理名 - 若真需要让某管理员受控,得显式收回其
EXEMPT ACCESS POLICY权限,但极少见且风险高
应用上下文必须提前创建并赋值
VPD本身不管理身份,它只读取上下文。跳过这步,SYS_CONTEXT永远返回NULL,策略就形同虚设。
- 先执行
CREATE CONTEXT HR_CTX USING hr.ctx_pkg;,再创建包hr.ctx_pkg提供set_dept过程 - 用户登录后必须显式调用
hr.ctx_pkg.set_dept(10),Web应用常在这里漏掉初始化 - 上下文名(如
HR_CTX)大小写敏感,策略函数里写的名称必须一字不差,否则静默失败 - 启用
sec_relevant_cols参数(如'SALARY')会触发列级掩码,但要求策略函数里不能对这些列做显式过滤,否则冲突
实际部署中最容易被忽略的,是上下文初始化和测试用户身份这两个环节——它们不报错,但会让整个VPD链路断在最前端。











