社内SEの徒然なる日記

NetCOBOLでSQLのエラーを確認する

エラー処理ってなんぞや

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


スポンサードリンク

PageTop

コメント


管理者にだけ表示を許可する