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
. - Наконец, если совпадение не найдено, ошибка распространяется и может быть перехвачена
исключение
пункт вмещающего блока. В случае отсутствия окружающего блока с предложениемexception
PL/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
Во-первых, избегайте подобных перехватов «любых исключений» без какого-либо конкретного поведения. За исключением очень простых функций, подумайте о том, чтобы зарегистрировать их где-нибудь или переписать код более элегантным образом.
Нашел тут: видимо, вообще ничего ставить не надо.
Вы должны попробовать следующее:
ИСКЛЮЧЕНИЕ КОГДА ДРУГИЕ ТОГДА -- Ничего не делать
Надеюсь, это поможет.