2026년 08월 29일 | DBMS Error 가이드
이 글에서 다루는 내용
ORA-06506 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
ORA-06506 PL/SQL: unhandled user-defined exception 는?
ORA-06506은 PL/SQL 블록 내에서 사용자가 직접 정의한 예외(Exception)가 발생했으나, 해당 예외를 처리하는 EXCEPTION 핸들러가 존재하지 않을 때 발생하는 오류입니다. 즉, 개발자가 RAISE 문이나 RAISE_APPLICATION_ERROR를 통해 예외를 발생시켰지만, 이를 잡아서 처리하는 WHEN 절이 누락된 상황입니다. 이 에러는 주로 복잡한 PL/SQL 패키지나 중첩 블록 구조에서 예외 전파(Exception Propagation) 경로가 명확하지 않을 때 실무에서 자주 마주하게 됩니다.
주요 발생 원인
1. EXCEPTION 핸들러 없이 사용자 정의 예외를 RAISE한 경우
PL/SQL에서 사용자 정의 예외를 선언(DECLARE)하고 RAISE로 발생시킨 후, 해당 예외를 잡는 WHEN 예외명 THEN 절을 작성하지 않으면 ORA-06506이 발생합니다. 특히 하위 블록에서 발생한 예외가 상위 블록으로 전파될 때, 상위 블록에도 핸들러가 없으면 최종적으로 이 에러가 호출자에게 반환됩니다.
2. 패키지 레벨에서 선언된 예외가 외부 블록에서 처리되지 않은 경우
패키지 스펙(Package Specification)에 선언된 전역 예외(Global Exception)를 패키지 내부 프로시저에서 발생시켰을 때, 이를 호출하는 익명 블록(Anonymous Block)이나 외부 프로시저에서 해당 예외에 대한 핸들러를 갖추지 않으면 에러가 발생합니다. 패키지 예외는 패키지명.예외명 형식으로 참조해야 하기 때문에, 이 점을 간과하면 핸들러가 있어도 매칭이 되지 않아 처리가 누락되는 경우가 생깁니다.
3. 중첩 블록(Nested Block)에서 예외 전파 경로 오해
PL/SQL에서 내부 블록(Inner Block)에서 발생한 예외는 해당 블록에서 처리되지 않으면 외부 블록(Outer Block)으로 전파됩니다. 개발자가 내부 블록에서 핸들러를 작성했다고 착각하거나, 예외 처리 후 다시 RAISE로 재발생(Re-raise)시켜 외부로 던졌는데 외부에 핸들러가 없는 경우 ORA-06506이 발생합니다. 이 케이스는 디버깅이 어려워 실무에서 특히 주의가 필요합니다.
해결 방법
원인 1 해결: EXCEPTION 핸들러 추가
사용자 정의 예외를 선언하고 RAISE하는 모든 블록에 반드시 EXCEPTION 핸들러를 추가합니다.
-- 문제가 되는 코드 (핸들러 없음)
DECLARE
e_invalid_salary EXCEPTION;
v_salary NUMBER := -5000;
BEGIN
IF v_salary < 0 THEN
RAISE e_invalid_salary; -- 핸들러 없음 -> ORA-06506 발생
END IF;
END;
/
-- 해결된 코드 (핸들러 추가)
DECLARE
e_invalid_salary EXCEPTION;
v_salary NUMBER := -5000;
BEGIN
IF v_salary < 0 THEN
RAISE e_invalid_salary;
END IF;
EXCEPTION
WHEN e_invalid_salary THEN
DBMS_OUTPUT.PUT_LINE('ERROR: 급여는 0 이상이어야 합니다.');
-- 필요 시 로그 테이블에 기록하거나 재처리 로직 추가
END;
/
원인 2 해결: 패키지 예외를 올바른 참조명으로 처리
패키지에 선언된 예외는 반드시 패키지명.예외명 형식으로 핸들러를 작성해야 합니다.
-- 패키지 스펙 정의
CREATE OR REPLACE PACKAGE pkg_hr AS
e_emp_not_found EXCEPTION;
PROCEDURE get_employee(p_emp_id IN NUMBER);
END pkg_hr;
/
-- 패키지 바디 정의
CREATE OR REPLACE PACKAGE BODY pkg_hr AS
PROCEDURE get_employee(p_emp_id IN NUMBER) IS
v_name VARCHAR2(100);
BEGIN
SELECT first_name INTO v_name
FROM employees
WHERE employee_id = p_emp_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE pkg_hr.e_emp_not_found; -- 패키지 예외를 재발생
END get_employee;
END pkg_hr;
/
-- 호출부에서 반드시 패키지명.예외명으로 핸들러 작성
BEGIN
pkg_hr.get_employee(p_emp_id => 99999);
EXCEPTION
WHEN pkg_hr.e_emp_not_found THEN
-- 패키지명 없이 e_emp_not_found만 쓰면 핸들러 매칭 실패!
DBMS_OUTPUT.PUT_LINE('ERROR: 해당 사원이 존재하지 않습니다.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('예상치 못한 오류: ' || SQLERRM);
END;
/
원인 3 해결: 중첩 블록에서 예외 전파 제어
중첩 블록 구조에서 예외가 외부로 전파될 경우를 대비해 외부 블록에도 핸들러를 마련합니다.
DECLARE
e_business_error EXCEPTION;
v_result NUMBER;
BEGIN
-- 외부 블록
BEGIN
-- 내부 블록
v_result := 10 / 0; -- 예시용 오류 유발
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('내부 블록: 0으로 나누기 오류 감지');
RAISE e_business_error; -- 사용자 정의 예외로 변환 후 외부 블록으로 전파
END;
EXCEPTION
WHEN e_business_error THEN
-- 외부 블록에서 최종 처리
DBMS_OUTPUT.PUT_LINE('외부 블록: 비즈니스 오류를 최종 처리합니다.');
-- 에러 로그 테이블에 기록 예시
INSERT INTO error_log (err_date, err_msg, err_code)
VALUES (SYSDATE, 'Business Error Occurred', -6506);
COMMIT;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('알 수 없는 오류: ' || SQLERRM);
ROLLBACK;
END;
/
EXCEPTION_INIT을 활용한 에러 코드 매핑
사용자 정의 예외에 특정 Oracle 에러 코드를 연결하면 더욱 체계적인 예외 관리가 가능합니다.
DECLARE
e_custom_error EXCEPTION;
PRAGMA EXCEPTION_INIT(e_custom_error, -20001); -- -20001 ~ -20999 사용자 정의 코드
BEGIN
RAISE_APPLICATION_ERROR(-20001, '사용자 정의 오류: 처리할 수 없는 데이터입니다.');
EXCEPTION
WHEN e_custom_error THEN
DBMS_OUTPUT.PUT_LINE('에러 코드: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('에러 메시지: ' || SQLERRM);
END;
/
예방 방법
1. 모든 PL/SQL 블록에 WHEN OTHERS 핸들러를 기본으로 포함
어떤 예외가 발생하더라도 처리되지 않은 채 상위로 전파되지 않도록, 프로시저나 함수의 최상위 EXCEPTION 절에는 반드시 WHEN OTHERS THEN 핸들러를 포함시키는 것을 팀 코딩 표준으로 정의하세요. 단, WHEN OTHERS 절에서는 반드시 SQLCODE와 SQLERRM을 활용해 에러 내용을 로그 테이블에 기록하고, 필요 시 RAISE로 재발생시켜 호출자에게 에러 사실을 알려야 합니다. 이를 통해 예외가 무음으로 흡수되는(Swallowing Exception) 안티패턴을 방지하면서도 ORA-06506을 예방할 수 있습니다.
-- Best Practice: 표준 에러 처리 템플릿
CREATE OR REPLACE PROCEDURE standard_proc_template AS
BEGIN
-- 비즈니스 로직
NULL;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO error_log (err_date, proc_name, err_code, err_msg)
VALUES (SYSDATE, 'STANDARD_PROC_TEMPLATE', SQLCODE, SUBSTR(SQLERRM, 1, 500));
COMMIT;
RAISE; -- 호출자에게 재전파
END;
/
2. 예외 처리 전용 유틸리티 패키지 도입
개별 프로시저마다 예외 처리 로직을 반복 작성하는 대신, 공통 에러 로깅 패키지를 만들어 일관된 방식으로 예외를 처리하세요. 이 패키지 안에 자주 사용하는 사용자 정의 예외를 중앙에서 선언하고 관리하면, 예외 핸들러 누락이나 잘못된 예외 참조로 인한 ORA-06506 발생 가능성을 크게 줄일 수 있습니다.
관련 에러
- ORA-06500: PL/SQL 스토리지 오류로 인해 예외가 정상 처리되지 못할 때 관련될 수 있습니다.
- ORA-06501: PL/SQL 프로그램 오류로, 예외 처리 로직 자체에 버그가 있을 때 발생할 수 있습니다.
- ORA-06502: 수치 또는 값 오류로, 예외 처리 중 데이터 타입 불일치 시 함께 발생하는 경우가 있습니다.
- ORA-01403 (NO_DATA_FOUND): SELECT INTO 문에서 데이터가 없을 때 발생하며, 이를 잡지 않고 사용자 정의 예외로 변환할 때 ORA-06506으로 이어질 수 있습니다.
- ORA-20000 ~ ORA-20999:
RAISE_APPLICATION_ERROR로 발생시키는 사용자 정의 에러 코드 범위로, EXCEPTION_INIT과 함께 ORA-06506 예방에 활용됩니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.