DL/I データベース・サポート

EGL で生成したコードは次のいずれかのターゲット・システム上にある、データ言語/I (DL/I) データベースにアクセスできます。 EGL ではこのアクセスを、2 つの方法で許可しています。

暗黙の DL/I コードおよび明示的 DL/I コードは、実際の DL/I コードとは若干異なる、優れた擬似 DL/I 構文を使用することに気をつけてください。 詳細については、『#dli ディレクティブ』を参照してください。

DL/I に精通していない場合は、『DL/I の基本概念』を参照してください。

EGL における DL/I I/O 文

DL/I データベースへの アクセスに利用できる EGL 文は、次の表のとおりです。 この表には、各キーワードが生成する可能性のある DL/I 呼び出しの例が含まれています。 例えば、EGL add 文をコード化する場合、DL/I ISRT 呼び出しが生成されます。キーワードを含むコードの行にカーソルを置くか、またはその行を右クリックすることにより、EGL が生成する DL/I 呼び出しの不定形式のバージョンをプレビューすることができます。 ポップアップ・メニューから、「DLI 文」 > 「表示」を選択します。

with #dli{ statement } 構文を使って DL/I 呼び出しを直接コード化することもできます。 この構文によって、ご使用のプログラムがデータベースにアクセスする 方法 (EGL が I/O 文から生成したデフォルトの DL/I 呼び出しでは 十分でない場合に必要) をさらに指定できます。

次のリストは DL/I データベースをサポートしている EGL I/O 文を 示しています。

add
DLISegment 型のレコードを DL/I データベースにおきます。または、(DLISegment レコードの動的配列を使用している場合は) 1 つの親セグメントの下に、配列の各エレメントの内容に基づいて一連のレコードを置きます。
delete
セグメントをデータベースから削除する。 まず get...forUpdateget next...forUpdate、または get next inParent...forUpdate 文 (DL/I GHU、GHN、または GHNP 文を生成する文) を使用してレコードを配置し、保持します。
get
データベースから固有のセグメントを読み取る。または、(DLISegment レコードの動的配列を使用している場合は) 配列の連続したエレメント内に連続したセグメントを読み込みます。 get を使用して配列に連続したレコードを読み込む場合、COBOL プログラムは最初の GU に続く一連の GN 呼び出しによってループします。
get (...forUpdate オプション)
データベースから固有のセグメントを読み取り、保持する。または、(DLISegment レコードの動的配列を使用している場合は) (最初の GHU の後に一連の GHN 呼び出しを発行することによって) 連続セグメントを読み取り、配列中の連続エレメントに読み込んで保持します。
get next
データベースの現在の位置に基づき、次のセグメントを読み取る。
get next (...forUpdate オプション)
データベースの現在の位置の基づき、次のセグメントを読み取り、保持する。
get next inParent
データベースの現在の位置に基づき、同じ親セグメントを持つ次のセグメントを読み取る。
get next inParent (...forUpdate オプション)
データベースの現在の位置に基づき、同じ親セグメントを持つ次のセグメントを読み取り、保持する。
replace

変更されたセグメントをデータベースに戻す。 まず get...forUpdateget next...forUpdate、または get next inParent...forUpdate 文 (DL/I GHU、GHN、または GHNP 文を生成する) を使用してレコードを配置し、保持します。

いかなる場合でも、複数のデータベース・セグメントを単一のデフォルト EGL replace 文によって更新することはできません。

EGL set 文 (特に フォーム set record position の文) は、DL/I もサポートしています。 この文は入出力を行いませんが、データベース内に指定したセグメントを 効果的に配置します。 文の操作について詳しくは、『set』を参照してください。

DL/I サポート用レコード・パーツ

次の 種類の Record パーツを作成できます。
DLISegment
DLISegment レコード・パーツは DL/I データベース中のセグメントに対応します。 そのパーツに基づいて変数を宣言し、次にその変数を使用してセグメントに アクセスします。
PSBRecord
PSBRecord パーツには、ランタイム・プログラム指定ブロック (PSB) に関する情報が含まれており、ランタイム・プログラム制御ブロック (PCB) に関する詳細をそれぞれ含んだ一連のレコードが入っています。

PSBRecord パーツに 基づいて変数を宣言し、次にその変数名をプログラムの psb プロパティーに 割り当てます。EGL はそのレコードを使用して、DL/I 呼び出しの作成と検証を行うコードを生成します。

DL/I を操作する場合は、次の、各々がランタイム PCB のレイアウトに一致する、定義済みレコード・パーツに基づくレコードも作成します。
IO_PCBRecord
この型のレコードでは、プログラムが端末を介してユーザーと通信できます。
ALT_PCBRecord
この型のレコードでは、プログラムが出力メッセージの宛先を変更することができます。
DB_PCBRecord
この型のレコードは、DL/I データベースへのアクセスを許可します。
GSAM_PCBRecord
この型のレコードは、z/OS バッチ または BMP 用の生成されたプログラム中のファイルに、汎用順次アクセス方式 (GSAM) を 介してアクセスするために使用されます。 このファイルは root-only DL/I データベースとして振る舞い、入出力は シリアル・レコードによって行われます。 コミットおよびロールバックはファイルに影響を与えます。

各 PCB レコード内で、ユーザーは複合プロパティー @PCB を使用して PCB のタイプと名前を定義し、場合によってはその PCB に可視のセグメント階層を定義します。 レコード・タイプの詳細については、『PCB レコード・パーツのプロパティー』および 『レコード・タイプとプロパティー』を参照してください。

最後に、定義済みレコード・パーツ PSBDataRecord に基づき、固定レコードを 宣言できます。そのレコードを使ってシステム変数 DLILib.psbData と対話することができます。このシステム変数にはランタイム PSB 名および PSB がアクセスされるアドレスの両方が含まれています。 このレコードは、PSB (実際は名前とアドレス) を別のプログラムに渡す必要がある場合、または別のプログラムから PSB を受け取る必要がある場合に役立ちます。

DLISegment パーツ

DL/I データベース中でアクセスしたい各セグメント・タイプは、使用しているプログラム中の DLISegment 型の相当するレコードを備えていなければなりません。

DL/I データベース例』の、顧客データベースおよびコードの例について考えてみましょう。それぞれの顧客ごとに、預金状況、履歴、および個々のロケーションのセグメントがあります。 各ロケーションにオーダー・セグメントがあり、各オーダーに行項目セグメントがあります。 この場合、ユーザーは DLISegment 型のレコードを、顧客、預金、履歴、ロケーション、オーダー、および明細について作成します。

マイグレーション問題や EGL のネーミング規則をはっきりさせるために、セグメント名またはフィールド名に DL/I ではなく、EGL で別名を使用したい場合があります。次の 1 つ以上のプロパティーを set-value ブロックに定義することができます。
  • segmentName char(8) 使用している DLISegment レコード名に DL/I セグメント名を使用しなかった場合は、ここでデータベースからセグメント名を提供します。 例えば、ユーザーが学生の記録を入れてある DL/I データベースを持ち、セグメント・タイプの 1 つに TRANSFER という名前が付けられていた場合、その名前を EGL の DLISegment レコードに使用することはできません。EGL は「transfer」を予約キーワードとして使用しているからです。 代わりに、DLISegment レコードに「xferStudents」と名前をつけ、segmentName="TRANSFER" と設定します。EGL は、COBOL ソース・コードの作成時にすべての名前を大文字に変換するので、EGL ソース中の custName は COBOL の CUSTNAME に相当します。
  • hostVarQualifier String EGL により、ユーザーは #dli ディレクティブを構成する際にホスト変数 (DL/I ではなく、EGL ホスト・プログラム内で定義された変数) を使用できます。 これらのディレクティブは、addget のような I/O キーワードから EGL が生成する、デフォルトの DL/I 呼び出しを上書きします。

    #dli ディレクティブがない場合は、EGL はデフォルト・セグメントの検索引数 (SSA) を作成して特定の DL/I セグメントを配置します。次の例に示すように、DLISegment レコード・パーツの hostVarQualifier プロパティーは、デフォルトの SSA で使用されるキー値を含むレコードを識別します。

    顧客セグメント STSCCST がロケーション・セグメント STSCLOC の親であり、ロケーション・セグメントのデータのみを検索したい場合を考えます。 3 つのレコード・パーツを定義してこの状況を設定する場合、(差し当たり) hostVarQualifier プロパティーは省略します。
    Record CustomerRecordPart type DLISegment
    { segmentName="STSCCST", keyItem="customerNo" }
    	10 customerNo char(6)      { dliFieldName = "STQCCNO" };  //key field
    	...
    end
    
    Record LocationRecordPart type DLISegment
    { segmentName="STSCLOC", keyItem="locationNo" }
    	10 locationNo char(6)      { dliFieldName = "STQCLNO" };  //key field
    	...
    end
    
    Record CustomerPSBRecordPart type PSBRecord { defaultPSBName="STBICLG" }
    	// データベース PCB
    	customerPCB DB_PCBRecord { @PCB {
    		pcbType = DB,
    		pcbName = "STDCDBL",
    		hierarchy = [
    			@Relationship { segmentRecord = "CustomerRecordPart" },
    			@Relationship { 
    				segmentRecord = "LocationRecordPart", parentRecord="CustomerRecordPart" },
    			...]}};
    end
    次に、このプログラムを PSBRecord パーツに基づくレコードと関連付け、レコード・パーツに基づいて変数を定義します。
    Program myProgram {
    	@DLI{ psb = "myCustomerPSB" }}
    
    	//変数を定義する
     myCustomerPSB CustomerPSBRecordPart;
     myCustomer CustomerRecordPart;
     myLocation LocationRecordPart;
    最後に関数で、まず顧客データを検索することなく、データベースの最初のロケーション・セグメントを検索するようにします。
    	get myLocation;
    この get 文から、EGL は次の擬似 DL/I コードを生成します。
    GU STSCCST (STQCCNO = :CustomerRecordPart.customerNo) 
       STSCLOC (STQCLNO = :myLocation.locationNo)

    EGL は変数 myLocation をセグメント STSCLOC と正しく関連付けましたが、myCustomer 変数を見つけることができなかったことに気をつけてください。EGL は、myLocation が CustomerRecordPart を 親セグメントに持つ LocationRecordPart タイプであり、CustomerRecordPart の keyItem は customerNo であるということのみを 知っていました。

    この問題は、変数が基づいているレコード・パーツと同じ名前を変数に与えることにより、解消することができました。 ただし、こうすることによって混乱が起きやすくなります。望ましい解決方法は、パーツと変数に別々の名前を使用することです。 #dli ディレクティブをコード化して、上記の DL/I コードを コピーし、":CustomreRecordPart" を ":myCustomer" に置き換えることもできます。 3 番目の方法は単純で、CustomreRecordPart の宣言に hostVarQualifier を、 次のように追加します。
    Record CustomerRecordPart type DLISegment
    { segmentName="STSCCST", hostVarQualifier="myCustomer", keyItem="customerNo" }
    これで、同じ get 文が正しい擬似 DL/I コードを作成するようになります。
    GU STSCCST (STQCCNO = :myCustomer.customerNo) 
       STSCLOC (STQCLNO = :myLocation.locationNo)

    プロパティー hostVarQualifier を使用して、データベースのセグメントに基づかないレコードのフィールドを参照することもできます。 例えば、EGL で基本レコード (トランザクション・レコードなど) 中の顧客セグメントのキー値を見つけたい場合は、そのレコード名を hostVarQualifier プロパティーに割り当てます。

  • lengthItem FieldReference DLISegment レコード・パーツが可変長レコードを定義する場合は、レコード長を指定するレコード内のフィールドに名前をつけます。
  • keyItem FieldReference データベースがこのセグメントのキーを指定する場合は、キー値を含むフィールドを識別します。 前述したように、フィールドは選択する任意のレコード中に置くことができますが、通常は定義されている DLISegment レコード・パーツに基づくレコード中にあります。EGL は keyItem プロパティーを使用してデフォルトの SSA を作成します。

相当するデータベース・セグメント・フィールドの名前と一致しない DLISegment レコード・フィールドを操作している場合は、レコード・フィールド・プロパティー dliFieldName をセグメント・フィールドの名前に設定します。

PSBRecord パーツ

PSBRecord パーツは、ご使用のプログラムの 1 つ以上のデータベースへのアクセスに関する情報を含んでおり、ランタイム PSB へのアクセスを提供するために使用されます。 そのパーツ・タイプの各レコードには次のフィールドが含まれます。
  • defaultPSBName char(8)。ランタイム PSB を名前で識別します。EGL は defaultPSBName の値を、システム変数 DLILib.psbData のフィールド psbName に割り当てます。 CICS ではこの割り当てによって、プログラムが 指定されたランタイム PSB を使用できるようになります。defaultPSBName のデフォルト値は PSBRecord パーツの名前です。

PSBDataRecord パーツ

この定義済みレコード・パーツは、システム変数 DLILib.psbData の 型定義です。PSBDataRecord パーツに基づくレコードには次のフィールドが含まれます。
psbName char(8)
CICS は この名前を使用して次の PSB の予定を決めます。IMS はこの名前を使用しません。
psbRef int
フィールド psbRef はランタイム PCB リストへのアクセスを提供します。このフィールドは直接変更しないでください。

CICS では psbName で識別された PSB の スケジュールを立てることができます。スケジューリングは、 コミットによって psbRef が消去された後で発生します。 この機能を使用するには、psbRef を 0 に設定します。

レコード・パーツの宣言

次の例では、DL/I データベース中のセグメントを参照する DLISegment レコードを宣言する方法を示しています。
Record CustomerRecordPart type DLISegment
{ segmentName="STSCCST", keyItem="customerNo" }
	10 customerNo char(6)      { dliFieldName = "STQCCNO" };  //key field
	10 customerName char(25)   { dliFieldName = "STUCCNM" };
	10 customerAddr1 char(25)  { dliFieldName = "STQCCA1" };
	10 customerAddr2 char(25)  { dliFieldName = "STQCCA2" };
	10 customerAddr3 char(25)  { dliFieldName = "STQCCA3" };
end

このデータベース例の完全なレコード・レイアウトについては、『DL/I データベース例』を参照してください。

このようなレコード宣言ではデータベース・セグメントの構造を、このプログラムに見えるように記述します。 実行時に、ランタイム PCB は個々のプログラムに見えるものを決めます。

レコード内の構造は、 DL/I がそれをプログラムに表示するときに、セグメントの構造に一致する必要があります。DL/I セグメント中にあるのと同じレコード長と位置を持つ keyItem および lengthItem フィールドを定義します。 セグメントが論理子である場合は、交差データと目標親の連結キーが構造に含まれている必要があります。 セグメントが論理データベースの連結セグメントである場合は、構造に連結キー、交差データ、および目的親セグメントが含まれている必要があります。

データベース I/O

DL/I データベースは階層型であるため、プログラムはデータベース中の現在のロケーションを把握しておく必要があります。 特定の子セグメントを配置する場合は、その子 (ある場合) の親セグメント、その親 (ある場合) の親セグメント、というように、データベースのルートまで遡って指定する必要があります。

例えば、項目レコードを操作するために顧客データベースを使用する場合、顧客、ロケーション、およびその項目の注文番号を設定する必要があります。 幸い、これは EGL ではたいへん簡単です。これらのすべてのレコードにキー・フィールドを正しく定義したと想定すると、アップデートしたい項目レコードを次のように簡単に得ることができます。
	//レコードのインスタンスを作成する
	myCustomer CustomerRecordPart;
	myLocation LocationRecordPart;
	myOrder    OrderRecordPart;
	myItem     ItemRecordPart;

	//セグメント検索引数を作成する
	myCustomer.customerNo = "5001";
	myLocation.locationNo = "22";
	myOrder.orderDateNo = "20050730A003";
	myItem.itemInventoryNo = "CHAIR";   //1st part compound key
	myItem.itemLineNo = 27;
	
	//項目を入手し、保持する
	try
		get myItem forUpdate;
		onException
			myErrorHandler(2);
	end

実行時に、DL/I は顧客用キー・フィールド (6 バイト)、ロケーション用 (6 バイト)、注文用 (12 バイト)、項目用 (6 + 2 バイト) を含む、30 バイトの連結セグメントの検索引数により、GU (get unique) 呼び出しを行います。

DL/I 文のカスタマイズ

DL/I レコードを 入出力オブジェクトとして使用する EGL 文が指定された場合、次のいずれかの方法を使用することができます。
  • 暗黙の DL/I 文を受け入れることができます。この場合、DL/I レコード・パーツに対して行う変更は、ユーザーのコードから EGL が生成する DL/I 文に影響を与えます。例えば、別のレコード項目を DL/I セグメントのキーとして使用したいと後で指示する場合は、EGL は生成時に自動的にその変更をピックアップします。
  • 文は、EGL I/O 文を with #dli{ statement } 構文で拡張することにより、明示的にすることができます。この場合、その DL/I 文の詳細は DL/I レコード・パーツと切り離され、DL/I レコード・パーツに行われた以降の変更は、実行時に使用される DL/I 文に何の影響も与えません。明示的 DL/I 文をソースから除去すると、暗黙の DL/I 文 (ある場合) は生成時に再度使用可能になります。 詳細については、『#dli ディレクティブ』を参照してください。
  • PCB の名前は usingPCB キーワードを含め、代替 PCB 名を EGL I/O 文に指定することによって変更できます。例えば、2 つの PCB がある場合、2 つの異なるポインターを同じデータベースに同時に保持し、あるセグメントを 2 回読み取ることができます。
  • 文を完全に置き換え、ライブラリー関数 DLILib.AIBTDLI(), DLILib.EGLTDLI()、または VGLib.VGTDLI() を使用して明示的 DL/I 呼び出しをコーディングすることができます。
フィードバック
(C) Copyright IBM Corporation 2000, 2005. All Rights Reserved.