SQL PLにおけるエラー処理、パート1
以前は、自分は物事を論理的に考えるタイプであると思っていました。けれどもコンピューターのプログラミングを始めたとき、その認識はガラッと変わりました。すぐに、自分にはエラーのないプログラムを書くことはできないと気づきました。経験のたまものだとすべき貴重な教訓もあります。想定される条件と想定外の条件の両方についてプログラムすることは経験を重ねるうちに学んだことです。そして今では、SQL PLを含め、使用するすべての言語に対してそうした考え方を適用しています。
SQL PLには、優れた例外処理の方法があり、しかもそれらの使い方は難しくありません。本記事と後述の「パート2」の記事では、SQL要求が正しく動作したこと、またはしなかったことを、DB2がどのように知らせてくれるのかについて見て行きます。次に、条件(プロシージャーの動作の前提となる様々な状態)について見て行きます。条件の後は、条件ハンドラーについて取り上げます。条件ハンドラーは何か間違ったことが起きたときに求められるルーチンの動作を決定します。最後に、目的を達成するために条件を強制する方法について取り上げます。
通知
DB2は、ナポレオン・ボナパルトに似ているところがあります。ナポレオンはこんな言葉を残しています。「敵が間違ったことをしているときは、それを止めさせることはない。」DB2も、操作が正常に終了しない場合に、プログラムの実行を止めさせることはしません。DB2が行うのは、テストできる値を持つ、SQL状態(SQLState)とSQLコード(SQLCode)という2つの変数をロードすることです。 SQL PLは、これらの変数を定義してくれません。それらを使いたい場合は、次のようにして、それらを宣言する必要があります。
どちらの変数でもテストすることができますが、名前付き条件および条件ハンドラーの場合、SQL状態は参照することができますが、SQLコードは参照できないため、SQL状態の方が有用です。RPGプログラムなど、他の設定でSQLコードを使用していた場合は、SQL状態に切り替えることをお勧めします。 SQL状態の最初の2文字は、 SQL状態クラスとして知られています。それらの値は、SQL状態IDが分類される一般カテゴリーを示しています。
条件
条件の定義について妥当なものが見つからなかったので、私なりに条件の定義を考えてみました。データベース操作への応答としてDB2が警告または例外を発行したときに存在する状態。条件には、一般的な条件と特定の条件の2種類があります。
一般的な条件は、データベース応答のカテゴリーをカバーします。以下の3種類があります。
SQLEXCEPTION: 重大なエラーが発生しました。SQL状態クラスは、「00」、「01」、「02」以外です。
SQLWARNING: DB2は不整合を検出しましたが、操作の取り消しは保証されませんでした。SQL状態クラスは「01」です。
NOT FOUND: DB2は検索に一致するデータを見つけられませんでした。SQL状態クラスは「02」です。
特定の条件は、1つのSQL状態値のみに適用します。たとえば、CREATE TABLEが、すでに存在している表を作成しようとすると、DB2はSQL状態変数を42710に設定します。
条件名
SQL PLでは、特定の条件に記述名を割り当てることができます。以下のステートメントは、3つとも同等で、SQL状態42710に CreateFailed という名前を与えます。
条件ハンドラー
条件ハンドラーは、警告または例外条件に対する応答としてシステムが実行するルーチンです。1つのハンドラーを1つ以上の条件に割り当てることができます。ハンドラーは1つのステートメントを実行します。これはコンパウンド ステートメントでもかまいません。
3種類のハンドラーがあり、ハンドラー実行後の処理によって区別されます。
Continueハンドラーは、条件を起こしたステートメントの次のステートメントに戻ります。
Exitハンドラーは、コンパウンド ステートメントを終了します。
Undoハンドラーはexitハンドラーに似ていますが、コンパウンド ステートメントを終了する前に、コミットされていないデータベース変更をロールバックする点が異なります。Undoハンドラーは、アトミック コンパウンド ステートメントでのみ許可されます。
以下に、例を示します。
すでにPLANTSという表がある場合、CREATE TABLEコマンドは失敗し、SQL状態42710が返されます。continueハンドラーは、v_Errorに「1」の値を割り当て、v_ErrorCountの値を1つ増やします。これはcontinueハンドラーであるため、制御はCREATE TABLEの次のLABELステートメントに渡されます。
しかし、PLANTSの存在が何らかの異常を意味するとしたら、どうなるでしょうか。その場合は、exitハンドラーを使用します。
すでにPLANTS表がある場合、DB2はSQLコード42710で応答します。その条件名はTable_Existsです。その条件に対するexitハンドラーがあり、制御にストアード プロシージャーのメイン ステートメントであるコンパウンド ステートメントを終了させます。これは制御にストアード プロシージャーを終了させて、呼び出し元に戻ることを意味します。exitハンドラーには、1つのステートメント「RESIGNAL」しかありません。これはどういうものなのでしょうか。それが「パート2」のテーマになります。