2017-02-03 12 views
1

これらの手順のうちALLが正常に実行された後、手順の一覧を削除しようとしています。そのため、プロシージャのいずれかに障害が発生した場合、そのプロシージャは破棄されることなくデバッグできます。手順の一覧を削除する

しかし、私は、ORA-04021を取得しています:オブジェクト

ここ

コードがあるにロックを待っている間にタイムアウトが発生しました。

パッケージ仕様:

create or replace package remove_procedures AUTHID CURRENT_USER is 

procedure dropProcedures(p_schema varchar2, p_type varchar2, p_object_list varchar2); 
procedure dropProceduresName(p_schema varchar2, p_object_list varchar2); 

end remove_procedures; 

パッケージ本体:

create or replace package body remove_procedures is 

-- type declaration for a collection of string 
type t_stringtab is table of varchar2(100); 

function listToTab (p_list in varchar2) 
    return t_stringtab is 
    l_str varchar2(32760) default p_list ||','; 
    l_n number; 
    l_retval t_stringtab := t_stringtab(); 
    l_item varchar2(100); 
begin 
    -- traverse the items in the comma seperated list into a nested table 
    loop 
    -- find the position of the first comma in l_str 
    l_n := instr(l_str, ','); 
    -- exit the loop if a comma was not found 
    exit when (nvl(l_n,0) = 0); 
    -- add an element to our collection to hold the next item parsed from the string 
    l_retval.extend; 
    -- parse the next item from the comma seperated string 
    l_item := ltrim(rtrim(substr(l_str,1,l_n-1))); 
    -- raise an exception if the length of the item exceeds 30 bytes (limit for oracle object names) 
    -- todo - add check for violations of other naming rules e.g. items beginning with a number 
    /* if lengthb(l_item) > 30 then 
     raise_application_error(-20000,'Error : 30 bytes limit exceeded for item : '|| l_item); --disabling this block for file names 
    end if; */ 
    -- otherwise add the item to the element in the collection 
    l_retval(l_retval.count) := l_item; 
    -- reset l_str variable to the remainder of the comma seperated list 
    l_str := substr(l_str, l_n+1); 
    end loop; 
    return l_retval; 
end listToTab; 

procedure dropProcedures(p_schema varchar2, p_type varchar2, p_object_list varchar2) is 
    l_objects t_stringtab := t_stringtab(); 
    l_object_found number; 
begin 
    l_objects := listToTab(p_object_list); 
    for i in l_objects.first .. l_objects.last loop 
    select count(*) into l_object_found 
    from user_objects 
    where upper(object_type) = upper(p_type) 
    and upper(object_name) = upper(l_objects(i)); 
    if l_object_found = 0 then 
     dbms_output.put_line('WARNING : Object '||upper(p_schema)||'.'||upper(l_objects(i))||' does not exist.'); 
    else 
     dbms_output.put_line('Dropping Object '||upper(p_type)||' named '||upper(p_schema)||'.'||upper(l_objects(i))||' now...'); 
     begin 
     execute immediate 'drop '||p_type||' '||upper(p_schema)||'.'||upper(l_objects(i)); 
     exception when others then 
     if sqlcode = -00942 then 
      null; 
     else 
      raise; 
     end if; 
     end; 
    end if; 
    end loop; 
end; 

次に、ここでは、すべての手順を実行するためのコードであり、そしてすべての手順を実行している場合は、その後、いくつかの手順をドロップします。

create or replace procedure ref_master is 
begin 
    ref_categories; 
    ref_country; 
    ref_currency; 
    ref_currency_to_country; 
    promotions.remove_procedures.dropProcedures(
     p_schema => 'PROMOTIONS', 
     p_type => 'PROCEDURE', 
     p_object_list => 'ref_country,ref_currency,ref_currency_to_country'); 
end; 

そしてここref_masterの実行であり、私は前述のエラーが出る場所です。驚くべきことに

begin 
    -- Call the procedure 
    ref_master; 
end; 

を、私は唯一の特定の行を実行したときに、それが引用[OK]を動作します。

begin 
promotions.remove_procedures.dropProcedures(
     p_schema => 'PROMOTIONS', 
     p_type => 'PROCEDURE', 
     p_object_list => 'ref_country,ref_currency,ref_currency_to_country'); 
end; 

すべてのアイデアをどのように進めることができるので、すべて正常に実行された場合は削除できますが、正常に実行されなかった場合は直ちに停止できます。ありがとうございます:-)

+3

したいなぜこの(テスト)

WHENEVER SQLERROR EXIT FAILURE ROLLBACK create or replace procedure test is begin dbms_output.put_line('done'); end; / begin test; end; / begin execute immediate 'drop procedure test'; end; / 

PLSQLのDevから、

のように私を探してどこに私が何を考えました実行した後の手順を削除するには?プロシージャーはワンショットのものではありません。 – APC

+0

はい、クライアントはプロシージャーを変更する傾向があると言っていますので、リスト内の前述のプロシージャーが破棄されないと、将来的に多くの廃止されたプロシージャーが多数存在する可能性があります。 – Jaanna

+0

まだ聞こえません。なぜ、「変更」は「ドロップ」を意味するのですか?どうして '作成するか置き換える? ' – APC

答えて

1

あなたが期待することを実行するための正しいコードを書いています。プロシージャの1つを実行する際に例外があり、Oracleは直ちに停止します。

しかし、問題は、あなたが削除する前に実行する手順の一つであり、それは時間がかかりすぎると、あなたが取得し、例外:

ORA-04021: timeout occurred while waiting to lock object 

あなたは

から入手できますか何を出力
set time on 

exec ref_categories; 
exec dbms_output.put_line('ref_categories:ok'); 
exec ref_country; 
exec dbms_output.put_line('ref_country:ok'); 
exec ref_currency; 
exec dbms_output.put_line('ref_currency:ok'); 
exec ref_currency_to_country; 
exec dbms_output.put_line('ref_currency_to_country:ok'); 
exec promotions.remove_procedures.dropProcedures(
    p_schema => 'PROMOTIONS', 
    p_type => 'PROCEDURE', 
    p_object_list => 'ref_country,ref_currency,ref_currency_to_country'); 

私の分析は、別のOracleアクション(insertupdate、...)によってテーブルや何かがロックされているので、時間がかかりすぎる(そして、この "タイムアウト"が発生します)。しかし、私たちは推測することはできません。

プロシージャの実行中に、データベースセッション(TOAD、PL/SQL Developerなどの適切なツールを使用)を調べ、ロックされているオブジェクトを確認することができます。

編集:プロシージャがどこから呼ばれている範囲内から削除することはできませんので、あなたはこのエラーを取得する

create or replace procedure test 
is 
begin 
    dbms_output.put_line('done'); 
end; 
/

begin 
    test; 
    execute immediate 'drop procedure test'; 
end; 

私たちはあなたのような問題をminimalizeことができます。

解決策は、2つの別個の呼び出しを実行することです:起動プロシージャ、次に削除を起動します。

sqlplus手順が正しく実行されなかった場合、削除を回避するには、WHENEVER SQLERROR EXIT FAILURE ROLLBACKを使用してください。 execute immediateをお使いの手順を呼び出すために:

begin 
    execute immediate 'begin test; end;'; 
    execute immediate 'drop procedure test'; 
end; 
/
+0

明確な通話の仕方はうまくいきました。ありがとう:-) – Jaanna

関連する問題