Общий код для нескольких конкретных исключений в PL / SQL - PullRequest
2 голосов
/ 26 июня 2019

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

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

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

Это нормально, и я понимаю, как использовать WHEN <EXCEPTION_NAME> THEN.

Проблема, с которой я столкнулся, заключается в том, что я не могу написать общий код, который возникает для любого исключенияподнятый, чтобы сделать что-то, что я всегда хочу сделать в случае исключения, например, записи в файл журнала.Это означает, что мне нужно продублировать строки кода для каждого типа исключения, как показано ниже.

DECLARE
    test_exception EXCEPTION;
BEGIN
    --some code
    RAISE test_exception;
    --some code
EXCEPTION        
    WHEN test_exception THEN        
        SEND_EMAIL('Something went wrong');
        WRITE_TO_LOG('Error ' || SQLCODE || ' | ' || SUBSTR(SQLERRM, 1, 200) || ' | ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    WHEN OTHERS THEN     
        SOME_OTHER_FUNCTION();
        WRITE_TO_LOG('Error ' || SQLCODE || ' | ' || SUBSTR(SQLERRM, 1, 200) || ' | ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE); 
END;

Я хотел бы добиться чего-то похожего на это, которое не компилируется.

DECLARE
    test_exception EXCEPTION;
BEGIN
    --some code
    RAISE test_exception;
    --some code
EXCEPTION        

    WRITE_TO_LOG('Error ' || SQLCODE || ' | ' || SUBSTR(SQLERRM, 1, 200) || ' | ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);

    WHEN test_exception THEN        
        SEND_EMAIL('Something went wrong');
    WHEN OTHERS THEN      
        SOME_OTHER_FUNCTION();
END;

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

Есть ли предложение WHEN ALL THEN или подобное?Будет ли это вариант использования для какого-то GOTO?Или я пытаюсь применить неправильную концепцию здесь.

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

Спасибо

Ответы [ 2 ]

3 голосов
/ 26 июня 2019

PL / SQL будет выполнять только один блок исключения. Поэтому, если у вас есть некоторый общий код (например, ведение журнала), который вы хотите запустить для каждого исключения, вы должны сделать это в when others.

Затем отметьте sqlcode, чтобы выполнить специфическую обработку исключений. Например:

begin

  raise TOO_MANY_ROWS;

exception
  when others then
    dbms_output.put_line ( 'Generic stuff' );
    case sqlcode 
      when -1422 then
        dbms_output.put_line ( 'TMR specific' );
      when -1476 then
        dbms_output.put_line ( 'ZD specific' );
      else
        null;
    end case;

    raise;
end;
/

Generic stuff
TMR specific

ORA-01422: exact fetch returns more than requested number of rows

begin

  raise ZERO_DIVIDE;

exception
  when others then
    dbms_output.put_line ( 'Generic stuff' );
    case sqlcode 
      when -1422 then
        dbms_output.put_line ( 'TMR specific' );
      when -1476 then
        dbms_output.put_line ( 'ZD specific' );
      else
        null;
    end case;

    raise;
end;
/

Generic stuff
ZD specific

ORA-01476: divisor is equal to zero

Теперь, является ли это хорошей идеей спорным.

when others блоки исключений должны каким-то образом повторно вызывать исключение. Это предотвращает серьезные непредвиденные ошибки (например, нехватку места на диске). Но для некоторых конкретных исключений вы можете продолжить обработку.


Добавление

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

Затем вы можете использовать эти определения для пользовательских исключений:

create or replace package excepts as 

  user_defined exception ;
  user_defined_val pls_integer := -20001;
  pragma exception_init ( user_defined, -20001 );

end;
/

begin

  raise excepts.USER_DEFINED;

exception
  when others then
    dbms_output.put_line ( 'Generic stuff' );
    case sqlcode 
      when -1422 then
        dbms_output.put_line ( 'TMR specific' );
      when -1476 then
        dbms_output.put_line ( 'ZD specific' );
      when excepts.user_defined_val then
        dbms_output.put_line ( 'User-defined specific' );
      else
        null;
    end case;

    raise;
end;
/

Generic stuff
User-defined specific

ORA-20001: 
0 голосов
/ 26 июня 2019

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

    DECLARE
    test_exception EXCEPTION;
begin
      RAISE test_exception;

    --some code
EXCEPTION        
    WHEN OTHERS THEN
      BEGIN
         dbms_output.put_line( 'WRITE_TO_LOG');
         RAISE;
      EXCEPTION
        WHEN test_exception THEN
          dbms_output.put_line( 'test_exception');
         WHEN OTHERS THEN
        dbms_output.put_line( 'some other function');
     end;
END;

Выход:

WRITE_TO_LOG
send mail
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...