通过SQL%BULK\u异常传播触发的异常

通过SQL%BULK\u异常传播触发的异常,sql,oracle,plsql,Sql,Oracle,Plsql,我正在处理一个包含{FORALL..SAVE EXCEPTIONS..UPDATE}语句的PL/SQL包 使用将要更新的数据表上的触发器来检查数据(对于业务规则)的有效性。此触发器调用能够使用以下方法生成错误的过程: RAISE_APPLICATION_ERROR( -20002, 'message'); 因此,在{FORALL..SAVE EXCEPTIONS..UPDATE}DML语句期间,可能会生成用户定义的错误。但是,当尝试使用SQL%BULK_异常记录异常处理中的错误时,我观察到以下

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

使用将要更新的数据表上的触发器来检查数据(对于业务规则)的有效性。此触发器调用能够使用以下方法生成错误的过程:

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

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\u异常的错误代码将丢失减号。此外,除了错误代码外,错误消息为空

我有两个问题:

  • (用户定义的)错误消息不会通过bulk_异常返回。(标准错误并非如此!例如:如果FORALL-UPDATE由于列大小限制而失败,则来自bulk_异常的错误消息可能是:“ORA-12899:值对于列来说太大”,并且不会为空。)
  • 引发此异常时,将传递SQLCODE+SQLERRM“ORA-24381:array DML中的错误”,而不是实际触发的(用户定义,-20000)错误代码和消息

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

一般来说,
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;
然后,您可以在代码中调用
mysqlerrm
(或者直接使用
pkg\u error\u code.g\u error\u code(SQL%BULK\u异常(i).error\u code)
,如果您愿意的话)

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

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