예외처리 - 2

    예외 처리기에서의 오류 조회 함수

    예외 처리기에서는 기본적으로 발생한 예외와 관련되는 오류 번호와 오류 메세지를 조회하는 함수를 사용하여 오류 정보를 확인할 수 있다. 오류 번호를 조회하는 함수는 SQLCODE고, 오류 메세지를 조회하는 함수는 SQLERRM이다.

    이 외에도 오류 관련된 정보를 출력하는 데 사용할 수 있는 추가적인 세 개의 함수가 내장 패키지 DBMS_UTILITY에 정의되어 있다.

     

    FORMAT_ERROR_BACKTRACE

    패키지 DBMS_UTILITY의 서브함수 FORMAT_ERROR_BACKTRACE는 오류가 발생한 지점에서부터 해당 예외를 처리하는 예외 처리기까지의 백트레이스(Backtrace)를 반환한다.

    DECLARE
    	PROCEDURE p IS
        BEGIN
        	RAISE_APPLICATION_ERROR(-20001, '사용자 지정 예외');
        END;
    BEGIN
    	P;
    EXCEPTION WHEN OTHERS THEN
    	DBMS_OUTPUT_PUT_LINE(SQLERRM);
        DBMS_OUTPUT_PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
    END;

     

    FORMAT_ERROR_STACK

    패키지 DBMS_UTILITY의 서브함수 FORMAT_ERROR_STACK은 현재의 오류 스택을 반환한다.

    DECLARE
    	PROCEDURE p IS
        BEGIN
        	RAISE_APPLICATION_ERROR(-20001, '사용자 지정 예외');
        END;
    BEGIN
    	p;
    EXCEPTION WHEN OTHERS THEN
    	DBMS_OUTPUT_PUT_LINE(SQLERRM);
        DBMS_OUTPUT_PUT_LINE(DBMS_UTILITY.FORMAT_ERROR_STACK);
    END;

    SQLERRM이 최대 512바이트까지의 정보를 알려 주는 데 비해 FORMAT_ERROR_STACK은 최대 2000바이트까지의 메시지를 알려준다.

     

    FORMAT_CALL_STACK

    패키지 DBMS_UTILITY의 서브함수 FORMAT_CALL_STACK은 함수가 호출되는 지점까지의 풀스택을 반환한다.

    CREATE OR REPLACE PROCEDURE p2 IS
    BEGIN
    	DBMS_OUTPUT_PUT_LINE(DBMS_UTILITY.FORMAT_CALL_STACK);
        RAISE_APPLICATION_ERROR(-20001, '사용자 지정 예외');
    END;
    CREATE OR REPLACE PROCEDURE p1 IS
    BEGIN
    	p2;
    EXCEPTION WHEN OTHERS THEN
    	DBMS_OUTPUT_PUT_LINE(SQLERRM);
        DBMS_OUTPUT_PUT_LINE(DBMS_UTILITY.FORMAT_CALL_STACK);
    END;

    두 프로시저는 각각 FORMAT_CALL_STACK을 호출하고 있다. 프로시저 p2의 3번 줄의 FORMAT_CALL_STACK은 오류와 관계없이 사용되었고 프로시저 p1의 6번 줄의 FORMAT_CALL_STACK은 예외 처리기에서 사용되었다. 여기서 알 수 있는 사실은 FORMAT_CALL_STACK 함수는 오류와 관련 없이 사용할 수 있다는 것이다. 예외가 발생하지 않았을 경우 FORMAT_ERROR_BACKTRACE나 FORMAT_ERROR_STACK을 호출하면 NULL을 반환하지만 FORMAT_CALL_STACK은 항상 현재 지점까지의 콜스텍을 반환한다.

     

    FORMAT_CALL_STACK에 의한 메시지는 마치 자바 프로그램에서 오류 발생 시에 콜스택을 뿌려주는 것과 비슷하다.

    출력은 세 개의 칼럼으로 이루어지는데, 오브젝트 핸들(object handle), 줄 번호(line number), 오브젝트 이름(object name)으로 구성되어 있다.

     

    FORMAT_CALL_STACK이 알려주는 위치는 오류가 발생한 지점의 콜스택이 아니라 이 함수가 호출된 지점의 콜스택이라는 것에 주의해야 한다.

     

    예외 처리에서 주로 하는 작업

    트랜잭션 마무리

    예외가 발생하는 경우 오류 발생 이전까지의 트랜잭션을 ROLLBACK하거나 COMMIT한다. 예외가 발생하면 목적하는 처리가 완료되지 않은 경우가 대부분이므로 ROLLBACK하는 경우가 많으며 이를 통해 트랜잭션의 일관성을 보장해 주는 역할을 한다.

    DECLARE
    	v_sal NUMBER;
        v_comm NUMBER;
    BEGIN
    	-- 정상 수행
        SELECT sal INTO v_sal
          FROM emp
         WHERE ename = 'SMITH';
         
        UPDATE emp
           SET comm = v_sal * 0.05
         WHERE ename = 'SMITH';
         
       -- SELECT문에서 NO_DATA_FOUND 예외 발생(ENAME='Martin'은 없음)
       SELECT sal INTO v_sal
         FROM emp
        WHERE ename = 'Martin';
        
       UPDATE emp
          SET comm = v_sal * 0.05
        WHERE ename = 'Martin';
        
      -- NO_DATA_FOUND 예외 처리기
      EXCEPTION WHEN NO_DATA_FOUND THEN
      	-- 트랜잭션 취소
        ROLLBACK;
    END;

    예외 처리를 하지 않거나 예외 처리기에서 ROLLBACK을 하지 않으면 10줄의 UPDATE만 데이터베이스에 반영되어 데이터의 무결성이 손상되는 상황이 발생할 수 있다. 위 프로그램에서는 15번 줄에서 NO_DATA_FOUND 예외가 발생하는데 24번 줄의 예외 처리기가 이를 잡아서 트랜잭션을 ROLLBACK 처리함으로써 처리가 일부만 COMMIT될 수 있는 가능성을 방지해 준다.

     

    변수나 반환값 지정

    예외가 발생하면 변수를 특정 값으로 설정하거나 RETURNING문으로 특정 값을 반환할 수 있다.

    DECLARE
    	v_name	VARCHAR2(100);
    BEGIN
    	BEGIN
        	SELECT ename INTO v_name
              FROM emp 
             WHERE empno = -1;	-- 사원번호 -1은 존재하지 않음
           EXCEPTION WHEN NO_DATA_FOUND THEN
           	-- 사원 미존재 시 사원명을 특정 값으로 함
            v_name := '<존재하지 않는 사원>';
           END;
           DBMS_OUTPUT_PUT_LINE('사원명 : '|| v_name);
    END;

    디버깅 정보 출력

    예외 발생 시 디버깅을 위한 메시지를 출력하거나 로그 테이블에 로그를 남긴다.

    이 출력은 프로그램 개발 시나 운영 시에 예측하지 못했던 오류가 발생하는 경우 이를 분석하는 데 유용하다.

    DECLARE
    	v_name	VARCHAR2(100);
        v_code	NUMBER;
        v_errm	VARCHAR2(60);
    BEGIN
    	SELECT ename INTO v_name
          FROM emp
         WHERE empno = -1;
        EXCEPTION WHEN OTHERS THEN
        	v_code := SQLCODE;
            v_errm := SUBSTR(SQLERRM, 1, 60);
            DBMS_OUTPUT_PUT_LINE('오류 코드 '||v_code||': '||v_errm);
    END;

    SQLERRM은 PL/SQL에서 발생한 오류 코드 SQLCODE에 대응되는 오류 메시지인데 최대 길이가 512바이트로 제한된다.

    PL/SQL 프로그램에서 처리되지 않은 예외가 발생할 때 출력되는 메시지는 여러 줄에 걸쳐서 상당히 자세한 정보를 보여 준다. 특히 이 출력에는 오류가 발생한 소스 코드의 위치 정보와 오류 콜스택 정보를 포함하고 있어서 유용하지만, SQLERRM에는 이런 정보는 포함되어 있지 않다.

     

    오류 무시

    발생한 오류를 무시하고 처리를 계속하거나 해당 PL/SQL 블록을 종료하는 방식의 처리를 할 수 있다.

    예외 처리는 최소한 하나의 문장을 가져야 하며 아무 문장도 지정하지 않으면 컴파일 오류가 발생한다.

    따라서 오류를 무시하고 아무것도 하지 않을 경우에는 예외 처리문으로 NULL문이라도 사용해야 한다,

    DECLARE
    	v_name VARCHAR2(100) := '<존재하지 않는 사원>';
    BEGIN
    	BEGIN
        	SELECT ename INTO v_name
              FROM emp
             WHERE empno = -1;
           EXCEPTION WHEN NO_DATA_FOUND THEN
           	-- 예외 무시
            NULL;
        END;
        DBMS_OUTPUT_PUT_LINE('사원명 : '||v_name);
    END;

     

    'DATABASE > SQL, PL-SQL' 카테고리의 다른 글

    Stored Function(저장 함수)  (0) 2021.03.09
    저장 서브프로그램 개요  (0) 2021.03.03
    예외 처리 - 1  (0) 2021.02.23
    동적 SQL  (0) 2021.02.20
    Cursor(커서) - 2  (0) 2021.02.18

    댓글