ProSortの実行手順

本章では、ProSortの実行手順について説明します。

1. SORT演算、COPY演算

ProSortでSORTおよびCOPY演算を実行する手順は以下のとおりです。

figure prosort sort flow
SORTおよびCOPY演算の実行手順

以下は、SORTおよびCOPY演算の実行手順についての説明です。

  1. SKIPREC

    SORT演算を実行する前にスキップするレコード数を指定するオプションです。指定した値以後のレコードから入力できます。

    以下は、6番目のレコードからの入力を取り込んで次のプロセスを実行する例です。

    SKIPREC = 5
  2. INCLUDE、OMIT

    特定条件のレコードのみを含むか、特定条件のレコードを除外します。

    オプション 説明

    INCLUDE

    特定条件のレコードのみ含め、それ以外のレコードは除外します。

    OMIT

    特定条件のレコードは除外し、残りのレコードのみ含めます。

    特定条件は、関係式を論理演算子で組み合わせて論理式で構成します。関係式は比較、文字列比較、ビット演算、日付比較に区分できます。

    関係式 説明

    比較

    フィールドとフィールド間、またはフィールドと定数間を比較します。

    文字列比較

    文字列を比較します。

    ビット演算

    1つまたは2つの2進数をビット単位で演算します。

    日付比較

    日付を比較します。

    以下の関係式は、レコードp1の位置でm1の長さを持ち、f1の形式を持つフィールドと、p2の位置でm2の長さを持ち、f2の形式を持つフィールドを比較する条件を示します。

    p1, m1, f1, {EQ|NE|GT|GE|LT|LE}, p2, m2, f2

    適用可能な演算子には、EQ、NE、GT、GE、LT、LEがあります。

    演算子 説明

    EQ

    フィールドが一致するか検査します。

    NE

    フィールドが一致しないか検査します。

    GT

    左側が右側より大きいか検査します。

    GE

    左側が右側より大きいか等しいかを検査します。

    LT

    左側が右側より小さいか検査します。

    LE

    左側が右側より小さいか等しいかを検査します。

    以下は、5~12バイトの浮動小数点の数字が13~20バイトの浮動小数点の数字より大きいか、105~108バイトの浮動小数点の数字が定数の1000より小さいか等しい条件を持つレコードを含む例です。

    INCLUDE COND=(5,8,GT,13,8,|,105,4,LE,1000),FORMAT=CSF
  3. STOPAFT

    1、2項の手順を実行した後、レコードの数が指定した数を超えないまでレコードを入力することができます。

    以下は、1000個のレコードまでを次のプロセスに転送する例です。

    STOPAFT = 1000
  4. INREC

    入力されたレコードを付与された形式に変換します。入力されたレコードはINRECで指定したフィールドに変換され、新しいレコードに変換されます。この際、フィールドは定数または(p,m)の形式で入力されたレコードの一部、(p,m,f,to)で入力されたレコードの形式を変換したフィールドなどで構成します。

    INRECを実行した後の処理はINRECで変換されたレコードを基準に行われます。

    以下は、入力レコードの10~12バイト、20~27バイト、33~43バイト、5バイトを新規レコードとして生成する例です。

    INREC FIELDS=(10,3,20,8,33,11,5,1)

    以下は、入力レコードの20~23バイト、12~14バイトを新規レコードに変換する例です。

    INREC FIELDS=(20,4,12,3)
    SORT FIELDS=(1,4,D,5,3,D),FORMAT=CH
  5. SORT(SUM)、COPY

    入力されたレコードを付与されたキー情報でソートします。ソートに使われるキーはフィールドで定義され、各フィールドはp、m、f、sの形で定義されます。

    フィールド・タイプ 説明

    p

    レコードの位置であり、バイトとビット単位で定義します。

    • pが4の場合:4バイトからフィールドが始まります。

    • pが4.2の場合:4バイトの2番目のビットから始まります。

    m

    フィールド長であり、バイトとビット単位で定義します。

    f

    形式を定義します。

    s

    昇順ソートまたは降順ソートを定義します。

    INRECでレコードが変換された場合には変換されたレコードを基準にして位置が決まります。EQUALSオプションを宣言すると、同一キーのレコードが本来の順序どおり表示されることを保証するstable sortで動作します。

    SUMオプションが使用された場合は、同一キーを持つレコードに指定されたフィールド値の合計を求めます。指定されたフィールドがない場合には、重複するキーを除去する機能のみを実行します。SKIPREC、STOPAFTオプションがある場合は、以前のプロセスで実行します。

    以下は、2~6バイトの浮動小数点の数字のキーを昇順でソートする例です。

    SORT FIELDS=(2,5,FS,A)

    以下は、7025~2028バイトのZD(zoned decimal fields、ゾーン10進数フィールド)を昇順で、5048~5055バイトのZDを昇順でソートする例です。

    SORT FILEDS=(7025,4,ZD,A,5048,8,ZD,A),EQUALS

    以下は、ソートせずにコピーする例です。

    SORT FILEDS=(COPY)

    以下は、ソートが実行された結果において、同一キーを持つレコードに対して、21~28バイトのPD(packed decimal fields)と11~14バイトのFIフィールドの合計値を求める例です。

    SUM FIELDS=(21,8,PD,11,4,FI)
  6. OUTREC

    ソートされたレコードを付与された形式に変換します。INRECと同様に使用します。ただし、INRECによりレコードが既に変換された場合には、変換されたレコードを基準にして位置が決まります。

    詳細については、SORT演算、COPY演算4項 INRECを参照してください。

  7. OUTFIL

    OUTFILの詳細については、OUTFIL演算を参照してください。

2. MERGE演算

MERGEは、ソートされた複数の入力ファイルをマージし、新しくソートされたレコードを出力します。MERGEはSKIPREC、STOPAFTオプションを除いてはSORTと同じ手順で演算を実行します。

ProSortでMERGE演算を実行する手順は以下のとおりです。

figure prosort merge flow
MERGE演算の実行手順

以下は、MERGE演算の実行手順についての説明です。

  1. INCLUDE、OMIT

  2. INREC

    SORT演算、COPY演算4項 INRECを参照します。

  3. MERGE(SUM)

    付与されたキー情報を基に複数の入力ファイルをマージします。正常な処理結果を保証するには、入力ファイルのキーがソートされていなければなりません。フィールドおよびオプションはSORTと同様に定義されます。

    以下は、25~28バイトのZD、48~55バイトのZDをキーに定義し、昇順で入力ファイルをマージする例です。

    MERGE FIELDS=(25,4,A,48,8,A),FORMAT=ZD
  4. OUTREC

    MERGE演算が実行されたレコードを付与された形式に変換します。INRECと同様に使われます。ただし、INRECによりレコードが既に変換された場合には、変換されたレコードを基準にして位置が決まります。

    詳細については、SORT演算、COPY演算4項 INRECを参照してください。

  5. OUTFIL

    OUTFILの詳細については、 OUTFIL演算を参照してください。

3. OUTFIL演算

OUTFILは、SORT、MERGE、COPY演算の結果出力されたレコードを様々な条件で再出力します。

ProSortでOUTFIL演算を実行する手順は以下のとおりです。

figure prosort outfil flow
OUTFIL演算の実行手順

以下は、OUTFIL演算の実行手順についての説明です。

  1. STARTREC

    出力レコードのうち指定した数を前方から除外します。

  2. ENDREC

    出力レコードのうち指定した数を後方から除外します。

  3. INCLUDE、OMIT、SAVE

    特定条件のレコードを除外するか含めます。SAVEオプションがある場合は、自分を除いたすべてのOUTFILで除外されていない条件のレコードのみ含めます。

    以下は、8 ~ 13バイトの文字列フィールドがACCTNGのレコードはファイルGP1に出力し、8 ~ 13バイトの文字列フィールドがDVPMNTのレコードはファイルGP2に出力する例です。

    OUTFIL INCLUDE=(8,6,CH,EQ,C’ACCTNG’),FNAMES=GP1
    OUTFIL INCLUDE=(8,6,CH,EQ,C’DVPMNT’),FNAMES=GP2
    OUTFIL SAVE,FNAMES=NOT1OR2
  4. OUTREC

    出力レコードを付与された形式に変換します。

4. ユーザー出口関数

ユーザーはProSortのスクリプトまたはProSort APIを利用して関数を登録することができます。このような関数をユーザー出口関数(User Exit Function)といいます。SORT、MERGE、COPY演算を実行するとき、この関数を利用してレコードを挿入、変換、削除できます。

ユーザー出口関数は以前の段階で渡されたレコードを編集して次の段階に渡します。最後のレコード以降はNULLが関数に渡されます。

SORT、MERGE、COPY演算はProSort APIを使ってレコードを直接入力する場合のみ動作し、ファイルを使ってレコードを入力する場合には動作しません。

ユーザー出口関数の詳細は以下のとおりです。

  • プロトタイプ

    int user_exit_func (void *rec_addr, int rec_len, int input_no,
                        void **ret_rec_addr, int *ret_rec_len);
  • パラメータ

    パラメータ 用途 説明

    *rec_addr

    入力

    以前の段階で渡されたレコード・アドレスのポインターです。

    rec_len

    入力

    以前の段階で渡されたレコードの長さです。

    input_no

    入力

    SORTINの番号であり、MERGE演算のユーザー出口関数E32でのみ使用できます。

    **ret_rec_addr

    出力

    変換または挿入されたレコードのアドレスであり、ポインターの形で渡されます。

    *ret_rec_len

    出力

    変換または挿入されたレコードの長さであり、ポインターの形で渡されます。

  • 戻り値

    戻り値 説明

    0

    No Action。レコードを変換せずに次の段階を実行します。

    **ret_rec_addr、*ret_rec_lenパラメータに入力された*rec_addr、rec_lenのアドレスをそのまま渡します。

    0

    Record Altered。変換されたレコードで次の段階を実行します。

    入力された*rec_addr、rec_len、input_noの情報を利用してレコードを変換した後、変換されたレコードのアドレスおよび長さを**ret_rec_addr、*ret_rec_lenパラメータに渡します。

    4

    Delete Record。レコードを削除します。

    削除されたレコードは次の段階に渡されません。

    8

    Do Not Return。次のレコードからユーザー出口関数を実行しません。

    12

    Insert Record。返却されたレコードを挿入します。

    挿入されたレコードは次の段階に即刻転送されず、再度ユーザー出口関数を実行して変換されるか削除されます。既存レコードは挿入されたレコードが次のレコードに転送された後、再度処理されます。

    16

    Terminate Prosort。ProSortを終了します。

    実行中の作業をすべて終了します。

  1. ProSortのスクリプトを利用してユーザー出口関数を登録する方法は MODSを参照してください。

  2. ProSort APIを利用してユーザー出口関数を登録する方法は ProSort API関数を参照してください。

4.1. ユーザー出口関数を含むSORT演算、COPY演算

ProSortでユーザー出口関数と一緒にSORTおよびCOPY演算を実行する手順は以下のとおりです。

figure prosort sort flow with ue
ユーザー出口関数を含むSORT、COPY演算の実行手順

SORTおよびCOPY演算ではユーザー出口関数E15を登録して入力されたレコードを編集できます。ユーザー出口関数E35は、OUREC実行後のレコードから編集できます。

4.2. ユーザー出口関数を含むMERGE演算

ProSortでユーザー出口関数と一緒にMERGE演算を実行する手順は以下のとおりです。

figure prosort merge flow with ue
ユーザー出口関数を含むMERGE演算の実行手順

MERGE演算ではユーザー出口関数E32を登録して入力されたレコードを編集できます。ユーザー出口関数E35は、OURECを実行した後のレコードから編集できます。

4.3. ユーザー出口関数の例

本節では、ユーザー出口関数を使用して関数を機能別に実行する例を記述します。

全レコードの転送

以下は、すべてのレコードをそのまま転送する関数の例です。

static int
exit_none(const void *rec_addr,
          const int rec_len,
          int file_no,
          void **ret_rec_addr,
          int *ret_rec_len)
{
    if (rec_addr == NULL)
        return 8; /* do not return */

    *ret_rec_addr = (void *) rec_addr;
    *ret_rec_len = rec_len;

    return 0; /* no action */
}
全レコードの削除

以下は、すべてのレコードを削除する関数の例です。

static int
exit_delete(const void *rec_addr,
           const int rec_len,
           int file_no,
           void **ret_rec_addr,
           int *ret_rec_len)
{
    if (rec_addr == NULL)
        return 8; /* do not return */

    return 4;
}
全レコードの挿入

以下は、すべてのレコードをコピーして挿入する関数の例です。レコードのa、b、cが以前の段階から渡されるとa、a、b、b、c、cの形で次の段階に転送されます。

static int
exit_insert(const void *rec_addr,
            const int rec_len,
            int file_no,
            void **ret_rec_addr,
            int *ret_rec_len)
{
    static char buf[REC_LEN];
    static int inserted = 0;

    /* 挿入されたレコードは編集しません */
    if (inserted) {
        inserted = 0;
        *ret_rec_addr = (void *) rec_addr;
        *ret_rec_len = rec_len;
        return 0; /* no action */
    }

    if (rec_addr == NULL)
        return 8; /* do not return */

    memcpy (buf, rec_addr, REC_LEN);

    *ret_rec_addr = buf;
    *ret_rec_len = rec_len;

    inserted = 1;

    return 12; /* insert record */
}
最後レコードの挿入

以下は、最後のレコード3個を追加挿入する関数の例です。レコードのa、b、cが以前の段階から渡されるとa、b、c、c、c、cの形で次の段階に転送されます。

static int
exit_insert_to_end(const void *rec_addr,
                  const int rec_len,
                  int file_no,
                  void **ret_rec_addr,
                  int *ret_rec_len)
{
    static char buf[256];
    static int buf_rec_len;
    static insert_cnt = 0;

    if (rec_addr != NULL) {
        memcpy(buf, rec_addr, rec_len);
        buf_rec_len = rec_len;

        *ret_rec_addr = buf;
        *ret_rec_len = buf_rec_len;

        return 0; /* do not action */
    }

    if (insert_cnt >= 3)  /* 3個までレコードを追加します */
        return 8; /* do not return */

    *ret_rec_addr = buf;
    *ret_rec_len = buf_rec_len;
    insert_cnt++;

    return 12; /* レコードの挿入 */
}