【问题标题】:How to get the stacktrace for the original exception in oracle PL/SQL from a RAISED exception?如何从 RAISED 异常中获取 oracle PL/SQL 中原始异常的堆栈跟踪?
【发布时间】:2017-04-15 03:31:22
【问题描述】:

我遇到了一个问题,即当我捕获异常时原始堆栈跟踪会丢失,然后引发它。

  1. 在 proc_a 中抛出异常
  2. 捕获异常。
  3. 执行回滚。
  4. 引发异常。
  5. 捕获异常(父块)
  6. 打印堆栈跟踪:SUBSTR(SQLERRM || chr(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(), 1, 3999)

示例:

DECLARE
BEGIN
   DECLARE
      lv_val VARCHAR2(1);
   BEGIN
      SELECT dummy INTO lv_val -- Line# 6 (desired)
      FROM   dual
      WHERE  dummy = 'FFF';
   EXCEPTION
      WHEN OTHERS THEN
         --DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM || chr(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(), 1, 3999));
         RAISE; -- Line# 12 (actual)
   END;
EXCEPTION
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM || chr(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(), 1, 3999));
END;
/

期望的结果:

原始异常的行号(第 1 步)。

ORA-01403: no data found
ORA-06512: at line 6

ORA-01403: no data found
ORA-06512: at line 12
Caused By:
ORA-01403: no data found
ORA-06512: at line 6

实际结果:

RAISE 的行号(第 4 步)。

ORA-01403: no data found
ORA-06512: at line 12

其他失败的尝试:

SQLERRM || chr(10) || DBMS_UTILITY.FORMAT_ERROR_STACK()

ORA-01403: no data found
ORA-01403: no data found

SQLERRM || chr(10) || DBMS_UTILITY.FORMAT_CALL_STACK()

ORA-01403: no data found
----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
0xee1cbd68        18  anonymous block

【问题讨论】:

  • 我不认为这是可能的。你已经在你的yedtion中说过:“当我捕获异常时”,即异常在异常处理程序中解决。
  • 并非如此。我已经在使用DBMS_UTILITY.FORMAT_ERROR_BACKTRACE()。而DBMS_UTILITY.FORMAT_ERROR_STACK() 只显示消息,这两个消息都是相同的,因为它被捕获然后引发。 DBMS_UTILITY.FORMAT_CALL_STACK 也给出了错误的行号。
  • 一旦异常被抓到了,相信你也没有办法再抓到了;你不能避免内部WHEN OTHERS 并在外部异常处理部分进行回滚和任何你需要的事情吗?
  • 我有时会检查dbms_utility.format_error_backtrace 是否已经包含sqlerrm,然后再连接它们。然而,这是一个老问题(我怀疑这不是 PL/SQL 独有的——例如,我在 Perl 中遇到过同样的情况)。有关异常处理的量子力学的一些说明,请参阅mikesmithers.wordpress.com/2015/07/24/…

标签: oracle exception plsql raise


【解决方案1】:

在您的内部异常处理程序中,不要使用RAISE 过程,而是使用RAISE_APPLICATION_ERROR 过程将dbms_utility.format_error_backtrace 函数的结果传递给它以获取原始行号:

BEGIN
   DECLARE
      lv_val VARCHAR2(1);
   BEGIN
      SELECT dummy INTO lv_val -- Line# 6 (desired)
      FROM   dual
      WHERE  dummy = 'FFF';
   EXCEPTION
      WHEN OTHERS THEN
         RAISE_APPLICATION_ERROR(-20001, dbms_utility.format_error_backtrace,true);
   END;
EXCEPTION
   WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM || chr(10) || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(), 1, 3999));
END;
/

如果没有外部异常处理程序,您将收到以下错误报告:

Error report -
ORA-20001: ORA-06512: at line 5
ORA-06512: at line 10
ORA-01403: no data found

使用外部异常处理程序,您将获得以下信息:

ORA-20001: ORA-06512: at line 5
ORA-01403: no data found
ORA-06512: at line 10

消息排序略有不同,但信息仍然存在。

【讨论】:

  • 这适用于我可以控制初始过程如何引发异常的任何情况。但是,由于它需要对原始 proc 进行更新,因此如果您无法更新原始 proc,它将无法使用。 +1
  • 您表示您正在捕获然后重新引发异常,因此每当您重新引发异常时,只需使用第三个参数设置为 true 的 RAISE_APPLICATION_ERROR 过程,包括 @ 的结果987654328@ 函数和第二个参数中的任何其他相关信息,以及您在 -20000 和 -20999 之间为第一个参数选择的值,整个错误堆栈将被传播出去。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-04
  • 2011-06-01
  • 2010-12-20
  • 2011-01-05
  • 2023-03-22
  • 1970-01-01
相关资源
最近更新 更多