処理の例外

Snowflakeスクリプトのブロックでは、エラーが発生した場合に例外を発生させることができます。Snowflakeスクリプトコードで発生する例外を処理することもできます。

このトピックの内容:

紹介

Snowflakeスクリプトは、ステートメントの実行中にエラーが発生した場合(例: ステートメントが存在しないテーブルを DROP しようとした場合)に例外を発生させます。

例外により、コードの次の行が実行されなくなります。

Snowflakeスクリプトのブロックでは、そのブロックおよびそのブロック内にネストされたブロックで宣言された特定のタイプの例外をキャッチする例外ハンドラーを記述できます。

さらに、コードで発生する可能性のあるエラーについては、エラー時に発生する可能性のある独自の例外を定義できます。

Snowflakeスクリプトのブロックで(コードまたは実行に失敗したステートメントによって)例外が発生すると、Snowflakeスクリプトはその例外のハンドラーを見つけようとします。

  • 例外が発生したブロックにその例外のハンドラーがある場合は、その例外ハンドラーの先頭から実行が再開されます。

  • ブロックに独自の例外ハンドラーがない場合、例外はそれを囲むブロックによってキャッチされる可能性があります。

    例外が複数のレイヤーの深さで発生した場合、例外は次のいずれかになるまで一度に1つのレイヤーずつ上向きに送信されます。

    • 適切な例外ハンドラーを持つレイヤーが例外を処理します。

    • 最も外側のレイヤーに到達した場合は、エラーが発生します。

  • 現在のブロックまたはそれを囲むブロックに例外のハンドラーがない場合、ブロックの実行は停止し、実行のためにブロックを送信するクライアント(例: ウェブインターフェイス、 SnowSQL)は、これをSnowflakeエラーとして報告します。

別の例外の処理中に例外が発生した場合に備えて、例外ハンドラーに独自の例外ハンドラーを含めることができます。

例外の宣言

ブロックの DECLARE セクションで独自の例外を宣言できます。 例外宣言構文 で説明されている構文を使用します。例:

DECLARE
  my_exception EXCEPTION (-20002, 'Raised MY_EXCEPTION.');
Copy

宣言された例外の生成

例外を発生させるには、 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;
Copy

注: SnowSQL または Classic Console を使用している場合は、代わりに次の例を使用します(SnowSQL および Classic Console での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;
$$
;
Copy

例外が発生した時点で実行が停止します。(この例では、 counter が増分されて返されることはありません。)

実行するためにこのブロックを送信するクライアント(例: Snowsight)はエラーを報告し、例外がキャッチされなかったことを示します。

-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Copy

発生した例外(およびステートメントの実行に失敗したときに発生した例外)を処理するコードを追加する場合は、例外ハンドラーを作成できます。 例外の処理 をご参照ください。

注釈

例外ハンドラーで、同じ例外を再生成する必要がある場合は、 例外ハンドラーでの同じ例外の再生成 をご参照ください。

例外の処理

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;
Copy

注: SnowSQL または Classic Console を使用している場合は、代わりに次の例を使用します(SnowSQL および Classic Console での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;
$$
;
Copy

この例では、例外に関する詳細を含むオブジェクトを作成して返すために OBJECT_CONSTRUCT を呼び出して、各タイプの例外を処理します。この例では、次の出力が生成されます。

+--------------------------------------+
| anonymous block                      |
|--------------------------------------|
| {                                    |
|   "Error type": "MY_EXCEPTION",      |
|   "SQLCODE": -20002,                 |
|   "SQLERRM": "Raised MY_EXCEPTION.", |
|   "SQLSTATE": "P0001"                |
| }                                    |
+--------------------------------------+
Copy

まれに、何もせずに例外を明示的に処理したい場合があります。これにより、例外が発生したときに中止するのではなく、続行することができます。詳細については、 NULL コマンドをご参照ください。

例外のハンドラーを設定しない場合は、実行するためにこのブロックを送信するクライアント(例: ウェブインターフェイス)がエラーを報告すること(宣言された例外の生成 で説明のとおり)に注意してください。

-20002 (P0001): Uncaught exception of type 'MY_EXCEPTION' on line 8 at position 4 : Raised MY_EXCEPTION.
Copy

注釈

同じ例外を再生成する必要がある場合は、 例外ハンドラーでの同じ例外の再生成 をご参照ください。

例外ハンドラーでの同じ例外の再生成

場合によっては、例外ハンドラーでキャッチしたのと同じ例外を生成する必要が生じる可能性があります。このような場合は、引数を指定せずに 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;
Copy

注: SnowSQL または Classic Console を使用している場合は、代わりに次の例を使用します(SnowSQL および Classic Console での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;
$$;
Copy