Soporte de excepciones y mensajes de error

Cualquier error que se produzca en un procedimiento NZPLSQL finaliza de forma abrupta la ejecución del procedimiento e interrumpe la transacción circundante. El sistema vuelve al bucle principal para obtener la siguiente consulta de la aplicación cliente. No es posible detectar todas las excepciones, especialmente si esa acción deja la base de datos en un estado incorrecto.

Para detectar y procesar un error que se produce en un bloque de procedimiento, puede añadir una sección de manejo de excepciones al final del bloque utilizando la palabra clave EXCEPTION. Si no se producen errores, la sección de manejo de excepciones no se tiene en cuenta. En la sección de manejo de excepciones, puede especificar uno o más manejadores de excepciones utilizando cláusulas WHEN que especifican la excepción que debe coincidir y las sentencias que se deben ejecutar cuando se produce una coincidencia. Una sentencia EXCEPTION tiene el formato siguiente:

EXCEPTION 
    WHEN clause THEN
        statements 
    [ WHEN ... ] 

NZPLSQL admite dos cláusulas para el proceso de excepción:

TRANSACTION_ABORTED
Utilice la cláusula TRANSACTION_ABORTED para especificar las sentencias que desea ejecutar cuando se produce un error que hace que la transacción termine anormalmente. En este caso, se necesita un ROLLBACK para continuar. Asegúrese de que el mandato ROLLBACK es el primer mandato de las sentencias de manejo de excepciones.
OTROS
Utilice la cláusula OTHERS para especificar las sentencias a ejecutar cuando se produce cualquier error en el bloque de procedimiento. Los errores tales como un error de análisis de SQL no terminan anormalmente la transacción y, por consiguiente, no coincidirán con una cláusula TRANSACTION_ABORTED.

Puede especificar ambas cláusulas en un bloque de excepción, como en el siguiente ejemplo. Cuando se produce un error en el procedimiento, el código de procedimiento utiliza la primera cláusula de excepción coincidente y ejecuta las sentencias de dicha cláusula. Las cláusulas después de la coincidencia se ignoran. Como práctica recomendada, especifique la cláusula OTHERS en último lugar porque coincide con cualquier tipo de error.

EXCEPTION 
    WHEN TRANSACTION_ABORTED THEN
       ROLLBACK;
       statements_case1 
       RAISE ERROR 'Procedure failed: %', sqlerrm;
    WHEN OTHERS THEN
       statements_case2
       RAISE NOTICE 'Caught error, continuing %', sqlerrm;

En este ejemplo, un error que termina anormalmente una transacción desencadena la cláusula TRANSACTION_ABORTED y el procedimiento almacenado ejecuta ROLLBACK, las sentencias en statements_case1 y genera el mensaje de error. Si el error no ha hecho que la transacción termine anormalmente, el proceso de excepción salta la cláusula OTHERS y el procedimiento almacenado ejecuta el conjunto statements_case2 y genera el mensaje de aviso. Si no había errores en el bloque, se saltan las sentencias de excepción.

La variable SQLERRM contiene el texto de un mensaje de error que se detecte. En ausencia de un bloque de excepción, la excepción se propaga hacia arriba al siguiente procedimiento almacenado de la pila de llamadas. Si sproc1 llama a sproc2, lo que genera una excepción, pero sproc2 no tiene un manejador de excepciones, el sistema busca un manejador en sproc1. El sistema también consulta las declaraciones de bloque incluidas.

Por ejemplo:
create or replace procedure sp_except01() returns BOOL LANGUAGE 
NZPLSQL AS 
BEGIN_PROC
DECLARE
    r record;
BEGIN
    <<inner>>
    BEGIN
        SELECT * INTO r FROM NONEXISTENT;
    END;
END;
END_PROC;

create or replace procedure sp_except02() returns BOOL LANGUAGE 
NZPLSQL AS 
BEGIN_PROC
BEGIN
    CALL sp_except01();
END;
END_PROC;

create or replace procedure sp_except03() returns BOOL LANGUAGE 
NZPLSQL AS 
BEGIN_PROC
BEGIN
    CALL sp_except02();
    EXCEPTION WHEN OTHERS THEN
        RAISE NOTICE 'Caught exception';
END;
END_PROC;

En estos ejemplos, la excepción se genera en sp_except01, en el bloque interior. El sistema busca primero un manejador de excepciones para el bloque interior, que no se encuentra. El control pasa al contexto padre, que es el procedimiento sp_except01, y tampoco se encuentra en este ámbito ningún manejador de excepciones. Entonces el control pasa a sp_except02 y finalmente sp_except03, donde se encuentra y utiliza un manejador de excepciones.

Si no se detecta ninguna excepción en ningún nivel, se envían mensajes de registro a nivel de AVISO adicionales para proporcionar contexto acerca del error y dónde se ha producido (número de línea y tipo de sentencia, a menos que el error sea de una sentencia RAISE EXCEPTION).

Si incluye manejadores de excepciones en procedimientos almacenados, los manejadores detectan los errores, y no se visualizan. Por ejemplo:
CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
  EXECUTE IMMEDIATE 'insert into NOTEXIST' || 'values(1,1)';
  EXCEPTION WHEN OTHERS THEN
  END;
END_PROC;

Suponiendo que NOTEXIST no existe en la base de datos, la consulta no visualiza ninguna salida de error porque el error lo ha tratado el manejador de excepciones.

Para visualizar el error, escriba el procedimiento de la manera siguiente:
CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
  EXECUTE IMMEDIATE 'insert into NOTEXIST' || ' values(1,1)';
  EXCEPTION WHEN OTHERS THEN
    RAISE NOTICE 'Got exception: %', SQLERRM;
  END;
END_PROC;
Al ejecutar esta consulta, se visualiza la salida siguiente:
NOTICE:  Got exception: ERROR:  Relation 'NOTEXIST' does not exist