我在子程序中引发异常,我希望看到调用函数暂时执行。但是,调用函数继续处理,好像什么也没发生,我不明白为什么。
我的功能看起来像这样:
FUNCTION getFooCursor (i_blah IN VARCHAR)
RETURN t_ref_cursor
IS
v_sum_variable NUMBER;
BEGIN
--lookup number
v_sum_variable := getNumber (i_blah);
--call function that raises NO_DATA_FOUND exception
doRaiseException();
--the exception handler is only supposed to catch for this block
BEGIN
--do stuff and end up with a cursor
RETURN barCursor(v_sum_variable);
EXCEPTION
WHEN OTHERS THEN
--set some variables
END
END;
让我们说doRaiseException()
看起来像这样:
PROCEDURE doRaiseException ()
IS
BEGIN
RAISE NO_DATA_FOUND;
END;
当我在TOAD中调试此函数时,它有助于通知我已经引发了NO_DATA_FOUND异常。然而,它然后立即继续执行下一行(调用barCursor()
)并且函数完成,好像什么都没有出错。
我尝试直接用doRaiseException();
替换RAISE NO_DATA_FOUND;
用于测试目的(它实际上做的不止于此)并且这会在getFooCursor()
内停止执行,但无论SQL再次调用它都会完全忽略异常
这是PL / SQL中异常的工作原理吗?他们不像在Java或C#中那样冒泡吗?也许我错过了一些关于Oracle异常的重要信息。如何获得一个例外以冒泡到主机?
这是我的Oracle版本(从v $版本返回):
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi
PL/SQL Release 10.2.0.5.0 - Production
CORE 10.2.0.5.0 Production
TNS for HPUX: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production
答案 0 :(得分:2)
您对异常的理解是正确的。但是,这是异常如何工作的一个值得注意的例外:在SQL上下文中忽略NO_DATA_FOUND。这是一个“功能”,因为这就是Oracle告诉其他进程不再需要读取数据的方式。
对于自定义异常,您可能需要捕获NO_DATA_FOUND并将其作为不同的异常引发。这通常是一种处理异常的可怕方式,但这里没有好的选择。
SQL> create or replace function function1 return number is
2 begin
3 raise no_data_found;
4 return 1;
5 end;
6 /
Function created.
SQL> select function1 from dual;
FUNCTION1
----------
1 row selected.
SQL> create or replace function function2 return number is
2 begin
3 raise no_data_found;
4 return 1;
5 exception when no_data_found then
6 raise_application_error(-20000, 'NO_DATA_FOUND raised');
7 end;
8 /
Function created.
SQL> select function2 from dual;
select function2 from dual
*
ERROR at line 1:
ORA-20000: NO_DATA_FOUND raised
ORA-06512: at "JHELLER.FUNCTION2", line 6
答案 1 :(得分:1)
例外工作正如你想象的那样“冒泡”,所以你必须在某个地方捕捉它。
这就是正在发生的事情......你正在捕捉每个异常,这不是最好的做法。如果您自己定义一个,则可以仅确保catch a specific exception。但是,这似乎不是你想要做的。您只想重新引发单个例外。
所以,你可以define a custom exception in a separate package,在你的子程序中提高它,然后在你的调用块中做这样的事情:
begin
RaiseException;
exception
when my_exception_package.my_exception then
raise;
when others then
DoSomethingElse;
end;
通过这种方式,您可以捕获要提升的异常,然后重新提升它们。如果异常不同,那么继续当前的程序流程。