捕捉錯誤 - Amazon Redshift

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

捕捉錯誤

本主題說明 Amazon Redshift 如何處理錯誤。

當預存程序中的查詢或命令造成錯誤時,後續查詢不會執行,而且會復原交易。但是您可以使用EXCEPTION塊處理錯誤。

注意

預設行為是,即使預存程序中沒有其他產生錯誤的條件,錯誤也會導致後續查詢無法執行。

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

當發生例外狀況時,您新增例外狀況處理區塊時,您可以撰寫RAISE陳述式和大多數其他 PL/ SQL PG 陳述式。例如,您可以使用自訂訊息引發例外狀況,或將記錄插入記錄資料表。

進入例外狀況處理區塊時,會復原目前的交易,並建立新的交易以執行區塊中的陳述式。如果區塊中的陳述式沒有錯誤地執行,就會遞交交易並重新擲回例外狀況。最後,預存程序會結束。

例外區塊中唯一支援的條件是OTHERS,符合除查詢取消以外的每個錯誤類型。此外,如果例外狀況處理塊中發生錯誤,則外部例外狀況處理塊可以捕獲該錯誤。

當NONATOMIC程序內部發生錯誤時,如果錯誤是由例外狀況區塊處理,則不會重新擲回錯誤。請參閱 PL/PG SQL 語句拋RAISE出異常處理塊捕獲的異常。此陳述式僅在例外狀況處理區塊中有效。如需詳細資訊,請參閱 RAISE

使用CONTINUE處理常式控制預存程序中發生錯誤之後的情況

CONTINUE處理常式是一種例外狀況處理常式,可控制NONATOMIC預存程序內的執行流程。透過使用的過程,您可以揪出問題點並處理例外狀況,而不需結束現有陳述式區塊。通常當預存程序中發生錯誤時,流程會中斷,並將錯誤傳回給呼叫者。但是,在某些使用案例中,錯誤情況還沒有嚴重到足以中斷流程。您可能想要按既定程序處理錯誤,使用您在不同的交易中選擇的錯誤處理邏輯,然後繼續執行錯誤後續的陳述式。語法如下列所示。

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

有數個系統資料表可協助您收集有關各種錯誤類型的資訊。如需詳細資訊,請參閱STL_LOAD_ERRORSSTL_ERRORSYS_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,會引發資訊訊息「發生例外狀況。」並將錯誤訊息插入記錄資料表的 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)

此範例示範如何使用兩個子區塊建立程序。呼叫預存程序時,第一個子區塊的錯誤會由其例外狀況處理區塊處理。在第一個子區塊完成之後,程序會繼續執行第二個子區塊。從結果可以看到,程序呼叫完成時沒有擲回任何錯誤。在表員工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;,它會傳回一個包含下列值的記錄:發生的錯誤42703tbl_1 中不存在資料欄 "val"

下列其他錯誤處理範例會同時使用處理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();

當內部異常塊中發生錯誤時,該異常塊由內部集合括住END,BEGIN並且由處理程序處理。EXIT外部區塊中發生的任何錯誤都會由處理CONTINUE常式處理。

呼叫範例預存程序之後,資料表包含下列記錄:

  • 如果執行 SELECT * FROM tbl_1;,它會傳回四個記錄,其值為 1、2、3 和 100。

  • 如果執行 SELECT * FROM tbl_error_logging;,它會傳回兩個記錄。它們具有以下值:發生的錯誤42703tbl_1 中不存在資料欄 "val"

如果表 tbl_error_logging 不存在,則會引發例外狀況。

下面的例子演示了如何使用CONTINUE異常處理程序與FOR循環。此範例會建立三個資料表,並在預存程序內的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;,它會傳回一個包含下列值的記錄:發生的錯誤42703tbl_2 中不存在資料欄 "val"

有關CONTINUE處理程序的使用說明:

  • CONTINUE_ HANDLER 和 EXIT _ HANDLER 關鍵字只能在NONATOMIC存儲過程中使用。

  • CONTINUE_ HANDLER 和 EXIT _ HANDLER 關鍵字是可選的。EXIT_ HANDLER 是預設值。