Oracle在以后的块中使用第一个块的异常处理程序
我遇到了这样一种行为:我试图在Flyway脚本中为几个Oracle PL/SQL块使用特定于大小写的异常处理程序,Oracle显然与它记录的异常处理程序范围相矛盾,将所有异常发送到第一个块的异常处理程序。例如,在此代码中:Oracle在以后的块中使用第一个块的异常处理程序,oracle,plsql,flyway,Oracle,Plsql,Flyway,我遇到了这样一种行为:我试图在Flyway脚本中为几个Oracle PL/SQL块使用特定于大小写的异常处理程序,Oracle显然与它记录的异常处理程序范围相矛盾,将所有异常发送到第一个块的异常处理程序。例如,在此代码中: begin begin execute immediate ' create table "test" ( "id" number not null, "name" varchar2(100) not null, constraint "test_p
begin
begin
execute immediate '
create table "test" (
"id" number not null,
"name" varchar2(100) not null,
constraint "test_pk" primary key ("id")
)
';
exception
when others then
if sqlcode != -955 then raise; end if;
end;
begin
execute immediate 'fail to create index "test_name_idx" on "test" ("name")';
exception
when others then
if sqlcode != -6512 then raise; end if;
end;
end;
ORA-06512异常未被捕获,引发的异常标记为第13行
将这些块包装成更多的块没有帮助
这是怎么回事?如何阻止这种情况发生?这似乎是一个bug,它(到目前为止)已在11.2.0.4、12.1.0.2和12.2.0.1中重现。它似乎不需要DDL,也不需要在第一个子块中执行任何实际操作(尽管仅将
null;
作为占位符不会触发它,可能是因为编译器将其删除),但它似乎需要两个异常处理程序中的if
:
begin
begin
dbms_output.put_line('Dummy message');
exception
when others then
dbms_output.put_line('In first exception handler');
if 1=1 then
raise;
end if;
end;
begin
execute immediate 'invalid';
exception
when others then
dbms_output.put_line('In second exception handler');
if 1=1 then
raise;
end if;
end;
end;
/
Dummy message
In second exception handler
ORA-00900: invalid SQL statement
ORA-06512: at line 8
ORA-06512: at line 13
与您的示例一样,异常是由第13行引发的,因此应在第18行报告为(重新)引发的;但事实上,它是从第8行提出来的,这是没有意义的。(第13行的信息仅在12.2中显示;在11.2和12.1中,它只报告了第一个ORA-06512,这相当令人困惑。至少在12.2中,您知道问题的真正所在。)
从调试中可以看出,它实际上没有使用第一个异常处理程序,而是进入了第二个异常处理程序。它“仅”似乎是针对错误的行号进行报告,而不是执行错误的代码
似乎在提升之前,在if
中进行实际工作可以解决异常处理部分的问题;这会在第一条中添加一条无法访问的消息:
begin
begin
dbms_output.put_line('Dummy message');
exception
when others then
dbms_output.put_line('In first exception handler');
if 1=1 then
dbms_output.put_line('This avoids the bug somehow');
raise;
end if;
end;
begin
execute immediate 'invalid';
exception
when others then
dbms_output.put_line('In second exception handler');
if 1=1 then
raise;
end if;
end;
end;
/
Dummy message
In second exception handler
ORA-00900: invalid SQL statement
ORA-06512: at line 19
ORA-06512: at line 14
第二种情况是:
begin
begin
dbms_output.put_line('Dummy message');
exception
when others then
dbms_output.put_line('In first exception handler');
if 1=1 then
raise;
end if;
end;
begin
execute immediate 'invalid';
exception
when others then
dbms_output.put_line('In second exception handler');
if 1=1 then
dbms_output.put_line('This avoids the bug somehow');
raise;
end if;
end;
end;
/
Dummy message
In second exception handler
ORA-00900: invalid SQL statement
ORA-06512: at line 19
ORA-06512: at line 13
在这两种情况下,报告的行号现在都是正确的。不知怎么的
它不必是一个dbms\u输出
调用,任何东西似乎都可以工作,例如一个伪过程调用或查询,甚至是一个额外的子块(例如开始执行立即的'select*from dual';结束;
,即使查询没有执行,因为没有进入
…)。再次使用null但是代码>不起作用
这有点难看,但至少给了你一种阻止它发生的方法
这显然是一种奇怪的、意外的、不一致的行为,而且已经存在了一段时间,因此可能应该通过我的Oracle支持部门将其作为服务请求提出。我看不到任何现有的报告,但我没有仔细查看,因此可能有一份潜伏在某处。这非常。。。。有趣。如果在第一次提升之前(在If内部)添加一个简单的dbms\u输出
调用,它会通过livesql.oracle.com上的快速测试报告正确的行号。但是,通过更多的调试,它实际上不会命中第一个异常处理程序(当然,正如您所期望的那样),即使它报告了错误的行号。看起来像一个(解析?)bug,可能在dbms\u sql
中?也许有兴趣看看它是否表现出相同的不同版本。看起来有点像10g的bug 8856896,但这是12cR2,至少在那个站点是这样。可能是时候向Oracle支持部门提出服务请求了?FWIW,在Oracle 12.1.0.2.0上重现了此问题。顺便说一句,我想知道你为什么要捕捉ORA-06512(“错误在n行”),因为我认为你会感兴趣的实际例外是ORA-00955(“名称已被现有对象使用”)和ORA-01408(“此类列列表已被索引”)。@JeffreyKemp:是的,这只是一个复制案例。