# 스토어드 프로그램 예외 발생 정리

Programming 2017. 10. 27. 11:56

이 글은  이성욱 저, 개발자와 DBA를 위한 Real MySQL, 위키북스 교재의 스토어드 프로그램중 예외 처리 부분을 정리한 내용이다.


※ SQLSTATE와 Error No

■ ERROR-NO

  - 4자리 숫자값으로 구성된 에러코드로, MySQL에서만 유효한 에러 식별번호

■ SQL-STATE 

  - 다섯 글자의 알파벳과 숫자로 구성되며, 에러뿐 아니라 여러 가지 상태를 의미하는 코드

→ 반드시 문자열로 입력해야 함

  - DBMS 종류가 다르다 하더라도 ANSI SQL 표준을 준수하는 DBMS에서는 모두 똑같은 값과 의미를 가짐

  - 대부분의 MySQL 에러 번호는 특정 SqlState 값과 매핑돼 있으며, 매핑되지 않는 ErrorNo는 SqlState값이 “HY000”(General error)으로 설정

  - SqlState값의 앞 2글자는 다음과 같은 의미를 가진다.

“00”

정상 처리됨 (에러 아님)

“01”

경고 메시지(Warning)

“02”

Not found

SELECT나 Cursor에서 결과가 없는 경우에만 사용

  - 에러 메시지의 목록은 아래의 MySQL메뉴얼에서 확인 가능

  - https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html


※ 핸들러

DECLARE ①handler_type HANDLER

FOR ②condition_value [, condition_value] ...

③handler_statements


■ handler_type

EXIT

정의된 handler_statements를 실행한 뒤에 이 핸들러가 정의된 BEGIN…END 블록을 벗어남

- 현재 핸들러가 최상위 BEGIN…END 블록에 정의됐다면 현재 스토어드 프로그램을 벗어나서 종료

- 스토어드 함수에서 EXIT 핸들러가 정의된다면 이 핸들러의 handler_statements 부분에서는 반드시 함수의 반환 타입에 맞는 적절한 값을 반환하는 코드가 포함되어야 함

CONTINUE

- handler_statements를 실행하고 스토어드 프로그램의 마지막 실행 지점으로 다시 돌아가 나머지 코드를 처리


■ condition_value

SQLSTATE

- 스토어드 프로그램이 실행되는 도중 어떤 이벤트가 발생했을 때 해당 이벤트의 SQLSTATE 값이 일치할 때 실행되는 핸들러를 정의할 때 사용

SQLWARNING

- 스토어드 프로그램에서 코드를 실행하던 도중 경고(SQL Warning)가 발생했을 때 실행되는 핸들러를 정의할 때 사용

- SQLSTATE값이 01로 시작하는 이벤트를 의미

ERROR NO

SQL STATE

ERROR NAME

설명

1265

01000

WARN_DATA_TRUNCATED

sql_mode 시스템 변수에 STRICT_ALL_TABLES가 설정되지 않은 경우 칼럼의 지정된 크기보다 큰 값을 저장하는 경우에 발생하는 경고

NOT FOUND

- SELECT 쿼리문의 결과 건수가 1건도 없거나, CURSOR의 레코드를 마지막까지 읽은 뒤에 실행하는 핸들러를 정의할 때 사용

- SQLSTATE값이 02로 시작하는 이벤트 의미

SQLEXCEPTION

- SQL Warning와 NOT FOUND 그리고 00(정상 처리)으로 시작하는 SQLSTATE 이외의 모든 케이스를 의미


■ CONDITION을 생성하고 그 CONDITION의 이름을 명시할 수도 있음

■ condition_value는 구분자(,)를 이용해 여러 개를 동시에 나열할 수도 있음

■ “00000”인 SQLSTATE와 에러 번호 0은 모두 정상적으로 처리되었음을 의미하므로 condition_value에 사용해서는 안됨

DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET error_flag=1;

DECLARE EXIT HANDLER FOR SQLEXCEPTION

BEGIN 

ROLLBACK;

SELECT ‘Error occurred – terminating’;

END;;

DECLARE CONTINUE HANDLER FOR 1022, 1062

SELECT ‘Duplicate key in index’;

DECLARE CONTINUE HANDLER FOR NOT FOUND

SET process_done=1;

DECLARE CONTINUE HANDLER FOR SQLSTATE ‘02000’

SET process_done=1;

DECLARE CONTINUE HANDLER FOR 1329

SET process_done=1;

DECLARE EXIT HANDLER FOR SQLWARNING, SQLEXCEPTION

BEGIN

ROLLBACK;

SELECT ‘Process terminated, Because error’;

SHOW ERRORS;

SHOW WARNING;

END;;


※ 컨디션

DECLARE condition_name CONDITION FOR condition_value

■ condition_name : 부여하려는 이름을 단순 문자열로 입력

■ condition_value 

  - MySQL의 에러 번호를 사용할 때는 condition_value에 바로 MySQL의 에러 번호를 입력

  - 컨디션을 정의할 때는 에러 코드의 값을 여러 개 동시에 명시할 수 없음

  - SQLSTATE를 명시하는 경우 SQLSTATE 키워드를 입력하고 그 뒤에 SQLSTATE값을 입력

DECLARE dup_key CONDITION FOR 1062;

DELIMITER ;;

CREATE FUNCTION sf_testfunc()

RETURNS BIGINT

BEGIN

DECLARE dup_key CONDITION FOR 1062;

DECLARE EXIT HANDLER FOR dup_key

BEGIN 

RETURN –1;

END;

 

INSERT INTO tb_test VALUES (1);

RETURN 1;

END ;;


※ 시그널 (딱히 정리할 개념이 없으므로 예제만 기록)

BEGIN

DECLARE null_divisor CONDITION FOR SQLSTATE '45000';

IF p_divisor IS NULL THEN

SIGNAL null_divisor SET MESSAGE_TEXT='Divisor can not null', MYSQL_ERRNO=9999;

ELSEIF p_divisor = 0 THEN

SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Divisor can not be 0', MYSQL_ERRNO=9998;

 

ELSEIF p_dividend IS NULL THEN

# 에러가 아닌 경고를 일으킴

SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT='Dividend is null, so regarding dividend as 0', MYSQL_ERRNO=9997;

RETURN 0;

END IF;

RETURN FLOOR(p_dividend / p_visor);

END

> ERROR 9999 (45000): Divisor can not be null

> ERROR 9998 (45000):  Divisor can not be 0

> 세 번째 조건문의 경우에는 SELECT sf_divide(NULL, 1);을 입력하면 경고 메시지가 발생해야 하는데 어쩐지 발생하지 않는다.






admin