

 Amazon Redshift は、パッチ 198 以降、新しい Python UDF の作成をサポートしなくなります。既存の Python UDF は、2026 年 6 月 30 日まで引き続き機能します。詳細については、[ブログ記事](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)を参照してください。

# エラーのトラップ
<a name="stored-procedure-trapping-errors"></a>

このトピックでは、Amazon Redshift がエラーを処理する方法について説明します。

ストアドプロシージャのクエリまたはコマンドでエラーが発生すると、それ以降のクエリが実行されず、トランザクションがロールバックされます。しかし、 EXCEPTION ブロックを使用してエラーに対処できます。

**注記**  
デフォルトの動作では、ストアドプロシージャにエラーを生成する条件が他にない場合でも、エラーが発生すると後続のクエリは実行されません。

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

例外が発生し、例外処理ブロックを追加すると、REASE ステートメントおよび他のほとんどの PL/pgSQL ステートメントを書き込みできます。たとえば、カスタムメッセージで例外を発生させたり、ロギングテーブルにレコードを挿入したりできます。

例外処理ブロックに入ると、現在のトランザクションがロールバックされ、新しいトランザクションがブロック内のステートメントを実行するために作成されます。ブロック内のステートメントがエラーなしで実行されると、トランザクションはコミットされ、例外が再スローされます。最後に、ストアドプロシージャが終了します。

例外ブロックでサポートされている条件は OTHERS のみです。この条件は、クエリのキャンセルを除いて、すべてのエラータイプに一致します。また、例外処理ブロックでエラーが発生すると、エラーは外部の例外処理ブロックでキャッチできます。

NONATOMIC プロシージャ内でエラーが発生しても、例外ブロックで処理されればエラーは再スローされません。例外処理ブロックでキャッチされた例外をスローする方法については、「PL/pgSQL ステートメント `RAISE`」を参照してください。このステートメントは例外処理ブロックでのみ有効です。詳細については、「[RAISE](c_PLpgSQL-statements.md#r_PLpgSQL-messages-errors)」を参照してください。

**CONTINUE ハンドラを使用して、ストアドプロシージャでエラーが発生した後の処理を制御する**

 `CONTINUE` ハンドラは、NONATOMIC ストアドプロシージャ内の実行フローを制御する例外ハンドラの一種です。これを使用すると、既存のステートメントブロックを終了せずに例外をキャッチして処理できます。通常、ストアドプロシージャでエラーが発生すると、フローが中断され、エラーが呼び出し元に返されます。ただし、ユースケースによっては、フローの中断を必要とするほどエラー状態が深刻ではない場合があります。別のトランザクションで選択したエラー処理ロジックを使用してエラーをスムーズに処理し、エラーの後にステートメントを実行し続けることもできます。以下にその構文を示します。

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

さまざまなタイプのエラーに関する情報を収集するのに役立つシステムテーブルがいくつかあります。詳細については[STL\_LOAD\_ERRORS](r_STL_LOAD_ERRORS.md)、[STL\_ERROR](r_STL_ERROR.md)、および[SYS\_STREAM\_SCAN\_ERRORS](r_SYS_STREAM_SCAN_ERRORS.md)を参照してください。エラーのトラブルシューティングに使用できるその他のシステムテーブルもあります。これらに関する情報は、「[システムテーブルとビューのリファレンス](cm_chap_system-tables.md)」を参照してください。

## 例
<a name="stored-procedure-trapping-errors-examples"></a>

次の例は、例外処理ブロックでステートメントを書き込みする方法を示しています。ストアドプロシージャはデフォルトのトランザクション管理動作を使用しています。

```
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 ステートメント](c_PLpgSQL-statements.md)」を参照してください。

次の例は、例外処理ブロックでステートメントを書き込みする方法を示しています。ストアドプロシージャは 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 つのサブブロックを持つプロシージャを作成する方法を示します。ストアドプロシージャが呼び出されると、最初のサブブロックからのエラーはその例外処理ブロックによって処理されます。最初のサブブロックが完了すると、プロシージャは引き続き 2 番目のサブブロックを実行します。結果から、プロシージャコールが完了してもエラーは発生しないことがわかります。テーブル従業員の 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 例外ハンドラの使用方法を示しています。このサンプルでは 2 つのテーブルを作成し、ストアドプロシージャで使用します。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 ブロックに制御が移ります。例外処理ブロックが入力されると、現在のトランザクションがロールバックされ、新しい暗黙的トランザクションが作成されてステートメントを実行します。

1. CONTINUE\_HANDLER のステートメントがエラーなく実行された場合、例外が発生したステートメントの直後のステートメントに制御が移ります。(CONTINUE\_HANDLER のステートメントによって新しい例外が発生した場合は、EXCEPTION ブロック内の例外ハンドラを使用してその例外を処理できます。)

サンプルストアドプロシージャを呼び出すと、テーブルに次のレコードが格納されます。
+ `SELECT * FROM tbl_1;` を実行すると、2 つのレコードが返されます。これらには値 `1` と `2` が含まれます。
+ `SELECT * FROM tbl_error_logging;` を実行すると、次の値を含むレコードが 1 つ返されます。「**エラーが発生しました」、「**42703」、「**val 列は tbl\_1 に存在しません」

以下の追加のエラー処理例では、EXIT ハンドラと CONTINUE ハンドラの両方を使用しています。データテーブルとロギングテーブルの 2 つのテーブルを作成します。また、エラー処理を示すストアドプロシージャも作成します。

```
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 を持つ 4 つのレコードが返されます。
+ `SELECT * FROM tbl_error_logging;` を実行すると、2 つのレコードが返されます。これらの値は次のとおりです。「**エラーが発生しました」、「**42703」、「**val 列は tbl\_1 に存在しません」

**tbl\_error\_logging** テーブルが存在しない場合、例外が発生します。

次の例は、CONTINUE 例外ハンドラを FOR ループで使用する方法を示しています。このサンプルでは 3 つのテーブルを作成し、ストアドプロシージャ内の 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;` を実行すると、2 つのレコードが返されます。これらには値 1 と 3 が含まれます。
+ `SELECT * FROM tbl_error_logging;` を実行すると、次の値を含むレコードが 1 つ返されます。「**エラーが発生しました」「**42703」、「**val 列は tbl\_2 に存在しません」

CONTINUE ハンドラに関する使用上の注意事項:
+ CONTINUE\_HANDLER キーワードと EXIT\_HANDLER キーワードは、NONATOMIC ストアドプロシージャでのみ使用できます。
+ CONTINUE\_HANDLER キーワードと EXIT\_HANDLER キーワードはオプションです。EXIT\_HANDLER がデフォルトです。