3

下面是一个最小的测试案例,由于某种原因失败,如何通过立即执行传播全局定义的异常?

ORA-06510:PL/SQL:未处理的用户定义的异常

CREATE PACKAGE my_test 
AS 
    global_exception EXCEPTION; 
END; 
/

set serveroutput on; 

BEGIN 
    execute immediate 'BEGIN RAISE my_test.global_exception; END;'; 
EXCEPTION 
    WHEN my_test.global_exception THEN 
    dbms_output.put_line('global_exception'); 
END; 
/

下面是测试情况下工作:

BEGIN 
    RAISE my_test.global_exception; 
EXCEPTION 
    WHEN my_test.global_exception THEN 
    dbms_output.put_line('global_exception'); 
END; 
/

有没有办法通过EXECUTE IMMEDIATE引发全局异常? 数据库版本12C或11g

回答

4

你能赶上它,如果你使用dbms_sql代替execute immediate(在11gR2中):

DECLARE 
    l_cur pls_integer; 
    l_rc pls_integer; 
BEGIN 
    l_cur := dbms_sql.open_cursor; 
    dbms_sql.parse (l_cur, 'BEGIN RAISE my_test.global_exception; END;', dbms_sql.native); 
    l_rc := dbms_sql.execute(l_cur); 
EXCEPTION 
    WHEN my_test.global_exception THEN 
    dbms_output.put_line('global_exception'); 
END; 
/

PL/SQL procedure successfully completed. 

global_exception 

不能完全确定为什么会工作,但你没有,但。

啊,investigating the different behaviour threw up a hint。如果您associate an error number with the exception在你的包,你可以用execute immediate抓住它:

CREATE PACKAGE my_test 
AS 
    global_exception EXCEPTION; 
    PRAGMA exception_init(global_exception, -20001); 
END; 
/

BEGIN 
    execute immediate 'BEGIN RAISE my_test.global_exception; END;'; 
EXCEPTION 
    WHEN my_test.global_exception THEN 
    dbms_output.put_line('global_exception'); 
END; 
/

PL/SQL procedure successfully completed. 

global_exception 

您现在可以静态地抛出异常在一个匿名块太大,虽然这不是非常有用的;没有编译这也得到ORA-06510,因为它是你那个execute immediate内做什么:

BEGIN 
    RAISE my_test.global_exception; 
END; 
/

Error report - 
ORA-20001: 
ORA-06512: at line 2 

这ORA-20001可现在execute immediate内抛出和编译允许其通过上下文识别开关。或类似的东西。看起来,dbms_sql包的处理方式略有不同。