通过 SQL%BULK_EXCEPTIONS 传播触发的异常

Posted

技术标签:

【中文标题】通过 SQL%BULK_EXCEPTIONS 传播触发的异常【英文标题】:Propagating triggered exceptions through SQL%BULK_EXCEPTIONS 【发布时间】:2014-03-17 18:25:05 【问题描述】:

我正在处理一个包含 FORALL .. SAVE EXCEPTIONS .. UPDATE 语句的 PL/SQL 包。

数据(根据业务规则)的有效性通过表上的触发器来检查,该表包含将要更新的数据。此触发器调用一个能够生成错误的过程:

RAISE_APPLICATION_ERROR( -20002, 'message');

因此可能会在 FORALL .. SAVE EXCEPTIONS .. UPDATE DML 语句期间生成用户定义的错误。但是,当尝试使用 SQL%BULK_EXCEPTIONS 在异常处理中记录错误时,我观察到以下输出;

SQLCODE:                                       ORA-24381
SQLERRM:                                       ORA-24381: error(s) in array DML
SQL%BULK_EXCEPTIONS(i).ERROR_CODE:             20002
SQLERRM(-(SQL%BULK_EXCEPTIONS(i).ERROR_CODE)): ORA-20002:

请注意,来自 sql%bulk_exceptions 的 error_code 会丢失减号。除了错误代码之外,错误消息也是空的。

这里有两个问题:

(用户定义的)错误消息不会通过 bulk_exceptions 返回。 (标准错误不是这种情况!例如:FORALL-UPDATE 是否会因为列大小限制而失败,来自 bulk_exceptions 的错误消息可能是:“ORA-12899: value too large for column ",并且不会为空。) 引发此异常时,会传递 SQLCODE+SQLERRM“ORA-24381: 数组 DML 中的错误”,而不是实际触发的(用户定义的,-20000)错误代码和消息。

是否可以将来自 RAISE_APPLICATION_ERROR 的消息与用户定义的错误代码联系起来,以便 SQLERRM 显示它?以及如何在不更改为 ORA-24381 错误的情况下传播此错误?

【问题讨论】:

【参考方案1】:

一般来说,sqlerrm 不可能返回用户定义的错误消息,因为完全有可能(并且在大多数应用程序中,很可能)相同的错误代码映射到多个错误消息。如果您的特定应用程序旨在为每个用户定义的错误使用与错误代码对应的单个消息进行单一定义,您可以维护自己的集合,将错误代码映射到错误消息并在错误处理程序中调用它。类似的东西

CREATE OR REPLACE PACKAGE pkg_error_codes
AS
  TYPE error_code_tbl IS TABLE OF VARCHAR2(100) INDEX BY PLS_INTEGER;
  g_error_codes error_code_tbl;

  FUNCITON My_SQLERRM( p_error_code IN INTEGER )
    RETURN VARCHAR2;
END;

CREATE OR REPLACE PACKAGE BODY pkg_error_codes
AS 
  FUNCITON My_SQLERRM( p_error_code IN INTEGER )
    RETURN VARCHAR2
  IS
  BEGIN
    RETURN g_error_codes( p_error_code );
  END;

BEGIN
  -- Initialize your error codes
  g_error_codes( 20001, 'Some error message' );
  g_error_codes( 20002, 'Another error message' );
END;

然后您可以在您的代码中调用My_SQLERRM(如果您愿意,也可以直接使用pkg_error_codes.g_error_codes( SQL%BULK_EXCEPTIONS(i).ERROR_CODE ))。

您可能希望创建一个将错误编号映射到错误消息的表,并在初始化块中读取该表,而不是将映射放入代码中。您可能希望命名异常并通过作为包主体一部分的pragma exception_init 调用将它们与错误代码相关联(尽管这会消除在正常操作中在错误堆栈中包含错误消息的能力)。

根据您的操作,使用 SQL 而不是 PL/SQL 可能更有意义,使用 dbms_errlog 表创建错误日志表并在 SQL 语句中使用 EXCEPTIONS INTO 子句写入任何错误到错误日志。这将包括引发的实际错误消息。

【讨论】:

以上是关于通过 SQL%BULK_EXCEPTIONS 传播触发的异常的主要内容,如果未能解决你的问题,请参考以下文章

FORALL......保存例外

最新后缀.*4444后缀勒索病毒文件及SQL Server数据库修复方案

带传播的 SQL 限制

“模拟”用户未传播到 SQL Server 2000

SQL Server 是不是在复杂视图中传播 WHERE 条件?

从 DB2 存储过程出口处理程序传播默认 SQL 异常