IBM i (旧AS400）の自己学習メモ０９　ファイル（Physical File／Logical File）の作成

# 自己学習メモインデックス

[IBM i (旧AS400）の自己学習メモ　インデックス](https://qiita.com/You_name_is_YU/items/3964849e7803c8eaf767)

# 概要

RDMBSでいうところのテーブルに該当する物理ファイル（Physical File）と、IndexやViewに該当する論理ファイル（Logical File）を作成します。

作成するファイルの定義は以下のようなものを想定。


**得意先マスタ（MTOKISKP）**

|論理名|物理名|型|サイズ|
|:--|:--|:--|:--|
|得意先コード|TOKCD|A|5|
|得意先名|TOKNM|O|40|
|得意先カナ|TOKKANA|A|80|
|電話番号|TOKTEL|A|15|

# 物理ファイル（PF:Physidcal File）の作成

## まずソースコードとなるメンバーを作成

1. `strpdm`コマンドを実行
1. `3`(3. Work with members)を入力してEnter

    ```shell-session
                            Programming Development Manager (PDM) 
                                                                  
    Select one of the following:                                  
                                                                  
         1. Work with libraries                                   
         2. Work with objects                                     
         3. Work with members                                     
                                                                  
         9. Work with user-defined options                        
                                                  
    Selection or command                                          
    ===> 3                                                                                 
    ```

1. Fileに`QDDSSRC`と入力、Libraryは任意のライブラリを指定してEnter

    ```shell-session
        Specify Members to Work With                      
                                                          
    Type choices, press Enter.                                              
                                                          
    File  . . . . . . . . . .   QDDSSRC      Name, F4 for list            
                                                          
    Library . . . . . . . .     YAMAGUCHI1 *LIBL, *CURLIB, name         
                                                          
    Member:                                                               
    Name  . . . . . . . . .   *ALL         *ALL, name, *generic*        
    Type  . . . . . . . . .   *ALL         *ALL, type, *generic*, *BLANK                                                                              
    ```

1. QDDSSRCファイル内に定義されているMemberの一覧が確認できる画面が表示されたら`F6`キーを押下
1. Source memberに`MTOKISKP`  Source typeに`PF`と入力してEnter

    ```shell-session
        Start Source Entry Utility (STRSEU)      
                                                 
    Type choices, press Enter.                                     
                                                 
    Source file  . . . . . . . . . . SRCFILE      > QDDSSRC        
    Library  . . . . . . . . . . .              >   YAMAGUCHI1   
    Source member  . . . . . . . . . SRCMBR         MTOKISKP       
    Source type  . . . . . . . . . . TYPE           PF             
    Text 'description' . . . . . . . TEXT           得意先マスタ                                                                                       
    ```

1. SEUの画面に遷移し、初期段階では以下のようになっている。

    ```shell-session
    FMT PF .....A..........T.Name++++++RLen++TDpB......Functions+++++++++++++++++++++++++++ ...+... 9 ...+... 0                      
           *************** Beginning of data *************************************************************************************** 
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
   '''''''                                                                                                                           
           ****************** End of data ****************************************************************************************** 
                                                                                                                                     
    F3=Exit   F4=Prompt   F5=Refresh   F9=Retrieve   F10=Cursor   F11=Toggle                                                         
    F16=Repeat find       F17=Repeat change          F24=More keys                                                                                                                                                        
    ```

## レコード様式を定義する

1. SEUの１行目にカーソルを合わせてF4キーを押下
1. NameTypeに`R` Nameに`MTOKISKR`と入力してEnter

![AS400-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/3bfda0f3-5453-a87c-f39f-74b45f670bba.gif)

## カラムを定義する

1. ２行目以降にカラムを定義するため、行番号の箇所に`I`と入力しEnter（１行挿入）
2. F4キーを押下
3. Nameにカラム名 Lengthにサイズ DataTypeにデータ型を指定してEnter

![AS400-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/33aeecbd-1d0d-1c7b-8e1f-dea0f43e8405.gif)

全てのカラム定義が完了すると以下のようになる。

```shell:MTOKISKP
 FMT PF .....A..........T.Name++++++RLen++TDpB......Functions+++++++++++++++++++++++++++ ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00                 R MTOKISKR                                                                          
0002.00                   TOKCD          5A                                                                 
0003.00                   TOKNM         40O                                                                 
0004.00                   TOKKANA       80A                                                                 
0005.00                   TOKTEL        15A                                                                 
        ****************** End of data *********************************************************************
```

## 一意制約の定義

得意先マスタは、得意先コードで一意とならなければいけない。という一意制約をこのPhysical Fileに定義します。

以下のようにUNIQUEの指定と、KEYの指定を挿入する。

```shell:MTOKISKP
 FMT PF .....A..........T.Name++++++RLen++TDpB......Functions+++++++++++++++++++++++++++ ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00                                             UNIQUE                                                  
0001.01                 R MTOKISKR                                                                          
0002.00                   TOKCD          5A                                                                 
0003.00                   TOKNM         40O                                                                 
0004.00                   TOKKANA       80A                                                                 
0005.00                   TOKTEL        15A                                                                 
0006.00                 K TOKCD                                                                             
        ****************** End of data *********************************************************************
```

**よく見かけるサンプルだと６桁目に`A`がビッシリ埋まっています。それって自分で６桁目に入力してるんでしょうか？F4のプロンプトからは自動的に入力されないものなのでしょうか？知っていたら教えてください m(_ _)m**

上記まで設定できたら SEU=>に`file`と入力してEnterを押下。
これでファイルを保存してそのファイルが保存されているメンバー一覧の画面が表示される。

```shell-session
                          Work with Members Using PDM                 PUB400   
                                                                               
File  . . . . . .   QDDSSRC                                                    
  Library . . . .     YAMAGUCHI1           Position to  . . . . .              
                                                                               
Type options, press Enter.                                                     
 2=Edit         3=Copy  4=Delete 5=Display       6=Print     7=Rename          
 8=Display description  9=Save  13=Change text  14=Compile  15=Create module...
                                                                               
Opt  Member      Type        Text                                              
___  MTOKISKP    PF                                                            
```

## コンパイルしてPhysical Fileオブジェクトを生成

1. MTOKISKPのOptに`14`と入力しF4キーを押下
2. FIle:`MTOKISKP` Library:'YAMAGUCHI1' と入力しF10キーを押下
3. F10キーで追加のオプション画面が表示されるためPageDownでオプション画面を次の画面に遷移していき、Member Sizeオプションが出てきたら、Initial number of recordsに`*NOMAX`と入力してEnter

これでコンパイルしたMTOKISKPがYAMAGUCHI1ライブラリに生成される。
![AS400-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/6fa771f0-91ea-03f2-2b48-256327d509eb.gif)

### Physical Fileコンパイルの補足

コンパイル時にInitial number of recordsに*NOMAXを指定しました。
デフォルトでは、

- Initial number of records: 10000
- Increment number of records: 1000

となっており、MTOKISKPが１１，000レコードを超える11,001件目のデータを登録した際に、追加で1,000レコードを増分レコードとして追加してくれるのですが、その際にユーザーに対して追加しますか？というような確認メッセージを出力し、そのメッセージの回答を待つような挙動をしてしまいます。

何らかのプログラムが動いていて、データがちょうどその境目の登録処理をしようとした際に、わざわざメッセージ処理をしなければいけなくなるため、予め*NOMAXに指定しておきました。

もちろん予め指定したレコード件数を絶対に超えない仕様で、超えた場合にはエラーにしなければいけない。検知しなければいけない。という仕様があれば、その件数を適切に指定した方が良いと思いますが、開発するうえで、上限件数がわかり切っているテーブルは非常に少ないと思いますので、*NOMAXは指定しておいた方がトラブルにならなくていいと思います。 

## テストデータを挿入してみる

`upddta`コマンドを使ってテストデータを挿入してみる。

1. `upddta`コマンドを入力しF4キーを押下
2. Data base file:MTOKISKP  Library:YAMAGUCHI1を指定してEnter
3. 各項目に任意の値を入力してEnter
4. 入力が終わったらF3キーを押下して終了

![AS400-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/d70dc370-ed97-4ddf-6934-0553ec8dea19.gif)

## 登録されたデータを表示してみる

`runqry () yamaguchi1/mtokiskp`とコマンドを入力してEnterで登録データを簡単にみることができる。

```shell-session
                                                         Display Report                                                            
                                                                                                 Report width . . . . . :     146  
Position to line  . . . . .                                                                  Shift to column  . . . . . .          
Line   ....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+...10....+...11....+...12....
       TOKCD  TOKNM                                     TOKKANA                                                                    
000001 00001  ほげほげ商店                            ﾎｹﾞﾎｹﾞｼｮｳﾃﾝ                                                                
000002 00002  テスト２                                ﾃｽﾄ2                                                                       
****** ********  End of report  ********                                                                                           
```

# 論理ファイル（LF:Logical File）の作成

## LFのソース作成

メンバー一覧画面でF4キーを押下して以下のような設定でソースコードを新規作成する。
得意先マスタ（MTOKISKP）の物理ファイルに対する論理ファイルを作成するので、名前を`MTOKISKL00`という名前にしました。
Source typeは`LF`と指定します。

```shell-session
                      Start Source Entry Utility (STRSEU)    
                                                             
Type choices, press Enter.                                   
                                                             
Source file  . . . . . . . . . . SRCFILE      > QDDSSRC      
  Library  . . . . . . . . . . .              >   YAMAGUCHI1 
Source member  . . . . . . . . . SRCMBR         MTOKISKL00   
Source type  . . . . . . . . . . TYPE           LF           
Text 'description' . . . . . . . TEXT           *BLANK       
```

ソースコードは以下のように定義します。
0005.00の定義は、得意先コード'00000'以外を選択（S）するという意味。
MTOKISKL00からデータを取得する際には、'00000'以外が抽出されます。

```shell:MTOKISKL00
 FMT LF .....A..........T.Name++++++.Len++TDpB......Functions+++++++++++++++++++++++++++ ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00                                             UNIQUE                                                  
0002.00                 R MTOKISKR                  PFILE(MTOKISKP)                                         
0003.00                 K TOKCD                                                                             
0004.00                                                                                                     
0005.00                 S TOKCD                     COMP(NE '00000')                                        
        ****************** End of data *********************************************************************
```

```shell-session:MTOKISKPのデータ
runqry () yamaguchi1/mtokiskp

Line   ....+....1....+....2....+....3....+....4....+....5....+....6....+.
       TOKCD  TOKNM                                     TOKKANA          
000001 00001  得意先１                                ﾄｸｲｻｷ1           
000002 00000  特別な得意先                            ﾄｸﾍﾞﾂﾅﾄｸｲｻｷ      
000003 00003  得意先３                                ﾄｸｲｻｷ3           
000004 00002  得意先２                                ﾄｸｲｻｷ2           
****** ********  End of report  ********                                 
```

```shell-session:MTOKISKL00から取得したデータ
runqry () yamaguchi1/mtokiskl00

 Line   ....+....1....+....2....+....3....+....4....+....5....+....6....+..
        TOKCD  TOKNM                                     TOKKANA           
 000001 00001  得意先１                                ﾄｸｲｻｷ1            
 000002 00003  得意先３                                ﾄｸｲｻｷ3            
 000003 00002  得意先２                                ﾄｸｲｻｷ2            
 ****** ********  End of report  ********                                  
```

このように、論理ファイルでは、抽出対象とする条件を予め指定しておくことができる。
`K`で指定している条件は、キーフィールドを表しており、またソート条件でもある。という説明をいろんなところで見かけます。

しかし、上記出力結果のように、キーフィールドにTOKCDを指定していても、取得結果がバラバラになってしまいました。
キーフィールドには、`DESCEND`という降順指定も可能なようで、それも試してみましたがソート順は変わりませんでした。

指定方法が間違っているのか、キーフィールドではソートされないのか、、誰か知っている人いたら教えてください。

## LFでキーフィールドでソートされるか検証

runqryなどではキーフィールドでのソートが検証できなかったので、CLによるDCLF/RCVFでソートされるのか検証しました。

以下のPF/LFを定義

```shell:MSAMPLEP
 FMT PF .....A..........T.Name++++++RLen++TDpB......Functions+++++++++++++++++++++++++++ ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00      A          R MSAMPLER                                                                          
0002.00      A*                                                                                             
0003.00      A            CD             5A                                                                 
0004.00      A            NAME          10A                                                                 
0005.00      A            NUM            3P                                                                 
        ****************** End of data *********************************************************************
```

```shell:MSAMPLEL00
 FMT LF .....A..........T.Name++++++.Len++TDpB......Functions+++++++++++++++++++++++++++ ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00      A                                      UNIQUE                                                  
0002.00      A          R MSAMPLER                  PFILE(MSAMPLEP)                                         
0003.00      A*                                                                                             
0004.00      A          K CD                                                                                
        ****************** End of data *********************************************************************
```

MSAMPLEPのファイルの中身は以下の状態
CDの項目ではソートされていないことが確認できる。

```shell-session
runqry () yamaguchi1/MSAMPLEP

Line   ....+....1....+....2...
       CD     NAME        NUM 
000001 00001  sample-1      1 
000002 00005  sample-5      5 
000003 00002  sample-2      2 
000004 00004  sample-4      4 
000005 00003  sample-3      3 
```

上記ファイルの論理ファイルであるMSAMPLEL00に対して読み込みを行うCLプログラムを以下のように開発

```shell:CLPGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCLF       FILE(YAMAGUCHI1/MSAMPLEL00)                                                 
0003.00  READ:       RCVF                                                                                   
0004.00              MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(END))                                       
0005.00              SNDPGMMSG  MSG(&CD *BCAT &NAME)                                                        
0006.00              GOTO       CMDLBL(READ)                                                                
0007.00  END:        ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

上記CLプログラムを実行すると、以下のようにCD項目でソートされた状態でファイルの中身５件が取得できたことを確認。

```shell-session
Previous commands and messages:
   > call yamaguchi1/clpgm15   
     00001 sample-1            
     00002 sample-2            
     00003 sample-3            
     00004 sample-4            
     00005 sample-5            
```

上記までの挙動から、RUNQRYやWRKQRYでの取得結果には、論理ファイルで指定したキーフィールドによるソートは影響しないが、CLプログラムから読み込んだファイルの結果には影響するということがわかった。

ちなみに、なぜMTOKISKPとMTOKISKL00のファイルを利用しなかったのかというと、
CLプログラムで読み込むプログラムを作り、コンパイルする際に以下のコンパイルエラーが発生してしまったからです。

```shell-session
 SEQNBR  *...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
    100-              PGM                                                                
    200-              DCLF       FILE(YAMAGUCHI1/MTOKISKP)                               
         QUALIFIED FILE NAME - YAMAGUCHI1/MTOKISKP                                       
            RECORD FORMAT NAME - MTOKISKR                                                
              CL VARIABLE               TYPE     LENGTH     PRECISION     TEXT           
               &TOKCD                   *CHAR       5                                    
               &TOKNM                   *CHAR      40                                    
* CPI0845 10  Character CL variable declared for DBCS field &TOKNM.                      
               &TOKKANA                 *CHAR      80                                    
               &TOKTEL                  *CHAR      15                                    
    300-  READ:       RCVF                                                               
    400-              MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(END))                   
```

このエラーコード`CPI0845`を調べると、どうやらCLプログラミングでファイルを読み込む処理では、DBCSを扱うことができないようです。
そのため、DBCSを扱うフィールドが存在しないファイルを用意して挙動の確認をしました。

そもそもCLではファイルを読み込むような処理を書くべきではないのかもしれませんが、私はまだCLの触り程度しか分からず、RPGの勉強はまだ着手していないので、わかる範囲で検証した結果をここに記載させていただきました。