删除程序列表

时间:2017-02-03 08:50:22

标签: oracle plsql oracle11g

我正在尝试在成功执行这些过程的 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;

任何想法如何继续,所以如果所有程序都成功执行,我将能够删除程序,或者如果任何程序没有正确执行,我将立即停止。在此先感谢: - )

1 个答案:

答案 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动作锁定(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;

您收到此错误,因为无法从调用它们的范围内删除该过程。

解决方案是进行2次不同的调用:启动程序,然后启动删除。

如果程序运行不正确,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;
/