詭異的 ORA-06550 PLS-00302錯誤

  今天接到一個朋友的求助:

一個用戶創建測試庫存儲過程時,以存儲過程所有者登錄後,執行過程時正常,但是如果執行過程的命令中帶上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> 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章