PostgreSQL 0Z002 오류 원인과 해결 방법 완벽 가이드

0Z002
2026년 08월 07일 | DBMS Error 가이드

이 글에서 다루는 내용

0Z002 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

0Z002 stacked diagnostics accessed without active handler 는?

PostgreSQL 에러 코드 0Z002GET STACKED DIAGNOSTICS 구문을 예외 핸들러(Exception Handler) 외부에서 사용하려 할 때 발생합니다. GET STACKED DIAGNOSTICS는 오직 EXCEPTION 블록 내부에서만 유효하게 동작하도록 설계되어 있으며, 활성화된 핸들러 없이 호출하면 PostgreSQL은 이 에러를 발생시킵니다. 이 에러는 주로 PL/pgSQL 함수나 프로시저를 작성하는 개발자가 예외 처리 구조를 잘못 이해하거나 코드 리팩토링 과정에서 진단 코드를 잘못 배치했을 때 나타납니다.


주요 발생 원인

  • EXCEPTION 블록 외부에서 GET STACKED DIAGNOSTICS 호출

가장 흔한 원인입니다. GET STACKED DIAGNOSTICS는 현재 스택에 쌓인 예외 정보를 가져오는 명령인데, 예외가 발생하지 않은 상황(즉, 핸들러가 활성화되지 않은 상태)에서 이를 호출하면 PostgreSQL은 참조할 예외 컨텍스트가 없기 때문에 0Z002 에러를 반환합니다. 예를 들어 함수 본문의 일반 실행 흐름에서 이 구문을 사용하는 경우가 대표적입니다.

  • 중첩 블록에서의 스코프 혼동

PL/pgSQL에서는 블록을 중첩하여 사용할 수 있는데, 내부 블록의 EXCEPTION 섹션에서 처리된 예외 정보가 외부 블록으로 전파되지 않습니다. 개발자가 외부 블록의 일반 실행 섹션에서 이전에 처리된 예외의 진단 정보를 가져오려 할 때 이 에러가 발생합니다. 즉, GET STACKED DIAGNOSTICS는 반드시 해당 예외가 포착된 바로 그 EXCEPTION 블록 안에서만 호출해야 합니다.

  • 코드 리팩토링 또는 복사-붙여넣기 오류

기존 예외 처리 코드를 다른 함수로 복사하거나 리팩토링하는 과정에서 GET STACKED DIAGNOSTICS 구문이 EXCEPTION 블록 밖으로 이동되는 실수가 발생할 수 있습니다. 특히 대규모 PL/pgSQL 코드베이스에서 공통 로깅 유틸리티 함수를 만들 때 진단 정보를 외부 함수로 전달하지 않고 그 함수 내부에서 직접 GET STACKED DIAGNOSTICS를 호출하는 잘못된 패턴이 나타납니다.


해결 방법

원인 1 해결: EXCEPTION 블록 내부로 이동

잘못된 코드 예시:

CREATE OR REPLACE FUNCTION bad_example()
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
BEGIN
    -- 잘못된 위치: EXCEPTION 블록 밖에서 호출
    GET STACKED DIAGNOSTICS
        v_state   = RETURNED_SQLSTATE,
        v_message = MESSAGE_TEXT;

    RAISE NOTICE 'State: %, Message: %', v_state, v_message;
END;
$$ LANGUAGE plpgsql;

올바른 코드 예시:

CREATE OR REPLACE FUNCTION good_example()
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
    v_context TEXT;
BEGIN
    -- 정상적인 비즈니스 로직
    PERFORM 1 / 0; -- 의도적 에러 발생

EXCEPTION
    WHEN OTHERS THEN
        -- 올바른 위치: EXCEPTION 블록 내부에서 호출
        GET STACKED DIAGNOSTICS
            v_state   = RETURNED_SQLSTATE,
            v_message = MESSAGE_TEXT,
            v_context = PG_EXCEPTION_CONTEXT;

        RAISE NOTICE 'Error State: %, Message: %, Context: %',
            v_state, v_message, v_context;
END;
$$ LANGUAGE plpgsql;

원인 2 해결: 중첩 블록 스코프 올바르게 관리

CREATE OR REPLACE FUNCTION nested_block_example()
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
BEGIN
    -- 외부 블록
    BEGIN
        -- 내부 블록: 여기서 예외를 처리하고 진단 정보를 저장
        BEGIN
            PERFORM 1 / 0;
        EXCEPTION
            WHEN OTHERS THEN
                -- 진단 정보를 변수에 저장 (DECLARE 변수 활용)
                GET STACKED DIAGNOSTICS
                    v_state   = RETURNED_SQLSTATE,
                    v_message = MESSAGE_TEXT;
                RAISE NOTICE '내부 블록 처리 - State: %, Message: %',
                    v_state, v_message;
        END;

        -- 외부 블록에서는 이미 저장된 변수를 사용
        -- GET STACKED DIAGNOSTICS를 다시 호출하지 않음!
        RAISE NOTICE '외부 블록에서 참조: %, %', v_state, v_message;
    END;
END;
$$ LANGUAGE plpgsql;

원인 3 해결: 공통 로깅 함수 올바르게 설계

진단 정보를 별도 함수로 전달하는 올바른 패턴:

-- 공통 에러 로깅 함수 (진단 정보를 파라미터로 받음)
CREATE OR REPLACE FUNCTION log_error(
    p_state   TEXT,
    p_message TEXT,
    p_context TEXT,
    p_source  TEXT DEFAULT 'unknown'
)
RETURNS void AS $$
BEGIN
    INSERT INTO error_log (sqlstate, message, context, source, logged_at)
    VALUES (p_state, p_message, p_context, p_source, NOW());
END;
$$ LANGUAGE plpgsql;

-- 실제 비즈니스 함수에서 올바르게 사용
CREATE OR REPLACE FUNCTION business_logic()
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
    v_context TEXT;
BEGIN
    -- 비즈니스 로직
    PERFORM some_risky_operation();

EXCEPTION
    WHEN OTHERS THEN
        -- EXCEPTION 블록 안에서 진단 정보 수집 후 함수에 전달
        GET STACKED DIAGNOSTICS
            v_state   = RETURNED_SQLSTATE,
            v_message = MESSAGE_TEXT,
            v_context = PG_EXCEPTION_CONTEXT;

        -- 수집한 정보를 파라미터로 전달
        PERFORM log_error(v_state, v_message, v_context, 'business_logic');
        RAISE;
END;
$$ LANGUAGE plpgsql;

예방 방법

  • 코드 리뷰 시 GET STACKED DIAGNOSTICS 위치 체크리스트 활용

PL/pgSQL 코드 리뷰 프로세스에 GET STACKED DIAGNOSTICS 구문이 항상 EXCEPTION WHEN 블록 내부에 위치하는지 확인하는 체크리스트 항목을 추가하세요. 정적 분석 도구나 간단한 grep 스크립트를 활용해 저장소 전체에서 잘못 배치된 GET STACKED DIAGNOSTICS 호출을 자동으로 탐지하는 CI/CD 파이프라인을 구성하는 것도 좋습니다.

  • 표준화된 예외 처리 템플릿 사용

팀 전체가 공유하는 표준 PL/pgSQL 함수 템플릿을 만들고, 예외 처리 패턴을 미리 포함시켜 두세요. 아래처럼 항상 EXCEPTION 블록이 포함된 기본 템플릿을 사용하면 실수를 줄일 수 있습니다.

-- 팀 표준 PL/pgSQL 함수 템플릿
CREATE OR REPLACE FUNCTION template_function(/* 파라미터 */)
RETURNS void AS $$
DECLARE
    v_sqlstate TEXT;
    v_message  TEXT;
    v_context  TEXT;
BEGIN
    /*
     * 비즈니스 로직을 여기에 작성
     * GET STACKED DIAGNOSTICS는 절대 이 섹션에 작성하지 말 것!
     */

EXCEPTION
    WHEN OTHERS THEN
        GET STACKED DIAGNOSTICS
            v_sqlstate = RETURNED_SQLSTATE,
            v_message  = MESSAGE_TEXT,
            v_context  = PG_EXCEPTION_CONTEXT;
        -- 에러 로깅 또는 재발생
        RAISE WARNING '[%] %', v_sqlstate, v_message;
        RAISE;
END;
$$ LANGUAGE plpgsql;

관련 에러

  • 0Z000diagnostics_exception: 0Z002의 상위 카테고리 에러로, 진단 관련 에러의 공통 부모 코드입니다. 0Z002가 발생하면 함께 확인해야 합니다.
  • P0000plpgsql_error: PL/pgSQL 런타임 전반에서 발생하는 일반 에러로, 잘못된 예외 처리 구조와 함께 나타날 수 있습니다.
  • 39000external_routine_exception: 외부 프로시저 호출 시 예외 처리와 관련된 에러로, 복잡한 중첩 예외 처리 구조에서 0Z002와 혼동될 수 있습니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기