PL / pgSQL에서 수동으로 발생한 예외에 대한 예외 컨텍스트를 얻는 방법은 무엇입니까?


11

Postgres에서는 다음 코드를 사용하여 예외의 "스택 추적"을 얻습니다.

EXCEPTION WHEN others THEN
    GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;

이것은 "자연스러운"예외에 대해서는 잘 작동하지만 다음을 사용하여 예외를 제기하면

RAISE EXCEPTION 'This is an error!';

... 스택 추적이 없습니다. 메일 링리스트 entry 에 따르면 , 이것은 내 의도를 알 수는 없지만 의도적 인 것일 수 있습니다. 를 사용하는 것 이외의 예외를 던지는 다른 방법을 찾고 싶습니다 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;

여기에 간단한 예를 보여주는 것이 좋습니다.
Craig Ringer

좋은 점 @CraigRinger. 끝난!
Taytay

독립형이 아닙니다. 무엇입니까 error_info? 사용자 정의 유형처럼 보입니다.
Craig Ringer

죄송합니다. 일반적인 상황을 원한다고 생각했습니다. 관련없는 것을 제거했습니다.
Taytay

답변:


9

이 동작은 의도적으로 설계된 것 같습니다.

에서는 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 서버의 오류보고 기능 이 호출 ereport되거나 elog호출되면 오류 컨텍스트 콜백을 호출합니다. 그러나 PL / PgSQL에서 RAISE콜백 에서 호출 된 것을 알면 의도적으로 아무것도하지 않습니다.

그 점을 감안할 때 PostgreSQL을 패치하지 않고 원하는 것을 달성 할 수있는 방법이 없습니다. RAISEPL / PgSQL이이 GET STACKED DIAGNOSTICS를 사용해야 하는 오류 컨텍스트를 제공하지 않는 이유를 묻는 메일을 pgsql-general에 게시하는 것이 좋습니다 .

(BTW, 예외 컨텍스트는 스택 추적이 아닙니다. PL / PgSQL은 각 함수 호출을 스택에 추가하지만 서버의 다른 세부 정보에도 사용되기 때문에 약간 비슷합니다.)


빠르고 철저한 답변을 해주신 Craig에게 대단히 감사합니다. 그것은 나에게 이상해 보이며, 확실히 내 기대에 반합니다. RAISE그 점검으로 인해 유용성 이 줄어 듭니다. 나는 그들에게 쓸 것이다.
Taytay

@Taytay 여기에 귀하의 질문에 대한 링크를 포함 시키십시오. 그러나 귀하의 메일이 완전하고 링크를 따르지 않고 이해할 수 있는지 확인하십시오 ; 많은 사람들이 링크 전용 또는 대부분 링크 게시물을 무시합니다. 여기에 의견에 게시물에 대한 링크를 표시 할 수있는 기회가 있다면 archives.postgresql.org 를 통해 나중에 다른 사람들을 도울 수있는 것이 좋습니다.
Craig Ringer

고마워 크레이그 좋은 조언. 여기에 스레드를 만들었습니다 : postgresql.org/message-id/… 현재로서는 문제에 대한 좋은 해결책을 찾고 있습니다.
Taytay April

6

당신은 할 수 있습니다 이 제한을 해결할 와 plpgsql 발광하게 오류 컨텍스트를 다른 함수를 호출하여 원하는대로 당신을 위해 레이즈 (경고, 통보, ...) 오류가.

dba.SE의 첫 번째 게시물 중 하나에 몇 년 전에 솔루션을 게시했습니다 .

-- helper function to raise an exception with CONTEXT
CREATE OR REPLACE FUNCTION f_raise(_lvl text = 'EXCEPTION'
                                  ,_msg text = 'Default error msg.')
  RETURNS void AS
$func$
BEGIN
   CASE upper(_lvl)
      WHEN 'EXCEPTION' THEN RAISE EXCEPTION '%', _msg;
      WHEN 'WARNING'   THEN RAISE WARNING   '%', _msg;
      WHEN 'NOTICE'    THEN RAISE NOTICE    '%', _msg;
      WHEN 'DEBUG'     THEN RAISE DEBUG     '%', _msg;
      WHEN 'LOG'       THEN RAISE LOG       '%', _msg;
      WHEN 'INFO'      THEN RAISE INFO      '%', _msg;
      ELSE RAISE EXCEPTION 'f_raise(): unexpected raise-level: "%"', _lvl;
   END CASE;
END
$func$  LANGUAGE plpgsql STRICT;

세부:

Postgres 9.3에서 작동하는지 보여주기 위해 게시 된 테스트 사례를 확장했습니다.

SQL 바이올린.


너무 너무 감사합니다! 재미있게도, 실제로 게시하기 전에 솔루션을 실험했지만 잘못한 일이 있었으며 예상했던 컨텍스트를 얻지 못했습니다. 나는 바이올린을 보았으므로 (나도 그것을 보여줘서 감사합니다), 나는 또 다른 기회를 줄 것입니다!
Taytay April

잘 했어요; 필요하지는 않지만 트릭을 수행하는 것처럼 보입니다.
Craig Ringer

@CraigRinger : 예외해야하기 때문에, 음, 예외 의 성능에 미치는 영향은 최소화해야 문제가되지, 중. 우리는이 방법으로 모든 옵션을 가지고 있습니다.
Erwin Brandstetter

완전히 동의합니다. 어떤 시점에서 해결 방법의 필요성이 사라지고 싶습니다.
Craig Ringer

@CraigRinger : 맞습니다. 그것이 곧 일어날 수 없다면, 우리는 매뉴얼에서이 해결 방법을 제안 할 것입니다 ...
Erwin Brandstetter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.