В Postgres мы получаем «трассировку стека» исключений, используя этот код:
EXCEPTION WHEN others THEN
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;
Это прекрасно работает для «естественных» исключений, но если мы возбуждаем исключение, используя
RAISE EXCEPTION 'This is an error!';
... тогда нет трассировки стека. Согласно записи в списке рассылки , это может быть преднамеренным, хотя я не могу понять, почему. Это заставляет меня хотеть найти другой способ вызвать исключение, кроме использования RAISE
. Я что-то упускаю из виду? У кого-нибудь есть хитрость для этого? Есть ли исключение, которое я могу заставить Postgres выдавать, который будет содержать выбранную мной строку, чтобы я мог получить не только свою строку в сообщении об ошибке, но и полную трассировку стека?
Вот полный пример:
CREATE OR REPLACE FUNCTION error_test() RETURNS json AS $$
DECLARE
v_error_stack text;
BEGIN
-- Comment this out to see how a "normal" exception will give you the stack trace
RAISE EXCEPTION 'This exception will not get a stack trace';
-- This will give a divide by zero error, complete with stack trace
SELECT 1/0;
-- In case of any exception, wrap it in error object and send it back as json
EXCEPTION WHEN others THEN
-- If the exception we're catching is one that Postgres threw,
-- like a divide by zero error, then this will get the full
-- stack trace of the place where the exception was thrown.
-- However, since we are catching an exception we raised manually
-- using RAISE EXCEPTION, there is no context/stack trace!
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;
RAISE WARNING 'The stack trace of the error is: "%"', v_error_stack;
return to_json(v_error_stack);
END;
$$ LANGUAGE plpgsql;
error_info
? Похоже, пользовательский тип.Ответы:
Такое поведение, кажется, по замыслу.
В
src/pl/plpgsql/src/pl_exec.c
контексте ошибки обратный вызов явно проверяет, вызывается ли он в контексте оператора PL / PgSQL,RAISE
и, если да, пропускает выдачу контекста ошибки:Я не могу найти какую-либо конкретную ссылку на то, почему это так.
Внутри на сервере стек контекста генерируется путем обработки
error_context_stack
обратного обратного вызова, который добавляет информацию в список при вызове.Когда PL / PgSQL входит в функцию, он добавляет элемент в стек обратного вызова контекста ошибки. Когда он покидает функцию, он удаляет элемент из этого стека.
Если функции отчетов об ошибках сервера PostgreSQL, такие как
ereport
илиelog
вызываются, вызывают обратный вызов контекста ошибки. Но в PL / PgSQL, если он замечает, что его вызывают из-заRAISE
своих обратных вызовов, намеренно ничего не делают.Учитывая это, я не вижу способа достичь того, чего вы хотите, не устанавливая исправления в PostgreSQL. Я предлагаю отправлять почту на pgsql-general, спрашивая, почему
RAISE
не предоставляется контекст ошибки сейчас, когда PL / PgSQL долженGET STACKED DIAGNOSTICS
использовать его.(Кстати, контекст исключения не является трассировкой стека как таковой. Он немного похож на один, потому что PL / PgSQL добавляет каждый вызов функции в стек, но он также используется для других деталей на сервере.)
источник
RAISE
проверка снижает полезность . Я напишу им.Вы можете обойти это ограничение и заставить plpgsql генерировать контекст ошибки по желанию, вызывая другую функцию, которая вызывает (предупреждение, уведомление, ...) ошибку для вас.
Я опубликовал решение для этого пару лет назад - в одном из моих первых сообщений здесь, на dba.SE :
Подробности:
Я расширил ваш тестовый пример, чтобы продемонстрировать, что он работает в Postgres 9.3:
SQL Fiddle.
источник