我正在尝试在成功执行这些过程的 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;
任何想法如何继续,所以如果所有程序都成功执行,我将能够删除程序,或者如果任何程序没有正确执行,我将立即停止。在此先感谢: - )
答案 0 :(得分: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动作锁定(insert
,update
,... )。但我们无法猜测。
您可以做的是在您的程序运行时,浏览数据库会话(使用适当的工具,例如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;
您收到此错误,因为无法从调用它们的范围内删除该过程。
如果程序运行不正确,sqlplus
要避免删除,请使用WHENEVER SQLERROR EXIT FAILURE ROLLBACK
;像这样(测试过)
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的我发现您在寻找的地方我认为: execute immediate
来调用您的程序 :
begin
execute immediate 'begin test; end;';
execute immediate 'drop procedure test';
end;
/