DL/I の例
親セグメント内での検索
デフォルトの get next ステートメントは、データベースの現在位置で開始し、すべての親の下にあるターゲット・セグメントの次のオカレンスについてデータベース全体を検索します。 検索の範囲を、現時点で確立されている従属チェーンに限定するには 、get next inParent ステートメントを使用します。
get myOrder with #dli {
GU STSCCST (STQCCNO = :myCustomer.customerNo)
STSCLOC (STQCLNO = :myLocation.locationNo)
STSOCORD (STQCODN = :myOrder.orderDateno) };
get next inParent myItem;
while (myItem not noRecordFound)
// process the current item
get next inParent myItem;
end
GNP STLCITM
別の非キー・フィールドによる検索
- クレジット・セグメント (STSCSTA) の creditBalance フィールド (STFCSBL) で検索が必要です。 これを実行するには、検索する指定金額を含む、型 decimal(12,2) の変数 (targetBalance など) を定義します。 targetBalance の定義は、クレジット・セグメントの creditBalance フィールドの定義と 一致させる必要があります。
- myCrStatus レコード用に get next ステートメントを書き込みます。
- #dli ディレクティブをその行に追加し、デフォルト・コードを変更します。creditBalance フィールドの金額が targetBalance よりも大きいセグメントを探す、 修飾 SSA を追加します。
- パス・コマンド・コード (*D) を組み込んで、クレジット・セグメントに対応するカスタマー・セグメント (STSCCST) を取り出します。
targetBalance decimal(12,2);
targetBalance = 10,000.00;
get next myCustomer,myCrStatus with #dli{
GU STSCCST*D STSCSTA (STFCSBL >= :targetBalance) };
別のレコードの情報に基づいた検索
Record CustomerData type basicRecord
10 customerNo char(6)
...
end
Program myProgram
(customerParm CustomerData)
{ @DLI{ psb = "myCustomerPSB" }}
//declare variables
myCustomerPSB CustomerPSBRecordPart;
myCustomer CustomerRecordPart;
- 以下のように、customerParm.customerNo の値
を myCustomer.customerNo に割り当ててから、暗黙的に DL/I I/O を使用します。
myCustomer.customerNo = CustomerParm.customerNo; get myCustomer;この場合、EGL は、通常のデフォルト SSA を作成し、その結果として次の疑似 DL/I コードが作成されます。
この方法の長所は、大変シンプルである点です。 欠点は、カスタマー番号をセグメント・レコードに移動するというパフォーマンス上の オーバーヘッドがわずかに発生する点です。GU STSCCST (STQCCNO = :myCustomer.customerNo) - 以下のように、#dli ディレクティブおよび明示的 DL/I I/O を使用すると、customerParm.customerNo フィールドをホスト変数として使用できます。
この方法では、 カスタマー番号を移動するというパフォーマンス上のオーバーヘッドが発生しません。 ただし、デフォルトの #dli ディレクティブに貼り付けてから、パラメーター・レコードに合わせて 正しいレコード変数名を使用するようにコードを変更するのに、やや時間がかかります。get myCustomer with #dli { GU STSCCST (STQCCNO = :customerParm.customerNo) } ; - 以下のように、DLISegment レコード
に hostVarQualifier プロパティーを追加して、ホスト変数の修飾子を指定します。
Record CustomerRecordPart type DLISegment {segmentName="STSCCST", keyItem="customerNo", hostVarQualifier="customerParm" } 10 customerNo char(6) { dliFieldName = "STQCCNO" }; //key field ... endこの後は、以下のように 暗黙的に DL/I I/O を使用することができ、 最初に customerParm.customerNo を myCustomer.customerNo に割り当てる必要はありません。get myCustomer;この場合、EGL が作成する疑似 DL/I コードは以下のとおりです。GU STSCCST (STQCCNO = :customerParm.customerNo)この方法の長所は、#dli ディレクティブ用にコード化したものと同じ疑似 DL/I コードが得られ、実際に #dli ディレクティブをコード化する必要がない点です。欠点は、EGL が、CustomerRecordPart を使用する 暗黙的 DL/I データベース I/O ステートメントごとに、customerParm を修飾子として使用するようになる点です。
非ルート・セグメントの検索
暗黙的 DL/I データベース I/O を使用して、非ルート・セグメントを検索できます。 EGL は、PCB でのターゲット・セグメントの階層ポジションに基づいて、SSA のチェーン全体を作成します。 ただし、階層のより高いレベルにあるセグメントについては、EGL は、プログラム変数の名前を自動的に決定してセグメントの修飾子として使用することはできません。
myCustomer CustomerRecordPart;
myLocation LocationRecordPart;
get myLocation;
EGL は、以下の疑似 DL/I コードを作成します。GU STSCCST (STQCCNO = :CustomerRecordPart.customerNo)
STSCLOC (STQCLNO = :myLocation.locationNo)
EGL は変数 myLocation をセグメント STSCLOC に正しく関連付けているものの、一方で EGL は、CustomerRecordPart に基づいている変数 myCustomer を検出できなかった点に注意してください。 EGL が認識しているのは、myLocation のタイプが LocationRecordPart であり、その親セグメントは CustomerRecordPart であること、 また CustomerRecordPart の keyItem は customerNo であることのみです。
- レコード変数に、そのレコード変数が基づいているレコード・パーツと同じ名前を付けることができます。
例えば、myCustomer の変数宣言を CustomerRecordPart に変更します。
次のように、EGL は同じ 疑似 DL/I コードを作成します。CustomerRecordPart CustomerRecordPart;GU STSCCST (STQCCNO = :CustomerRecordPart.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo)EGL は、PCB 階層情報からデフォルトの SSA を作成するので、この方法で簡単に、EGL が使用する変数名をご使用のプログラムのレコード変数宣言と必ず 一致させることができます。 欠点として、この手法は、パーツおよび変数に別の名前を使用するという、一般的な慣例に従わない点があります。
- 次のように、#dli ディレクティブおよび明示的 DL/I データベース I/O を使用します。
get myLocation with #dli { GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo)この手法の長所は、使用されているホスト変数が大変わかりやすい点です。 ホスト変数修飾子またはフィールド名が、DL/I セグメント・レコードに基づくレコード変数と異なる場合には、簡単に使用できる手法です。 欠点は、すべての明示的 I/O の場合と同様です。つまり、階層またはキー・フィールドが変更されても、明示的 DL/I データベース I/O ステートメントは、自動的に変更されません。
- 次のように、CustomerRecordPart の定義を変更して
、hostVarQualifier プロパティーを組み込みます。
ここで、以下の get ステートメントを使用する場合:Record CustomerRecordPart type DLISegment { segmentName="STSCCST", keyItem="customerNo", hostVarQualifier = "myCustomer" } 10 customerNo char(6) { dliFieldName = "STQCCNO" }; //key field ... end
EGL は、以下の正しい 疑似 DL/I コードを生成します。get myLocation;GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo)この手法の長所は、暗黙的 DL/I データベース I/O を使用できることと、レコード変数および DL/I セグメント・レコードに別の名前を指定することができる点です。 欠点は、EGL が、CustomerRecordPart を使用する暗黙的 DL/I データベース I/O ステートメントごとに、myCustomer を修飾子として使用するようになる点です。
2 次索引による検索
// database PCB for customer by Name
customerNamePCB DB_PCBRecord
{ @PCB { pcbType = DB, pcbName = "STDCNAM",
secondaryIndex = "STUCCNM",
hierarchy = [ @relationship { segmentRecord = "CustomerRecordPart" },
... ] }
}
pcbName プロパティーは、ランタイム PSB の実際 の DL/I データベース PCB と一致させる必要があります。 secondaryIndex プロパティーには、データベース管理者 が、ランタイム PCB の XDFLD ステートメントで指定するフィールド名と同じものを指定する必要があります。ここで、階層に CustomerRecordPart を含む PSB レコードには 、2 つの PCB レコードが存在します。
myCustomer CustomerRecordPart;
get myCustomer;
EGL は、CustomerRecord パーツを含む PSB レコードの最初の PCB レコードに基づいて、疑似 DL/I コードを作成します。get myCustomer usingPCB customerNamePCB;
EGL は、以下の疑似 DL/I コードを作成します。GU STSCCST (STUCCNM = :myCustomer.customerName)
- セグメントの DL/I 名 (プロパティー segmentName = "STSCCST")
- 2 次索引フィールドの DL/I 名 (プロパティー secondaryIndex = "STUCCNM")
- 比較値の EGL EGL フィールド名 (プロパティー dliFieldName = "STUCCNM" と対応するフィールド名 customerName)
// orders view of customer database
ordersByReferencePCB DB_PCBRecord
{ @PCB { pcbType = DB, pcbName = "STDCDBL",
secondaryIndex = "STFCORF", //use DL/I name
hierarchy = [
@relationship { segmentRecord = "OrderRecordPart" },
@relationship { segmentRecord = "LocationRecordPart",
parentRecord = "OrderRecordPart" },
@relationship { segmentRecord = "CustomerRecordPart",
parentRecord = "LocationRecordPart" },
@relationship { segmentRecord = "ItemRecordPart",
parentRecord = "OrderRecordPart" }
]}
};
end
get myOrder, myCustomer with #dli{
GU STPCORD*D (STQCODN = :myOrder.orderReference)
STSCLOC
STSCCST };
パス呼び出しを使用した複数セグメントへのアクセス
get myCustomer, myLocation, myOrder;
このステートメントは、以下の DL/I 疑似コードを生成します。GU STSCCST*D (STQCCNO = :myCustomer.customerNo)
STSCLOC*D (STQCLNO = :myLocation.locationNo)
STPCORD (STQCDDN = :myOrder.orderDateNo)
get myCustomer, myLocation, myOrder forUpdate;
replace myOrder with #dli{
REPL STSCCST*N
STSCLOC*N
STPCORD };
D コマンド・コードを指定した get forUpdate ステートメントに従う delete 関数に対するデフォルトの DL/I 呼び出し EGL ビルドは、検索される各セグメントを削除しません。
delete ステートメントで指定されたターゲット・セグメントのみを削除します。単一 I/O ステートメントによる全セグメントの読み取り
- データベースで最大のセグメントを表すレコードに、get next ステートメントを書き込む。 これにより、読み取るセグメントはいずれも、割り振られたメモリーを超過することはありません。
- デフォルトの DL/I 呼び出しをコードに追加する。#dli ディレクティブを編集して、1 つ の SSA を削除します。
- データベースのその他のセグメントに一致するレコードを作成する。プログラムでそのレコードを宣言し、それぞれのレコードが、上記のステップ 1 で使用したレコードを再定義し、すべてのレコードがメモリーの同じ領域を占めるように指定します。
- get next ステートメントの後ろの dliVar.segmentName を確認し、検索されたセグメントのタイプを判別する。
- 対応するレコード構造から検索されたセグメントにアクセスする。
myHistory HistoryRecordPart
redefCustomer CustomerRecordPart {redefines=myHistory};
redefLocation LocationRecordPart {redefines=myHistory};
...
//read next segment, whatever type it is, into history record
while (myHistory not EOF)
get next myHistory with #dli{
GN };
//so what type was it?
case (dliVar.segmentName)
when "STSCCST" // it was a customer
printCustomer();
when "STSCLOC" // it was a location
printLocation();
...
end
end
動的配列の使用
get ステートメント および get next ステートメントを使用して 、動的配列に対して DL/I セグメントを検索できます。配列 そのもの (配列のメンバーについてのみ) にキー・フィールドはないので、いくつかの特殊な手法 を使用して、EGL が正しいコードを作成できるようにする必要があります。
myCustomer CustomerRecordPart;
myLocation LocationRecordPart;
myOrder OrderRecordPart;
myOrderArray OrderRecordPart [] {maxsize = 20}; // オーダーの配列
myCustomer.customerNo = "123456";
myLocation.locationNo = "ABCDEF";
myOrderDateNo = "20050730A003";
get myOrderArray; // 最初に配列を埋める
... do some processing
get next myOrderArray; // 20 オーダーの次のバッチを取得する
get myOrderArray with #dli{
GU STSCCST (STQCCNO = :CustomerRecordPart.customerNo)
STSCLOC (STQCLNO = :LocationRecordPart.locationNo)
STPCORD (STQCODN = :OrderRecordPart.orderDateNo)
GN STPCORD };
get next myOrderArray with #dli{
GN STPCORD };
20 オーダーの最初のバッチに対する動的配列を get ステートメントによって埋めるには、初回の GU 呼び出しを行った後で、配列がフルになるか、 または DL/I がセグメント・オカレンスをすべて検索するまで、GN 呼び出しをループさせる必要があります。 EGL が作成する疑似 DL/I コードで、GU 呼び出しは、最初のオーダー・セグメントを検索します。 EGL は、GN 呼び出しをループとして扱い、配列がフルになるか、DL/I がセグメント・オカレンスをすべて検索するまで、ループするロジックを提供します。 同様に、EGL は get next ステートメントをループとして扱い、 ループ制御ロジックをユーザーに提供します。
- DL/I セグメント・レコードに、DL/I データベースのセグメントと同じ名前を付けます。また、レコード変数名を、DL/I データベースのセグメントと同じ名前に変更します。例えば、以下のカスタマー・レコード・パーツの定義を変更します。
この関数を、次のように変更します。Record CustomerRecordPart type DLISegment { segmentName="STSCCST", keyItem="customerNo" } 10 customerNo char(6) { dliFieldName = "STQCCNO" }; //key field ... endRecord STSCCST type DLISegment { segmentName="STSCCST", keyItem="customerNo" } 10 customerNo char(6) { dliFieldName = "STQCCNO" }; //key field ... endロケーション・セグメント (STSCLOC) およびオーダー・セグメント (STPCORD) に対して、同様の変更を行います。 その後、次のように PSB レコードを変更して、新規名を使用するようにします。Record CustomerPSBRecordPart type PSBRecord { defaultPSBName="STBICLG" } // database PCB customerPCB DB_PCBRecord { @PCB { pcbType = DB, pcbName = "STDCDBL", hierarchy = [ @relationship { segmentRecord = "STSCCST" }, @relationship {segmentRecord="STSCLOC", parentRecord="STSCCST"}, @relationship {segmentRecord="STPCORD", parentRecord="STSCLOC"} ]}}; end次のように、レコード変数および myOrderArray の宣言を変更して、 新規の DL/I セグメント・レコード・パーツを参照するようにします。STSCCST STSCCST; STSCLOC STSCLOC; STPCORD STPCORD; myOrderArray STPCORD [] {maxsize = 20}; // array of ordersここで、以下の get ステートメントを実行する場合:
EGL は、get ステートメントに対して以下の疑似 DL/I コードを作成し、ホスト変数修飾子は、正しいレコード変数名を使用します。get myOrderArray; // 最初に配列を埋めるget myOrderArray with #dli{ GU STSCCST (STQCCNO = :STSCCST.customerNo) STSCLOC (STQCLNO = :STSCLOC.locationNo) STPCORD (STQCODN = :STPCORD.orderDateNo) GN STPCORD };EGL は、PCB 階層情報からデフォルトの SSA を作成するので、この方法で簡単に、EGL が使用する変数名をご使用のプログラムのレコード変数宣言と必ず 一致させることができます。 欠点として、この手法は、パーツおよび変数に別の名前を使用するという、一般的な慣例に従わない点があります。
- 次のように、#dli ディレクティブおよび明示的 DL/I データベース I/O を使用します。
get myOrderArray with #dli{ GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo) STPCORD (STQCODN = :myOrder.orderDateNo) GN STPCORD };この手法の長所は、使用されているホスト変数が大変わかりやすい点です。 この手法は、デフォルトの DL/I コードを変更する必要がある場合に特に有効です。例えば、顧客の最初のオーダー番号が不明で、以下の DL/I コードを使用したい場合などです。myOrder.orderDateNo = ""; get myOrderArray with #dli{ GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo) STPCORD (STQCODN >= :myOrder.orderDateNo) // using >= instead of = GN STPCORD };この手法の欠点は、すべての明示的 I/O の場合と同様です。つまり、階層またはキー・フィールドが変更されても、 明示的 DL/I データベース I/O ステートメントは、自動的に変更されません。
- それぞれの DL/I セグメント・レコードの定義を変更して 、プログラム・レコード変数の名前で hostVarQualifier プロパティーを組み込みます。 例えば、CustomerRecordPart を以下のように変更します。
Record CustomerRecordPart type DLISegment { segmentName="STSCCST", keyItem="customerNo", hostVarQualifier = "myCustomer" } 10 customerNo char(6) { dliFieldName = "STQCCNO" }; //key field ... endここで、以下のレコード宣言および get ステートメントを使用する場合:myCustomer CustomerRecodPart; myLocation LocationRecordPart; myOrder OrderRecordPart; myOrderArray OrderRecordPart [] {maxsize = 20}; // オーダーの配列 get myOrderArray; // 最初に配列を埋めるEGL は、以下の正しい 疑似 DL/I コードを生成します。get myOrderArray with #dli{ GU STSCCST (STQCCNO = :myCustomer.customerNo) STSCLOC (STQCLNO = :myLocation.locationNo) STPCORD (STQCODN = :myOrder.orderDateNo) GN STPCORD };この手法の長所は、暗黙的 DL/I データベース I/O を使用できることと、レコード変数および DL/I セグメント・レコードに別の名前を指定することができる点です。 欠点は、CustomerRecordPart、LocationRecordPart、および OrderRecordPart を使用するそれぞれの暗黙的 DL/I データベース I/O ステートメントごとに、修飾子として myCustomer を使用するようになる点です。