
サブルーチンだけコンパイル
もう3年ほど前の話ですが、当時サブルーチンの機能を拡張しようとした時に、メインプログラムをリコンパイルせずに実行させたことがあります。
コンパイル
障害の内容
問題となったサブルーチンは引数の受け渡しのための専用のソースを使用しています。
メインプログラムとサブプログラムで、このCOPY句を使用してパラメータの受け渡しをします。
サブルーチンの機能拡張のために、COPY句に項目を追加、サブルーチンも修正してコンパイルして実行したのですが、OracleのInsert文でCOPY句に追加した項目が原因で異常終了しました。
ORA-01413: パック10進数のバッファの値が無効です。
障害発生時の状況
下記が修正したCOPY句の内容です。
11/25 の追加個所が障害発生時の修正個所です。
【COPY句】
01 ()-PARM.
10 ()-KIDOU-KBN PIC X(001). *> 起動区分
10 ()-SOUSINMOTO-CODE PIC X(006). *> 送信元担当者コード
10 ()-SOUSINSAKI-CODE PIC X(006). *> 送信先担当者コード
10 ()-GYOUMU PIC X(040). *> 業務名
10 ()-RENRAKU1 PIC X(040). *> 連絡内容1
10 ()-RENRAKU2 PIC X(040). *> 連絡内容2
10 ()-KEKKA PIC 9(001). *> 結果
10 ()-ERRORCODE PIC X(002). *> エラーコード
* 2009.11.25 ADD START ---
10 ()-COMMIT PIC X(001). *> コミットフラグ(0:COMMITする 1:COMMITしない)
10 ()-CHARGE-CODE PIC X(006). *> 受付担当者コード
10 ()-ORDER-NUM PIC X(008). *> 伝票番号
10 ()-KUBUN PIC S9(012)V9(3) COMP-3. *> 区分(1:入荷 2:出荷)
10 ()-MANAGER-NUM PIC S9(012)V9(3) COMP-3. *> 管理番号
10 ()-DETAIL-NUM PIC S9(012)V9(3) COMP-3. *> 明細番号
10 ()-ORDER-METHOD PIC X(001). *> 発注方式
* 2009.11.25 ADD END -----
下の7つの項目(コメントの2009.11.25の範囲内)を追加しています。
次にサブルーチンに、追加した項目をホスト変数に設定する処理を追加します。
H-で始まるのがホスト変数です。
【サブルーチン】
MOVE P1-ORDER-NUM TO H-ATRCHREXP01. *> 伝票番号
MOVE P1-CHARGE-CODE TO H-ATRCHREXP02. *> 受付担当者コード
MOVE P1-ORDER-METHOD TO H-ATRCHREXP03. *> 発注方式
COMPUTE H-ATRNUMEXP01 = P1-MANAGER-NUM. *> 管理番号
COMPUTE H-ATRNUMEXP02 = P1-KUBUN. *> 区分(1:入荷 2:出荷)
COMPUTE H-ATRNUMEXP03 = P1-DETAIL-NUM. *> 明細番号
異常終了したInsert文は下記の内容です。
追加した項目を設定してInsert文を実行させます。
【INSERT文(一部抜粋)】
*-- テーブルへの登録
EXEC SQL
INSERT INTO ABCD
(TESTAA,
:
:
TESTBB
)
VALUES(RTRIM(:H-TESTAA),
:
:
* -- 2009.11.25 ADD START ---
RTRIM(:H-ATRCHREXP01), -- 伝票番号
RTRIM(:H-ATRCHREXP02), -- 受付担当者コード
RTRIM(:H-ATRCHREXP03), -- 発注方式
* -- 2009.11.25 ADD END -----
:
:
* -- 2009.11.25 ADD START ---
:H-ATRNUMEXP01, -- 管理番号
:H-ATRNUMEXP02, -- 区分(1:入荷 2:出荷)
:H-ATRNUMEXP03, -- 明細番号
* -- 2009.11.25 ADD END -----
:
:
''
)
END-EXEC.
メインプログラムは未修
実装は、下記のようにします。
メインプログラム
* *> 引数設定
MOVE "2" TO P1-KIDOU-KBN. *> 引数.起動区分(1:オンライン、2:バッチ)
MOVE CS-CHRID TO P1-SOUSINMOTO-CODE. *> 引数.送信元担当者コード
MOVE "データ調査" TO P1-GYOUMU. *> 引数.業務名
MOVE "エラーメッセージ1です" TO P1-RENRAKU1.
MOVE "エラーメッセージ2です" TO P1-RENRAKU2.
*
* *> サブルーチン実行
CALL "TEST999" USING P1-PARM.
*
* *> エラートラップ
IF P1-ERRORCODE NOT = "00"
DISPLAY "サブルーチンエラー"
END-IF.
これを実行したところ、前述のエラーが発生しました。
障害の切り分け
下記の手順で、障害の発生個所を特定しました。
① メインプログラムをリコンパイルして再処理したのですが、同じエラーが発生しました(ーー;)
② どの引数でエラーが発生しているのか、トライ&エラーで探索。数値項目がエラー個所と特定。
③ 引数の値を、ホスト変数に設定する処理を MOVE文 から COMPUTE文 に変更。同じエラー発生。
④ DISPLAY文で、引数の数値項目と設定後のホスト変数の値をログ出力。 +000000000000000 が表示。
⑤ 引数の初期化が原因と想定して、引数の数値項目が LOW-VALLUE だったら ZERO にするロジックを追加。コンパイルエラー。( 数値項目 = LOW-VALUE の比較式は使えない )
⑥ メインプログラムを修正。引数を起動側で初期化( INITIALIZE文 を発行)。正常に実行完了。
ただし、サブルーチンを使用しているPGが余りにも多い( 200本近い )ので別の手段を検討。
⑦ サブルーチン側で、数値項目が ZERO であれば ZERO を設定するロジックを追加。
正常終了することを確認。
...しかし、このロジックで動くということは、メモリの割当とかその辺りに何かあるということだろうか。
なんだかなぁ(-_-)
対応方法
障害切り分けで確認した通り、サブルーチン側にZERO であれば ZERO を設定するロジックを追加しました。
【追加内容】
* 引数の補正
IF P1-KUBUN = ZERO
COMPUTE P1-KUBUN = ZERO
END-IF.
IF P1-MANAGER-NUM = ZERO
COMPUTE P1-MANAGER-NUM = ZERO
END-IF.
IF P1-DETAIL-NUM = ZERO
COMPUTE P1-DETAIL-NUM = ZERO
END-IF.
あれから3年たって思う
あれから3年たって、当時の資料からこの記事を起こしているのですが、いろいろと考えさせられる事例ですね。
障害時切り分けの中で、メインプログラムのリコンパイルをしても状況が再現したということから考えると、「 WORKING STARAGE SECTION」で宣言した変数を初期化しないで使用すると、同じ現象を発生させられそうですね。
こうして考えると、「変数は初期化してから使用する」っていう作法がとても大切だということが分りますね。
たしか、COBOLの言語仕様も、初期化していない変数の値は保障していなかったはずなので、奇妙な現象が発生するのは無理もないかもしれませんね。
それにしても、当時はこれで納得したんですけど、今にして思えば危険なことをしたように思います。
現在まで、特に障害にはならずに動作してるので、まぁ問題なかったのかもしれませんが、気合い入れて200本のメインプログラムを全部直した方がよかったかも知れません。
本数は多くても、1行追加するだけですしね。
余談
当社の運用ルールとしてソースを修正した場合は、日付付きのコメントを付けることになっています。
現在はsubversionで資産管理はしているので、無用と言えばその通りなのですが、昔の修正分との整合性を保つために続けています。
「ソースが汚くなる」とか「可読性が云々...」とか「追えなくなる」とか騒ぐ人もいるのですが、私の答えは「サンデープログラマじゃあるまいし、気合い入れて追えよ」だったりします。
...少し傲慢ですかね?
前回:NetCOBOLのコンパイルエラー集
次回:NetCOBOLでロードモジュールからSQLを取り出す
投稿記事の一覧 : http://harikofu.blog.fc2.com/blog-entry-22.html
--- blog end ---
スポンサードリンク


