SQL PLにおけるエラー処理、パート2
このエキサイティングでアクションいっぱいのシリーズの前号では、IBMがSQL PLに組み込んだ例外処理の方法について紹介しました。次の記事でRESIGNALについて取り上げると書いてから、早いもので4か月が過ぎてしまいました。そろそろRESIGNALについて説明する時が来たようです。約束を守ります。また、併せてSIGNALについてもここで説明します。
構文についての説明を始める前に、基本的な考え方について少し説明しておく必要があります。RPGおよびCOBOLプログラムにSQLを組み込む際、私は hit-the-ball-drag-Harry(ボールを打ってはハリーを運ぶ、ゴルフのジョーク)方式で例外処理を行います。すなわち、コマンドを実行してはSQL状態をテストして、コマンドを実行してはSQL状態をテストして、コマンドを実行しては . . . . ということを繰り返すわけです。たぶん、皆さんも同じかもしれません。
SQL PLは、それとは異なる考えを念頭に置いた設計になっています。それは、特定の条件または条件のクラスが発生した場合に制御を行う条件ハンドラーを設定しておくという考え方です(条件ハンドラーについて理解しているという自信がない場合は、先に進む前に 「パート1」 を読み直しておくとよいかもしれません)。正しく実行されたか各ステートメントをチェックする必要はありません。 データベース マネージャーが検知できるエラーについてはそれで結構ですが、プログラミング ロジックでのみテストできるエラーについてはどうでしょうか。この疑問から、いつもは思い浮かばないような別のアイデアが浮かんできます。データベース マネージャーがそうすることができないとしたら、自分で強制的に条件を発生させればよいのです。
ここでは、このような考え方を倉庫管理の例を用いて説明しようと思います。1つの場所から別の場所への在庫の移動を記録するストアード プロシージャー(すなわちプログラム)について考えてみます(ブラウザーでコードが折り返して表示される場合は、コードをコピーしてテキスト エディターに貼り付けてください。メモ帳などでもよいでしょう)。
呼び出し元は、品目番号、移動される品目の数量、品目の移動元、および品目の移動先を送信します。
ストアード プロシージャーの本文は、アトミック コンパウンド ステートメントです。このことは、プロシージャー全体が1つのトランザクションとして扱われることを意味します。いずれかの部分が失敗した場合、データベースに対して行われたすべての変更がロールバックされます。
このアトミック コンパウンド ステートメントの中には、発生し得るすべての例外に対する1つのハンドラーがあります。条件ハンドラーは1つのステートメント、この例ではRESIGNALステートメントを実行します。 RESIGNAL は、呼び出し元が処理する条件を発生させるために条件ハンドラー内でのみ使用されます。この例のようにパラメーターがない場合、RESIGNALは、条件ハンドラーをアクティブ化した同じ条件(SQL状態)を転送します。そうしたほうがよければ、他の条件を発生させることも可能です。
最初のテストは、品目番号が有効な識別子であることを確認することです。有効でない場合、このプロシージャーはエラー77001を発生させ、メッセージ テキストおよびジョブ ログで無効な番号を報告します。SIGNALがその条件を発生させると、先程のexitハンドラーがアクティブ化し、呼び出し元へその条件を転送します。
次のテストは、データの移動元の在庫の場所を検証し、また、その場所に要求を満たす十分な在庫があることも確認します。どちらのエラーを見つけたかに応じて、このプロシージャーは、 SIGNAL ステートメントを使用してエラー条件77002または77003を発生させます。 前のテストと同じように、SQLEXCEPTION条件に対するexitハンドラーは、これらのエラー条件を捕捉し、呼び出し元にそれらを転送します。
元の場所から数量を差し引きます。この更新が失敗した場合、exitハンドラーは条件を再通知します。
新しい場所に数量を追加します。ここで、MERGEは「 upsert(アップサート)」を実行します。この品目がすでにある程度の数量この場所にある場合、移動数量が既存数量に加えられます。そうでない場合は、その品目が新しい場所に追加されます。この処理が失敗した場合、どういうことが起こるかお分かりでしょう。
最後のステップは、在庫移動のレコードを記録することです。
先に進む前に、必ず、このプロセスを通じてexitハンドラーの役割を理解しておくようにしてください。SIGNALステートメントは、呼び出し元へ条件( エラーとも言う)を送信しません。SIGNALステートメントはこのルーチン内で条件を発生させ、exitハンドラーがその条件を捕捉し、exitハンドラー内のRESIGNALが呼び出し元へその条件を伝えます。呼び出し元がその条件で何を行うかは、それがどのようにプログラムされたかによって異なります。
条件ハンドラーを使用して想定外および想定内のエラーを処理する手法は、私にとって手慣れた手法というわけではありませんが、完全に理に適った手法であるように思われます。想定されるエラーに対処し、想定外のエラーに対して先回りする堅牢なアプリケーションを書こうとお考えなら、SQL PLは強力な味方となります。