Статья основана на двадцать шестом видео из 31 темы курса SQL 2.0 — PL/pgSQL в PostgreSQL от Аристова Евгения, который является логическим продолжением курса SQL c 0. Ссылки на видео на платформах RUTUBE и VK video.
В данной статье подробно разбираются обработка ошибок для команд INSERT и как получить информацию об ошибке.
В прошлой статье мы разобрали условия возникновения исключений (секция EXCEPTION), которая помогает перехватить и обработать ошибки.
Презентация и исходники доступны по ссылке.
Обработка ошибок для команд INSERT
Например, обработка исключений помогает выполнить либо команду UPDATE, либо INSERT, в зависимости от ситуации.
Однако в современных приложениях вместо этого приёма рекомендуется использовать INSERT с ON CONFLICT DO UPDATE, так как обработка ошибок очень дорога с точки зрения потребления ресурсов. Но иногда без обработки ошибок не обойтись.
Получение информации об ошибке
При обработке исключений часто бывает необходимым получить детальную информацию о произошедшей ошибке. Для этого в PL/pgSQL есть два способа: использование специальных переменных и команда получения стека диагностики GET STACKED DIAGNOSTICS.
Внутри секции EXCEPTION специальная переменная SQLSTATE содержит код ошибки, для которой было вызвано исключение. Специальная переменная SQLERRM содержит сообщение об ошибке, связанное с исключением. Эти переменные являются неопределёнными вне секции EXCEPTION.
Также в обработчике исключения можно получить информацию о текущем исключении командой GET STACKED DIAGNOSTICS, которая имеет вид:
GET STACKED DIAGNOSTICS переменная { = | := } элемент [ , ... ];
Каждый элемент представляется ключевым словом, указывающим, какое значение состояния нужно присвоить заданной переменной.
Получение информации о месте возникновения ошибки
Команда GET DIAGNOSTICS, получает информацию о текущем состоянии выполнения кода (тогда как команда GET STACKED DIAGNOSTICS, рассмотренная ранее, выдаёт информацию о состоянии выполнения в момент предыдущей ошибки). Её элемент состояния PG_CONTEXT позволяет определить текущее место выполнения кода. PG_CONTEXT возвращает текст с несколькими строками, описывающий стек вызова. В первой строке отмечается текущая функция и выполняемая в данный момент команда GET DIAGNOSTICS, а во второй и последующих строках отмечаются функции выше по стеку вызовов.
Exception пример
DECLARE
text_var1 text;
text_var2 text;
text_var3 text;
BEGIN
-- здесь происходит обработка, которая может вызвать исключение
...
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
text_var2 = PG_EXCEPTION_DETAIL,
text_var3 = PG_EXCEPTION_HINT;
END;
Потом например записать в таблицу с логами проблему. Или сделать raise notice — вывести сообщение в консоль. И если повысить детализацию системы логирования, эта информация также попадет в журнал.
При выполнении команд в секции EXCEPTION локальные переменные функции на PL/pgSQL сохраняют те значения, которые были на момент возникновения ошибки. Однако, будут отменены все изменения в базе данных, выполненные в блоке
Наличие секции EXCEPTION значительно увеличивает накладные расходы на вход/выход из блока, поэтому не используйте EXCEPTION без надобности.
Наличие секции EXCEPTION не позволит создавать транзакции внутри блока.
Примеры кода с обработкой ошибок:
-- Процедура с комплексной обработкой ошибок:
CREATE OR REPLACE PROCEDURE safe_data_operation()
AS $$
DECLARE
error_context TEXT;
BEGIN
-- Блок 1: Основные операции
BEGIN
UPDATE important_table SET status = 'processing';
CALL critical_operation();
EXCEPTION
WHEN others THEN
GET STACKED DIAGNOSTICS error_context = PG_EXCEPTION_CONTEXT;
RAISE NOTICE 'Ошибка в основном блоке: %, контекст: %', SQLERRM, error_context;
-- Откат всей процедуры
RAISE EXCEPTION 'Критическая ошибка, откат операции';
END;
-- Блок 2: Не критические операции
BEGIN
CALL non_critical_operation();
EXCEPTION
WHEN others THEN
RAISE NOTICE 'Не критическая ошибка проигнорирована: %', SQLERRM;
END;
-- Блок 3: Логирование (всегда выполняется)
BEGIN
INSERT INTO process_log (operation, status, details)
VALUES ('safe_data_operation', 'completed', 'Process finished at ' || CURRENT_TIMESTAMP);
EXCEPTION
WHEN others THEN
RAISE NOTICE 'Ошибка логирования: %', SQLERRM;
END;
END;
$$ LANGUAGE plpgsql;
Больше примеров доступно на гитхабе и в видео.
В следующей статье мы разберём функции для работы с массивами, в т.ч. многомерными.
Добавить комментарий