今天在執行乙個過程是報了乙個ora-4068錯誤。雖然問題很簡單,而且也很容易解決,但是要真正理解的錯誤產生的原因,還需要對概念理解的比較清晰。
下面做乙個簡單的例子重現錯誤:
sql> create table t as select * from tab;
表已建立。
sql> create or replace procedure p_recreate as
2 begin
3 execute immediate 'drop table t';
4 execute immediate 'create table t as select * from tab';
5 end;
6 /過程已建立。
sql> create or replace procedure p_insert_t as
2 begin
3 insert into t select * from t;
4 end;
5 /過程已建立。
sql> begin
2 p_recreate;
3 p_insert_t;
4 end;
5 /begin
*第1 行出現錯誤
:ora-04068: 已丟棄程式包的當前狀態
ora-04065:
未執行, 已更改或刪除
stored procedure "yangtk.p_insert_t"
ora-06508: pl/sql: 無法找到正在呼叫: "yangtk.p_insert_t" 的程式單元
ora-06512:
在line 3
如果單獨執行兩個過程,則不會報錯:
sql> exec p_recreate
pl/sql
過程已成功完成。
sql> exec p_insert_t
pl/sql
過程已成功完成。
看到ora-04068錯誤,我首先想到的是由於在p_recreate過程中,對錶進行了刪除重建工作,導致和這個表相關的儲存過程變為invalid。
於是,我嘗試在呼叫過程之前重編譯p_insert_t過程:
sql> begin
2 p_recreate;
3 execute immediate 'alter procedure p_insert_t compile';
4 p_insert_t;
5 end;
6 /begin
*第1 行出現錯誤
:ora-04068: 已丟棄程式包的當前狀態
ora-04065:
未執行, 已更改或刪除
stored procedure "yangtk.p_insert_t"
ora-06508: pl/sql: 無法找到正在呼叫: "yangtk.p_insert_t" 的程式單元
ixdba.net社群論壇
ora-06512:
在line 4
但是發現,錯誤依舊。
sql> begin
2 p_recreate;
3 execute immediate 'begin p_insert_t; end;';
4 end;
5 /pl/sql
過程已成功完成。
但如果使用動態sql的方式呼叫p_insert_t過程,則不會報錯。
問題已經基本上清楚了,但是要想說明白,還需要從頭說起。
儲存過程在編譯時,自動檢查語法錯誤、許可權以及所有物件依賴性等。等到執行的時候,oracle不會再進行類似的檢查,而是直接執行過程,這也是儲存過程擁有較高效率的乙個原因。
當儲存過程依賴的物件發生變化了,oralce會自動將儲存過程的狀態置為invalid,而儲存過程的狀態如果為invalid,則會在下次執行的時候嘗試重新編譯,如果編譯通過,則繼續執行,編譯失敗則報錯。
這就是為什麼兩個過程單獨執行時不會報錯。
那麼,為什麼兩個過程放到一起執行就會報錯,即使嘗試重新編譯也無效呢。這是由於導致過程p_insert_t失效的過程就在呼叫p_insert_t過程的匿名塊中。在將匿名塊提交給oracle時,oracle對裡面每個過程的狀態進行了檢查,由於導致p_insert_t失效的p_recreate過程還沒有執行,這時候,所有過程的狀態都是valid,於是oracle記錄下來過程的資訊準備到直接執行。但是呼叫p_recreate過程後,由於t表被刪除重建,p_insert_t的狀態發生變化,但是oracle對過程p_insert_t的檢查已經完成,因此在嘗試直接執行p_insert_t的**的時候發現p_insert_t的狀態已經發生變化,因此,這裡報錯ora-04068,同樣的道理,即使對p_insert_t進行了重新編譯,oracle在執行時發現檢查時的**已經發生了變化,仍然會報錯,即使這個時候儲存過程的狀態已經時valid了。
而採用動態sql不會報錯的原因就更容易理解了,由於採用動態sql,oracle將編譯是進行的操作推遲到執行時進行,也就是說,oracle會在呼叫p_recreate之後,呼叫p_insert_t過程之前對p_insert_t進行檢查並重新編譯,因此,採用動態sql不會報錯。
呼叫儲存過程報錯 ORA 01031
a使用者呼叫b使用者的儲存過程,如果儲存過程中有動態建表的sql語句,如create table test,那麼管理員 如dba 必須給b使用者賦予create table的許可權,即使b已經是dba角色也必須單獨授予建表的許可權 如果是create table a.test,則必須給b使用者授予c...
oracle 執行儲存過程 ora 0131
今天一開發同事反應新建的測試使用者無法執行儲存過程,使用plsq遠端連線執行儲存過程報錯如下 報錯資訊是 ora 0131 insufficient privileges,就是使用者沒有儲存過程的除錯執行許可權 debug connect session 需要具有dba許可權的使用者登入授權即可 c...
Oracle儲存過程跨使用者執行查詢報錯
在oracle 中,在usera下編寫乙個儲存過程,該儲存過程中引用了另乙個使用者userb下的表或檢視物件。編譯該儲存過程,出現編譯錯誤。報ora 00942 table or view does not exist。但是該錶或檢視的確在userb下存在,而且已經授予了usera dba角色的許可...