COBOLのプログラム連携というと、CALL文とUSING句による引数渡しが真っ先に浮かびます。しかし「引数に乗せたくないが複数プログラムで使いたい共有領域」が必要になる場面があります。そのときに使うのが IS EXTERNAL 句 です。
EXTERNAL句を使うと、同じラン単位(run unit)内のすべてのプログラムが、引数を渡すことなく同一のデータ領域を参照・更新できます。ファイルコネクタにも適用でき、複数プログラムが同じファイルを開いた状態で扱うことも可能です。本記事ではEXTERNAL句の仕組みを丁寧に解説し、USING句・GLOBAL句との使い分けや実践パターンまで詳しく説明します。
EXTERNAL句とは
EXTERNAL句(正式には IS EXTERNAL)は、COBOLのデータ定義に付加する句で、そのデータ項目をラン単位外部データ(run-unit external data)として宣言します。
「ラン単位外部データ」とは、特定のプログラムに属さず、ラン単位全体で1か所だけ存在するデータ領域のことです。同一ラン単位に属するプログラムが同名・同定義のEXTERNAL項目を宣言すれば、すべてが同一メモリを指します。
メインプログラムから始まり、CALLで呼ばれるすべてのサブプログラムを含む、1回の実行フローの全体を指します。STOP RUNで終了します。
EXTERNAL句が使える場所
| 適用場所 | 記述対象 | 効果 |
|---|---|---|
| WORKING-STORAGE SECTION | 01レベルの集団項目または基本項目 | プログラム間共有データ領域 |
| FILE SECTION(FDエントリ) | FD(ファイル記述エントリ) | プログラム間共有ファイルコネクタ |
LINKAGE SECTION や LOCAL-STORAGE SECTION には使えません。また、WORKING-STORAGEでは 01レベルのみに指定できます(下位レベルへの直接指定は不可)。
WORKING-STORAGE EXTERNAL の基本構文
WORKING-STORAGEにおけるEXTERNAL句の書き方は次のとおりです。
DATA DIVISION.
WORKING-STORAGE SECTION.
01 共有データ名 IS EXTERNAL.
05 項目1 PIC X(10).
05 項目2 PIC 9(5).
05 項目3 PIC 9(3)V99.
別のプログラムで同じデータ領域を参照するには、まったく同じデータ名・まったく同じ定義でEXTERNAL句を再宣言します。
*> プログラムBでの宣言(プログラムAと同一定義が必要)
DATA DIVISION.
WORKING-STORAGE SECTION.
01 共有データ名 IS EXTERNAL.
05 項目1 PIC X(10).
05 項目2 PIC 9(5).
05 項目3 PIC 9(3)V99.
EXTERNALを使う全プログラムで、データ名・レベル番号・PIC句・USAGE句が一致している必要があります。定義が異なると、コンパイラや実行時に不定動作を引き起こす可能性があります。COPY句で共通定義を管理するのが実務の基本です。
FD EXTERNAL の基本構文
ファイル記述エントリ(FD)にEXTERNAL句を指定すると、ファイルコネクタ自体が共有されます。一方のプログラムがファイルをOPENすれば、別のプログラムもそのファイルコネクタを通じて読み書きできます。
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT 共有ファイル ASSIGN TO "SHARED.DAT"
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD 共有ファイル IS EXTERNAL.
01 共有レコード.
05 レコードID PIC 9(8).
05 データ内容 PIC X(50).
05 更新フラグ PIC X(1).
別プログラムでも同様に宣言します。FILECONTROLのSELECT文も同じASSIGN先でなければなりません。
EXTERNAL・USING・GLOBALの使い分け
COBOLにはプログラム間でデータを共有する手段が複数あります。それぞれの特性を理解して使い分けることが重要です。
| 方式 | スコープ | 対象 | 宣言方法 | 主な用途 |
|---|---|---|---|---|
| EXTERNAL | ラン単位全体 | 別コンパイル単位間 | 引数なし・定義一致必須 | 設定テーブル・共有カウンタ |
| USING(BY REFERENCE) | CALL先のみ | 直接の呼び元・呼び先間 | CALL毎に明示指定 | 計算引数・処理結果の受け渡し |
| GLOBAL | 宣言プログラムと内包プログラム | ネスト(内包)されたプログラム間 | 上位プログラムで宣言するだけ | 上位管理変数・フラグの共有 |
・USING:1回のCALL呼び出しで渡す一時的なデータ(計算値・処理結果など)
・GLOBAL:ネスト構造内の上位フラグや管理変数(別コンパイル不可)
・EXTERNAL:ラン単位を通じて生き続ける共有設定・累積カウンタ・共有ファイルコネクタ
実践パターン
パターン1:共通設定テーブルの共有
複数のサブプログラムが参照する設定値(処理日付・環境区分・パラメータ)を、メインプログラムで一度ロードし、EXTERNALで全プログラムに公開する定番パターンです。
*> EXTSHARE.CPY - すべてのプログラムでCOPYして使う
01 共通設定領域 IS EXTERNAL.
05 処理日付 PIC 9(8). *> YYYYMMDD
05 環境区分 PIC X(1). *> P:本番 T:テスト
05 処理件数 PIC 9(9) COMP. *> 累積件数カウンタ
05 エラーコード PIC X(4). *> 最終エラーコード
05 FILLER PIC X(10).
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN-PGM.
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY EXTSHARE.
PROCEDURE DIVISION.
*> 起動時に設定値をロード
MOVE FUNCTION CURRENT-DATE(1:8)
TO 処理日付
MOVE 'P' TO 環境区分
MOVE ZEROS TO 処理件数
MOVE SPACES TO エラーコード
CALL 'SUB-PGM-A'
CALL 'SUB-PGM-B'
DISPLAY '総処理件数: ' 処理件数
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. SUB-PGM-A.
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY EXTSHARE. *> 同一定義を宣言するだけで共有される
PROCEDURE DIVISION.
*> 処理日付・環境区分を引数なしで参照できる
IF 環境区分 = 'P'
DISPLAY '本番処理: ' 処理日付
END-IF
ADD 1 TO 処理件数 *> カウンタを更新(メインに即時反映)
GOBACK.
パターン2:FD EXTERNALによる共有ファイルコネクタ
メインプログラムでファイルをOPENし、サブプログラムでREAD/WRITEするパターンです。ファイルのOPEN/CLOSEを分散させず、OPENはメインのみ、読み書きはサブという役割分担が実現できます。
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN-PGM.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT 入力ファイル ASSIGN TO "INPUT.DAT"
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD 入力ファイル IS EXTERNAL.
01 入力レコード.
05 顧客コード PIC X(8).
05 顧客名 PIC X(20).
05 金額 PIC 9(7).
PROCEDURE DIVISION.
OPEN INPUT 入力ファイル
CALL 'READ-PGM' *> READはサブプログラムに委譲
CLOSE 入力ファイル
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. READ-PGM.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT 入力ファイル ASSIGN TO "INPUT.DAT" *> 同一ASSIGN
ORGANIZATION IS SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD 入力ファイル IS EXTERNAL.
01 入力レコード.
05 顧客コード PIC X(8).
05 顧客名 PIC X(20).
05 金額 PIC 9(7).
WORKING-STORAGE SECTION.
01 WS-EOF-FLAG PIC X(1) VALUE 'N'.
PROCEDURE DIVISION.
PERFORM UNTIL WS-EOF-FLAG = 'Y'
READ 入力ファイル
AT END
MOVE 'Y' TO WS-EOF-FLAG
NOT AT END
DISPLAY 顧客コード ' ' 顧客名 ' ' 金額
END-READ
END-PERFORM
GOBACK.
パターン3:エラー情報の共有(集中エラー管理)
どのサブプログラムで発生したエラーも、共通のEXTERNAL領域に書き込むパターンです。メインプログラムは処理後に一括してエラー内容を確認できます。
*> EXTERR.CPY
01 エラー共有領域 IS EXTERNAL.
05 エラー発生数 PIC 9(4) COMP.
05 エラー詳細 OCCURS 10 TIMES.
10 エラープログラム名 PIC X(8).
10 エラーコード PIC X(4).
10 エラーメッセージ PIC X(40).
IDENTIFICATION DIVISION.
PROGRAM-ID. PROC-PGM.
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY EXTERR.
01 WS-ERR-IDX PIC 9(4) COMP.
PROCEDURE DIVISION.
*> エラー発生時:共有領域に記録
ADD 1 TO エラー発生数
MOVE エラー発生数 TO WS-ERR-IDX
MOVE 'PROC-PGM' TO エラープログラム名(WS-ERR-IDX)
MOVE '0001' TO エラーコード(WS-ERR-IDX)
MOVE '金額が負値です' TO エラーメッセージ(WS-ERR-IDX)
GOBACK.
落とし穴と注意点
定義不一致による未定義動作
最も危険な落とし穴です。プログラムAとプログラムBで同名のEXTERNAL項目を宣言しても、PIC句やUSAGE句が少しでも異なると、同一メモリを別の構造で読み書きすることになります。コンパイルエラーにならずに実行され、データ破損やアベンドが後から気づきにくい形で発生します。必ずCOPY句で単一の定義を全プログラムに共有してください。
EXTERNAL領域の初期化タイミング
EXTERNAL領域はラン単位の開始時に一度だけ確保され、プログラムが複数回CALLされても初期化されません。WORKING-STORAGEの通常項目はCALLのたびにVALUE句で再初期化されますが、EXTERNAL項目はその対象外です。カウンタや累積値を使う場合は、初期化するタイミングを設計で明確にしておく必要があります。
FD EXTERNALの二重OPEN問題
FD EXTERNALを使う場合、ファイルコネクタは共有されていますが、OPENは一度だけしか行えません。メインプログラムでOPENした後にサブプログラムが再度OPENしようとすると実行時エラーになります。「誰がOPEN/CLOSEを担当するか」を設計段階で明確に決め、コメントで明記しておきましょう。
ネスト(内包)プログラムにはGLOBALを使う
CONTAIN句でネストされた内包プログラム(Contained program)の場合、EXTERNAL句は使用できません。コンパイラによってはエラーになります。内包プログラムには IS GLOBAL 句を使い、上位プログラムのデータを参照してください。EXTERNALは別コンパイル単位のプログラム間専用です。
マルチスレッド環境での競合
一部のCOBOL処理系でマルチスレッドを使用する場合、EXTERNAL領域は複数スレッドから同時アクセスされる可能性があります。排他制御(MUTEX相当)を別途実装しないとデータ破損が起きます。シングルスレッド・バッチ処理の文脈で使うのが最も安全です。
よくある質問
まとめ
EXTERNAL句の要点を整理します。
| 項目 | 内容 |
|---|---|
| 適用場所 | WORKING-STORAGE SECTION の01項目 / FILE SECTION のFDエントリ |
| 効果 | 同一ラン単位内の全プログラムが同名・同定義で宣言すれば同一領域を共有 |
| 定義ルール | データ名・レベル・PIC・USAGEが完全一致必須。COPY句での一元管理が原則 |
| 初期化 | ラン単位開始時に一度だけ確保。CALLのたびの再初期化はされない |
| FD EXTERNAL | ファイルコネクタを共有。OPENは一方のプログラムのみ、READは別プログラムという分担が可能 |
| USING比較 | USINGはCALL単位・一時的な引数渡し。EXTERNALはラン単位を通じた永続的な共有領域 |
| GLOBAL比較 | GLOBALはネスト(内包)プログラム向け。EXTERNALは別コンパイル単位向け |
| 主な用途 | 共通設定テーブル・累積カウンタ・集中エラー管理・共有ファイルコネクタ |
| 注意点 | 定義不一致は実行時の無音のデータ破損につながる。マルチスレッド環境では競合に要注意 |
EXTERNAL句は使いどころを絞れば強力なプログラム間連携手段です。ただし「見えない共有」はバグの温床にもなります。COPY句による定義の一元管理と、初期化タイミングの設計を徹底することで、保守性の高いマルチモジュールCOBOLシステムを構築できます。
引数渡しの仕組みについては引数の使い方完全ガイド(BY REFERENCE・BY CONTENT・LINKAGE SECTION)を、サブルーチン呼び出し全般についてはCALL文完全ガイドも合わせてご覧ください。
