ILE RPG での可変長の扱いかた

ILE RPG ではフィールドを可変長として扱うことができます。

コマンドや SQL文などの文字列を扱う場合、想定される最大長の指定だとたいていの場合後続ブランクが多く、なんとなくムダな気がしてしまいませんか?

それほど大きな値を定義してしていない場合や、処理してもプログラム内で一つだけといった場合はあまり大きな影響はないかもしれません。
ただ、今後指定できるサイズが大きくなってきた場合や、大量に処理する必要が出てきた場合には問題が出てくる可能性がありますね。

また、どちらかと聞かれれば、そういう大きなサイズのフィールドを使用する場合は可変長フィールドを使った方が効率がよいことが多いのは間違いのないところで、扱い方を理解しておいて損はないでしょう。

ということで、今回は ILE RPG で可変長フィールドを扱う上での基本的なことを見ていきたいと思います。

理解する必要があるキーワードは 2つ、VARYING と option(*varsize) です。


データ型の指定としての VARYING

まず、フィールドを可変長として扱う場合は VARYING というキーワードの指定を行います。
つまり、VARYING は A や G などといった定義とともにデータ型の属性になります。

RPG 解説書 V5R4」での記載を見てみましょう。
「文字データ・タイプ」の「可変長の文字形式、図形形式およびUCS-2 形式」部分からの抜粋です。

可変長文字フィールドには、宣言された最大長と、プログラムの実行時に変化する現在の長さがあります。この長さは、文字形式の場合は1 バイト単位で、図形形式およびUCS-2 形式の場合は2 バイト単位で測定されます。可変長文字フィールドに割り振られる記憶域は、宣言された最大長より2 バイト長くなります。左端の2 バイトは、現在の長さを示す文字数、図形文字数、またはUCS-2 文字数が入っている符号なし整数フィールドです。実際の文字データは可変長フィールドの3番目のバイトから開始します。

VARYING を指定した文字フィールドについては、内部的に文字数がトラッキングされていることがわかります。
RPG のいろんな命令や、データベース操作がこの"文字数を知っている"ことで恩恵を受ける、という仕組みになっているわけですね。

RPG 解説書 V5R4」では↓のような例が挙げられています。

DSPLY 命令では、可変長結果フィールドの長さが、ユーザーによって入力された値の長さに変更されます。たとえば、結果フィールドが長さ10 の文字フィールドであり、ユーザーによって入力された値が’12345’ である場合、このフィールドの長さは、DSPLY 命令によって5 に設定されます。

CLEAR 命令では、可変長フィールドの長さが0 に変更されます。

PARM 命令では、結果フィールドの長さが、演算項目2 (指定されている場合) の中のフィールドの長さに設定されます。

固定形式命令のMOVE、MOVEL、CAT、SUBST およびXLATE は、可変長結果フィールドの長さを変更しません。たとえば、値’XYZ’ が、MOVE を使用して、現在の長さが2 である長さ10 の可変長文字フィールドに移動された場合、このフィールドの長さは変更されず、データが切り捨てられます。
注: MOVE とMOVEL について推奨される使用法は、EVAL とは対照的に、一時的に長さを固定したいフィールドの値を変更する場合です。たとえば、報告書を作成する場合に、その列のサイズが毎日異なっていて、ただし、プログラムの所定の実行時にはそれを固定する必要がある、という場合などです。

フィールドがファイル(入力仕様書) から読み取られるとき、可変長フィールドの長さは入力データの長さに設定されます。

出力仕様書の「後で消去」機能は、可変長フィールドの長さを0 に設定します。

また、「SQL データ・タイプと ILE RPG データ・タイプの対応関係の判別」を見れば、RPG で指定された VARYING が SQL での VARCHAR に相当していることがわかります。
ホスト変数を介した保管時に桁数を自動的に調整してくれる、ということですね。

小さいサイズの変数の場合はそれほど影響があるわけではないでしょうが、コマンド文字列や SQL文字列 などはかなり大きなサイズになることがあるので、こうした可変長フィールドの検討をしてみる価値はあると思います。

Options(*Varsize) はパラメータチェックのオプション

この VARYING と似たキーワードに Options(*varsize) というのがあります。

混同/混乱されている方もいるのではないでしょうか?! (実は私もそうでしたので …)

この Options というキーワード自体、Parameter passing options の意味です。
プロトタイプに指定されたサブプロシージャの引数チェック時のいろいろなオプションを指定するために使われるものです。

つまり、サブプロシージャの引数の定義の時にしか使われないものなんですね。

たとえば↓のように、2つの 5桁の文字フィールドをパラメータとして受けとる concat というプロシージャがあったとします。

プログラムの中で、a と b というそれぞれ 5桁の文字フィールドが定義されており、この a と b を concat プロシージャのパラメータにセットしています。

↑の例では a にも b にも 3桁の文字を代入しています。
たとえば「いつもこれは 3文字なので、これを 3桁の文字フィールドと定義しよう」としたら、どうなるでしょうか?

答えは「コンパイル・エラーになる」なんですね。
また、これが別のプログラムに存在するプロシージャだった場合、コンパイル・エラーを避けるためにここのプロトタイプ記述だけ場当たり的に直す、ということを思いつくかもしれませんが、呼び出し時にエラーになってしまいます。

そんな時に、この options(*varsize) を使うんですね。

このプロシージャのパラメータには、ここで予期しているバイト数(ここの例では 5桁)と異なるバイト数のフィールドがセットされてくるかもしれない、ということを表現しているわけなんです。
チェックを特別にゆるめてあげる、というようなかんじですかね?!

もちろん、呼び出されたプロシージャ側の処理でそれを知った上での処理がいろいろ必要になります。
(↑の例では、それぞれのバイト数を調べた上でブランクの処理をどうするのか、といったような考慮をする必要がありますね)

VARYING と Options(*varsize)

ちょっとまとめてみると、Options(*varsize) というのはサブプロシージャのパラメータ処理のときに指定するもので、必ずしも"可変長"と直接関係するキーワードではない、ということです。

ただ、可変長で定義されているフィールドがパラメータに指定されていた場合、定義されているバイト数と異なるサイズのフィールドがセットされてくる可能性はありますね。
ですから、可変長のフィールドを受け渡しに使う場合は使われる可能性が高いわけです。

たとえば、「ソケットごとの実行 SQL の収集 (V5R4)」で、モジュール間で受け渡す長いフィールド(具体的には SQL 文)は↓のように定義されています。

     D RtvSQLInf       PR                                                                           
     D  JobName                      10a   CONST                                                    
     D  UserName                     10a   CONST                                                    
     D  JobNumber                     6a   CONST                                                    
     D  SQLStmt                   65535a   Options(*VarSize)                                        
     D  SQLStmtLen                   10u 0                                                          

これを元のプロシージャでは↓のように返しています。

            SQLStmt = %trimR(SQLStmt) ;                                                                      
            SQLStmtLen = %len(SQLStmt) ;                                                     

右ブランクをトリムしているのですが、実際にどのようにわたってきているか、デバッグ用にパラメータ自体のサイズを %len で取って見てみましょう。

定義されているとおりの値、なんですね。

パラメータ定義を(呼び出し先も元も)可変長フィールドに変えてみましょう。

     D RtvSQLInf       PR                                                                           
     D  JobName                      10a   CONST                                                    
     D  UserName                     10a   CONST                                                    
     D  JobNumber                     6a   CONST                                                    
     D  SQLStmt                   65535a   VARYING Options(*VarSize)                                

↓のようにきちんとトリムされた状態で渡されてきていることがわかります。

ちょっとしたまとめ

繰り返しになりますが

ということです。

ですから、「ソケットごとの実行 SQL の収集 (V5R4)」での options(*varsize) は実はあまり意味がなく、「もしきちんとトリムされた文字列がわたされてきてしまったら」の "念のため" といった意味合いで定義されているだけなんです。

     D RtvSQLInf       PR                                                                           
     D  JobName                      10a   CONST                                                    
     D  UserName                     10a   CONST                                                    
     D  JobNumber                     6a   CONST                                                    
     D  SQLStmt                   65535a   Options(*VarSize)                                        
     D  SQLStmtLen                   10u 0                                                          

VARYING で定義されているパラメータは、VARYING で定義されているフィールドを呼び出し先では return する必要がありますし、呼び出し元(受け取り側)では VARYING で定義されている必要があります。
ただし、VARYING で定義されていれば文字数はトラッキングされているので、「ソケットごとの実行 SQL の収集 (V5R4)」のように文字数まで渡してあげる必要は必ずしもなくなります。

ソケットごとの実行 SQL の収集 (V5R4)」では、ILE RPG でない言語で使われることも考えて "念のため"の options(*varsize) と、受けとってからの処理のために文字列数を渡す、という設計になっています。
受け取った側で、改めて文字数を参照して切り取る、ということを想定しているんですね。

ILE RPG とのあいだでしかこのプロシージャは使わない、という観点で書き直したのが「ソケットごとの実行 SQL (可変長) の収集 (V5R4)」です。
ILE RPG の VARYING 指定フィールドであれば、文字数は自分でわかっているわけですね。つまり、文字数をわざわざ渡さなくてもいいわけです。
受け渡しするパラメータもひとつ減りますし、文字数を測定したり、文字列を文字数にあわせて切り取ったりする処理も必要なくなります。

こちらもよかったら参考にしてみてください。

[Top Pageに戻る]

Ads by TOK2