RPGサイクルとともに驚くほどサブファイル(SFL) の使用方法についての誤解が多いので、あえて
ここで改めて解説する。
SFL は明細行の表示画面を作成するに当たって、これほどやさしくて便利な機能は無い。
しかし多くの誤解のために SFLを正しく扱われていない場合も多い。
まず、SFL とは何であろうか?
多くのスクロール可能な明細行を大量に表示したい場合、SFLは次のような機能を提供する。

SFL はメモリ上に多くの行数のレコードを表示するが、実際にユーザーの目に見えているのは
サブ・ファイル・ページ数として定義された行数のみである。
このような状態となった SFL は
ユーザーがロール・アップ/ダウンキーを押しても OS400が制御して画面上の表示のスクロールを行い、ユーザー・プログラムに制御は渡らない
つまり一旦、サブファイルが表示されてしまうとユーザー・プログラムはスクロールのための制御を記述する必要がないのである。
制御を行う必要がないとユーザー・プログラムは今、ユーザーがどの辺りを眺めているのか
知ることができないように思えるが、これは心配する必要がない。
これについては後述する。
ユーザー・プログラムに制御が渡るのは操作員がサブファイル・ページを超過してさらにロール・アップ要求を行った場合のみである
つまり最初にすべてのデータをサブファイルに書き込んでしまってから操作員に制御を渡すのではなく、ロールアップ要求があったときのみに、次に表示すべき画面のサブファイル・
レコードを書き出すようにすれば良いのである。
例えばプラウザ上での検索エンジンによる検索を想像してみて欲しい。
検索して見つかったサイトが 1200件見つかったものとしても、検索エンジンは最初の10行
程度しか表示しないはずである。
SFL もこれと同じで最初のページだけを表示するようにするだけで十分である。
SFLSIZ を SFLPAG の +1だけ大きく定義しておくと SFL は自動拡張される。
SFL を表示レコードをすべて収容できるだけのサイズを予め指定しておく必要はない。
SFLPAG(17) のように SFLSIZ数を SFLPAG数 + 1 にしておくだけでOS400 に
よって自動拡張される。
サブ・ファイルの誤解
①サブ・ファイルはパフォーマンスが悪い ?
SFL の自動拡張機能を知らずに SFL には最初から該当レコードをすべて埋め込む必要が
あると考えて、最初にすべての該当レコードを SFL に書き出すような記述をすると、当然の
ことながら、該当レコードが例えば 10000件あれば SFL が表示されるまでに時間がかかって
しまう。
SFL には最初の表示ページ数のレコード件数だけ書き出せばさっさと表示してしまうだけで
十分なのである。
次に操作員が次頁を要求したときに初めて次のレコードを読めばよい。
SFL はその時点で自動拡張されるのである。
②SFLSIZ = SFLPAG として定義してしまう。
これでは自動拡張もされずに SFL を使うメリットが無くなってしまう。
SFLSIZ = SFLPAG としてしまう誤解の背景には、スクロール中にユーザー・プログラムに
制御が渡らないのでカーソル位置などによるレコードの取得ができないのではないかと思い
込んでいるせいである。
OS400 の SFL は実に良く考慮されていて例外処理のために SFL の使用が不便になる
ことはまず無い。
③SFL の記述は複雑になる ?
SFL を使って処理の記述がもし複雑になっているとしたら、それはどこかに SFL の使用方法
に大きな誤解が潜んでいると思って間違いないであろう。
SFL の使用に特殊なテクニックは必要ない。
むしろ SFL を使ったほうが処理は非常に単純なものとなるはずである。
④WRITE したばかりの SFL に CHAIN/UPDATE する ?
これも多い誤解の使用方法で、LOOP文で WRITE SFL した後で再び LOOP させて SFL
に CHAIN して UPDATE を行う処理も多い誤解のひとつである。
もし、このような複雑な処理を記述していたとしたら SFL が理解されてないことになる。
SFL は記述を単純にするために考慮されたもので、複雑なテクニックをもし使用していたとしたら、
それは SFL の使用方法を誤っていることになる。
サブファイルの作り方
サブファイルの作成は実に簡単である。
①SFLCLR によってサブファイルを初期クリヤーする。
最初に SFLCLR を入れない開発者もいるが、行儀の良いPGM のために必ず最初に
SFLCLR を実行させるようにする。
②レコードを読んでサブファイルにレコードを追加する。
該当レコードを読んで SFLPAG の文だけ LOOP してレコードを WRITE SFL にして追加する。
③ロールアップ・キーが押されたら再び②の処理で SFL へ追加する。
たった、これだけのことである。
ロールダウン・キーが押されたときの処理は記述する必要はない。
サブファイルの特殊なテクニック
①変更のあったレコードだけを読む READC
READC ( READ CHANGE) 命令を使用するとユーザーが何らかの手を加えた行だけを読み
取ることができる。
例えばある 100として表示されている項目を操作員が 120 と変更するとその行だけが
READC によって読み取られるのはもちろんであるが、100という数字を同じ 100に変更した
場合でも READC には読み取ることができるのである。
これは SFL でないとできないことはないが配列型であれば複雑な処理が必要である。
DO
READC SFL 50
50 LEAVE
(変更レコードだけの処理をここに入れる)
END
②今、処理しているサブファイル・レコードの RRN (レコード番号) を調べる
サブファイルを使用している DSPF に INFDS を定義して INFDS から取得することができる。
FANS004FM CF E WORKSTN
F SFILE(SFREC01:RRN1)
F INFDS(INFDS)
:
D INFDS DS
D LINE 370 371B 0
D TOPRRN 378 379B 0
D BRRN 376 377B 0
のように記述するものとする。
このうち SFL に対して入/出力を行うと、 BRRN には今、入/出力を行った直後に
そのサブファイル・レコードの RRN が更新されている。
例えば READC を行った直後には BRRN にはそのレコードのRRN が保管されている。
③ カーソルの位置からサブファイル・レコードを特定する
操作員がサブファイルの特定の行にカーソルを位置づけてある機能キーを押してプロンプト要求
などを試みたときに、カーソルが位置づけられたのは、どのレコードであるかを特定することが
できる。
前述の②の INFDS を見て欲しい。
INFDS のうち、TOPRRN とは今、現在表示されているサブファイルの先頭の SFLレコードの
RRNが保管されている。
サブファイル全体を操作員がどのようにスクロールしても制御がプログラムに戻ったときには最後に
表示されているサブファイルの先頭のRRNが入っている。
これを取得することによって、どのようなサブファイルであっても、どのあたりに位置されているかを
特定することができる。これによって SFLSIZ = SFLPAG に設定する必要が無いことはお分かり
頂けるものと思う。
次に INFDS の LINE にはカーソルの位置が保管されている。
そこで、
LINE DIV 256 LIN 3 0 <--- カーソル行番号
MVR POS 3 0 <--- カーソル桁番号
によってカーソルが位置づけられた行と桁を算出することができる。
サブファイル・レコードの開始行(表示行) を STRGYO とすると
LIN SUB STRGYO RRN1
ADD TOPRRN RRN1
この RRN1 が求める「操作員がカーソルを位置づけた SFL レコードの RRN」である。
そこで、
RRN1 CHAIN SFREC01 90
によって求める SFL レコードを取り出すことができる。
以上のようにサブファイルの処理は何も難しい処理は無い。
もしサブファイルに特殊なロジックを入れているとすると必ずそれはサブファイルを誤解して使用して
いるものと判断して、ほぼ間違いない。
サブファイルは処理をやさしくするための機能であって、決して複雑にするための機能ではないのだ。
クリヤーしてからレコードを追加する。ただこれだけのことである。
