【実務・中級編】DB2カーソル処理におけるDECLARE/OPEN/FETCH/CLOSEのライフサイクル – PL/Iの基本構文とデータ制御実践ガイド

おい、最近入った若手が「先輩、PL/IのDB2カーソル処理って、なんだかCOBOLのそれと勝手が違って頭がこんがらがります」って泣きついてきたんだよ。

無理もない。COBOLなら`WORKING-STORAGE SECTION`に`EXEC SQL DECLARE …`を書いて、手続き部で素直に`OPEN`、`FETCH`、`CLOSE`を叩けばいい。だが、PL/Iの世界――特にIBMメインフレームの基幹系バッチを長年支えてきたこの言語には、PL/I独自のデータ構造、ポインタの概念、そして独特の「予約語を持たない(キーワードがコンテキストで決まる)」という懐の深さが絡み合ってくる。

今日はな、DB2の複数行検索(カーソル処理)におけるDECLAREからCLOSEまでのライフサイクルを、実際の現場で即戦力となる実務コードと共にお前らに叩き込んでやる。これさえ読めば、夜間バッチの急なトラブル対応で冷汗をかくこともなくなるはずだ。

—

1. PL/IとDB2カーソル処理の基本心構え

まず大前提として、PL/IでDB2を扱うときは、COQL(コボルではなくPL/Iね)のプリコンパイラが吐き出すCSIやホスト変数のマッピングを意識する必要がある。
PL/Iの最大の特徴は「予約語という概念がほぼ存在しない(Contextual Keywords)」という点だ。例えば `IF` や `READ` といった一見して予約語に見えるものでさえ、文脈によっては単なる変数名として使えてしまう。そのため、SQL文を埋め込む `EXEC SQL` プレフィックスとの境界をコンパイラが正しく解釈できるように、宣言と処理のスコープを明確にする必要があるんだ。

カーソル処理のライフサイクルは以下の4ステップで完結する。

1. DECLARE(宣言): SQL文とカーソル名の結び付け
2. OPEN(オープン): 検索条件に基づいた結果セット(Result Set)の生成
3. FETCH(取得): カーソルを進めながら1行ずつホスト変数へデータを取り込む
4. CLOSE(クローズ): リソースの解放とカーソルの無効化

これを踏まえて、実際のプロダクションコードを見ていこう。

—

2. 実践PL/Iソースコード:DB2複数行検索バッチの模範解答

以下のコードは、顧客マスタ(CUSTOMER_TBL)から特定地域(例: ‘TOKYO’)の顧客を複数件フェッチし、合算処理やログ出力を行うバッチプログラムの骨格だ。大文字記述、適切なインデント、そして実務で必須となる `SQLCODE`/`SQLSTATE` のチェックを網羅している。

1
—————————————————————-;

  • 顧客マスタ複数件検索バッチサンプル

—————————————————————-;
CUST_BATCH: PROC OPTIONS(MAIN);

DCL 1 H_CUST,
5 H_CUST_ID CHAR(6),
5 H_CUST_NAME CHAR(30),
5 H_BALANCE DEC FIXED(11,2);

DCL H_IND_BAL BIN FIXED(15); / インジケータ変数(NULL対策) /

DCL 1 W_WK,
5 W_EOF_FLG CHAR(1) INIT(‘0’),
5 W_READ_CNT DEC FIXED(7,0) INIT(0);

— DB2通信領域およびSQL制御変数の宣言
EXEC SQL INCLUDE SQLCA;

— エラーハンドリング用ONユニット(重大エラー時)
ON ERROR BEGIN;
PUT SKIP LIST(‘ 予期せぬシステムエラーが発生しました ‘);
EXEC SQL ROLLBACK;
SIGNAL FINISH;
END;

PUT SKIP LIST(‘ 顧客バッチ処理 開始 ‘);

— 1. カーソルの宣言

  • 検索条件(AREA_CODE)をホスト変数で動的にバインドする

EXEC SQL
DECLARE CUST_CURSOR CURSOR FOR
SELECT CUST_ID, CUST_NAME, BALANCE
FROM CUSTOMER_TBL
WHERE AREA_CODE = ‘TOKYO’
ORDER BY CUST_ID;

— 2. カーソルのオープン
EXEC SQL OPEN CUST_CURSOR;

IF SQLCODE ^= 0 THEN DO;
PUT SKIP LIST(‘ OPEN ERROR: SQLCODE = ‘, SQLCODE);
GOTO ERROR_RTN;
END;

— 3. フェッチ・ループの開始
DO WHILE (W_EOF_FLG = ‘0’);

EXEC SQL
FETCH CUST_CURSOR
INTO :H_CUST_ID,
:H_CUST_NAME,
:H_BALANCE INDICATOR :H_IND_BAL;

SELECT (SQLCODE);
WHEN (0) DO;
W_READ_CNT = W_READ_CNT + 1;

  • NULL値の判定(必要に応じてデフォルト値に置き換え)

IF H_IND_BAL < 0 THEN H_BALANCE = 0;

  • 実際のビジネスロジック(ここではログ出力のみ)

PUT SKIP EDIT (‘ID:’, H_CUST_ID, ‘ NAME:’, H_CUST_NAME, ‘ BAL:’, H_BALANCE)
(A, A, A, A, A, F(12,2));
END;
WHEN (100) DO;

  • データ終了(EOF)

W_EOF_FLG = ‘1’;
END;
OTHERWISE DO;

  • FETCH時の予期せぬSQLエラー

PUT SKIP LIST(‘ FETCH ERROR: SQLCODE = ‘, SQLCODE);
GOTO ERROR_RTN;
END;
END;

END;

— 4. カーソルのクローズ
EXEC SQL CLOSE CUST_CURSOR;

IF SQLCODE ^= 0 THEN DO;
PUT SKIP LIST(‘ CLOSE ERROR: SQLCODE = ‘, SQLCODE);
GOTO ERROR_RTN;
END;

PUT SKIP EDIT(‘ 正常終了 処理件数 = ‘, W_READ_CNT) (A, F(7));
RETURN;

ERROR_RTN:

  • 異常時クローズ試行(オープン状態の場合のみDB2がよしなに処理するが念のため)

EXEC SQL CLOSE CUST_CURSOR;
PUT SKIP LIST(‘ 異常終了しました。ロールバックします。’);
EXEC SQL ROLLBACK;
SIGNAL FINISH;

END CUST_BATCH;

—

3. ベテランが教える「現場の知見」とハマりどころ

このコードを見て、「おっ、基本を押さえているな」と思ったお前、甘い。実務の現場では、これだけでは本番障害を防げないケースがあるんだ。いくつか重要なポイントを伝授しよう。

① インジケータ変数(INDICATOR)の省略は死を意味する

データベースの設計書で「NULL不許可(NOT NULL)」と書いてあったとしても、将来的な改修やデータ移行のゴミデータによって、ある日突然 `SQLCODE = -305`(ホスト変数にNULLが割り当てられたがインジケータがない)という致命的なエラーを踏むことになる。
複数行検索の `FETCH` では、数値項目や文字数に余裕を持たせるだけでなく、必ず `INDICATOR` 句をセットで実装する癖をつけろ。PL/Iでは `BIN FIXED(15)` がインジケータの標準的な型だ。

② SELECT(SQLCODE)構文の活用

COBOLだと `IF SQLCODE = 100` のあとに `ELSE IF` をダラダラと並べがちだが、PL/Iには強力な `SELECT` 構文がある。`SQLCODE` の値に応じて綺麗に分岐できるため、エラーハンドリングの視認性が劇的に向上する。
特に `SQLCODE = +100`(データ終了)と `SQLCODE = 0`(正常)以外の、例えばデッドロックを示すマイナスコードなどを捕捉するときにこの構造化された `SELECT` が非常に役立つ。

③ 異常系(ERROR_RTN)での二重クローズとロールバック

カーソル処理中に異常が発生した場合、そのままプログラムを異常終了させると、DB2のスレッドやロックが中途半端に残る恐れがある。
必ず `CLOSE CUST_CURSOR` を通してから `ROLLBACK` を発行するフローを組むこと。ただし、既にオープンに失敗している状態で `CLOSE` を叩くとさらに別のSQLエラーが返ることがあるため、実務ではトランザクション管理と連動した堅牢なエラーパスの設計が求められる。

—

最後に

PL/Iの記述は一見すると古臭く見えるかもしれないが、言語仕様の奥深さと、メインフレームのハードウェア特性に最適化されたコンパイラの挙動を理解すれば、これほど信頼性の高い言語はない。
DB2カーソル処理は、バッチのパフォーマンス(コミット間隔やフェッチブロッキングなど)にも直結する生命線だ。今回のコードと解説をベースに、お前の現場のプログラムを今一度見直してみてくれ。頼もしい成果を期待しているぞ!

タイトルとURLをコピーしました