【IT168 技术文档】调用者权限和定义者权限存储过程不同,调用者权限不但存在上一篇文章介绍的问题,还可能导致存储过程执行报错。
新建对象也可能导致存储过程的失效:http://yangtingkun.itpub.net/post/468/223040
由于调用者权限的存储过程在执行时才去真正的访问表,如果用户添加了新增对象,而这个新增对象又和存储过程中需要访问的某个对象(一般是PUBLIC同义词)重名,那么对于调用者权限存储过程,由于不是存储过程的拥有者对象发生了改变,因此不会影响到存储过程的状态,但是在新建对象用户下执行存储过程时就可能发生错误。
SQL> SELECT OBJECT_NAME, PROCEDURE_NAME, AUTHID
2 FROM DBA_PROCEDURES
3 WHERE PROCEDURE_NAME = 'GATHER_TABLE_STATS';
OBJECT_NAME PROCEDURE_NAME AUTHID
------------------------------ --------
DBMS_STATS GATHER_TABLE_STATS CURRENT_USER
SQL> SELECT NAME, REFERENCED_NAME
2 FROM DBA_DEPENDENCIES
3 WHERE NAME = 'DBMS_STATS'
4 AND REFERENCED_NAME = 'DUAL';
NAME REFERENCED_NAME
------------------------------ -------------
DBMS_STATS DUAL
SQL> COL OBJECT_NAME FORMAT A30
SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS FROM DBA_OBJECTS WHERE OBJECT_NAME = 'DBMS_STATS';
OBJECT_NAME OBJECT_TYPE STATUS
------------------------------ ---------
DBMS_STATS PACKAGE VALID
DBMS_STATS PACKAGE BODY VALID
DBMS_STATS SYNONYM VALID
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T')
PL/SQL 过程已成功完成。
从上面的结果看,DBMS_STATS包参考DUAL表,而且DBMS_STATS包的GATHER_TABLE_STATS过程是调用者权限存储过程。
下面在当前用户下建立与DUAL表同名的同义词:
SQL> CREATE SYNONYM DUAL FOR T;
同义词已创建。
SQL> SELECT COUNT(*) FROM DUAL;
COUNT(*)
----------
3
SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS FROM DBA_OBJECTS WHERE OBJECT_NAME = 'DBMS_STATS';
OBJECT_NAME OBJECT_TYPE STATUS
------------------------------ ------------------ -------
DBMS_STATS PACKAGE VALID
DBMS_STATS PACKAGE BODY VALID
DBMS_STATS SYNONYM VALID
由于DBMS_STATS包不在建立在当前用户下,因此当前用户下新增表不会影响DBMS_STATS包的状态,但是,如果这时执行GATHER_TABLE_STATS过程,会发现:
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T')
BEGIN DBMS_STATS.GATHER_TABLE_STATS(USER, 'T'); END;
*
ERROR 位于第 1 行:
ORA-20000: Cannot parse for clause: FOR ALL COLUMNS SIZE 1
ORA-06512: 在"SYS.DBMS_STATS", line 9375
ORA-06512: 在"SYS.DBMS_STATS", line 9389
ORA-06512: 在line 1
看来,对于调用者权限而言,建立与PUBLIC同义词同名对象的危害更大,而且存储过程的状态显示也是正常的,从错误提示上也很难进行判断。这也是定义者权限存储过程比调用者权限存储过程更安全的一个因素吧。