PSBGENの深層:アプリケーション要件をDBMSの物理構造に縛り付けるな
こんにちは。チーフアーキテクトの私だ。
今日のコードレビューで、また「全セグメントが見える巨大なPSB」を平然と定義しているプルリクエストを見かけた。
「とりあえず動くから」「将来どこを使うか分からないから」——そんな怠惰な理由で定義されたPSB(Program Specification Block)は、階層型DBMS(IMS DBなど)の最大の武器である「データ独立性とアクセスコントロールの極限的最適化」をドブに捨てる行為に他ならない。
現代の分散RDBやNoSQLに慣り親しんだ世代には、PSBGEN(Program Specification Block Generation)のマクロ定義は、呪術的なレガシーコードに映るかもしれない。だが、見くびるな。これはアプリケーションと物理データ構造をミリ単位で制御し、セキュリティとパフォーマンスの境界線を引くための極めて先鋭的なスキーマ定義言語(DDL)なのだ。
今回は、実務の現場でシステムを崩壊させないための「PSBGENの正しい設計哲学と実装パターン」を伝授する。
—
1. PSBとPCBのアーキテクチャ再確認
大前提として、PSBは単なるビューの集まりではない。「あるオンライン/バッチプログラムが、どのデータベースの、どのセグメントに、どの権限(処理モード)でアクセスできるか」を定義した実行時セキュリティ&アクセスパスマップである。
- PSB (Program Specification Block): プログラム単位で必要なPCBの集合体。
- PCB (Program Communication Block): 個々のデータベース(または端末)に対するアプリケーションの窓口。
[アプリケーションプログラム]
│ (呼出: CBLTDLI)
▼
┌─────────── PSB ───────────┐
│ [PCB 1] ──> DB-A (読取) │
│ [PCB 2] ──> DB-B (更新) │
└───────────────────────────┘
この分離構造により、アプリケーションは物理的なデータベース全体の構造を知る必要がなくなり、DBMS側で不正なセグメントへのアクセスをハードウェアレベル(および制御ブロックレベル)で遮断できる。
—
2. PSBGENの実装例:アンチパターンからプロダクション品質へ
百聞は一見にしかず。まずは、よくある「危険な定義」と、我々が目指すべき「堅牢な定義」を比較する。
【アンチパターン】すべてが見える「肥大化PSB」
すべてのセグメントに `PROCOPT=A`(All: 読取・追加・置換・削除)を付与し、どのプログラムからも全能の神のように振る舞えるようにした最悪の例だ。
- ————————————————————
- [危険] アンチパターン: 権限過剰・スコープ過大なPSB定義
- ————————————————————
BADPSB PSBGEN PSB=BADPSB,LANG=COBOL
PCB TYPE=DB,DBD=CUSTDB,PROCOPT=A,KFREQ=YES
SENSEG NAME=CUSTSEG,PARENT=0
SENSEG NAME=ORDSEG,PARENT=CUSTSEG
SENSEG NAME=ITEMSEG,PARENT=ORDSEG
PSBGEN FINISH
END
何が問題か?
1. セキュリティリスク: 参照系プログラムであっても、バグや脆弱性を突かれれば注文や顧客データを改ざん・削除できる。
2. パフォーマンス劣化: 不要なセグメント(`ITEMSEG`など)まで論理階層に含まれるため、バッファプールや内部制御ブロックのフットプリントが無駄に拡大する。
—
【プロダクション品質】最小特権の原則に基づくPSB定義
では、参照(Inquiry)専用のバッチプログラムに向けた、セキュアかつ洗練されたPSBGENを見てみよう。
- ————————————————————
- [推奨] プロダクション品質: 最小特権と処理最適化を極めたPSB
- ————————————————————
CUSTINQ PSBGEN PSBGENVER=2.0, 制御ブロックバージョン指定
PSB=CUSTINQ, PSB名
LANG=COBOL 対象言語
- 顧客データベースに対する参照専用PCB
- PROCOPT=G (Get: 読取専用) を強制し、誤更新の余地をゼロにする
PCB TYPE=DB, データベースPCB
DBD=CUSTDB, ターゲットDBD名
PROCOPT=G, 処理オプション: 読取のみ(Get)
MODIFY=YES 拡張修飾子を許可
- アクセスを許可するセグメントの厳格な絞り込み
- 親であるCUSTSEGを介して、直近のORDSEGまでをスコープとする
- ITEMSEG(明細)は業務要件外のため、SENSEGを定義せず隠蔽する
SENSEG NAME=CUSTSEG, 顧客セグメント
PARENT=0 ルートセグメント
SENSEG NAME=ORDSEG, 注文セグメント
PARENT=CUSTSEG, 顧客セグメントの子
PROCOPT=G 必要に応じて個別にPROCOPTを絞る
PSBGEN FINISH PSBGEN終了マクロ
END アセンブラ終了
—
3. チーフアーキテクトが教える:実務で踏み抜く「4つの罠」と設計指針
長年の運用現場で、我々は幾度となくPSB起因の障害や性能劣化に直面してきた。そこから得られた実践的な知見を共有しよう。
① `PROCOPT` の選定ミスはシステム障害の元
- `PROCOPT=G` (Get): 読取のみ。最も安全。
- `PROCOPT=L` (Load): 初期ロード専用。通常オンラインでは使用厳禁。
- `PROCOPT=A` (All): 読取・追加・置換・削除。「とりあえずA」にする開発者は即座にコードレビューで差し戻せ。
- 更新が必要なプログラムであっても、極力 `PROCOPT=R`(Replace)や `PROCOPT=I`(Insert)など、必要な操作に限定して権限を最小化せよ。
② `SENSEG` の省略による「暗黙のデータ隠蔽」の活用
PSBで定義されなかったセグメントは、アプリケーションからは存在しないものとして扱われる。
例えば、機密情報(給与やクレカ情報など)を含むセグメントを、一般参照用のPSBのSENSEGから外すだけで、アプリ側がどれだけバグを起こしても、あるいはSQLインジェクション的なアプローチを試みても、物理的にデータに到達できなくなる。アプリケーションコードに依存しない、DBMSレベルの強固な多層防御だ。
③ ポインタ競合とバッファプールの最適化
頻繁に更新されるルートセグメントや、大量の子セグメントを持つ階層において、不適切なPSB定義はデータベースのロック競合を引き起こす。
特にバッチ処理用のPSBで、広範囲のセグメントを `PROCOPT=A` で長期間保持すると、オンライン側のトランザクションがデッドロックや待ち状態に陥る。バッチ用PSBは、処理単位を細分化し、必要なセグメント群だけに絞り込むことで、排他制御のフットプリントを最小限に抑えなければならない。
④ PSBGENの変更忘れ(デプロイメントの罠)
DBDの変更(セグメントの追加やフィールドの拡張)を行った際、それに依存するPSBの再生成(PSBGEN)を忘れると、実行時abend(S070やU0841など)を引き起こす。
CI/CDパイプラインにおいて、DBDの変更検知と、依存するすべてのPSBの自動再生成・カタログ更新を完全に同期させる仕組みが、モダンなメインフレーム/階層型DB運用には不可欠である。
—
4. まとめ
PSBGENは、単なるマクロの羅列ではない。
「誰が、どこに、どのような権限でアクセスするか」というデータガバナンスの根幹を定義する、極めて重要なアーキテクチャ成果物だ。
「動けばいい」という甘えた設計は、セキュリティの穴を広げ、パフォーマンスをスポイルし、将来の拡張性を確実に殺す。
次に君がPSBを設計、あるいはレビューするときは、こう自問してほしい。
> 「このプログラムは、本当にこのセグメントの、この権限を必要としているか?」
その問いに自信を持って「YES」と言えるとき、君のシステムは真に堅牢な領域へと到達する。
コメント