오류 트래핑 - Amazon Redshift

오류 트래핑

저장 프로시저의 쿼리 또는 명령에 오류가 발생하면 후속 쿼리가 실행되지 않고 트랜잭션이 롤백됩니다. 그러나 EXCEPTION 블록을 사용하여 오류를 처리할 수 있습니다.

참고

기본 동작은 저장 프로시저에 추가 오류 생성 조건이 없는 경우에도 오류로 인해 후속 쿼리가 실행되지 않는 것입니다.

[ <<label>> ] [ DECLARE declarations ] BEGIN statements EXCEPTION WHEN OTHERS THEN statements END;

예외가 발생하고 예외 처리 블록을 추가하면 RAISE 문과 대부분의 다른 PL/pgSQL 문을 작성할 수 있습니다. 예를 들어 사용자 정의 메시지로 예외를 발생시키거나 기록을 로깅 테이블에 삽입할 수 있습니다.

예외 처리 블록에 들어갈 때 현재 트랜잭션이 롤백되고 블록의 명령문을 실행하기 위해 새 트랜잭션이 생성됩니다. 블록의 문이 오류 없이 실행되면 트랜잭션이 커밋되고 예외가 다시 발생합니다. 마지막으로 저장 프로시저가 종료됩니다.

예외 블록에서 지원되는 유일한 조건은 쿼리 취소를 제외한 모든 오류 유형과 일치하는 OTHERS입니다. 또한 예외 처리 블록에서 오류가 발생하면 외부 예외 처리 블록에서 이를 catch할 수 있습니다.

NONATOMIC 프로시저 내에서 오류가 발생하여 예외 블록에서 처리되는 경우 오류가 다시 발생하지 않습니다. 예외 처리 블록에서 포착한 예외를 발생시키려면 PL/pgSQL 문 RAISE를 참조하세요. 이 문은 예외 처리 블록에서만 유효합니다. 자세한 내용은 RAISE 섹션을 참조하세요.

저장 프로시저에서 오류가 나타난 후 발생하는 상황을 CONTINUE 핸들러를 사용하여 제어

CONTINUE 핸들러는 NONATOMIC 저장 프로시저 내의 실행 흐름을 제어하는 일종의 예외 핸들러입니다. 핸들러를 사용하면 기존 문 블록을 종료하지 않고도 예외를 파악하고 처리할 수 있습니다. 일반적으로 저장 프로시저에서 오류가 발생하면 흐름이 중단되고 오류가 호출자에게 반환됩니다. 하지만 일부 사용 사례에서는 오류 상태가 흐름이 중단될 만큼 심각하지 않을 수도 있습니다. 별도의 트랜잭션에서 선택한 오류 처리 로직을 사용하여 오류를 적절하게 처리한 다음 오류 다음에 오는 문을 계속 실행하는 것이 좋습니다. 다음은 구문을 보여줍니다.

[ DECLARE declarations ] BEGIN statements EXCEPTION [ CONTINUE_HANDLER | EXIT_HANDLER ] WHEN OTHERS THEN handler_statements END;

다양한 유형의 오류에 대한 정보를 수집하는 데 도움이 되는 몇 가지 시스템 테이블이 있습니다. 자세한 내용은 STL_LOAD_ERRORS, STL_ERROR, SYS_STREAM_SCAN_ERRORS 단원을 참조하세요. 오류 해결에 사용할 수 있는 추가 시스템 테이블도 있습니다. 이에 대한 자세한 정보는 시스템 테이블 및 뷰 참조에서 찾아볼 수 있습니다.

다음 예는 예외 처리 블록에서 문을 작성하는 방법을 보여줍니다. 저장 프로시저는 기본 트랜잭션 관리 동작을 사용합니다.

CREATE TABLE employee (firstname varchar, lastname varchar); INSERT INTO employee VALUES ('Tomas','Smith'); CREATE TABLE employee_error_log (message varchar); CREATE OR REPLACE PROCEDURE update_employee_sp() AS $$ BEGIN UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith'; EXECUTE 'select invalid'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; $$ LANGUAGE plpgsql; CALL update_employee_sp(); INFO: An exception occurred. ERROR: column "invalid" does not exist CONTEXT: SQL statement "select invalid" PL/pgSQL function "update_employee_sp" line 3 at execute statement

이 예에서 update_employee_sp를 호출하면 예외 발생(An exception occurred.)이라는 정보 메시지가 나타나고 로깅 테이블의 employee_error_log 로그에 오류 메시지가 삽입됩니다. 저장 프로시저가 종료되기 전에 원래 예외가 다시 발생합니다. 다음 쿼리는 예제를 실행한 결과로 생성된 레코드를 보여줍니다.

SELECT * from employee; firstname | lastname -----------+---------- Tomas | Smith SELECT * from employee_error_log; message ------------------------------------------------ Error message: column "invalid" does not exist

형식 관련 도움말 및 추가 수준 목록 등 RAISE에 대한 자세한 내용은 지원되는 PL/pgSQL 문 섹션을 참조하세요.

다음 예는 예외 처리 블록에서 문을 작성하는 방법을 보여줍니다. 저장 프로시저는 NONATOMIC 트랜잭션 관리 동작을 사용합니다. 이 예제에서는 프로시저 호출이 완료된 후 호출자에게 다시 오류가 발생하지 않습니다. 다음 문의 오류로 인해 UPDATE 문이 롤백되지 않습니다. 정보 메시지가 표시되고 오류 메시지가 로깅 테이블에 삽입됩니다.

CREATE TABLE employee (firstname varchar, lastname varchar); INSERT INTO employee VALUES ('Tomas','Smith'); CREATE TABLE employee_error_log (message varchar); -- Create the SP in NONATOMIC mode CREATE OR REPLACE PROCEDURE update_employee_sp_2() NONATOMIC AS $$ BEGIN UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith'; EXECUTE 'select invalid'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; $$ LANGUAGE plpgsql; CALL update_employee_sp_2(); INFO: An exception occurred. CALL SELECT * from employee; firstname | lastname -----------+---------- Adam | Smith (1 row) SELECT * from employee_error_log; message ------------------------------------------------ Error message: column "invalid" does not exist (1 row)

이 예에서는 2개의 하위 블록으로 프로시저를 만드는 방법을 보여줍니다. 저장 프로시저가 호출되면 첫 번째 하위 블록의 오류가 해당 예외 처리 블록에서 처리됩니다. 첫 번째 하위 블록이 완료된 후 프로시저는 두 번째 하위 블록을 계속 실행합니다. 결과를 보면 프로시저 호출이 완료될 때 오류가 발생하지 않음을 알 수 있습니다. employee 테이블에 대한 UPDATE 및 INSERT 작업이 커밋됩니다. 두 예외 블록의 오류 메시지가 로깅 테이블에 삽입됩니다.

CREATE TABLE employee (firstname varchar, lastname varchar); INSERT INTO employee VALUES ('Tomas','Smith'); CREATE TABLE employee_error_log (message varchar); CREATE OR REPLACE PROCEDURE update_employee_sp_3() NONATOMIC AS $$ BEGIN BEGIN UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith'; EXECUTE 'select invalid1'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred in the first block.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; BEGIN INSERT INTO employee VALUES ('Edie','Robertson'); EXECUTE 'select invalid2'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred in the second block.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; END; $$ LANGUAGE plpgsql; CALL update_employee_sp_3(); INFO: An exception occurred in the first block. INFO: An exception occurred in the second block. CALL SELECT * from employee; firstname | lastname -----------+----------- Adam | Smith Edie | Robertson (2 rows) SELECT * from employee_error_log; message ------------------------------------------------- Error message: column "invalid1" does not exist Error message: column "invalid2" does not exist (2 rows)

다음 예시는 CONTINUE 예외 핸들러를 사용하는 방법을 보여줍니다. 이 샘플은 두 개의 테이블을 만들어 저장 프로시저에서 사용합니다. CONTINUE 핸들러는 NONATOMIC 트랜잭션 관리 동작을 사용하여 저장 프로시저의 실행 흐름을 제어합니다.

CREATE TABLE tbl_1 (a int); CREATE TABLE tbl_error_logging(info varchar, err_state varchar, err_msg varchar); CREATE OR REPLACE PROCEDURE sp_exc_handling_1() NONATOMIC AS $$ BEGIN INSERT INTO tbl_1 VALUES (1); -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_1 VALUES ("val"); INSERT INTO tbl_1 VALUES (2); EXCEPTION CONTINUE_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; $$ LANGUAGE plpgsql;

저장 프로시저를 호출합니다.

CALL sp_exc_handling_1();

흐름은 다음과 같이 진행됩니다.

  1. 호환되지 않는 데이터 유형을 열에 삽입하려고 하면 오류가 발생합니다. 제어가 EXCEPTION 블록으로 전달됩니다. 예외 처리 블록이 입력될 때 현재 트랜잭션이 롤백되고 문을 실행하기 위해 새 암시적 트랜잭션이 생성됩니다.

  2. CONTINUE_HANDLER의 문이 오류 없이 실행되면 제어가 문 바로 뒤에 있는 문으로 전달되어 예외가 발생합니다. CONTINUE_HANDLER의 문에서 새 예외가 발생하는 경우 EXCEPTION 블록 내에서 예외 핸들러를 사용하여 해당 예외를 처리할 수 있습니다.

샘플 저장 프로시저를 호출한 후 테이블에 다음 레코드가 포함됩니다.

  • SELECT * FROM tbl_1;을 실행하면 두 개의 레코드가 반환됩니다. 여기에는 12 값이 포함됩니다.

  • SELECT * FROM tbl_error_logging;을 실행하면 오류 발생, 42703, 'val' 열이 tbl_1에 존재하지 않음이라는 값이 있는 레코드 하나가 반환됩니다.

다음 추가 오류 처리 예시에서는 EXIT 핸들러와 CONTINUE 핸들러를 모두 사용합니다. 그러면 데이터 테이블과 로깅 테이블이라는 두 개의 테이블이 생성됩니다. 또한 오류 처리를 보여주는 저장 프로시저가 생성됩니다.

CREATE TABLE tbl_1 (a int); CREATE TABLE tbl_error_logging(info varchar, err_state varchar, err_msg varchar); CREATE OR REPLACE PROCEDURE sp_exc_handling_2() NONATOMIC AS $$ BEGIN INSERT INTO tbl_1 VALUES (1); BEGIN INSERT INTO tbl_1 VALUES (100); -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_1 VALUES ("val"); INSERT INTO tbl_1 VALUES (101); EXCEPTION EXIT_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; INSERT INTO tbl_1 VALUES (2); -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_1 VALUES ("val"); INSERT INTO tbl_1 VALUES (3); EXCEPTION CONTINUE_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; $$ LANGUAGE plpgsql;

저장 프로시저를 만든 후 다음을 사용하여 호출합니다.

CALL sp_exc_handling_2();

BEGIN과 END라는 내부 세트로 괄호가 묶인 내부 예외 블록에서 오류가 발생하면 EXIT 핸들러가 오류를 처리합니다. 외부 블록에서 발생하는 모든 오류는 CONTINUE 핸들러에서 처리합니다.

샘플 저장 프로시저를 호출한 후 테이블에 다음 레코드가 포함됩니다.

  • SELECT * FROM tbl_1;을 실행하면 값이 1, 2, 3, 100인 레코드 네 개가 반환됩니다.

  • SELECT * FROM tbl_error_logging;을 실행하면 두 개의 레코드가 반환됩니다. 값은 오류 발생, 42703, 'val' 열이 tbl_1에 존재하지 않음입니다.

tbl_error_logging 테이블이 존재하지 않는 경우 예외가 발생합니다.

다음 예시는 FOR 루프와 함께 CONTINUE 예외 핸들러를 사용하는 방법을 보여줍니다. 이 샘플은 세 개의 테이블을 만들어 저장 프로시저 내의 FOR 루프에서 사용합니다. FOR 루프는 결과 세트 변형입니다. 즉, 쿼리 결과를 반복합니다.

CREATE TABLE tbl_1 (a int); INSERT INTO tbl_1 VALUES (1), (2), (3); CREATE TABLE tbl_2 (a int); CREATE TABLE tbl_error_logging(info varchar, err_state varchar, err_msg varchar); CREATE OR REPLACE PROCEDURE sp_exc_handling_loop() NONATOMIC AS $$ DECLARE rec RECORD; BEGIN FOR rec IN SELECT a FROM tbl_1 LOOP IF rec.a = 2 THEN -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_2 VALUES("val"); ELSE INSERT INTO tbl_2 VALUES (rec.a); END IF; END LOOP; EXCEPTION CONTINUE_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; $$ LANGUAGE plpgsql;

저장 프로시저를 호출합니다.

CALL sp_exc_handling_loop();

샘플 저장 프로시저를 호출한 후 테이블에 다음 레코드가 포함됩니다.

  • SELECT * FROM tbl_2;을 실행하면 두 개의 레코드가 반환됩니다. 여기에는 1 및 3 값이 포함됩니다.

  • SELECT * FROM tbl_error_logging;을 실행하면 오류 발생, 42703, 'val' 열이 tbl_2에 존재하지 않음이라는 값이 있는 레코드 하나가 반환됩니다.

CONTINUE 핸들러와 관련된 사용 참고 사항:

  • CONTINUE_HANDLER 및 EXIT_HANDLER 키워드는 NONATOMIC 저장 프로시저에서만 사용할 수 있습니다.

  • CONTINUE_HANDLER 및 EXIT_HANDLER 키워드는 선택 사항입니다. EXIT_HANDLER가 기본값입니다.