Во встроенном процедурном языке PL/pgSQL для СУБД PostgreSQL отсутствуют привычные операторы TRY / CATCH для для перехвата исключений возникающих в коде во время выполнения. Аналогом является оператор EXCEPTION, который используется в конструкции:
BEGIN
-- код, в котором может возникнуть исключение
EXCEPTION WHEN OTHERS -- аналог catch
THEN
-- код, обрабатывающий исключение
END
Если необходимо обработать только конкретную ошибку, то в условии WHEN нужно указать идентификатор или код конкретной ошибки:
BEGIN
-- код, в котором может возникнуть исключение
EXCEPTION WHEN '<идентификатор_или_код_ошибки>'
THEN
-- код, обрабатывающий исключение
END
Внутри секции EXCEPTION код ошибки можно получить из переменной SQLSTATE, а текст ошибки из переменной SQLERRM:
BEGIN
-- код, в котором может возникнуть исключение
EXCEPTION WHEN OTHERS
THEN
RAISE NOTICE 'ERROR CODE: %. MESSAGE TEXT: %', SQLSTATE, SQLERRM;
END
Более подробную информацию по исключению можно получить командой GET STACKED DIAGNOSTICS:
BEGIN
-- код, в котором может возникнуть исключение
EXCEPTION WHEN OTHERS
THEN
GET STACKED DIAGNOSTICS
err_code = RETURNED_SQLSTATE, -- код ошибки
msg_text = MESSAGE_TEXT, -- текст ошибки
exc_context = PG_CONTEXT, -- контекст исключения
msg_detail = PG_EXCEPTION_DETAIL, -- подробный текст ошибки
exc_hint = PG_EXCEPTION_HINT; -- текст подсказки к исключению
RAISE NOTICE 'ERROR CODE: % MESSAGE TEXT: % CONTEXT: % DETAIL: % HINT: %',
err_code, msg_text, exc_context, msg_detail, exc_hint;
END
Полный список переменных, которые можно получить командой GET STACKED DIAGNOSTICS:
Имя |
Тип |
Описание |
|
|
код исключения |
|
|
имя столбца, относящегося к исключению |
|
|
имя ограничения целостности, относящегося к исключению |
|
|
имя типа данных, относящегося к исключению |
|
|
текст основного сообщения исключения |
|
|
имя таблицы, относящейся к исключению |
|
|
имя схемы, относящейся к исключению |
|
|
текст детального сообщения исключения (если есть) |
|
|
текст подсказки к исключению (если есть) |
|
|
строки текста, описывающие стек вызовов в момент исключения |
Пример обработки исключения
В качестве примера будет рассмотрена обработка ошибки деления на ноль в функции catch_exception:
CREATE OR REPLACE FUNCTION catch_exception
(
arg_1 int,
arg_2 int,
OUT res int
)
LANGUAGE plpgsql
AS $$
DECLARE
err_code text;
msg_text text;
exc_context text;
BEGIN
BEGIN
res := arg_1 / arg_2;
EXCEPTION
WHEN OTHERS
THEN
res := 0;
GET STACKED DIAGNOSTICS
err_code = RETURNED_SQLSTATE,
msg_text = MESSAGE_TEXT,
exc_context = PG_CONTEXT;
RAISE NOTICE 'ERROR CODE: % MESSAGE TEXT: % CONTEXT: %',
err_code, msg_text, exc_context;
END;
END;
$$;
Вызов функции catch_exception со значением 0 в качестве второго параметра вызовет ошибку деления на ноль:
DO $$
DECLARE
res int;
BEGIN
SELECT e.res INTO res
FROM catch_exception(4, 0) AS e;
RAISE NOTICE 'Result: %', res;
END;
$$;
Результаты обработки ошибки будут выведены на консоль:
ERROR CODE: 22012
MESSAGE TEXT: деление на ноль
CONTEXT: функция PL/pgSQL catch_exception(integer,integer), строка 14, оператор
GET STACKED DIAGNOSTICS
SQL-оператор: "SELECT e.res FROM catch_exception(4, 0) AS e"
функция PL/pgSQL inline_code_block, строка 5, оператор SQL-оператор
Result: 0
Комментарии (6)
coregabe
28.03.2022 09:05На всех углах просят не писать процедуры в базе. Как потом мигрировать?
oracle_schwerpunkte
28.03.2022 10:25+2А с Java на Питон как мигрировать? А с одной библиотеки на другую?
Если закладываться на миграцию, все надо писать на каком нибудь ANSI С без библиотек.
AndryPetrov
28.03.2022 11:11Для высоконагруженных баз данных часто приходится использовать сохраненные процедуры, так как они позволяют существенно сократить время выполнения. За счёт того, что процедура в базе хранится в скомпилированном виде с уже сохранённым планом выполнения.
IvanPetrof
28.03.2022 13:26Хм. А что за база? В postgre, на сколько мне известно, процедура не компилируется и вообще может обращаться к несуществующим таблицам, о чём-то станет известно только в момент исполнения. В оракле вроде как компилируется (по крайней мере зависимости сразу проверяются), но план исполнения по-моему всё равно выбирается оптимизатором в момент исполнения.
Portnov
28.03.2022 18:28зануда моде он
Всё-таки хранимые процедуры это в основном не про компиляцию. В оракле есть какая-то компиляция, но там, насколько я понимаю, что-то типа байт-кода. Есть режим компиляции в нативный код, но его ещё включить надо. И даёт он единицы процентов производительности.
А в первую очередь, хранимые процедуры — это про прямой доступ к данным. Т.е. в них для обращения к данным из таблиц не надо ходить с сервера приложений к серверу СУБД и обратно. При сложной обработке большого количества данных это иногда даёт очень большую разницу в производительностью по сравнению с "вся логика на сервере, в БД ходим только с простыми селектами".
asvici
месяц учу джаваскрипт, ничего не понятно, но картинка очень смешная