2011-05-16 1137 views
62

¿Es posible crear excepciones definidas por el usuario y poder cambiar el SQLERRM?Oracle PL/SQL - Elevar la excepción definida por el usuario con SQLERRM personalizado

Por ejemplo:

DECLARE 
    ex_custom  EXCEPTION; 
BEGIN 
    RAISE ex_custom; 
EXCEPTION 
    WHEN ex_custom THEN 
     DBMS_OUTPUT.PUT_LINE(SQLERRM); 
END; 
/

la salida es "Excepción definido por el usuario". ¿Es posible cambiar ese mensaje?

EDITAR: Aquí hay más detalles.

Espero que este ilustre lo que trato de hacer mejor.

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 forma de hacer que una única excepción definida por el usuario para cada uno de esos subbloques se eleve, pero que proporcione un mensaje diferente, en lugar de crear una excepción separada definida por el usuario para cada subbloque.

En .NET, sería algo así como tener una excepción personalizada así:

public class ColorException : Exception 
    { 
     public ColorException(string message) 
      : base(message) 
     { 
     } 
    } 

Y entonces, 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!"); 
     } 
+0

Lo siento si yo no estaba clara. Agregaré otro ejemplo. – tgxiii

Respuesta

117

Sí. Solo tiene que usar la función RAISE_APPLICATION_ERROR. Si también desea nombrar su excepción, deberá usar el pragma EXCEPTION_INIT para asociar el número de error a la excepción especificada. Algo así como

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 ex_custom EXCEPTION; 
    3 PRAGMA EXCEPTION_INIT(ex_custom, -20001); 
    4 begin 
    5 raise_application_error(-20001, 'This is a custom error'); 
    6 exception 
    7 when ex_custom 
    8 then 
    9  dbms_output.put_line(sqlerrm); 
10* end; 
SQL>/
ORA-20001: This is a custom error 

PL/SQL procedure successfully completed. 
+1

¡Exactamente lo que necesito! Supongo que hice mi edición mientras usted ya había respondido mi pregunta. Muchas gracias. – tgxiii

29

Usted podría utilizar RAISE_APPLICATION_ERROR como este:

DECLARE 
    ex_custom  EXCEPTION; 
BEGIN 
    RAISE ex_custom; 
EXCEPTION 
    WHEN ex_custom THEN 
     RAISE_APPLICATION_ERROR(-20001,'My exception was raised'); 
END; 
/

Eso levantará una excepción que se parece a:

ORA-20001: My exception was raised 

El número de error puede ser cualquiera entre -20001 y -20999.

4
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; 
19

que suelo perder el rastro de todos mis -20001 de tipo códigos de error, así que trato de consolidar todos mis errores de aplicación en un paquete agradable, como por ejemplo:

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; 
/

Entonces errors.raise_err(errors.invalid_foo_num, 'optional extra text') llamar a utilizarlo, como por ejemplo:

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:

ORA-20123: Invalid Foo! - Insufficient Foo-age! 
ORA-20156: Illegal Bar! - Insufficient Bar-age! 
ORA-20001: Unknown Error Specified! - USR-10000: This Doesn't Exist!! 
+1

Buen consejo! ¡Fue muy útil para mi proyecto! – SnakeSheet

+1

Esta es una buena práctica. Dos problemas menores en [raise_application_error] (http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/errors.htm#LNPLS99960) pensaban: 1) el tamaño del 2º parámetro está limitado a 2048 bytes y 2) Prefiero que el 3er parámetro sea 'true' (en lugar del' false' predeterminado) para obtener un seguimiento completo de la pila. – user272735

2
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; 
+0

La salida de ORACLE 11g será así: -Conectando a la base de datos HR. ORA-20001: cliente duplicado cliente excetpion Proceso salido. Desconexión de la base de datos HR. –

Cuestiones relacionadas