본문 바로가기
■Development■/《Database》

[DB] ORA-06512 에러 원인과 해결 방법

by 은스타 2024. 7. 1.
반응형

Oracle ORA-06512 에러 완벽 가이드: 원인과 해결 방법 총정리

안녕하세요.

이번 포스팅은  Oracle 데이터베이스를 사용하다 보면 자주 마주치게 되는 ORA-06512 에러에 대해 상세히 알아보겠습니다. 이 에러는 많은 개발자와 DBA들이 처음 접했을 때 다소 혼란스러울 수 있지만, 본질적으로는 매우 중요한 정보를 제공하는 메시지입니다. 이 글에서는 ORA-06512 에러의 정확한 의미와 이를 효과적으로 해결하는 방법에 대해 자세히 설명해 드리겠습니다.


목차

  1. ORA-06512 에러란?
  2. ORA-06512 에러 메시지 구조
  3. ORA-06512 에러의 주요 원인
  4. ORA-06512 에러 해결 방법
  5. 자주 함께 발생하는 관련 에러
  6. 실제 사례를 통한 문제 해결
  7. 개발자를 위한 디버깅 팁
  8. 마무리

 

#1. ORA-06512 에러란?

ORA-06512는 Oracle 데이터베이스에서 PL/SQL 코드 실행 중 예외(Exception)가 발생했을 때 호출 스택 정보를 전달하는 에러 메시지입니다. 이 에러 자체가 문제의 원인이 아니라, 어디서 문제가 발생했는지 위치 정보를 알려주는 일종의 정보 전달 메시지입니다.

ORA-06512는 일반적으로 다른 Oracle 에러 메시지와 함께 발생하며, 에러가 발생한 정확한 위치를 알려줍니다. 즉, 이 에러는 "무엇이" 문제인지가 아니라 "어디서" 문제가 발생했는지를 알려주는 역할을 합니다.

 

#2. ORA-06512 에러 메시지 구조

ORA-06512 에러 메시지는 다음과 같은 구조로 표시됩니다:

ORA-06512: at "스키마명.프로시저/함수명"line 행번호

또는

ORA-06512at line 행번호

이 메시지는 다음 정보를 제공합니다:

  • 스키마명: 에러가 발생한 객체의 소유자
  • 프로시저/함수명: 예외가 발생한 PL/SQL 코드 블록(프로시저, 함수, 패키지 등)
  • 행번호: 해당 코드 블록 내에서 에러가 발생한 정확한 줄 번호

예를 들어:

ORA-06512: at "HR.UPDATE_EMPLOYEE"line 45

이는 HR 스키마의 UPDATE_EMPLOYEE 프로시저/함수의 45번 줄에서 에러가 발생했음을 의미합니다.

 

#3. ORA-06512 에러의 주요 원인

ORA-06512 자체는 원인이 아니라 위치 정보를 제공하는 메시지이므로, 실제 문제의 원인은 함께 표시되는 다른 에러 메시지에서 찾아야 합니다. 일반적으로 에러 스택의 맨 처음에 나타나는 에러 메시지가 실제 문제의 원인입니다.

주요 원인으로는 다음과 같은 경우가 있습니다:

  1. 명시적 예외 발생: RAISE 문을 통해 명시적으로 예외를 발생시킨 경우
  2. 사전 정의된 예외: NO_DATA_FOUND, TOO_MANY_ROWS 등의 사전 정의된 예외가 발생한 경우
  3. SQL 오류: SQL 문 실행 중 발생한 오류(테이블/컬럼 없음, 제약조건 위반 등)
  4. 사용자 정의 예외: 사용자가 정의한 예외가 발생한 경우
  5. 리소스 제한: 메모리 부족, 커서 개수 초과 등 리소스 제한에 도달한 경우
  6. 중첩 프로시저/함수 호출: 여러 계층의 호출 스택에서 발생한 에러

 

#4. ORA-06512 에러 해결 방법

ORA-06512 에러를 해결하기 위한 기본 접근법은 다음과 같습니다:

1) 실제 에러 메시지 확인

에러 스택의 첫 번째 메시지가 실제 문제의 원인을 알려줍니다. 예를 들어:

ORA-01403: no data found
ORA-06512 : at "HR.GET_EMPLOYEE", line 22
ORA-06512 : at "HR.UPDATE_SALARY", line 15
ORA-06512: at line 3

여기서 실제 문제는 ORA-01403: no data found로, 조회하려는 데이터가 없다는 것을 의미합니다.

2) 코드 검사

에러 메시지에서 언급된 코드 위치를 확인합니다:

-- 해당 프로시저의 소스 코드 확인
SELECT TEXT 
FROM USER_SOURCE 
WHERE NAME = 'UPDATE_EMPLOYEE' 
ORDER BY LINE;

3) 예외 처리 로직 추가

발생 가능한 예외에 대한 적절한 처리 로직을 추가합니다:

CREATE OR REPLACE PROCEDURE update_employee(p_emp_id IN NUMBER) AS
BEGIN
  -- 기존 코드

  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      -- 데이터가 없을 때 처리 로직
      DBMS_OUTPUT.PUT_LINE('Employee ID ' || p_emp_id || ' not found.');
    WHEN  OTHERS THEN
      -- 기타 예외 처리
      DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
      -- 오류 로깅 등 추가 처리
END;

4) 디버깅 정보 추가

문제 파악을 위해 디버깅 정보를 추가합니다:

CREATE OR REPLACE PROCEDURE debug_proc AS
  v_var NUMBER;
BEGIN
  DBMS_OUTPUT.PUT_LINE('Starting procedure...');

  -- 문제 구간 전
  DBMS_OUTPUT.PUT_LINE('Before problematic section');

  -- 문제 발생 가능성이 있는 코드
  SELECT salary INTO v_var FROM employees WHERE employee_id = 999;

  -- 문제 구간 후 (이 부분은 예외 발생 시 실행되지 않음)
  DBMS_OUTPUT.PUT_LINE('After problematic section');

EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
    DBMS_OUTPUT.PUT_LINE('Error stack: ' || DBMS_UTILITY.FORMAT_ERROR_STACK);
    DBMS_OUTPUT.PUT_LINE('Error backtrace: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    RAISE; -- 선택적으로 예외를 다시 발생시킴
END;

 

#5. 자주 함께 발생하는 관련 에러

ORA-06512와 함께 자주 발생하는 에러들과 그 의미를 살펴보겠습니다:

  1. ORA-01403: no data found
    • SELECT INTO 문에서 데이터를 찾지 못한 경우
    • 해결: 데이터 존재 여부 확인 또는 예외 처리 추가
  2. ORA-01422: exact fetch returns more than requested number of rows
    • SELECT INTO 문에서 여러 행이 반환된 경우
    • 해결: WHERE 조건 구체화 또는 CURSOR 사용
  3. ORA-00001: unique constraint violated
    • 고유 제약조건 위반
    • 해결: 중복 데이터 체크 로직 추가
  4. ORA-04068: existing state of packages has been discarded
    • 패키지 재컴파일 후 이전 상태가 무효화된 경우
    • 해결: 세션 재접속 또는 패키지 초기화 로직 검토
  5. ORA-06502: PL/SQL: numeric or value error
    • 수치 연산 에러 또는 변수 크기 제한 초과
    • 해결: 데이터 유형 및 크기 조정
  6. ORA-06511: PL/SQL: cursor already open
    • 이미 열린 커서를 다시 열려고 시도
    • 해결: 커서 관리 로직 검토

 

#6. 실제 사례를 통한 문제 해결

실제 ORA-06512 에러 사례와 해결 방법을 살펴보겠습니다:

사례 1: 저장 프로시저 내 NO_DATA_FOUND 예외

에러 메시지:

ORA-01403: no data found
ORA-06512: at "HR.GET_EMPLOYEE_SALARY", line 15

문제 코드:

CREATE OR REPLACE PROCEDURE get_employee_salary(p_emp_id IN NUMBER, p_salary OUT NUMBER) AS
BEGIN
  SELECT salary INTO p_salary
  FROM employees
  WHERE employee_id = p_emp_id;
END;

해결 방법:

CREATE OR REPLACE PROCEDURE get_employee_salary(p_emp_id IN NUMBER, p_salary OUT NUMBER) AS
BEGIN
  SELECT salary INTO p_salary
  FROM employees
  WHERE employee_id = p_emp_id;

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    p_salary := NULL;
    -- 또는 로그 기록, 사용자 정의 예외 발생 등
END;

사례 2: 트리거에서의 예외

에러 메시지:

ORA-00001unique constraint violated
ORA-06512: at "HR.EMP_ID_CHECK_TRIGGER", line 5
ORA-04088: error during execution of trigger 'HR.EMP_ID_CHECK_TRIGGER'

문제 코드:

CREATE OR REPLACE TRIGGER emp_id_check_trigger
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
  -- 중복 ID 체크 없이 바로 삽입
  INSERT INTO employee_audit(employee_id, action_date, action)
  VALUES (:new.employee_id, SYSDATE, 'INSERT');
END;

해결 방법:

CREATE OR REPLACE TRIGGER emp_id_check_trigger
BEFORE INSERT ON employees
FOR EACH ROW
DECLARE
  v_count NUMBER;
BEGIN
  -- 감사 테이블에 이미 존재하는지 확인
  SELECT COUNT(*) INTO v_count
  FROM employee_audit
  WHERE employee_id = :new.employee_id AND action = 'INSERT';

  -- 존재하지 않는 경우에만 삽입
  IF v_count = 0 THEN
    INSERT INTO employee_audit(employee_id, action_date, action)
    VALUES (:new.employee_id, SYSDATE, 'INSERT');
  ELSE
    -- 이미 존재하면 업데이트 또는 무시
    UPDATE employee_audit
    SET action_date = SYSDATE
    WHERE employee_id = :new.employee_id AND action = 'INSERT';
  END IF;
END;

 

#7. 개발자를 위한 디버깅 팁

ORA-06512 에러를 효과적으로 디버깅하기 위한 팁을 소개합니다:

1) 자세한 오류 정보 출력

DECLARE
  v_error_stack VARCHAR2(4000);
  v_call_stack VARCHAR2(4000);
BEGIN
  -- 문제 코드 실행

EXCEPTION
  WHEN OTHERS THEN
    v_error_stack := DBMS_UTILITY.FORMAT_ERROR_STACK;
    v_call_stack := DBMS_UTILITY.FORMAT_ERROR_BACKTRACE;

    -- 오류 정보 기록
    INSERT INTO error_log (
      error_time, error_code, error_message, 
      error_stack, call_stack, procedure_name
    ) VALUES (
      SYSTIMESTAMP, SQLCODE, SQLERRM,
      v_error_stack, v_call_stack, 'your_procedure_name'
    );

    -- 원래 예외 다시 발생
    RAISE;
END;

2) 코드 섹션별 디버깅

CREATE OR REPLACE PROCEDURE debug_sections AS
  v_section VARCHAR2(30);
BEGIN
  v_section := 'INITIALIZATION';
  DBMS_OUTPUT.PUT_LINE('Starting section: ' || v_section);
  -- 초기화 코드

  v_section := 'DATA_RETRIEVAL';
  DBMS_OUTPUT.PUT_LINE('Starting section: ' || v_section);
  -- 데이터 조회 코드

  v_section := 'DATA_PROCESSING';
  DBMS_OUTPUT.PUT_LINE('Starting section: ' || v_section);
  -- 데이터 처리 코드

  v_section := 'COMPLETION';
  DBMS_OUTPUT.PUT_LINE('Starting section: ' || v_section);
  -- 완료 처리 코드

EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Error in section: ' || v_section);
    DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
    RAISE;
END;

3) 조건부 컴파일 사용

CREATE OR REPLACE PROCEDURE debug_mode_proc
$IF $$DEBUG_MODE $THEN
  -- 디버그 모드일 때만 선언되는 변수들
  (p_debug IN BOOLEAN DEFAULT TRUE)
$ELSE
  -- 일반 모드의 매개변수
  (p_debug IN BOOLEAN DEFAULT FALSE)
$END
AS
BEGIN
  -- 기본 로직

  $IF $$DEBUG_MODE $THEN
  -- 디버그 모드에서만 실행되는 코드
  IF p_debug THEN
    DBMS_OUTPUT.PUT_LINE('Debug information...');
  END IF;
  $END

EXCEPTION
  WHEN OTHERS THEN
    $IF $$DEBUG_MODE $THEN
    -- 디버그 모드의 상세 오류 처리
    DBMS_OUTPUT.PUT_LINE('Detailed error: ' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    $ELSE
    -- 일반 모드의 기본 오류 처리
    NULL;
    $END
    RAISE;
END;

4) 로깅 유틸리티 활용

CREATE OR REPLACE PACKAGE log_util AS
  PROCEDURE log_debug(p_message VARCHAR2);
  PROCEDURE log_error(p_message VARCHAR2, p_error_code NUMBER := SQLCODE, p_error_msg VARCHAR2 := SQLERRM);
  PROCEDURE log_info(p_message VARCHAR2);
END;

CREATE OR REPLACE PACKAGE BODY log_util AS
  PROCEDURE log_debug(p_message VARCHAR2) IS
  BEGIN
    INSERT INTO application_logs(log_time, log_level, message)
    VALUES(SYSTIMESTAMP, 'DEBUG', p_message);
    COMMIT;
  END;

  PROCEDURE log_error(p_message VARCHAR2, p_error_code NUMBER := SQLCODE, p_error_msg VARCHAR2 := SQLERRM) IS
  BEGIN
    INSERT INTO application_logs(log_time, log_level, message, error_code, error_message)
    VALUES(SYSTIMESTAMP, 'ERROR', p_message, p_error_code, p_error_msg);
    COMMIT;
  END;

  PROCEDURE log_info(p_message VARCHAR2) IS
  BEGIN
    INSERT INTO application_logs(log_time, log_level, message)
    VALUES(SYSTIMESTAMP, 'INFO', p_message);
    COMMIT;
  END;
END;

 

#8. 마무리

ORA-06512 에러는 그 자체로 문제를 일으키는 에러가 아니라, 어디서 문제가 발생했는지 위치 정보를 알려주는 메시지입니다. 이 에러를 효과적으로 처리하기 위해서는:

  1. 함께 발생한 다른 에러 메시지를 확인하여 실제 원인을 파악합니다.
  2. 에러가 발생한 정확한 위치(프로시저/함수와 줄 번호)를 확인합니다.
  3. 적절한 예외 처리 로직을 추가하여 예상 가능한 예외 상황에 대처합니다.
  4. 로깅 및 디버깅 정보를 활용하여 문제 발생 경로를 추적합니다.

PL/SQL 개발에서 ORA-06512 에러 메시지는 결국 문제 해결의 시작점이 되는 중요한 단서를 제공합니다. 이 에러 메시지가 제공하는 정보를 올바르게 해석하고 활용한다면, 복잡한 PL/SQL 애플리케이션에서도 문제를 빠르고 정확하게 해결할 수 있을 것입니다.

업무에서 PL/SQL 코드를 개발하거나 유지보수할 때, 이 가이드가 도움이 되길 바랍니다. 문제 발생 시 침착하게 에러 스택을 분석하고, 적절한 디버깅 기법을 활용하여 효과적으로 문제를 해결하시기 바랍니다.

긴 글 읽어주셔서 감사합니다!


참고 자료:

반응형