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

0Z002
2026년 10월 11일 | DBMS Error 가이드

이 글에서 다루는 내용

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

0Z002 stacked diagnostics accessed without active handler 는?

PostgreSQL 에러 코드 0Z002는 PL/pgSQL 또는 관련 절차형 언어에서 GET STACKED DIAGNOSTICS 구문을 예외 핸들러(Exception Handler) 블록 외부에서 호출했을 때 발생합니다. GET STACKED DIAGNOSTICS는 오직 EXCEPTION 블록 내부에서만 유효하며, 활성화된 핸들러 없이 이를 사용하면 PostgreSQL은 즉시 이 에러를 발생시킵니다. 실무에서는 코드 리팩터링 도중 예외 처리 블록 구조가 변경되거나, 처음 PL/pgSQL을 접하는 개발자가 GET DIAGNOSTICS와 GET STACKED DIAGNOSTICS의 차이를 혼동할 때 자주 나타납니다.


주요 발생 원인

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

가장 흔한 원인으로, GET STACKED DIAGNOSTICS를 일반 실행 블록(BEGIN ~ END) 내부 또는 함수 최상위 레벨에서 호출하는 경우입니다. 이 구문은 반드시 EXCEPTION WHEN ... THEN 절 내부에서만 호출해야 하며, 그 외 어느 위치에서도 유효하지 않습니다.

2. GET DIAGNOSTICS와 GET STACKED DIAGNOSTICS 혼동

GET DIAGNOSTICS는 일반 실행 흐름에서 사용하는 구문이고, GET STACKED DIAGNOSTICS는 예외 핸들러 전용 구문입니다. 두 구문은 이름이 비슷하지만 사용 가능한 컨텍스트가 완전히 다르며, 이를 혼동하여 잘못된 위치에 배치하면 0Z002 에러가 발생합니다.

3. 중첩 블록(Nested Block) 구조에서의 범위 오류

중첩된 BEGIN 블록 안에서 예외 처리를 구성할 때, 내부 블록의 EXCEPTION 절이 아닌 외부 블록의 일반 실행 영역에서 GET STACKED DIAGNOSTICS를 호출하는 실수가 발생할 수 있습니다. 블록의 중첩이 깊어질수록 현재 실행 컨텍스트가 어느 블록에 속하는지 파악하기 어려워지며, 이 과정에서 핸들러 범위를 벗어나는 오류가 생깁니다.


해결 방법

원인 1 해결: EXCEPTION 블록 안으로 이동

잘못된 예시:

CREATE OR REPLACE FUNCTION bad_diagnostics_example()
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
BEGIN
    -- 일반 실행 블록에서 GET STACKED DIAGNOSTICS 호출 → 0Z002 에러 발생
    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_diagnostics_example()
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
BEGIN
    -- 의도적으로 에러를 발생시키는 로직
    PERFORM 1 / 0;

EXCEPTION
    WHEN OTHERS THEN
        -- EXCEPTION 블록 내부에서만 GET STACKED DIAGNOSTICS 사용 가능
        GET STACKED DIAGNOSTICS
            v_state   = RETURNED_SQLSTATE,
            v_message = MESSAGE_TEXT;

        RAISE NOTICE '에러 코드: %, 에러 메시지: %', v_state, v_message;
END;
$$ LANGUAGE plpgsql;

원인 2 해결: GET DIAGNOSTICS vs GET STACKED DIAGNOSTICS 올바르게 구분

일반 실행 흐름에서 영향받은 행 수 등을 조회할 때는 GET DIAGNOSTICS를 사용합니다.

CREATE OR REPLACE FUNCTION row_count_example()
RETURNS void AS $$
DECLARE
    v_row_count INTEGER;
BEGIN
    UPDATE employees SET salary = salary * 1.1 WHERE department = 'IT';

    -- 일반 실행 후 영향받은 행 수 조회: GET DIAGNOSTICS 사용
    GET DIAGNOSTICS v_row_count = ROW_COUNT;

    RAISE NOTICE '업데이트된 행 수: %', v_row_count;

EXCEPTION
    WHEN OTHERS THEN
        DECLARE
            v_state   TEXT;
            v_message TEXT;
        BEGIN
            -- 예외 상황에서 상세 정보 조회: GET STACKED DIAGNOSTICS 사용
            GET STACKED DIAGNOSTICS
                v_state   = RETURNED_SQLSTATE,
                v_message = MESSAGE_TEXT;

            RAISE WARNING '실패 - 코드: %, 메시지: %', v_state, v_message;
        END;
END;
$$ LANGUAGE plpgsql;

원인 3 해결: 중첩 블록에서 올바른 컨텍스트 유지

CREATE OR REPLACE FUNCTION nested_block_example()
RETURNS void AS $$
DECLARE
    v_outer_msg TEXT;
BEGIN
    -- 외부 블록
    BEGIN
        -- 내부 블록
        BEGIN
            PERFORM 1 / 0; -- 에러 유발
        EXCEPTION
            WHEN division_by_zero THEN
                -- 내부 블록의 EXCEPTION 안에서 올바르게 사용
                GET STACKED DIAGNOSTICS
                    v_outer_msg = MESSAGE_TEXT;
                RAISE NOTICE '[내부 블록] 에러 처리: %', v_outer_msg;
        END;
        -- 여기서는 GET STACKED DIAGNOSTICS 사용 불가 (핸들러 밖)
        RAISE NOTICE '내부 블록 처리 완료';
    EXCEPTION
        WHEN OTHERS THEN
            -- 외부 블록의 EXCEPTION에서 별도 처리 가능
            GET STACKED DIAGNOSTICS
                v_outer_msg = MESSAGE_TEXT;
            RAISE NOTICE '[외부 블록] 에러: %', v_outer_msg;
    END;
END;
$$ LANGUAGE plpgsql;

실무용 에러 로깅 패턴 (종합 예시)

실무에서는 아래처럼 에러 로그 테이블과 결합하여 완전한 에러 추적 시스템을 구성하는 것이 일반적입니다.

-- 에러 로그 테이블 생성
CREATE TABLE IF NOT EXISTS error_log (
    id          SERIAL PRIMARY KEY,
    func_name   TEXT,
    sql_state   TEXT,
    message     TEXT,
    detail      TEXT,
    hint        TEXT,
    context     TEXT,
    logged_at   TIMESTAMPTZ DEFAULT now()
);

-- 에러 로깅 함수
CREATE OR REPLACE FUNCTION process_with_logging(p_input INTEGER)
RETURNS void AS $$
DECLARE
    v_state   TEXT;
    v_message TEXT;
    v_detail  TEXT;
    v_hint    TEXT;
    v_context TEXT;
BEGIN
    IF p_input = 0 THEN
        RAISE EXCEPTION '입력값이 0입니다.'
            USING DETAIL = '0은 허용되지 않는 값입니다.',
                  HINT   = '양수 정수를 입력하세요.';
    END IF;

    RAISE NOTICE '처리 완료: %', p_input;

EXCEPTION
    WHEN OTHERS THEN
        -- 반드시 EXCEPTION 블록 안에서 사용
        GET STACKED DIAGNOSTICS
            v_state   = RETURNED_SQLSTATE,
            v_message = MESSAGE_TEXT,
            v_detail  = PG_EXCEPTION_DETAIL,
            v_hint    = PG_EXCEPTION_HINT,
            v_context = PG_EXCEPTION_CONTEXT;

        INSERT INTO error_log (func_name, sql_state, message, detail, hint, context)
        VALUES ('process_with_logging', v_state, v_message, v_detail, v_hint, v_context);

        RAISE WARNING '에러가 로깅되었습니다. SQL State: %', v_state;
END;
$$ LANGUAGE plpgsql;

-- 테스트
SELECT process_with_logging(0);
SELECT * FROM error_log;

예방 방법

1. 코드 리뷰 시 GET STACKED DIAGNOSTICS 사용 위치 체크리스트 적용

팀 내 코드 리뷰 프로세스에 GET STACKED DIAGNOSTICS가 반드시 EXCEPTION 블록 내부에 위치하는지 확인하는 항목을 명시적으로 추가하세요. 특히 함수 리팩터링 시 예외 처리 블록이 삭제되거나 재구성될 때 이 규칙이 쉽게 깨질 수 있으므로, CI/CD 파이프라인에 정적 분석 도구(pgTAP, plpgsql_check 등)를 통합하여 자동 검증하는 것을 권장합니다.

2. 표준화된 예외 처리 템플릿 도입

팀 전체가 공유하는 PL/pgSQL 함수 작성 표준 템플릿을 만들어 GET STACKED DIAGNOSTICS의 올바른 사용 위치와 패턴을 코드 스니펫으로 제공하세요. 신규 개발자가 처음부터 올바른 패턴을 따르도록 유도하며, GET DIAGNOSTICS와 GET STACKED DIAGNOSTICS의 차이를 주석으로 명시하면 혼동을 크게 줄일 수 있습니다.


관련 에러

  • 0Z000 (diagnostics_exception): GET STACKED DIAGNOSTICS 관련 일반 진단 예외의 부모 에러 코드로, 0Z002와 함께 자주 참조됩니다.
  • P0000 (plpgsql_error): PL/pgSQL 실행 중 발생하는 일반 런타임 에러로, 잘못된 예외 처리 구조와 연관되어 나타날 수 있습니다.
  • 39000 (external_routine_exception): 외부 루틴 호출 중 예외 처리와 관련된 에러로, 진단 정보 접근 오류와 맥락이 유사합니다.
  • XX000 (internal_error): 드문 경우지만 PostgreSQL 내부 상태 불일치로 인해 진단 정보에 접근하지 못할 때 나타날 수 있습니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기