예외 상황 처리(PL/SQL)

기본적으로 PL/SQL 프로그램에서 발생한 오류는 프로그램 실행을 중지합니다. EXCEPTION 섹션을 사용하여 오류를 트랩하고 복구할 수 있습니다.

예외 상황 처리기(exception handler) 구문은 BEGIN 블록 구문의 확장입니다.

구문

구문 도표 읽기시각적 구문 도표 생략
                                        .---------------.   
                                        V               |   
>>-+--------------------------+--BEGIN----+-----------+-+------->
   |          .-------------. |           '-statement-'     
   |          V             | |                             
   '-DECLARE----declaration-+-'                             

>--+------------------------------------------------------------------------------------------+-->
   |                                       .-------------------.        .-------------------. |   
   |                                       V                   |        V                   | |   
   '-EXCEPTION--WHEN--exception-condition----+---------------+-+--THEN----handler-statement-+-'   
                                             '-OR--condition-'                                    

>--END---------------------------------------------------------><

오류가 발생하지 않은 경우 블록은 단순히 statement를 실행하고 END 다음의 명령문으로 제어가 전달됩니다. 그러나 statement 실행 중 오류가 발생한 경우 statement 처리가 중단되고 EXCEPTION 섹션으로 제어가 전달됩니다. WHEN절에서 발생한 오류와 일치하는 첫 번째 예외를 검색합니다. 일치하는 항목이 있으면 대응하는 handler-statement가 실행되고 END 다음의 명령문으로 제어가 전달됩니다. 일치하는 항목이 없으면 프로그램 실행이 중지됩니다.

handler-statement 실행 중에 새 오류가 발생하는 경우에는 주위의 EXCEPTION절에 의해서만 오류가 예외 처리(catch)될 수 있습니다.

WHEN절의 예외는 사용자 정의 예외이거나 내장 예외입니다. 사용자 정의 예외는 현재 블록 또는 주변 블록의 DECLARE 섹션이나 PL/SQL 패키지의 DECLARE 섹션에 정의할 수 있습니다. 예외 정의 바로 뒤에 PRAGMA EXCEPTION_INIT 또는 PRAGMA DB2_EXCEPTION_INIT 구문을 사용하여 사용자 정의 예외에 대응하는 sqlcode 또는 sqlstate를 지정할 수 있습니다.

다음 예에서는 DECLARE 섹션에 이름 지정된 세 예외의 정의가 포함됩니다. 블록의 본문은 프로시저 MyApp.Main에 대한 호출입니다. EXCEPTION 섹션에는 다음 세 예외에 대한 핸들러가 있습니다.
  1. exception1은 sqlcode 또는 sqlstate와 연관되어 있지 않습니다.
  2. exception2는 sqlcode -942(정의되지 않은 이름)와 연관되어 있습니다.
  3. exception3은 sqlstate 42601(구문 오류)과 연관되어 있습니다.
DECLARE
  exception1 EXCEPTION;
  exception2 EXCEPTION;
  PRAGMA EXCEPTION_INIT(exception2,-942);
  exception3 EXCEPTION;
  PRAGMA DB2_EXCEPTION_INIT(exception3,'42601');
BEGIN
  MyApp.Main(100);
EXCEPTION
  WHEN exception1 THEN
      DBMS_OUTPUT.PUT_LINE('User-defined exception1 caught');
  WHEN exception2 THEN
      DBMS_OUTPUT.PUT_LINE('User-defined exception2 (Undefined name) caught');
  WHEN exception3 THEN
      DBMS_OUTPUT.PUT_LINE('User-defined exception3 (Syntax error) caught');
END
참고: 데이터 서버에서 PRAGMA EXCEPTION_INIT에 대한 인수로 수락할 수 있는 Oracle sqlcode 수는 제한되어 있습니다. 전체 목록은 Oracle-IBM Db2 on Cloud, IBM Db2 Warehouse on Cloud 및 IBM Db2 Warehouse 오류 맵핑(PL/SQL)의 내용을 참조하십시오.

PRAGMA EXCEPTION_INIT로 초기화된 예외가 예외 처리(catch)된 경우, SQLCODE 함수가 리턴하는 값은 Oracle 값이 아니라 예외와 연관된 sqlcode입니다. 앞의 예에서 exception2가 예외 처리(catch)되는 경우, SQLCODE가 리턴하는 값은 Oracle sqlcode -942에 대응하는 sqlcode인 -204입니다. PRAGMA EXCEPTION_INIT에 지정된 Oracle sqlcode가 Oracle- 오류 맵핑 테이블에 나열되어 있지 않는 경우에는 컴파일에 실패합니다. PRAGMA EXCEPTION_INIT를 PRAGMA DB2_EXCEPTION_INIT로 대체하고 식별하려는 오류에 대응하는 sqlstate를 지정하면 이를 방지할 수 있습니다.

표 1에서는 사용 가능한 내장 예외를 요약합니다. 특수 예외 이름 OTHERS는 모든 예외와 일치합니다. 조건 이름은 대소문자를 구분하지 않습니다.
표 1. 내장 예외 이름
예외 이름 설명
CASE_NOT_FOUND CASE문에 있는 어느 케이스도 "true"로 평가되지 않으며, ELSE 조건이 없습니다.
CURSOR_ALREADY_OPEN 이미 열린 커서를 열려고 했습니다.
DUP_VAL_ON_INDEX 인덱스 키에 대한 중복 값이 있습니다.
INVALID_CURSOR 열리지 않은 커서에 액세스하려고 했습니다.
INVALID_NUMBER 숫자 값이 유효하지 않습니다.
LOGIN_DENIED 사용자 이름 또는 암호가 유효하지 않습니다.
NO_DATA_FOUND 선택 기준을 만족시키는 행이 없습니다.
NOT_LOGGED_ON 데이터베이스 연결이 없습니다.
OTHERS 예외 섹션에서 이전 조건에 의해 예외 처리(catch)되지 않은 예외에 해당합니다.
SUBSCRIPT_BEYOND_COUNT 배열 인덱스가 범위를 벗어났거나 존재하지 않습니다.
SUBSCRIPT_OUTSIDE_LIMIT 배열 인덱스 표현식의 데이터 유형을 배열 인덱스 유형에 지정할 수 없습니다.
TOO_MANY_ROWS 선택 기준을 만족시키는 행이 둘 이상 있지만 하나의 행만 리턴할 수 있습니다.
VALUE_ERROR 값이 유효하지 않습니다.
ZERO_DIVIDE 0으로 나누려고 했습니다.