Postgresql

如何獲取 PL/pgSQL 中手動引發的異常的異常上下文?

  • April 4, 2015

在 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;

這種行為似乎是設計使然。

src/pl/plpgsql/src/pl_exec.c錯誤上下文回調中顯式檢查它是否在 PL/PgSQL 語句的上下文中被呼叫RAISE,如果是,則跳過發出錯誤上下文:

/*
* error context callback to let us supply a call-stack traceback
*/
static void
plpgsql_exec_error_callback(void *arg)
{
       PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;

       /* if we are doing RAISE, don't report its location */
       if (estate->err_text == raise_skip_msg)
               return;

我找不到任何關於為什麼會這樣的具體參考。

在伺服器內部,上下文堆棧是通過處理 生成的error_context_stack,這是一個鍊式回調,在呼叫時將資訊附加到列表中。

當 PL/PgSQL 進入一個函式時,它會將一個項目添加到錯誤上下文回調堆棧中。當它離開一個函式時,它會從該堆棧中刪除一個項目。

如果 PostgreSQL 伺服器的錯誤報告函式,likeereport或被elog呼叫,它會呼叫錯誤上下文回調。但是在 PL/PgSQL 中,如果它注意到它是從RAISE它的回調中呼叫的,那麼它會故意什麼都不做。

鑑於此,如果不修補 PostgreSQL,我看不到任何方法可以實現您想要的。我建議向 pgsql-general 發送郵件,詢問既然 PL/PgSQL 必須使用它,為什麼RAISE不提供錯誤上下文。GET STACKED DIAGNOSTICS

(順便說一句,異常上下文本身並不是堆棧跟踪。它看起來有點像,因為 PL/PgSQL 將每個函式呼叫添加到堆棧中,但它也用於伺服器中的其他細節。)

引用自:https://dba.stackexchange.com/questions/96743