
エラー処理ってなんぞや
NetCOBOLでは、SQLの実行でエラーが発生してもそのまま処理が続行される性質があります。
なので、何もしなければSQLでエラーが発生してもCOBOL自体の処理は続けて実行されてしまいます。
そこで、SQLのエラー状態をプログラム側でチェックする必要があります。
エラーチェックにはSQLCAのSQLCODEの値を判定する方法と、WHENEVER文を使用する方法がありますが、WHENEVER文を使用する方がまっとうと思われるので、こちらの話のみ書いておきます。
WHENEVER文
WHENEVER文を使用することで、SQL実行時にエラーが発生したときに自動的にエラー処理を行うことが出来ます。
取得できるのは「異常・警告・データ無し」の3つの状態で、それぞれの状態に対してエラー処理を記述できます。
【構文】
EXEC SQL
WHENEVER 「状態」
「アクション」
END-EXEC.
状態
状態は、下記の3つの何れかを指定できます。
・SQLERROR
致命的なエラーを検出した場合。SQLCODEには負の値が設定されます。
・SQLWARNING
警告となった場合。詳細はSQLCAを見ないと解らないが、続行可能である場合もあります。
・NOT FOUND
SQLの実行結果が0件の時に発生します。フェッチで最終行に達した時もこの状態となるので、明示カーソルを使用して処理を行う時は、この状態を検出することでフェッチの終了を判断します。(SQLCODEには+1403が戻される)
アクション
・CONTIMUE
「状態」チェックをオフにします。WHENEVER文を設定していない状態に戻すという事です。
・DO CALL
指定したサブプログラムを実行します。
サブプログラムの実行が終了すると、失敗したSQLの次の文が実行されます。
・DO PERFORM
指定したCOBOL節、段落が実行されます。つまり、通常のPERFORM文と同じ動作です。
節の最後まで実行した後に、失敗したSQLの次の文が実行されます。
・GOTO 又は GO TO
指定した段落または節に移動する。
STOP
プログラムを終了する。COMMITされていない作業はロールバックされる。
WHENEVER文による異常時の実行例
下記のソースを例として、SQLエラートラップの記述方法を解説します。
MAIN-RTN SECTION.
*A.エラー宣言
EXEC SQL WHENEVER SQLERROR
DO PERFORM SQLERROR-RTN
END-EXEC.
*B.SQL実行
EXEC SQL
SELECT NVL(NMDPT , ' ' ) INTO :H-NMDPT FROM MDPT
WHERE CDCOM = RTRIM(:H-CDCOM) AND CDDPT = RTRIM(:H-CDDPT)
END-EXEC.
*C.エラートラップ
IF WK-ERR-FLG = "1" THEN
DISPLAY ERR-MSG
GO TO ERR-STOP
END-IF.
MAIN-EXIT.
EXIT.
*D.エラー処理
SQLERROR-RTN SECTION.
MOVE "1" TO WK-ERR-FLG.
EXIT.
*E.強制終了処理
ERR-STOP.
EXEC SQL ROLLBACK WORK RELEASE END-EXEC.
STOP RUN.
上記ソース中のBで致命的なエラーが発生した場合、下記の順で処理が実行されます。
【処理の遷移】
1.Bでエラー発生!
2.Dの異常処理を実行
3.Dの実行後、Bの次の分であるCを実行
4.Dでエラーフラグが設定されているため、Eが実行されて処理が終了する
NOT FOUNDを使用した処理
明示カーソルを使用したSELECT文で、選択された全ての行を順次処理するサンプルです。
【使用例】
PROCEDURE DIVISION.
MAIN-RTN SECTION.
EXEC SQL WHENEVER NOT FOUND
DO PERFORM NOT-FOUND-RTN
END-EXEC.
< 初期処理を記述する(ファイルIOやORACLE接続など) >
EXEC SQL DECLARE TEST
CURSOR FOR
SELECT CDITM ,
NVL(CDUNT , ' ' )
FROM MITM
END-EXEC.
EXEC SQL OPEN TEST END-EXEC.
PERFORM UNTIL END-FLG = "END"
PERFORM LOOP
END-PERFORM.
< 終了処理を記述する >
STOP RUN.
MAIN-RTN-END.
EXIT.
LOOP SECTION.
MOVE "0" TO FLG-SQL-WHENEVER.
EXEC SQL FETCH TEST
INTO :H-CDITM ,
:H-CDUNT
END-EXEC.
IF FLG-SQL-WHENEVER = "2"
MOVE "END" TO END-FLG
ELSE
MOVE H-CDITM TO OUT-CDITM
MOVE H-CDUNT TO OUT-CDUNT
WRITE OUT-REC
END-IF.
LOOP-END.
EXIT.
NOT-FOUND-RTN SECTION.
MOVE "2" TO FLG-SQL-WHENEVER.
NOT-FOUND-RTN-EXIT.
EXIT.
エラー処理の設定順(すごく大事)
WHENEVER文の使用にあたって、最も注意しなければならないことは「複数のWHENEVER文が設定されていた場合、ソースの記述で上にあたる設定が使用される」ということです。
言葉を変えると、「ロジックの順番ではない」ということです。
なにを言っているか分らないと思うので、実際にサンプルをご覧ください。
CNTL-RTN SECTION.
* A.SQL例外宣言
EXEC SQL WHENEVER SQLERROR
DO PERFORM SQLERROR1-RTN
END-EXEC.
*
* B.SQL-RTNルーチンを実行
PERFORM SQL-RTN.
*
* C.SQL文を実行
EXEC SQL
SELECT NVL(NMDPT , ' ' ) INTO :H-NMDPT FROM MDPT
WHERE CDCOM = RTRIM(:H-CDCOM)
END-EXEC.
*
STOP RUN.
CNTL-EXIT.
EXIT.
*
* D.SQL例外宣言
SQL-RTN SECTION.
EXEC SQL WHENEVER SQLERROR
DO PERFORM SQLERROR2-RTN
END-EXEC.
SQL-EXIT.
EXIT.
*
* E.SQLイレギュラー処理1
SQLERROR1-RTN SECTION.
MOVE "1" TO FLG-SQL-WHENEVER.
SQLERROR1-RTN-EXIT.
EXIT.
*
* F.SQLイレギュラー処理2
SQLERROR2-RTN SECTION.
MOVE "9" TO FLG-SQL-WHENEVER.
SQLERROR2-RTN-EXIT.
EXIT.
上記のサンプルを実行した時に、C のSQL文でエラーが発生した時に実行されるエラー処理は、EかFかという話です。
COBOLのロジックで考えると、最後に実行されたWHENEVER文はFを実行するようにしているので、Fが実行されると思うかもしれませんが、実際にはEが実行されます。
ロジックの順番じゃないっていうのは、こういう事です。
今一つ釈然としませんが、たぶんプリコンパイルを実行した時にCOBOL自体のロジックまで判断できないってことなんでしょうかね?
やっぱり、言語の設計時に想定していなかった機能を追加しようとすると、所々に無理がでるんでしょうね。
前回:NetCOBOLでSQL文を使ってみた
次回:NetCOBOLでのコミットとロールバックの考察
投稿記事の一覧 : http://harikofu.blog.fc2.com/blog-entry-22.html
--- blog end ---
スポンサードリンク


