TRY / CATCH в PostgreSQL
Во встроенном процедурном языке 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
© Habrahabr.ru
TRY / CATCH в PostgreSQL
Во встроенном процедурном языке PL/pgSQL для СУБД PostgreSQL отсутствуют привычные операторы TRY / CATCH для для перехвата исключений возникающих в коде во время выполнения. Аналогом является оператор
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:
Имя | Тип | Описание |
|
| код исключения |
|
| имя столбца, относящегося к исключению |
|
| имя ограничения целостности, относящегося к исключению |
|
| имя типа данных, относящегося к исключению |
|
| текст основного сообщения исключения |
|
| имя таблицы, относящейся к исключению |
|
| имя схемы, относящейся к исключению |
|
| текст детального сообщения исключения (если есть) |
|
| текст подсказки к исключению (если есть) |
|
| строки текста, описывающие стек вызовов в момент исключения |
В качестве примера будет рассмотрена обработка ошибки деления на ноль в функции
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
Исключение PostgreSQL
Резюме : в этом руководстве вы узнаете, как перехватывать исключения PostgreSQL в PL/pgSQL.
Введение в пункт об исключении PL/pgSQL
Когда в блоке возникает ошибка, PostgreSQL прерывает выполнение блока, а также окружающую транзакцию.
Чтобы устранить ошибку, вы можете использовать предложение исключения в блоке begin...end .
Ниже показан синтаксис исключение пункт:
<<метка>> объявить начинать заявления; исключение когда условие [или условие...] тогда обработать_исключение; [когда условие [или условие...] тогда обработать_исключение;] [когда другие тогда обрабатывать_другие_исключения; ] конец;
Язык кода: диалект PostgreSQL SQL и PL/pgSQL (pgsql)
Как это работает.
- Во-первых, когда возникает ошибка между
beginиисключение, PL/pgSQL останавливает выполнение и передает управление в список исключений. - Во-вторых, PL/pgSQL ищет первое условие
, которое соответствует возникшей ошибке. - В-третьих, если есть совпадение, будут выполнены соответствующие операторы
handle_exception. PL/pgSQL передает управление оператору после ключевого словаend. - Наконец, если совпадение не найдено, ошибка распространяется и может быть перехвачена
исключениепункт вмещающего блока. В случае отсутствия окружающего блока с предложениемexceptionPL/pgSQL прервет обработку.
Имена условия могут быть no_data_found в случае select оператор не возвращает ни одной строки или too_many_rows если select оператор возвращает более одной строки. Полный список имен условий можно найти на веб-сайте PostgreSQL.
Также возможно указать состояние ошибки с помощью Код SQLSTATE . Например, P0002 для no_data_found и P0003 для too_many_rows .
Как правило, вы перехватываете конкретное исключение и обрабатываете его соответствующим образом. Для обработки других исключений, а не того, которое вы указали в списке, вы можете использовать предложение , когда другие, а затем .
Примеры обработки исключений
Для демонстрации мы будем использовать таблицу film из примера базы данных.
1) Пример обработки исключения no_data_found
В следующем примере возникает ошибка, поскольку фильм с идентификатором 2000 не существует.
Язык кода: диалект PostgreSQL SQL и PL/pgSQL (pgsql)
сделать $$ объявить запись записи; v_film_id интервал = 2000; начинать -- выбрать фильм выберите film_id, название в строгую запись из фильма где film_id = v_film_id; конец; $$ язык plpgsql;
Вывод:
Язык кода: сеанс оболочки (оболочка)
ОШИБКА: запрос не вернул строк КОНТЕКСТ: функция PL/pgSQL inline_code_block, строка 6 в операторе SQL Состояние SQL: P0002
В следующем примере используется предложение исключения для перехвата исключения no_data_found и выдачи более значимого сообщения:
Язык кода: диалект PostgreSQL SQL и PL/pgSQL (pgsql)
do $$ объявить запись записи; v_film_id интервал = 2000; начинать -- выбрать фильм выберите film_id, название в строгую запись из фильма где film_id = v_film_id; -- поймать исключение исключение когда no_data_found тогда вызвать исключение «фильм % не найден», v_film_id; конец; $$ язык plpgsql;
Вывод:
Язык кода: Сеанс оболочки (оболочка)
ОШИБКА: фильм 2000 не найден КОНТЕКСТ: функция PL/pgSQL inline_code_block, строка 14 в RAISE Состояние SQL: P0001
2) Пример обработки исключения too_many_rows
В следующем примере показано, как обрабатывать исключение too_many_rows :
1 do $$ объявить запись записи; начинать -- выбрать фильм выберите film_id, название в строгую запись из фильма где заголовок LIKE 'A%'; исключение когда too_many_rows тогда вызвать исключение «Поисковой запрос возвращает слишком много строк»; конец; $$ язык plpgsql;
Язык кода: диалект PostgreSQL SQL и PL/pgSQL (pgsql)
Вывод:
Язык кода: Сеанс оболочки (оболочка)
ОШИБКА: Поисковый запрос возвращает слишком много строк КОНТЕКСТ: функция PL/pgSQL inline_code_block, строка 15 в RAISE Состояние SQL: P0001
В этом примере исключение too_many_rows возникает из-за того, что оператор select into возвращает более одной строки, в то время как он должен возвращать одну строку.
3) Обработка нескольких исключений
В следующем примере показано, как перехватывать несколько исключений:
Язык кода: диалект PostgreSQL SQL и PL/pgSQL (pgsql)
do $$ объявить запись записи; v_length интервал = 90; начинать -- выбрать фильм выберите film_id, название в строгую запись из фильма где длина = v_длина; -- поймать исключение исключение когда sqlstate 'P0002' тогда вызвать исключение «фильм с длиной % не найден», v_length; когда sqlstate 'P0003' тогда поднять исключение «С длиной % не является уникальным», v_length; конец; $$ язык plpgsql;
Вывод:
Язык кода: Сеанс оболочки (оболочка)
ОШИБКА: длина 90 не уникальна КОНТЕКСТ: функция PL/pgSQL inline_code_block, строка 17 в RAISE Состояние SQL: P0001
4) Обработка исключений в виде кодов SQLSTATE
Следующий пример аналогичен приведенному выше, за исключением того, что вместо условия используются коды SQLSTATE имена:
Язык кода: диалект PostgreSQL SQL и PL/pgSQL (pgsql)
сделать $$ объявить запись записи; v_length интервал = 30; начинать -- выбрать фильм выберите film_id, название в строгую запись из фильма где длина = v_длина; -- поймать исключение исключение когда sqlstate 'P0002' тогда вызвать исключение «фильм с длиной % не найден», v_length; когда sqlstate 'P0003' тогда поднять исключение «С длиной % не является уникальным», v_length; конец; $$ язык plpgsql;
Вывод:
Язык кода: Сеанс оболочки (оболочка)
ОШИБКА: фильм длиной 30 не найден КОНТЕКСТ: функция PL/pgSQL inline_code_block, строка 15 в RAISE Состояние SQL: P0001
Сводка
- Используйте предложение
exceptionв блокеbegin.для перехвата и обработки исключений.
..end
Было ли это руководство полезным?
postgresql — ИСКЛЮЧЕНИЕ, КОГДА ДРУГИЕ ТОГДА НОЛЬ в Postgres
спросил
Изменено 2 года, 9 месяцев назад
Просмотрено 9к раз
У меня есть исключение в Oracle PL/SQL, которое необходимо перенести в PostgreSQL pl/pgsql. Ниже приведен вариант оракула
ИСКЛЮЧЕНИЕ КОГДА ДРУГИЕ ТОГДА НУЛЕВОЙ;
Что такое вариант PL/PGSQL?
- postgresql
- исключение
- plpgsql
1
Тот же синтаксис. Сравните 2 следующих исполнения:
DO $$ НАЧИНАТЬ ПОВЫСИТЬ деление_на_ноль; ИСКЛЮЧЕНИЕ КОГДА ДРУГИЕ ТОГДА НУЛЕВОЙ; КОНЕЦ; $$ ДЕЛАТЬ
А:
ДО $$ НАЧИНАТЬ ПОВЫСИТЬ деление_на_ноль; КОНЕЦ; $$ ОШИБКА: Division_by_zero КОНТЕКСТ: функция PL/pgSQL inline_code_block, строка 3 в RAISE
НЕ портировать как есть.
Это ОШИБКА ВСЕГДА . Если вы ничего не делаете, по крайней мере, зарегистрируйте ошибку. Если это происходит в интерактивном режиме, или при загрузке данных, или при создании отчетов, или в целом ряде других, создайте какое-либо сообщение, указывающее, что процесс не удался. Если пользователи зависят от этих данных, а их там нет, это ваше приложение сломано, а не ожидания пользователей. Я понимаю, что вы переносите систему, но при этом вы не должны переносить очевидные ошибки. Это один.
1
Во-первых, избегайте подобных перехватов «любых исключений» без какого-либо конкретного поведения. За исключением очень простых функций, подумайте о том, чтобы зарегистрировать их где-нибудь или переписать код более элегантным образом.
Нашел тут: видимо, вообще ничего ставить не надо.
Вы должны попробовать следующее:
ИСКЛЮЧЕНИЕ КОГДА ДРУГИЕ ТОГДА -- Ничего не делать
Надеюсь, это поможет.

res INTO res
FROM catch_exception(4, 0) AS e;
RAISE NOTICE 'Result: %', res;
END;
$$;
MESSAGE TEXT: %', SQLSTATE, SQLERRM;
END
res INTO res
FROM catch_exception(4, 0) AS e;
RAISE NOTICE 'Result: %', res;
END;
$$;
..] тогда
обработать_исключение;
[когда условие [или условие...] тогда
обработать_исключение;]
[когда другие тогда
обрабатывать_другие_исключения;
]
конец; 
..end