エラーハンドリング
Denaliでは、新しくTHROWステートメントが追加されます。THROWステートメントを使用すると、ユーザーは任意のタイミングでエラーを発生させることができます。
これまでにSQL Serverを使用されたことのある方はお気づきかもしれませんが、T-SQLには、ユーザーが任意のタイミングでエラーを発生させるためのRAISERRORステートメントが既にあります。エラーを発生させるという意味において、THROWステートメントと、RAISERRORステートメントは同じです。
では、何が大きく異なるのかというと、THROWステートメントは、TRY…CATCH構造でキャッチしたエラーを、そのまま上位へスローすることができるようになるのです。RAISERRORステートメントでは、TRY…CATCH構造でキャッチしたエラーを、そのまま上位へスローという機能を備えていませんでした。
例えば、キャッチしたエラーを、上位へスローしようとして以下のように実装しても実際にはうまく機能しません。
… END TRY BEGIN CATCH DECLARE @ErrorMessage NVARCHAR(4000); DECLARE @ErrorSeverity INT; DECLARE @ErrorState INT; DECLARE @Err INT; SELECT @ErrorMessage = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(), @Err = ERROR_NUMBER() RAISERROR (@Err, @ErrorMessage, @ErrorSeverity, @ErrorState); END CATCH
第一に、RAISERRORの第一引数に指定できるエラー番号は、50000以上の値でないといけないため、50000以下のシステムエラーの場合にRAISERRORステートメントがエラーとなります。第二に、エラー番号が50000以上のエラーであっても、TRYブロック内のRAISERRORステートメントでエラーを発生させたときに指定したパラメータ(エラーメッセージの置換文字列)を受け取るすべがないので、まったく同じようにRAISERRORでエラーを発生させることができません。キャッチブロック内のRAISERRORステートメントの第一引数を、エラー番号の代わりにERROR_MESSAGE関数で取得したエラーメッセージにすることも考えられますが、そうすると今度はエラー番号がデフォルトの50000となってしまいます。
これまでは、このような制限があったため、RAISERRORとTRY…CATCH構造を使用する場合のエラーハンドリングについてはあらかじめ考慮しておかなければならない点も多く、多少煩わしい部分もあったかと思います。しかし、上記のような例で困っていた方は、DenaliでTHROWステートメントが実装されることで随分と楽になるはずです。
では、簡単ではありますがTHROWステートメントを使用して、エラーを上位へスローする例を以下に紹介します。
… END TRY BEGIN CATCH INSERT SAMPLE_THROW VALUES (@@ERROR); THROW; END CATCH
この例では、エラーをキャッチした後、SAMPLE_THROWテーブルにINSERTして、キャッチした上位へエラーをスローしています。キャッチしたエラーをそのまま上位へスローする場合は、THROWステートメントのパラメータに何も指定しません。お気づきの方もいらっしゃるとは思いますが、一番のポイントはTHROWステートメントで上位へスローされるエラーは、あくまでキャッチしたエラーであり、INSERT文が実行された直後のエラーではないことです。なお、この動作を保障する為には、THROWステートメント直前のステートメントがすべてセミコロン(;)で終わってなければならないので注意が必要です。
THROWステートメントは、RAISERRORステートメントとよく似ていますが、他にも異なる点がいくつかあります。例えば、THROWステートメントはパラメータに重大度を指定できなくなっており、固定で16が設定されます。これも重要な点です。
RAISERRORステートメントは、重大度を指定できるがゆえに、エラーハンドリングを複雑化させていた部分があります。RAISERRORステートメントに指定する重大度によっては、バッチがアボートしたり、接続がアボートするなど、エラー時のアクションが異なることがあるからです。(必ずしも”重大度 = エラー時のアクション”ではないので注意)
THROWステートメントの詳細については、こちらを参照ください。RAISERRORステートメントと異なる点についても表でわかりやすくまとめられています。
* * *
いかがだったでしょうか?今回紹介した機能は、実際に私がお客様から「こういう機能があるといいな」というお声をいただいたことのある機能です。そのため、「待っていました!」と思われた方も結構いらっしゃるかもしれません。
Denaliでは、まだまだ他にもT-SQLの新機能が実装されていますので、次回も引き続きT-SQLの新機能紹介を行っていきます。おたのしみに!