今天接到一個朋友的求助:
一個用戶創建測試庫存儲過程時,以存儲過程所有者登錄後,執行過程時正常,但是如果執行過程的命令中帶上schema名後,則報錯 ORA-06550 PLS-00302錯誤。
場景:
SQL> show user
USER is "JOHN"
SQL> create or replace procedure p1
2 authid current_user
3 as
4 begin
5 null;
6 end p1;
7 /
Procedure created.
SQL>
SQL> exec p1;
PL/SQL procedure successfully completed.
SQL> exec john.p1;
BEGIN john.p1; END;
*
ERROR at line 1:
ORA-06550: line 1, column 12:
PLS-00302: component 'P1' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>
解決思路:
第一個想到的就是權限問題,即使是執行自己的procedure,也需要顯式賦權?於是給自己賦權了:
SQL> grant execute on p1 to john;
Grant succeeded.
SQL> exec john.p1;
BEGIN john.p1; END;
*
ERROR at line 1:
ORA-06550: line 1, column 12:
PLS-00302: component 'P1' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL> exec p1;
PL/SQL procedure successfully completed.
SQL>
依舊報錯,於是查看john的系統權限:
SQL> select * from dba_sys_privs where grantee='JOHN';
GRANTEE PRIVILEGE ADMIN_OPTION
------------------------------ ------------------------------ -----------------------------
JOHN UNLIMITED TABLESPACE NO
SQL> select * from dba_role_privs where grantee='JOHN';
GRANTEE GRANTED_ROLE ADMIN_OPTION DEFAUL
---------- ------------------------------ ------------------------------ ------
JOHN CONNECT NO YES
JOHN RESOURCE NO YES
懷疑是不是因爲存儲過程是以調用者方式創建的,導致需要執行用戶有execute any procedure權限,於是給john用戶增加權限:
SQL> select * from dba_role_privs where grantee='JOHN';
GRANTEE GRANTED_ROLE ADMIN_OPTION DEFAUL
---------- ------------------------------ ------------------------------ ------
JOHN CONNECT NO YES
JOHN RESOURCE NO YES
SQL> select * from dba_sys_privs where grantee='JOHN';
GRANTEE PRIVILEGE ADMIN_OPTION
---------- ------------------------------ ------------------------------
JOHN CREATE TRIGGER NO
JOHN EXECUTE ANY PROCEDURE NO
JOHN CREATE VIEW NO
JOHN ALTER ANY PROCEDURE NO
JOHN CREATE TABLE NO
JOHN SELECT ANY DICTIONARY NO
JOHN CREATE ANY PROCEDURE NO
7 rows selected.
再次嘗試:
SQL> exec p1;
PL/SQL procedure successfully completed.
SQL> exec john.p1;
BEGIN john.p1; END;
*
ERROR at line 1:
ORA-06550: line 1, column 12:
PLS-00302: component 'P1' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>
情況依舊。
還是懷疑跟以調用者方式創建的有關,於是嘗試默認創建的方式創建:
SQL> create or replace procedure p2 as begin null;end p2;
2 /
Procedure created.
SQL> exec p2;
PL/SQL procedure successfully completed.
SQL> exec john.p2;
BEGIN john.p2; END;
*
ERROR at line 1:
ORA-06550: line 1, column 12:
PLS-00302: component 'P2' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>
到這裏基本可以判斷,跟以調用者創建的方式是無關的了。
開始網上查一把,查到類似文章:
http://www.itpub.net/thread-1834519-1-1.html
情況類似,它產生問題的原因是PUBLIC角色中,有一個同義詞跟schema同名了。
於是,開始查看PUBLIC的同義詞:
SQL> select owner,synonym_name from dba_synonyms where synonym_name='JOHN';
no rows selected
沒有類似同義詞。到這裏,筆者基本猜到了,有可能相同的名字空間中有跟schema_name同名的對象,於是查看之:
SQL> select owner,object_name,object_type from dba_objects where object_name='JOHN';
OWNER OBJECT_NAME OBJECT_TYPE
---------- ------------------------------ --------------------------------------
JOHN JOHN TABLE
果然有一條記錄,欣喜,像是抓到救命稻草。
於是rename之(因爲是測試環境):
SQL> alter table john rename to john_bak;
Table altered.
SQL> exec p1;
PL/SQL procedure successfully completed.
SQL> exec john.p1;
PL/SQL procedure successfully completed.
SQL>
果然,原因找到了。
警示:
現網環境的對象命名時需要注意,不要跟schema_name同名,否則很容易引起歧義,執行時因爲名字空間的問題,導致一些存儲過程、函數等執行起來會有問題。
延伸測試:
SQL> show user
USER is "JOHN"
VIEW:
SQL> select owner,object_name,object_type from dba_objects where object_name='JOHN';
OWNER OBJECT_NAME OBJECT_TYPE
---------- ------------------------------ --------------------------------------
JOHN JOHN VIEW
SQL> exec p1;
PL/SQL procedure successfully completed.
SQL> exec john.p1;
BEGIN john.p1; END;
*
ERROR at line 1:
ORA-06550: line 1, column 12:
PLS-00302: component 'P1' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL> drop view john;
SYNONYM:
SQL> create synonym john for test;
SQL> select owner,object_name,object_type from dba_objects where object_name='JOHN';
OWNER OBJECT_NAME OBJECT_TYPE
---------- ------------------------------ --------------------------------------
JOHN JOHN SYNONYM
SQL> exec p1;
PL/SQL procedure successfully completed.
SQL> exec john.p1;
BEGIN john.p1; END;
*
ERROR at line 1:
ORA-06550: line 1, column 12:
PLS-00302: component 'P1' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>