Представьте, вы пишете функцию, которая считает средний балл студента. Что произойдет, если попытаетесь разделить на ноль (например, если оценки отсутствуют)? Попробуете выпустить в реальную жизнь такой код — и нежданный гость в лице ошибки тут же заявится. PL/pgSQL предоставляет мощные инструменты для обработки таких ошибок, делая ваш код устойчивым, безопасным и приятным для работы.
Обработка ошибок в PL/pgSQL позволяет:
- Генерировать сообщения, объясняющие, что пошло не так.
- Прекращать выполнение кода в случае критических ошибок.
- Логировать проблемы для последующего анализа.
Основные уровни сообщений PL/pgSQL
PL/pgSQL поддерживает несколько уровней сообщений, которые помогают разработчикам эффективно диагностировать и устранять проблемы. Вот они:
- NOTICE: выводит информационное сообщение. Применяется для отладки.
- WARNING: уведомление о потенциальной проблеме, которая не прерывает выполнение программы.
- EXCEPTION: критическая ошибка, прерывающая выполнение программы (и возвращающая управление вызывающему коду).
Уровни сообщений в PL/pgSQL
| Уровень сообщения | Описание |
|---|---|
NOTICE |
Информация или отладочные сообщения. Не влияет на выполнение |
WARNING |
Предупреждение о возможных проблемах. Работает как подсказка |
EXCEPTION |
Серьезная ошибка, которая завершает выполнение программы |
Синтаксис команды RAISE
Для генерации сообщений и обработки ошибок используется оператор RAISE. Вот его базовый синтаксис:
RAISE <уровень сообщения> 'текст сообщения' [, переменные...];
<уровень сообщения>—NOTICE,WARNING,EXCEPTION.'текст сообщения'— описание проблемы.[переменные...]— дополнительные значения, которые можно передать в текст сообщения.
Пример 1: использование RAISE NOTICE
Иногда важно знать, что происходит внутри вашей функции. Скажем, для отладки цикла:
DO $$
BEGIN
FOR i IN 1..5 LOOP
RAISE NOTICE 'Текущее значение i: %', i;
END LOOP;
END
$$;
Результат: Вывод в консоль строк Текущее значение i: 1, Текущее значение i: 2 и так далее до 5.
Пример 2: использование RAISE EXCEPTION
Теперь представим, вы пишете функцию, которая должна завершаться с ошибкой при определённых условиях:
DO $$
BEGIN
IF 1 = 1 THEN
RAISE EXCEPTION 'Что-то пошло не так!';
END IF;
END
$$;
Результат: выполнение прерывается, и сообщение ошибки выводится в консоль.
Работа с параметрами в RAISE
Используя параметры, вы можете персонализировать текст сообщения. Для этого применяются плейсхолдеры %:
Пример 3: вставка переменных в RAISE
DO $$
DECLARE
student_name TEXT := 'Иван';
average_score NUMERIC := NULL;
BEGIN
IF average_score IS NULL THEN
RAISE EXCEPTION 'У студента % нет среднего балла!', student_name;
END IF;
END
$$;
Результат: сообщение У студента Иван нет среднего балла!.
Как видите, % заменяется на переменную student_name, что делает сообщение более осмысленным.
Генерация пользовательских ошибок
Ошибки — это не только форс-мажор! Иногда их нужно создавать намеренно, чтобы защитить код от неправильных данных.
Пример 4: проверка входных значений
Напишем функцию, которая проверяет входное значение числа и вызывает ошибку, если оно отрицательное:
CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
IF value < 0 THEN
RAISE EXCEPTION 'Число % является отрицательным!', value;
END IF;
RETURN 'Число корректно.';
END;
$$ LANGUAGE plpgsql;
Теперь протестируем функцию:
SELECT check_positive(-5);
Результат: сообщение об ошибке Число -5 является отрицательным!.
Если же передать положительное значение:
SELECT check_positive(10);
Результат: Число корректно.
Обработка ошибок в контексте
Хорошо, если вы умеете генерировать ошибки. Но ещё лучше — обрабатывать их в зависимости от ситуации. Для этого используется блок BEGIN ... EXCEPTION.
Структура обработки ошибок
BEGIN
-- Ваш основной код
EXCEPTION
WHEN ОШИБКА_ТИП THEN
-- Что делать в случае ошибки
WHEN ДРУГАЯ_ОШИБКА THEN
-- Действия при другой ошибке
WHEN OTHERS THEN
-- Обработка всех остальных ошибок
END;
Расшифруем компоненты:
EXCEPTION— ключевое слово, обозначающее начало блока обработки ошибок.WHEN— позволяет указать конкретный тип обрабатываемой ошибки, например,unique_violationилиdivision_by_zero.OTHERS— используется для обработки всех ошибок, которые не были явно указаны в блокахWHEN.
Пример 5: обработка деления на ноль
Проиллюстрируем обработку ошибки с простым примером функции деления:
CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
-- Пытаемся выполнить деление
RETURN a / b;
EXCEPTION
WHEN division_by_zero THEN
RAISE WARNING 'Попытка деления на ноль. Возвращаю NULL.';
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Протестируем функцию:
SELECT safe_divide(10, 2); -- Ожидаемый результат: 5
SELECT safe_divide(10, 0); -- Ожидаемый результат: NULL и предупреждение в консоли
Типичные ошибки при использовании RAISE
Пропуск уровня сообщения. Если вы забыли указать уровень, PostgreSQL выдаст ошибку.
Неправильно:
RAISE 'Сообщение без уровня';
Правильно:
RAISE NOTICE 'Сообщение с уровнем NOTICE';
Неверные параметры. Если используете %, убедитесь, что передаёте необходимое количество переменных.
Неправильно:
RAISE NOTICE 'Пример с параметром %';
Правильно:
RAISE NOTICE 'Пример с параметром %', 'значение';
Перебивание. Чрезмерное использование RAISE EXCEPTION может прерывать выполнение важных операций. Используйте его разумно.
Полезные советы
- Будьте внимательны с блоком
WHEN OTHERS. По возможности указывайте конкретные ошибки, чтобы избежать перехвата ошибок, которые должны быть обработаны по-другому. - Используйте
RAISEдля отладки. Никогда не оставляйте ошибки необработанными. - Не забывайте про производительность. Обработка ошибок может быть затратной, особенно в больших процедурах.
Если вы все сделаете правильно, то ваши процедуры станут устойчивыми и смогут выдержать даже неожиданные сбои. PM может быть очень горд за вас!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ