Est-il possible de créer des exceptions définies par l'utilisateur et de pouvoir changer SQLERRM?
Par exemple:
DECLARE
ex_custom EXCEPTION;
BEGIN
RAISE ex_custom;
EXCEPTION
WHEN ex_custom THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
Le résultat est "Exception définie par l'utilisateur". Est-il possible de changer ce message?
EDIT: Voici quelques détails supplémentaires.
J'espère que celui-ci illustre ce que j'essaie de faire mieux.
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 réalité, il existe des dizaines de ces sous-blocs. Je me demande s'il existe un moyen de créer une seule exception définie par l'utilisateur pour chacun de ces sous-blocs, mais de lui donner un message différent, au lieu de créer une exception distincte définie par l'utilisateur pour chaque sous-bloc.
En .NET, cela ressemblerait à avoir une exception personnalisée comme celle-ci:
public class ColorException : Exception
{
public ColorException(string message)
: base(message)
{
}
}
Et puis, une méthode aurait quelque chose comme ça:
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!");
}
Oui. Vous devez juste utiliser la fonction RAISE_APPLICATION_ERROR
. Si vous souhaitez également nommer votre exception, vous devez utiliser le pragma EXCEPTION_INIT
afin d'associer le numéro d'erreur à l'exception nommée. Quelque chose comme
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.
Vous pouvez utiliser RAISE_APPLICATION_ERROR comme ceci:
DECLARE
ex_custom EXCEPTION;
BEGIN
RAISE ex_custom;
EXCEPTION
WHEN ex_custom THEN
RAISE_APPLICATION_ERROR(-20001,'My exception was raised');
END;
/
Cela soulèvera une exception qui ressemble à:
ORA-20001: My exception was raised
Le numéro d'erreur peut être compris entre -20001 et -20999.
Habituellement, je perds la trace de tous mes codes d'erreur de type -20001
-. J'essaie donc de regrouper toutes mes erreurs d'application dans un package Nice comme celui-ci:
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;
/
Ensuite, appelez errors.raise_err(errors.invalid_foo_num, 'optional extra text')
pour l'utiliser, comme ceci:
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;
/
produit cette sortie:
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!!
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;
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 sortie d'Oracle 11g sera comme ceci:
Connecting to the database HR.
ORA-20001: Duplicate president customer excetpion
Process exited.
Disconnecting from the database HR