Open PL/I の索引 I/O (仮想記憶アクセス方式 (Virtual Storage Access Method; VSAM) とも呼ばれる) では、ファイルのレコードに格納される文字列キーを使用します。各レコードに 1 つのキーが含まれ、キーはファイルに関連付けられている索引で辞書順に並べられます。レコードには、目的のレコードのキーを指定してランダムにアクセスするか、キーの順序に従って順番にアクセスするか、これらの方法を組み合わせてアクセスすることができます (次の表を参照)。
INDEXED (VSAM と同等) ファイルは、ENVIRONMENT 属性の INDEXED または VSAM オプションを含めることで宣言します。次に例を示します。
DECLARE MASTER RECORD OUTPUT FILE ENVIRONMENT(VSAM KEYLOC(1) KEYLENGTH(12) RECSIZE(130));
KEYLOC オプションは、レコードにあるキーの先頭バイトを KEYLOC(1) としてカウントして、その先頭バイトのバイト位置を指定します。KEYLENGTH オプションは、キーの文字数を指定します。RECSIZE は、レコード長を指定するか、可変長レコードのファイルの場合は最大レコード長を指定します。
実際には、ファイルの RECSIZE、KEYLOC、および KEYLENGTH を指定する必要があるのは、そのファイルの作成時だけです。既存の索引ファイルの読み取りまたは更新を行うプログラムでは、これらのオプションを含めることもできますが、その必要はありません。Open PL/I ではこれらの特性を既存のファイルから判別できます。完全な IBM モードを使用している場合は、ENVIRONMENT 属性で RECSIZE、KEYLOC、または KEYLENGTH を指定する必要はなく、出力用に VSAM ファイルを開くときにはファイル ヘッダー情報が使用されます。
ENVIRONMENT 属性ではさまざまなオプションを指定できます。これらのオプションを次の表に示します。この表には、Open PL/I では必要ない、またはサポートされていないオプションもいくつか示しています。ユーザーが他のコンパイラの使用経験から、これらのオプションも含まれていると想定する可能性があるためです。
INPUT 属性または UPDATE 属性によって開かれた索引 (VSAM) ファイル内のレコードのランダム アクセス読み取りを行うには、KEY オプションを指定した READ 文を使用します。次に例を示します。
READ FILE(PARTS) INTO(PART_REC) KEY(PART_NUM);
順次読み取りでは、キーの順序を使用して、ファイルで最後に読み取ったレコードの次にあるレコードを読み取るか、前に読み取ったレコードがない場合はファイルの最初のレコードを読み取ります。順次 READ 文の場合、KEY オプションは省略します。
UPDATE 属性によって開かれたファイルからレコードが既に読み取られていて、他の I/O 操作が間で実行されていない場合は、キーを指定せずに REWRITE を実行できます。この場合、既に読み取ったレコードは新しい値で上書きされます。次に例を示します。
READ FILE(PARTS) INTO(PART_REC) KEY(PART_NUM); PART_REC = NEW VALUE; REWRITE FILE(PARTS) FROM(PART_REC);
ただし、索引ファイルのレコードをランダムに更新するには、REWRITE 文で KEYFROM オプションを指定します。次に例を示します。
REWRITE FILE(PARTS) FROM(PART_REC) KEYFROM('12XJ04');
索引ファイルを OUTPUT 属性または UPDATE 属性によって開いた場合は、KEYFROM オプションを指定した WRITE 文を使用してファイルに新しいレコードを追加できます。KEYFROM を指定せずに WRITE 文を実行すると、ファイルに新しいレコードが順番に追加されます。
DELETE 文を使用すると、UPDATE 属性によって開かれた索引ファイルからレコードを削除できます。レコードを削除するには KEY オプションを使用する必要があります。
索引 (VSAM) ファイルで使用するキーはすべて CHARACTER 型である必要があります。KEY オプションまたは KEYFROM オプションが CHARACTER 型以外の値を参照している場合、その値は I/O 操作が開始される前に CHARACTER に変換されます。PICTURE 型のキーが CHARACTER に変換される場合、キーの内容は実際には変更されません (「データ型変換」の章を参照)。
索引 (VSAM) ファイルには、固定長レコードまたは可変長レコードを含めることができます。レコードは、ファイルの作成時に ENVIRONMENT 属性で F オプションを使用した場合は固定長で、V オプションを使用した場合は可変長です (上記の表を参照)。F も V も指定していない場合は、F と想定されます。
固定長レコード ファイルでは、すべてのレコードの長さが同じである必要があります。この長さは、ファイルの作成時に ENVIRONMENT 属性の RECSIZE オプションで指定した長さです。可変長レコード ファイルの場合は、RECSIZE でファイルにおいて許可される最大レコード長を指定します。可変長レコード ファイルでは MINRECSIZE オプションも指定する必要があります。この値は、ファイル内のすべてのレコードに最低限必要な長さを指定します。ファイルのキーは、ファイルのこの最小限の部分に含まれている必要があります。
SCALARVARYING オプションでは、データ ファイル内のすべてのレコードに 2 バイトのプレフィックスがあることを指定します。ユーザーは、KEYLOC の値を指定するときにこのことを考慮する必要があります。KEYLOC の値は、1 から始まるレコードの絶対バイト位置です。このオプションは、レコード形式が F または V の場合に使用できます。これにより、I/O 文で文字可変レコードをより一般に使用できるようになりますが、文字レコードを送信することもできます。文字可変項目を WRITE 文または REWRITE 文で使用する場合、SCALARVARYING オプションが設定されていると、レコードがデータ ファイルに書き込まれるときに 2 バイトのプレフィックスはレコードとともに保持されます。SCALARVARYING オプションを設定しない場合、プレフィックスは書き込まれません。この場合、現在の長さを超えるレコードの残りの部分は不定長になります。文字レコードが書き込まれるとき、SCALARVARYING オプションが設定されている場合はプレフィックスが追加されます。SCALARVARYING オプションを使用すると、RECORD 条件を発生させずに、最大レコード サイズよりも小さいレコードの書き込みおよび読み取りを実行できます。これは、位置指定モードの I/O を実行する際にも役立ちます。
SCALARVARYING オプションの使用時に KEYLOC を設定する際は、2 バイトのプレフィックスを「補正」することが非常に重要です。
V タイプのレコードを使用すると、一部のレコードを送信できます。Open PL/I では、このサポートのためにレコードに制御バイトを含める必要はありません。ランタイム システムによって、送信されるバイト数に関する情報が自動的に保持されます。レコードに制御情報を含める必要がないため、ユーザーがレコード タイプに基づいて KEYLOC を変更することはありません。KEYLOC の位置に影響するのは SCALARVARYING オプションだけです。
PL/I 言語には 1 つのファイルに複数のキーを指定できるメカニズムは用意されていませんが、Open PL/I では複数のキーを介してデータにアクセスできます。1 つのキー (主キーと呼ばれる) を使用して索引ファイルを作成した後、ユーティリティ Ipivsam を使用してファイルに索引 (つまり、キー) を追加できます。PL/I プログラムで、データの異なる各キー バージョンを個別のファイルとして宣言する必要があります。ただし、宣言したすべてのファイルで、実際には同じデータ セットを参照することができます。次に例を示します。
DECLARE EMPFILE1 RECORD UPDATE FILE ENV(VSAM KEYLOC(1) KEYLENGTH(6) RECSIZE(145)); DECLARE EMPFILE2 RECORD UPDATE FILE ENV(VSAM KEYLOC(31) KEYLENGTH(3) RECSIZE(145) GENKEY); DECLARE 1 EMP_ 2 EMP_ID (CHAR(6), 2 NAME (CHAR(24), 2 DEPARTMT (CHAR(3), ... OPEN FILE(CUSTFILE1) TITLE('employee'); OPEN FILE(CUSTFILE2) TITLE('employee'); /* same file, different key */
次のサンプル プログラムは、VSAM 編成のファイルの I/O 用に ENVIRONMENT 変数とそのオプションを使用する例を示しています。
/* Example of VSAM I/O */ TEST: PROCEDURE OPTIONS(MAIN); %REPLACE TRUE BY '1'B; %REPLACE FALSE BY '0'B; DECLARE DB FILE ENV(VSAM KEYLOC(21) KEYLENGTH(120) RECSIZE(244)); DECLARE DBG FILE ENV(INDEXED GENKEY KEYLOC(21) KEYLENGTH(120) RECSIZE(244)); DECLARE 1 DB_RECORD, 2 HEADER CHAR(20), 2 DBKEY CHAR(120), 2 STUFF CHAR(100), 2 NUMBER FIXED BIN(31); DECLARE I FIXED BIN(31); DECLARE CS CHAR(26) STATIC INIT('THEQUICKBROWNFXJMPSVLAZYDG'); DECLARE C(26) CHAR DEFINED(CS); DECLARE LETTERS CHAR(30); /* CREATE DB */ OPEN FILE(DB) RECORD KEYED SEQUENTIAL OUTPUT TITLE('MYFILE1'); HEADER = 'DATA RECORD HEADER'; STUFF = COPY('ABCDE',20); DO I = 1 TO 26; NUMBER = I; DBKEY = '@'||C(I) ||COPY('@',118); WRITE FILE(DB) FROM(DB_RECORD) KEYFROM(DBKEY); END; CLOSE FILE(DB); /* TRY A GENERIC READ THEN MOVE SEQUENTIALLY THRU THE FILE */ OPEN FILE(DBG) RECORD KEYED SEQUENTIAL INPUT TITLE('MYFILE1'); ON ENDFILE(DBG) GOTO EXIT_1; READ FILE(DBG) KEY('@') INTO(DB_RECORD); LETTERS = SUBSTR(DBKEY,2,1); DO WHILE(TRUE); READ FILE(DBG) INTO(DB_RECORD); LETTERS = TRIM(LETTERS) ||SUBSTR(DBKEY,2,1); END; EXIT_1: CLOSE FILE(DBG); PUT EDIT(LETTERS)(A); IF LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' THEN PUT SKIP LIST('TEST PASSES'); ELSE PUT SKIP LIST('TEST FAILS'); PUT SKIP; END TEST;