¿Es posible crear excepciones definidas por el usuario y poder cambiar SQLERRM?
Por ejemplo:
DECLARE
ex_custom EXCEPTION;
BEGIN
RAISE ex_custom;
EXCEPTION
WHEN ex_custom THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
El resultado es "Excepción definida por el usuario". ¿Es posible cambiar ese mensaje?
EDITAR: Aquí hay algunos detalles más.
Espero que este ilustre mejor lo que trato de hacer.
DECLARE
l_table_status VARCHAR2(8);
l_index_status VARCHAR2(8);
l_table_name VARCHAR2(30) := 'TEST';
l_index_name VARCHAR2(30) := 'IDX_TEST';
ex_no_metadata EXCEPTION;
BEGIN
BEGIN
SELECT STATUS
INTO l_table_status
FROM USER_TABLES
WHERE TABLE_NAME = l_table_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- raise exception here with message saying
-- "Table metadata does not exist."
RAISE ex_no_metadata;
END;
BEGIN
SELECT STATUS
INTO l_index_status
FROM USER_INDEXES
WHERE INDEX_NAME = l_index_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- raise exception here with message saying
-- "Index metadata does not exist."
RAISE ex_no_metadata;
END;
EXCEPTION
WHEN ex_no_metadata THEN
DBMS_OUTPUT.PUT_LINE('Exception will be handled by handle_no_metadata_exception(SQLERRM) procedure here.');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
En realidad, hay docenas de esos sub-bloques. Me pregunto si hay una manera de tener una única excepción definida por el usuario para que se genere cada uno de esos sub-bloques, pero que dé un mensaje diferente, en lugar de crear una excepción definida por el usuario separada para cada sub-bloque.
En .NET, sería como tener una excepción personalizada como esta:
public class ColorException : Exception
{
public ColorException(string message)
: base(message)
{
}
}
Y luego, un método tendría algo como esto:
if (isRed)
{
throw new ColorException("Red is not allowed!");
}
if (isBlack)
{
throw new ColorException("Black is not allowed!");
}
if (isBlue)
{
throw new ColorException("Blue is not allowed!");
}
fuente
Podrías usar RAISE_APPLICATION_ERROR así:
DECLARE ex_custom EXCEPTION; BEGIN RAISE ex_custom; EXCEPTION WHEN ex_custom THEN RAISE_APPLICATION_ERROR(-20001,'My exception was raised'); END; /
Eso generará una excepción que se parece a:
El número de error puede estar comprendido entre -20001 y -20999.
fuente
Por lo general, pierdo la pista de todos mis
-20001
códigos de error de tipo, así que trato de consolidar todos los errores de mi aplicación en un paquete agradable como este:SET SERVEROUTPUT ON CREATE OR REPLACE PACKAGE errors AS invalid_foo_err EXCEPTION; invalid_foo_num NUMBER := -20123; invalid_foo_msg VARCHAR2(32767) := 'Invalid Foo!'; PRAGMA EXCEPTION_INIT(invalid_foo_err, -20123); -- can't use var >:O illegal_bar_err EXCEPTION; illegal_bar_num NUMBER := -20156; illegal_bar_msg VARCHAR2(32767) := 'Illegal Bar!'; PRAGMA EXCEPTION_INIT(illegal_bar_err, -20156); -- can't use var >:O PROCEDURE raise_err(p_err NUMBER, p_msg VARCHAR2 DEFAULT NULL); END; / CREATE OR REPLACE PACKAGE BODY errors AS unknown_err EXCEPTION; unknown_num NUMBER := -20001; unknown_msg VARCHAR2(32767) := 'Unknown Error Specified!'; PROCEDURE raise_err(p_err NUMBER, p_msg VARCHAR2 DEFAULT NULL) AS v_msg VARCHAR2(32767); BEGIN IF p_err = unknown_num THEN v_msg := unknown_msg; ELSIF p_err = invalid_foo_num THEN v_msg := invalid_foo_msg; ELSIF p_err = illegal_bar_num THEN v_msg := illegal_bar_msg; ELSE raise_err(unknown_num, 'USR' || p_err || ': ' || p_msg); END IF; IF p_msg IS NOT NULL THEN v_msg := v_msg || ' - '||p_msg; END IF; RAISE_APPLICATION_ERROR(p_err, v_msg); END; END; /
Luego llame
errors.raise_err(errors.invalid_foo_num, 'optional extra text')
para usarlo, así:BEGIN BEGIN errors.raise_err(errors.invalid_foo_num, 'Insufficient Foo-age!'); EXCEPTION WHEN errors.invalid_foo_err THEN dbms_output.put_line(SQLERRM); END; BEGIN errors.raise_err(errors.illegal_bar_num, 'Insufficient Bar-age!'); EXCEPTION WHEN errors.illegal_bar_err THEN dbms_output.put_line(SQLERRM); END; BEGIN errors.raise_err(-10000, 'This Doesn''t Exist!!'); EXCEPTION WHEN OTHERS THEN dbms_output.put_line(SQLERRM); END; END; /
produce esta salida:
fuente
true
(en lugar del predeterminadofalse
) para obtener un seguimiento de pila completo.declare z exception; begin if to_char(sysdate,'day')='sunday' then raise z; end if; exception when z then dbms_output.put_line('to day is sunday'); end;
fuente
create or replace PROCEDURE PROC_USER_EXP AS duplicate_exp EXCEPTION; PRAGMA EXCEPTION_INIT( duplicate_exp, -20001 ); LVCOUNT NUMBER; BEGIN SELECT COUNT(*) INTO LVCOUNT FROM JOBS WHERE JOB_TITLE='President'; IF LVCOUNT >1 THEN raise_application_error( -20001, 'Duplicate president customer excetpion' ); END IF; EXCEPTION WHEN duplicate_exp THEN DBMS_OUTPUT.PUT_LINE(sqlerrm); END PROC_USER_EXP;
La salida de ORACLE 11g será así:
fuente