処理の例外¶
Snowflakeスクリプトのブロックでは、エラーが発生した場合に例外を発生させることができます。Snowflakeスクリプトコードで発生する例外を処理することもできます。
概要¶
Snowflakeスクリプトは、ステートメントの実行中にエラーが発生した場合(例: ステートメントが存在しないテーブルを DROP しようとした場合)に例外を発生させます。例外により、コードの次の行が実行されなくなります。
Snowflakeスクリプトのブロックでは、そのブロックおよびそのブロック内にネストされたブロックで宣言された特定のタイプの例外をキャッチする例外ハンドラーを記述できます。
さらに、コードで発生する可能性のあるエラーについては、エラー時に発生する可能性のある独自の例外を定義できます。
Snowflakeスクリプトのブロックで(コードまたは実行に失敗したステートメントによって)例外が発生すると、Snowflakeスクリプトはその例外のハンドラーを見つけようとします。
例外が発生したブロックにその例外のハンドラーがある場合は、その例外ハンドラーの先頭から実行が再開されます。
ブロックに独自の例外ハンドラーがない場合、例外はそれを囲むブロックによってキャッチされる可能性があります。
例外が複数のレイヤーの深さで発生した場合、例外は次のいずれかになるまで一度に1つのレイヤーずつ上向きに送信されます。
適切な例外ハンドラーを持つレイヤーが例外を処理します。
最も外側のレイヤーに到達した場合は、エラーが発生します。
現在のブロックまたはそれを囲むブロックに例外のハンドラーがない場合、ブロックの実行は停止し、実行のためにブロックを送信するクライアント(例: ウェブインターフェイス、 SnowSQL)は、これをSnowflakeエラーとして報告します。
別の例外の処理中に例外が発生した場合に備えて、例外ハンドラーに独自の例外ハンドラーを含めることができます。
例外の宣言¶
ブロックの DECLARE セクションで独自の例外を宣言できます。 例外宣言構文 で説明されている構文を使用します。例:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
宣言された例外の生成¶
例外を発生させるには、 RAISE コマンドを実行します。例:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
END;
注: SnowSQL、 Classic Console、 execute_stream
または execute_string
メソッドを Python Connector コードで使用している場合は、代わりにこの例を使用してください(SnowSQL、 Classic Console、Python ConnectorでSnowflakeスクリプトを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
END;
$$
;
例外が発生した時点で実行が停止します。(この例では、 counter
が増分されて返されることはありません。)
実行するためにこのブロックを送信するクライアント(例: Snowsight)はエラーを報告し、例外がキャッチされなかったことを示します。
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
発生した例外(およびステートメントの実行に失敗したときに発生した例外)を処理するコードを追加する場合は、例外ハンドラーを作成できます。 例外の処理 をご参照ください。
注釈
例外ハンドラーで、同じ例外を再生成する必要がある場合は、 例外ハンドラーでの同じ例外の再生成 をご参照ください。
例外の処理¶
EXCEPTION 句を使用して例外をキャッチすることで例外を明示的に処理するか、囲んでいるブロックに例外を渡すことをブロックに許可します。
EXCEPTION 句内で、 WHEN 句を使用して名前別に例外を処理します。宣言した例外と組み込みの例外を処理できます。現在、Snowflakeは次の組み込み例外を提供しています。
STATEMENT_ERROR: この例外は、ステートメントの実行中にエラーが発生したことを示します。たとえば、存在しないテーブルを削除しようとすると、この例外が発生します。
EXPRESSION_ERROR: この例外は、式に関連するエラーを示します。たとえば、 VARCHAR と評価される式を作成し、その式の値を FLOAT に割り当てようとすると、このエラーが発生します。
例外が発生した場合、次の3つの組み込み変数を読み取ることにより、例外に関する情報を取得できます。
SQLCODE: これは5桁の符号付き整数です。ユーザー定義の例外の場合、これは、 例外を宣言するための構文 に示されている
exception_number
です。SQLERRM: これはエラーメッセージです。ユーザー定義の例外の場合、これは、 例外を宣言するための構文 に示されている
exception_message
です。SQLSTATE: これは、 ANSI SQL 標準 SQLSTATE をモデルにした5文字コードです。Snowflakeは、 ANSI SQL 標準にある値以外の追加の値を使用します。
WHEN 句を持たない他のすべての例外を処理するには、 WHEN OTHER THEN 句を使用します。
例:
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
EXCEPTION
WHEN statement_error THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
注: SnowSQL、 Classic Console、 execute_stream
または execute_string
メソッドを Python Connector コードで使用している場合は、代わりにこの例を使用してください(SnowSQL、 Classic Console、Python ConnectorでSnowflakeスクリプトを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
BEGIN
LET counter := 0;
LET should_raise_exception := true;
IF (should_raise_exception) THEN
RAISE my_exception;
END IF;
counter := counter + 1;
RETURN counter;
EXCEPTION
WHEN statement_error THEN
RETURN OBJECT_CONSTRUCT('Error type', 'STATEMENT_ERROR',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN my_exception THEN
RETURN OBJECT_CONSTRUCT('Error type', 'MY_EXCEPTION',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
WHEN OTHER THEN
RETURN OBJECT_CONSTRUCT('Error type', 'Other error',
'SQLCODE', sqlcode,
'SQLERRM', sqlerrm,
'SQLSTATE', sqlstate);
END;
$$
;
この例では、例外に関する詳細を含むオブジェクトを作成して返すために OBJECT_CONSTRUCT を呼び出して、各タイプの例外を処理します。この例では、次の出力が生成されます。
+--------------------------------------+
| anonymous block |
|--------------------------------------|
| { |
| "Error type": "MY_EXCEPTION", |
| "SQLCODE": -20002, |
| "SQLERRM": "Raised MY_EXCEPTION.", |
| "SQLSTATE": "P0001" |
| } |
+--------------------------------------+
まれに、何もせずに例外を明示的に処理したい場合があります。これにより、例外が発生したときに中止するのではなく、続行することができます。詳細については、 NULL コマンドをご参照ください。
例外のハンドラーを設定しない場合は、実行するためにこのブロックを送信するクライアント(例: ウェブインターフェイス)がエラーを報告します(宣言された例外の生成 で説明のとおり)。
-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
注釈
同じ例外を再生成する必要がある場合は、 例外ハンドラーでの同じ例外の再生成 をご参照ください。
例外ハンドラーでの同じ例外の再生成¶
場合によっては、例外ハンドラーでキャッチしたのと同じ例外を生成する必要が生じる可能性があります。このような場合は、引数を指定せずに RAISE コマンドを実行します。
たとえば、例外処理中に、同じ例外を再生成する前に、例外に関する詳細をキャプチャする必要があるとします。詳細をキャプチャした後に、 RAISE コマンドを実行します。
BEGIN
SELECT * FROM non_existent_table;
EXCEPTION
WHEN OTHER THEN
LET LINE := SQLCODE || ': ' || SQLERRM;
INSERT INTO myexceptions VALUES (:line);
RAISE; -- Raise the same exception that you are handling.
END;
注: SnowSQL、 Classic Console、 execute_stream
または execute_string
メソッドを Python Connector コードで使用している場合は、代わりにこの例を使用してください(SnowSQL、 Classic Console、Python ConnectorでSnowflakeスクリプトを使用する を参照)。
EXECUTE IMMEDIATE $$
BEGIN
SELECT * FROM non_existent_table;
EXCEPTION
WHEN OTHER THEN
LET LINE := SQLCODE || ': ' || SQLERRM;
INSERT INTO myexceptions VALUES (:line);
RAISE; -- Raise the same exception that you are handling.
END;
$$;
例外ハンドラーに変数を渡す¶
例外ハンドラーに変数を渡すことができます。例外ハンドラーは変数の値に基づいてコードを実行することができ、変数の値はエラーメッセージで返すことができます。
変数を EXCEPTION セクションのハンドラーに渡すには、 DECLARE セクションでその変数を宣言する必要があります。ブロックの BEGIN... END セクションで宣言された変数は、 EXCEPTION セクションではアクセスできません。
さらに、引数を受け付ける Snowflake Scripting ストアド プロシージャを記述する場合、それらの引数を例外ハンドラーで使用できます。
例えば、以下の匿名ブロックは、 counter_val
変数の値を例外ハンドラーに渡します。
DECLARE
counter_val INTEGER DEFAULT 0;
my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
WHILE (counter_val < 12) DO
counter_val := counter_val + 1;
IF (counter_val > 10) THEN
RAISE my_exception;
END IF;
END WHILE;
RETURN counter_val;
EXCEPTION
WHEN my_exception THEN
RETURN 'Error ' || sqlcode || ': Counter value ' || counter_val || ' exceeds the limit of 10.';
END;
注: SnowSQL、 Classic Console、 execute_stream
または execute_string
メソッドを Python Connector コードで使用している場合は、代わりにこの例を使用してください(SnowSQL、 Classic Console、Python ConnectorでSnowflakeスクリプトを使用する を参照)。
EXECUTE IMMEDIATE $$
DECLARE
counter_val INTEGER DEFAULT 0;
my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
WHILE (counter_val < 12) DO
counter_val := counter_val + 1;
IF (counter_val > 10) THEN
RAISE my_exception;
END IF;
END WHILE;
RETURN counter_val;
EXCEPTION
WHEN my_exception THEN
RETURN 'Error ' || sqlcode || ': Counter value ' || counter_val || ' exceeds the limit of 10.';
END;
$$
;
このブロックは次のエラーメッセージを返します。
+---------------------------------------------------------+
| anonymous block |
|---------------------------------------------------------|
| Error -20002: Counter value 11 exceeds the limit of 10. |
+---------------------------------------------------------+
以下は、引数を渡す Snowflake Scripting ストアドプロシージャの例です。この例では、例外ハンドラで引数を使用する方法を示しています。
CREATE OR REPLACE PROCEDURE exception_test_vars(amount INT)
RETURNS TEXT
LANGUAGE SQL
AS
DECLARE
my_exception_1 EXCEPTION (-20002, 'Value too low');
my_exception_2 EXCEPTION (-20003, 'Value too high');
BEGIN
CREATE OR REPLACE TABLE test_order_insert(units INT);
IF (amount < 1) THEN
RAISE my_exception_1;
ELSEIF (amount > 10) THEN
RAISE my_exception_2;
ELSE
INSERT INTO test_order_insert VALUES (:amount);
END IF;
RETURN 'Order inserted successfully.';
EXCEPTION
WHEN my_exception_1 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too low (1 or greater required).';
WHEN my_exception_2 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too high (exceeds limit of 10).';
END;
注: SnowSQL、 Classic Console、 execute_stream
または execute_string
メソッドを Python Connector コードで使用している場合は、代わりにこの例を使用してください(SnowSQL、 Classic Console、Python ConnectorでSnowflakeスクリプトを使用する を参照)。
CREATE OR REPLACE PROCEDURE exception_test_vars(amount INT)
RETURNS TEXT
LANGUAGE SQL
AS
$$
DECLARE
my_exception_1 EXCEPTION (-20002, 'Value too low');
my_exception_2 EXCEPTION (-20003, 'Value too high');
BEGIN
CREATE OR REPLACE TABLE test_order_insert(units INT);
IF (amount < 1) THEN
RAISE my_exception_1;
ELSEIF (amount > 10) THEN
RAISE my_exception_2;
ELSE
INSERT INTO test_order_insert VALUES (:amount);
END IF;
RETURN 'Order inserted successfully.';
EXCEPTION
WHEN my_exception_1 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too low (1 or greater required).';
WHEN my_exception_2 THEN
RETURN 'Error ' || sqlcode || ': Submitted amount ' || amount || ' is too high (exceeds limit of 10).';
END;
$$
;
以下のストアド・プロシージャの呼び出しは、期待される出力を示しています。
CALL exception_test_vars(7);
+------------------------------+
| EXCEPTION_TEST_VARS |
|------------------------------|
| Order inserted successfully. |
+------------------------------+
CALL exception_test_vars(-3);
+-----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|-----------------------------------------------------------------------|
| Error -20002: Submitted amount -3 is too low (1 or greater required). |
+-----------------------------------------------------------------------+
CALL exception_test_vars(20);
+----------------------------------------------------------------------+
| EXCEPTION_TEST_VARS |
|----------------------------------------------------------------------|
| Error -20003: Submitted amount 20 is too high (exceeds limit of 10). |
+----------------------------------------------------------------------+