Обработка исключений в Oracle PL/SQL (примеры)

⚡ Умное резюме

Обработка исключений в Oracle PL/SQL перехватывает ошибки времени выполнения, которые останавливают выполнение блока кода, позволяя механизму передать управление в секцию EXCEPTION, где предопределенные, определяемые пользователем и обработчики OTHERS безопасно реагируют, генерируют или распространяют ошибки.

  • ⚙️ Ошибки времени выполнения: Исключение возникает, когда механизм PL/SQL встречает инструкцию, которую он не может выполнить, например, деление числа на ноль.
  • 🧱 Блочная структура: Исключения обрабатываются в разделе EXCEPTION с использованием предложений WHEN, при этом предложение WHEN OTHERS всегда располагается в конце.
  • 📚 Предопределенные исключения: Oracle В пакете STANDARD указаны распространенные ошибки, такие как NO_DATA_FOUND и ZERO_DIVIDE, которые можно перехватывать напрямую.
  • 🇧🇷 Пользовательские исключения: Программисты объявляют свои собственные переменные EXCEPTION и явно вызывают исключения с помощью ключевого слова RAISE.
  • 🇧🇷 Распространение: Необработанное исключение передается в окружающий блок, а функция RAISE повторно отправляет сигнал родительской программе.
  • 🤖 Помощь ИИ: Инструменты программирования на основе ИИ создают блоки исключений и отмечают необработанные пути ошибок во время проверки.

Обработка исключений в Oracle PL/SQL

Что такое обработка исключений в PL/SQL?

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

Например, если движок PL/SQL получает инструкцию деления числа на ноль, он генерирует ошибку в виде исключения. Исключение генерируется движком PL/SQL только во время выполнения.

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

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

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

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

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

Приведённый ниже синтаксис объясняет, как перехватывать и обрабатывать исключения.

BEGIN
<execution block>
.
.
EXCEPTION
WHEN <exceptionl_name>
THEN
  <Exception handling code for the “exception 1 _name’' >
WHEN OTHERS
THEN
  <Default exception handling code for all exceptions >
END;

Объяснение синтаксиса:

  • В приведенном выше синтаксисе блок обработки исключений содержит ряд условий WHEN для обработки исключений.
  • За каждым условием WHEN следует имя исключения, которое, как ожидается, будет сгенерировано во время выполнения.
  • Когда во время выполнения возникает исключение, механизм PL/SQL ищет это конкретное исключение в части обработки исключений, начиная с первого предложения WHEN и продвигаясь последовательно.
  • Если обнаруживается обработчик для возникшего исключения, выполняется код этого конкретного обработчика.
  • Если ни один из операторов WHEN не соответствует возникшему исключению, механизм PL/SQL выполняет часть WHEN OTHERS, если она присутствует. Этот обработчик является общим для всех исключений.
  • После выполнения обработчика управление покидает текущий блок.
  • В режиме реального времени для каждого блока может выполняться только один обработчик исключений. После его выполнения движок пропускает остальные обработчики и покидает текущий блок.

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

Типы исключений

В этом случае существуют два типа исключений. PL/SQL.

  • Предопределенные исключения
  • Пользовательские исключения

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

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

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

Исключение Ошибка Code Причина исключения
ACCESS_INTO_NULL ORA-06530 Присвоение значения атрибутам неинициализированного объекта
CASE_NOT_FOUND ORA-06592 Ни один из пунктов WHEN в операторе CASE не выполняется, и пункт ELSE не указан.
COLLECTION_IS_NULL ORA-06531 Использование методов коллекции (кроме EXISTS) или доступ к атрибутам коллекции в неинициализированной коллекции.
CURSOR_ALREADY_OPEN ORA-06511 Пытаюсь открыть курсор который уже открыт
DUP_VAL_ON_INDEX ORA-00001 Хранение повторяющегося значения в столбце базы данных, ограниченном уникальным индексом.
INVALID_CURSOR ORA-01001 Недопустимые операции с курсором, такие как закрытие неоткрытого курсора.
НЕПРАВИЛЬНЫЙ НОМЕР ORA-01722 Преобразование символа в число не удалось из-за недопустимого числового символа.
ДАННЫЕ НЕ НАЙДЕНЫ ORA-01403 Оператор SELECT, содержащий предложение INTO, не извлекает ни одной строки.
ROW_MISMATCH ORA-06504 Тип данных переменной курсора несовместим с фактическим типом возвращаемого значения курсора.
SUBSCRIPT_BEYOND_COUNT ORA-06533 Обращение к коллекции по индексному номеру, размер которого превышает размер коллекции.
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 Обращение к коллекции по индексному номеру, выходящему за пределы допустимого диапазона (например, -1).
TOO_MANY_ROWS ORA-01422 Оператор SELECT с предложением INTO возвращает более одной строки.
VALUE_ERROR ORA-06502 Арифметическая ошибка или ошибка, связанная с ограничением размера (например, присвоение значения, превышающего размер переменной).
ZERO_DIVIDE ORA-01476 Деление числа на ноль

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

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

Синтаксис: на уровне подпрограммы

DECLARE
<exception_name> EXCEPTION;
BEGIN
<Execution block>
EXCEPTION
WHEN <exception_name> THEN
<Handler>
END;
  • В приведенном выше синтаксисе переменная 'exception_name' определена как тип EXCEPTION.
  • Затем его можно использовать так же, как и предопределенное исключение.

Синтаксис: На уровне спецификации пакета

CREATE PACKAGE <package_name>
 IS
<exception_name> EXCEPTION;
.
.
END <package_name>;
  • В приведенном выше синтаксисе переменная 'exception_name' определена как тип EXCEPTION в спецификации пакета. .
  • Его можно использовать во всей базе данных везде, где можно вызвать пакет 'package_name'.

PL/SQL вызывает исключение

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

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

На скриншоте ниже показано использование команды RAISE отдельно для повторного вызова исключения в окружающем блоке:

Передача исключения в родительский блок с помощью простого вызова RAISE.

CREATE [ PROCEDURE | FUNCTION ]
 AS
BEGIN
<Execution block>
EXCEPTION
WHEN <exception_name> THEN
             <Handler>
RAISE;
END;

Объяснение синтаксиса:

  • В приведенном выше синтаксисе ключевое слово RAISE используется внутри блока обработки исключений.
  • Всякий раз, когда программа сталкивается с исключением 'exception_name', исключение обрабатывается, и программа завершает работу в обычном режиме.
  • Затем ключевое слово RAISE в обработчике передает это же исключение в родительскую программу.

Примечание: При генерации исключения в родительском блоке, генерируемое исключение также должно быть видимым в родительском блоке; в противном случае... Oracle выдает ошибку.

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

На скриншоте ниже показано, как с помощью команды RAISE, а затем имени исключения, генерируется конкретное исключение:

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

CREATE [ PROCEDURE | FUNCTION ]
AS
BEGIN
<Execution block>
RAISE <exception_name>
EXCEPTION
WHEN <exception_name> THEN
<Handler>
END;

Объяснение синтаксиса:

  • В приведенном выше синтаксисе ключевое слово RAISE используется в части выполнения, за которым следует имя исключения 'exception_name'.
  • Это приводит к возникновению данного исключения во время выполнения, и затем его необходимо обработать или сгенерировать дополнительно.

Пример 1: В этом примере мы увидим:

  • Как объявить исключение
  • Как вызвать объявленное исключение
  • Как распространить его на основной блок

На скриншоте ниже показан полный блок кода, который объявляет исключение sample_exception, вызывает его внутри вложенного блока и передает его в основной блок:

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

На следующем скриншоте показано продолжение того же примера, где основной блок, наконец, перехватывает распространившееся исключение:

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

DECLARE
Sample_exception EXCEPTION;
PROCEDURE nested_block
IS
BEGIN
Dbms_output.put_line('Inside nested block');
Dbms_output.put_line('Raising sample_exception from nested block');
RAISE sample_exception;
EXCEPTION
WHEN sample_exception THEN
Dbms_output.put_line ('Exception captured in nested block. Raising to main block');
RAISE;
END;
BEGIN
Dbms_output.put_line('Inside main block');
Dbms_output.put_line('Calling nested block');
Nested_block;
EXCEPTION
WHEN sample_exception THEN
Dbms_output.put_line ('Exception captured in main block');
END;
/

Code Объяснение:

  • Code строка 2: Объявление переменной 'sample_exception' как объекта типа EXCEPTION.
  • Code строка 3: Объявление процедуры nested_block.
  • Code строка 6: Вывод сообщения «Внутри вложенного блока».
  • Code строка 7: Выводится сообщение «Вызывается исключение sample_exception из вложенного блока».
  • Code строка 8: Вызов исключения с помощью RAISE sample_Exception.
  • Code строка 10: Обработчик исключений для исключения sample_exception во вложенном блоке.
  • Code строка 11: Выводится сообщение «Исключение перехвачено во вложенном блоке. Вызов функции в основной блок».
  • Code строка 12: Генерация исключения в основной блок (его распространение).
  • Code строка 15: Вывод сообщения «Внутри основного блока».
  • Code строка 16: Печать оператора «Вызов вложенного блока».
  • Code строка 17: Вызов процедуры nested_block.
  • Code строка 19: Обработчик исключений для sample_Exception в основном блоке.
  • Code строка 20: Выводится сообщение «Исключение перехвачено в главном блоке».

Важные моменты, на которые следует обратить внимание в исключении

  • В функции исключение всегда должно либо возвращать значение, либо вызывать дальнейшее исключение; в противном случае... Oracle Во время выполнения возникает ошибка «Функция вернула значение».
  • Заявления о контроле транзакций может быть отправлено внутри блока обработки исключений.
  • SQLERRM и SQLCODE — это встроенные функции, которые возвращают сообщение об исключении и код исключения соответственно.
  • Если исключение не обрабатывается, то по умолчанию все активные транзакции в этой сессии откатываются.
  • RAISE_APPLICATION_ERROR (- , Вместо команды RAISE можно использовать ) для генерации ошибки с пользовательским кодом и сообщением. Код ошибки должен находиться в диапазоне от -20000 до -20999.

Часто задаваемые вопросы (FAQ)

PRAGMA EXCEPTION_INIT связывает заданное пользователем имя исключения с конкретным Oracle номер ошибки. После привязки вы можете перехватить эту ошибку ORA по имени в предложении WHEN вместо использования WHEN OTHERS и проверки SQLCODE.

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

Избегайте использования конструкции WHEN OTHERS, которая молча подавляет каждую ошибку. Без логирования SQLCODE и SQLERRM или повторного вызова с помощью RAISE она скрывает ошибки. Используйте её только для логирования, очистки и последующего распространения исключения.

Функция RAISE_APPLICATION_ERROR принимает номер ошибки от -20000 до -20999 и сообщение размером до 2048 байт. Она останавливает выполнение и возвращает пользовательскую ошибку вызывающему приложению, благодаря чему условие, заданное пользователем, выглядит как нативное. Oracle ошибка.

Не в том же блоке — как только управление переходит к разделу EXCEPTION, этот блок завершается. Чтобы продолжить, заключите рискованное выражение во внутренний блок BEGIN…EXCEPTION…END; после обработки ошибки внешний блок продолжит выполнение.

Ошибка — это любая проблема, возникающая во время выполнения или компиляции кода. Исключение — это механизм обработки ошибок во время выполнения в PL/SQL, который передает управление в раздел EXCEPTION, чтобы программа могла отреагировать, а не внезапно завершиться.

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

Второй пилот GitHub Автоматически дополняет условия WHEN, вызовы RAISE_APPLICATION_ERROR и полные блоки EXCEPTION на основе короткого комментария, описывающего намерение. Это ускоряет написание стандартного кода обработчика, хотя сгенерированные коды ошибок и сообщения требуют проверки на точность.

Подведем итог этой публикации следующим образом: