Поиск…


Вступление

Oracle производит множество исключений. Вы можете быть удивлены, насколько утомительным может быть ваш код с некоторым неясным сообщением. Чтобы улучшить способность кода PL / SQL легко фиксироваться, необходимо обрабатывать исключения на самом низком уровне. Никогда не скрывайте исключение «под ковром», если только вы здесь, чтобы сохранить свою часть кода только для вас и никому больше не поддерживать.

Предопределенные ошибки .

Обработка исключений

  1. Что такое исключение?

    Исключение в PL / SQL является ошибкой, созданной во время выполнения программы.

    У нас есть три типа исключений:

    • Исключенные внутри страны исключения
    • Предопределенные исключения
    • Пользовательские исключения
  1. Что такое обработка исключений?

    Обработка исключений - это возможность поддерживать нашу программу даже при появлении ошибки времени выполнения, вызванной, например, ошибками кодирования, сбоями оборудования. Мы избегаем его внезапного выхода из строя.

Синтаксис

Общий синтаксис для секции исключения:

declare
    declaration Section
begin
    some statements

exception
    when exception_one then
        do something
    when exception_two then
        do something
    when exception_three then
        do something
    when others then
        do something
end;

Секция исключений должна быть в конце блока PL / SQL. PL / SQL дает нам возможность блокировать блоки, тогда каждый блок может иметь свой собственный раздел исключения, например:

create or replace procedure nested_blocks
is
begin
    some statements
    begin
        some statements
        
    exception
        when exception_one then
            do something
    end;
exception 
    when exception_two then
        do something
end;

Если исключение будет поднято во вложенном блоке, оно должно быть обработано во внутреннем разделе исключения, но если внутренняя секция исключения не обрабатывает это исключение, то это исключение перейдет в секцию исключения внешнего блока.

Исключенные внутри страны исключения

Внутренне определенное исключение не имеет имени, но имеет свой собственный код.

Когда его использовать?

Если вы знаете, что в вашей операции с базой данных могут возникать определенные исключения, те, у которых нет имен, вы можете дать им имена, чтобы вы могли специально писать для них обработчики исключений. В противном случае вы можете использовать их только с others обработчиками исключений.

Синтаксис

declare 
    my_name_exc exception;
    pragma exception_init(my_name_exc,-37);
begin
    ...
exception 
    when my_name_exc then
        do something
end;

my_name_exc exception; это объявление имени исключения.

pragma exception_init(my_name_exc,-37); присваивать имя коду ошибки внутреннего исключения.

пример

У нас есть emp_id, который является первичным ключом в таблице emp и внешним ключом в таблице dept. Если мы попытаемся удалить emp_id, когда у него есть дочерние записи, он будет исключен с кодом -2292.

create or replace procedure remove_employee
is
    emp_exception exception;
    pragma exception_init(emp_exception,-2292);
begin
    delete from emp where emp_id = 3;
exception
    when emp_exception then
        dbms_output.put_line('You can not do that!');
end;
/

Документация Oracle гласит: «Внутренне определенное исключение с объявленным пользователем именем по-прежнему является внутренне определенным исключением, а не определяемым пользователем исключением».

Предопределенные исключения

Предопределенные исключения являются внутренне определенными исключениями, но имеют имена. База данных Oracle автоматически генерирует этот тип исключений.

пример

create or replace procedure insert_emp
is
begin
    insert into emp (emp_id, ename) values ('1','Jon');

exception
    when dup_val_on_index then
        dbms_output.put_line('Duplicate value on index!');
end;
/

Ниже приведены примеры исключений с их кодами:

Имя исключения Код ошибки
ДАННЫЕ НЕ НАЙДЕНЫ -1403
ACCESS_INTO_NULL -6530
CASE_NOT_FOUND -6592
ROWTYPE_MISMATCH -6504
TOO_MANY_ROWS -1422
ZERO_DIVIDE -1476

Полный список имен исключений и их кодов на веб-сайте Oracle.

Пользовательские исключения

Как видно из названия, пользовательские исключения создаются пользователями. Если вы хотите создать свое собственное исключение, вы должны:

  1. Объявить исключение
  2. Поднимите его из своей программы
  3. Создайте подходящий обработчик исключений, чтобы поймать его.

пример

Я хочу обновить все зарплаты рабочих. Но если нет рабочих, создайте исключение.

create or replace procedure update_salary
is
    no_workers exception;
    v_counter number := 0;
begin
    select count(*) into v_counter from emp;
    if v_counter = 0 then
        raise no_workers;
    else
        update emp set salary = 3000;
    end if;

    exception
        when no_workers then
            raise_application_error(-20991,'We don''t have workers!');                
end;
/

Что значит raise ?

Исключения создаются сервером базы данных автоматически, когда есть необходимость, но если вы хотите, вы можете явно выражать любое исключение, используя raise .

Процедура raise_application_error(error_number,error_message);

  • error_number должен находиться между -20000 и -20999
  • error_message для отображения при возникновении ошибки.

Определите настраиваемое исключение, поднимите его и посмотрите, откуда он

Чтобы проиллюстрировать это, вот функция, которая имеет 3 разных «неправильных» поведения

  • параметр полностью тупой: мы используем пользовательское выражение
  • параметр имеет опечатку: мы используем стандартную ошибку Oracle NO_DATA_FOUND
  • другой, но не обработанный случай

Не стесняйтесь адаптировать его к своим стандартам:

DECLARE
  this_is_not_acceptable EXCEPTION;
  PRAGMA EXCEPTION_INIT(this_is_not_acceptable, -20077);
  g_err varchar2 (200) := 'to-be-defined';
  w_schema all_tables.OWNER%Type;

  PROCEDURE get_schema( p_table in Varchar2, p_schema out Varchar2)
  Is 
    w_err varchar2 (200) := 'to-be-defined';
  BEGIN
    w_err := 'get_schema-step-1:';
    If (p_table = 'Delivery-Manager-Is-Silly') Then
      raise this_is_not_acceptable;
    end if;
    w_err := 'get_schema-step-2:';
    Select owner Into p_schema 
      From all_tables
     where table_name like(p_table||'%');
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
    -- handle Oracle-defined exception
     dbms_output.put_line('[WARN]'||w_err||'This can happen. Check the table name you entered.');
  WHEN this_is_not_acceptable THEN
    -- handle your custom error
     dbms_output.put_line('[WARN]'||w_err||'Please don''t make fun of the delivery manager.');
  When others then
     dbms_output.put_line('[ERR]'||w_err||'unhandled exception:'||sqlerrm);
     raise;    
  END Get_schema;  

BEGIN
  g_err := 'Global; first call:';
  get_schema('Delivery-Manager-Is-Silly', w_schema);
  g_err := 'Global; second call:';
  get_schema('AAA', w_schema);
  g_err := 'Global; third call:';
  get_schema('', w_schema);
  g_err := 'Global; 4th call:';
  get_schema('Can''t reach this point due to previous error.', w_schema);
  
EXCEPTION
  When others then
     dbms_output.put_line('[ERR]'||g_err||'unhandled exception:'||sqlerrm);
  -- you may raise this again to the caller if error log isn't enough.
--  raise;
END;
/

Предоставление регулярной базы данных:

[WARN]get_schema-step-1:Please don't make fun of the delivery manager.
[WARN]get_schema-step-2:This can happen. Check the table name you entered.
[ERR]get_schema-step-2:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
[ERR]Global; third call:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows

Помните, что исключение здесь для обработки редких случаев. Я видел приложения, которые создавали исключение при каждом доступе, просто чтобы запросить пароль пользователя, сказав «не подключен» ... столько отходов вычислений.

Исключение ошибок связи

Каждая стандартная ошибка Oracle связана с номером ошибки. Важно предугадать, что может пойти не так в коде. Здесь для подключения к другой базе данных это может быть:

  • -28000 заблокирован
  • -28001 пароль истек
  • -28002 льготный период
  • -1017 неправильный пользователь / пароль

Вот способ проверить, что не так с пользователем, используемым ссылкой базы данных:

declare
  v_dummy number;
begin
  -- testing db link
  execute immediate 'select COUNT(1) from dba_users@pass.world' into v_dummy ;
  -- if we get here, exception wasn't raised: display COUNT's result
  dbms_output.put_line(v_dummy||' users on PASS db');

EXCEPTION
  -- exception can be referred by their name in the predefined Oracle's list
    When LOGIN_DENIED 
    then  
        dbms_output.put_line('ORA-1017 / USERNAME OR PASSWORD INVALID, TRY AGAIN');
    When Others 
    then 
  -- or referred by their number: stored automatically in reserved variable SQLCODE    
        If  SQLCODE = '-2019'
        Then    
          dbms_output.put_line('ORA-2019 / Invalid db_link name');
        Elsif SQLCODE = '-1035'
        Then
          dbms_output.put_line('ORA-1035 / DATABASE IS ON RESTRICTED SESSION, CONTACT YOUR DBA');        
        Elsif SQLCODE = '-28000'
        Then
          dbms_output.put_line('ORA-28000 / ACCOUNT IS LOCKED. CONTACT YOUR DBA');
        Elsif SQLCODE = '-28001'
        Then
          dbms_output.put_line('ORA-28001 / PASSWORD EXPIRED. CONTACT YOUR DBA FOR CHANGE');
        Elsif SQLCODE  = '-28002'
        Then
          dbms_output.put_line('ORA-28002 / PASSWORD IS EXPIRED, CHANGED IT');
        Else
   -- and if it's not one of the exception you expected
          dbms_output.put_line('Exception not specifically handled');
          dbms_output.put_line('Oracle Said'||SQLCODE||':'||SQLERRM);
        End if;
END;
/


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow