Обработка ошибок в PostgreSQL

PostgreSQLPostgreSQLBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этой лабораторной работе вы изучите методы обработки ошибок в PostgreSQL с использованием PL/pgSQL. Вы узнаете, как выводить уведомления (notices), перехватывать исключения (exceptions), регистрировать ошибки (log errors) и тестировать логику обработки ошибок. Эта лабораторная работа предназначена для начинающих и проведет вас через каждый шаг.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL postgresql(("PostgreSQL")) -.-> postgresql/PostgreSQLGroup(["PostgreSQL"]) postgresql/PostgreSQLGroup -.-> postgresql/func_init("Define Simple Function") postgresql/PostgreSQLGroup -.-> postgresql/func_call("Call Stored Function") subgraph Lab Skills postgresql/func_init -.-> lab-550952{{"Обработка ошибок в PostgreSQL"}} postgresql/func_call -.-> lab-550952{{"Обработка ошибок в PostgreSQL"}} end

Вывод уведомлений (Raising Notices) в функции

В этом шаге вы узнаете, как выводить уведомления (notices) внутри PL/pgSQL функции. Уведомления – это информационные сообщения, которые могут быть полезны для отладки или предоставления обратной связи. Они менее серьезны, чем ошибки, и не останавливают выполнение функции.

Для начала подключитесь к базе данных PostgreSQL от имени пользователя postgres:

sudo -u postgres psql

Теперь давайте создадим функцию с именем greet, которая принимает имя в качестве входных данных и выводит уведомление с приветственным сообщением. Выполните следующую SQL-команду в оболочке psql:

CREATE OR REPLACE FUNCTION greet(name TEXT)
RETURNS TEXT AS $$
BEGIN
  RAISE NOTICE 'Hello, %!', name;
  RETURN 'Greeting sent!';
END;
$$ LANGUAGE plpgsql;

Эта функция принимает аргумент name типа TEXT. Строка RAISE NOTICE 'Hello, %!', name; отображает уведомление. Символ % является заполнителем (placeholder), который будет заменен значением переменной name. Затем функция возвращает строку 'Greeting sent!'.

Давайте вызовем функцию с именем 'LabEx':

SELECT greet('LabEx');

Вы должны увидеть вывод, подобный этому:

NOTICE:  Hello, LabEx!
   greet
-----------
 Greeting sent!
(1 row)

Сообщение NOTICE "Hello, LabEx!" отображается, показывая, что оператор RAISE NOTICE был выполнен.

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

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

CREATE OR REPLACE FUNCTION greet(name TEXT)
RETURNS TEXT AS $$
BEGIN
  IF name = '' THEN
    RAISE WARNING 'Name is empty!';
  ELSE
    RAISE NOTICE 'Hello, %!', name;
  END IF;
  RETURN 'Greeting sent!';
END;
$$ LANGUAGE plpgsql;

Теперь, если вы вызовете функцию с пустой строкой:

SELECT greet('');

Вы увидите предупреждающее сообщение:

WARNING:  Name is empty!
   greet
-----------
 Greeting sent!
(1 row)

Это демонстрирует, как использовать RAISE NOTICE и RAISE WARNING для предоставления обратной связи внутри PL/pgSQL функции.

Перехват исключений (Catching Exceptions) в PL/pgSQL

В этом шаге вы узнаете, как перехватывать исключения (exceptions) в PL/pgSQL с помощью блока EXCEPTION. Обработка исключений позволяет вам корректно обрабатывать ошибки, предотвращая сбой вашей функции и предоставляя информативные сообщения об ошибках.

Основная структура блока обработки исключений выглядит следующим образом:

BEGIN
  -- Code that might raise an exception
EXCEPTION
  WHEN exception_name THEN
    -- Code to handle the exception
END;

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

Давайте создадим функцию, которая пытается разделить число на ноль и перехватывает возникающее исключение. Мы назовем ее safe_divide.

CREATE OR REPLACE FUNCTION safe_divide(numerator INTEGER, denominator INTEGER)
RETURNS INTEGER AS $$
BEGIN
  RETURN numerator / denominator;
EXCEPTION
  WHEN division_by_zero THEN
    RAISE NOTICE 'Division by zero occurred!';
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

Эта функция принимает два целочисленных аргумента: numerator (числитель) и denominator (знаменатель). Внутри блока BEGIN она пытается разделить numerator на denominator. Если denominator равен нулю, будет вызвано исключение division_by_zero (деление на ноль). Блок EXCEPTION перехватывает это исключение, выводит уведомление и возвращает NULL.

Теперь давайте вызовем функцию с делителем, равным нулю:

SELECT safe_divide(10, 0);

Вы должны увидеть вывод, подобный этому:

NOTICE:  Division by zero occurred!
 safe_divide
-------------
          NULL
(1 row)

Сообщение NOTICE "Division by zero occurred!" отображается, и функция возвращает NULL, указывая, что исключение было перехвачено и обработано.

Теперь давайте вызовем функцию с допустимыми входными данными:

SELECT safe_divide(10, 2);

Вы должны увидеть вывод, подобный этому:

 safe_divide
-------------
           5
(1 row)

Функция возвращает правильное частное, 5, без вызова каких-либо исключений.

Вы также можете перехватывать другие типы исключений, такие как numeric_value_out_of_range (числовое значение вне диапазона), null_value_not_allowed (недопустимое нулевое значение) и others (другие). Обработчик исключений others перехватывает любое исключение, которое не обрабатывается явно предыдущим предложением WHEN.

Давайте изменим функцию, чтобы перехватывать любое исключение и возвращать -1:

CREATE OR REPLACE FUNCTION safe_divide(numerator INTEGER, denominator INTEGER)
RETURNS INTEGER AS $$
BEGIN
  RETURN numerator / denominator;
EXCEPTION
  WHEN division_by_zero THEN
    RAISE NOTICE 'Division by zero occurred!';
    RETURN NULL;
  WHEN OTHERS THEN
    RAISE NOTICE 'An unexpected error occurred: %', SQLERRM;
    RETURN -1;
END;
$$ LANGUAGE plpgsql;

В этой измененной функции, если возникает какое-либо исключение, отличное от division_by_zero, будет выполнен обработчик исключений OTHERS. SQLERRM — это встроенная переменная, которая содержит сообщение об ошибке, связанное с исключением.

Итог (Summary)

В этой лабораторной работе вы изучили методы обработки ошибок в PostgreSQL с использованием PL/pgSQL. Вы узнали, как выводить уведомления (notices) внутри функций с помощью RAISE NOTICE, RAISE WARNING и RAISE INFO для предоставления информационных сообщений. Вы также узнали, как перехватывать исключения (exceptions) с помощью блоков BEGIN...EXCEPTION...END и записывать детали ошибок в таблицу для аудита и отладки. Наконец, вы попрактиковались в тестировании логики обработки ошибок, чтобы обеспечить надежность.