Обработка ошибок, возникших при выполнении кода PL/SQL, страница 2

Связывание исключения со стандартным номером ошибки осуществляется с помощью директивы PRAGMA. Эта директива выполняется во время компиляции, а не во время выполнения. Она определяет, что компилятор должен обработать специфичное для языка условие.

DECLARE

   имя_исключения EXCEPTION;

PRAGMAEXCEPTION_INIT (имя_исключения, номер_ошибки);

   ...

BEGIN

   операторы;

EXCEPTION

WHEN имя_исключенияTHEN

      операторы;

   ...

END;

имя_исключения – имя исключения

номер_ошибки – номер стандартной ошибки сервера Oracle

Рассмотрим пример обработки стандартной ошибки сервера Oracle – нарушение целостности. Эта ошибка не является предопределенным исключением, поэтому, прежде чем ссылаться на исключение в секции обработки исключений, необходимо описать это исключение и связать его с номером стандартной ошибки сервера Oracle (-2291 – родительский ключ не найден).

SQL> SELECT * FROM dept;

    DEPTNO DNAME          LOC

---------- -------------- -------------

        10 ACCOUNTING     NEW_YORK

        20 RESEARCH       DALLAS

        30 SALES          CHICAGO

        40 OPERATIONS     BOSTON

SQL> DECLARE

  2     e_no_dept EXCEPTION;

  3     PRAGMA EXCEPTION_INIT (e_no_dept, -2291);

  4  BEGIN

  5     INSERT INTO emp (empno, deptno) VALUES (99, 50);

  6  EXCEPTION

  7     WHEN e_no_dept THEN

  8        DBMS_OUTPUT.put_line ('Parent key is not found');

  9     WHEN OTHERS THEN

 10        DBMS_OUTPUT.put_line ('Other error occurred');

 11  END;

 12  /

Parent key is not found

PL/SQL procedure successfully completed.

Перехват пользовательских исключений

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

DECLARE

   имя_исключенияEXCEPTION;

   ...

BEGIN

   ...

RAISE имя_исключения;

   ...

EXCEPTION

WHEN имя_исключенияTHEN

      операторы;

   ...

END;

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

SQL> VARIABLE v_job VARCHAR2(20);

SQL> EXECUTE :v_job := 'President'

PL/SQL procedure successfully completed.

SQL> DECLARE

  2     e_president_exist EXCEPTION;

  3     v_count NUMBER;

  4  BEGIN

  5     SELECT COUNT(*) INTO v_count FROM emp WHERE LOWER(job)=LOWER(:v_job);

  6     IF LOWER(:v_job)='president' AND v_count>0 THEN

  7        RAISE e_president_exist;

  8     END IF;

  9  EXCEPTION

 10     WHEN e_president_exist THEN

 11        DBMS_OUTPUT.put_line('President exist already!');

 12  END;

 13  /

President exist already!

PL/SQL procedure successfully completed.

Функции для перехвата ошибок

Для обработки всех ошибок, которые не были перехвачены обработчиками исключений, используется предложение WHEN OTHERS. Обработчик WHEN OTHERS может быть только один и всегда располагается после всех других обработчиков исключений. Чтобы определить, какое именно исключение перехвачено обработчиком исключений, можно использовать две функции:

·  SQLCODE – возвращает числовое значение кода ошибки

-  0 – исключений не было

-  1 – пользовательское исключение

-  +100 – исключение NO_DATA_FOUND

-  отрицательное целое – номер ошибки сервера Oracle

·  SQLERRM – возвращает сообщение, связанное с кодом ошибки

Почти все коды исключений сервера Oracle имеют отрицательное значение, кроме NO_DATA_FOUND, код которого +100. Это происходит потому, что в соответствии со стандартом ANSI, если строка не найдена значение SQLCODE должно быть равно +100.

SQL> VARIABLE v_job VARCHAR2(20);

SQL> EXECUTE :v_job := 'Engineer'

PL/SQL procedure successfully completed.

SQL> DECLARE

  2     v_error_code NUMBER;

  3     v_error_text VARCHAR2(100);

  4     v_sal emp.sal%TYPE;

  5  BEGIN

  6     SELECT sal INTO v_sal FROM emp WHERE LOWER(job)=LOWER(:v_job);

  7     DBMS_OUTPUT.put_line('Salary of ' || :v_job || ' is ' || TO_CHAR(v_sal));

  8  EXCEPTION

  9     WHEN OTHERS THEN

 10        v_error_code := SQLCODE;

 11        v_error_text := SQLERRM;

 12        DBMS_OUTPUT.put_line(TO_CHAR(v_error_code) || ' - ' || v_error_text);

 13  END;

 14  /

100 - ORA-01403: no data found

PL/SQL procedure successfully completed.

Обработка исключений во вложенных блоках

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

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

Если ни в одном из внешних блоков не будет найден подходящий обработчик исключения, исключение распространяется в вызывающую среду. Каждая вызывающая среда имеет собственные средства для показа ошибок. Например, SQL*Plus выдает на экран номер необработанного исключения и соответствующее сообщение.

SQL> DECLARE

  2     v_error_code NUMBER;

  3     v_error_text VARCHAR2(100);

  4     v_sal emp.sal%TYPE;

  5  BEGIN

  6     SELECT sal INTO v_sal FROM emp WHERE LOWER(job)=LOWER(:v_job);

  7     DBMS_OUTPUT.put_line('Salary of ' || :v_job || ' is ' || TO_CHAR(v_sal));

  8  END;

  9  /

DECLARE

*

ERROR at line 1:

ORA-01403: no data found

ORA-06512: at line 6

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

EXCEPTION

   WHEN OTHERS THEN

      BEGIN

         операторы;

      EXCEPTION

         WHEN OTHERS THEN

            NULL;

      END;

END;

Именованные блоки PL/SQL

Именованные блоки PL/SQL называются программными единицами. Программные единицы делятся на три категории:

§  Процедуры, позволяющие задавать параметры и выполняющие заданные действия

§  Функции, позволяющие задавать параметры, вычисляющие и возвращающие значения

§  Пакеты, объединяющие логически связанные процедуры и функции

Программные единицы подразделяются на хранимые и прикладные подпрограммы (подпрограммы приложения):