Pull to refresh

TRY / CATCH в PostgreSQL

Reading time2 min
Views21K

Во встроенном процедурном языке 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:

Имя

Тип

Описание

RETURNED_SQLSTATE

text

код исключения

COLUMN_NAME

text

имя столбца, относящегося к исключению

CONSTRAINT_NAME

text

имя ограничения целостности, относящегося к исключению

PG_DATATYPE_NAME

text

имя типа данных, относящегося к исключению

MESSAGE_TEXT

text

текст основного сообщения исключения

TABLE_NAME

text

имя таблицы, относящейся к исключению

SCHEMA_NAME

text

имя схемы, относящейся к исключению

PG_EXCEPTION_DETAIL

text

текст детального сообщения исключения (если есть)

PG_EXCEPTION_HINT

text

текст подсказки к исключению (если есть)

PG_EXCEPTION_CONTEXT

text

строки текста, описывающие стек вызовов в момент исключения

Пример обработки исключения

В качестве примера будет рассмотрена обработка ошибки деления на ноль в функции 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
Tags:
Hubs:
Total votes 10: ↑9 and ↓1+8
Comments6

Articles