Oracle PL/SQL - повысить пользовательское исключение с помощью пользовательского SQLERRM
Можно ли создавать определяемые пользователем исключения и иметь возможность изменять SQLERRM?
Например:
DECLARE
ex_custom EXCEPTION;
BEGIN
RAISE ex_custom;
EXCEPTION
WHEN ex_custom THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
Вывод "Пользовательское исключение". Можно ли изменить это сообщение?
РЕДАКТИРОВАТЬ: Вот еще несколько деталей.
Я надеюсь, что этот иллюстрирует то, что я пытаюсь сделать лучше.
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;
/
На самом деле, есть десятки таких подблоков. Мне интересно, есть ли способ создать по одному отдельному пользовательскому исключению для каждого из этих подблоков, но дать ему другое сообщение вместо создания отдельного пользовательского исключения для каждого подблока.
В.NET это было бы похоже на пользовательское исключение, подобное этому:
public class ColorException : Exception
{
public ColorException(string message)
: base(message)
{
}
}
И тогда метод будет иметь что-то вроде этого:
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!");
}
5 ответов
Да. Вы просто должны использовать RAISE_APPLICATION_ERROR
функция. Если вы также хотите назвать свое исключение, вам нужно использовать EXCEPTION_INIT
Прагма, чтобы связать номер ошибки с именованным исключением. Что-то вроде
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.
Вы можете использовать RAISE_APPLICATION_ERROR следующим образом:
DECLARE
ex_custom EXCEPTION;
BEGIN
RAISE ex_custom;
EXCEPTION
WHEN ex_custom THEN
RAISE_APPLICATION_ERROR(-20001,'My exception was raised');
END;
/
Это вызовет исключение, которое выглядит так:
ORA-20001: My exception was raised
Номер ошибки может быть любым между -20001 и -20999.
Я обычно теряю все свои -20001
-типы кодов ошибок, поэтому я пытаюсь объединить все ошибки моего приложения в хороший пакет, например:
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;
/
Тогда позвони errors.raise_err(errors.invalid_foo_num, 'optional extra text')
использовать его, например:
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;
/
производит этот вывод:
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;