ユニコードとRPGアプリケーションの変換についてもっと詳しく
RPGアプリを変換して言語をサポートするのが大変だなんてあり得ない
「ユニコードと System i: 革新というより進化」(2009年11月号)の記事で、「英語だけの」対話式 RPG アプリケーションを例にとり、それを 5250 ディスプレイ・ファイルでいかに簡単に英語、ロシア語、中国語など多様な言語を同時にサポートするよう変換できたかについてお話しました。その記事で示した SHIPTORPG サンプル・プログラムの場合、この多言語サポートはユニコードを利用するため Change Physical File (CHGPF) コマンドでデータベースを変更し、*DSPF および RPG アプリケーションを再コンパイルするぐらい簡単でした。11 月号をまだ読んでいない方は、その記事を読むことをお勧めします。この記事では、最初の記事でレビューしたプログラム、ディスプレイ・ファイル、データベースへの参照を多数記載しています。
前回の記事でも、すべての RPG プログラムが SHIPTORPG サンプルのように簡単にユニコードに進化するわけではないことをお話しました。今回の記事では、それら「そう簡単ではない」プログラムについてお話します。
明示的変換サポート
Reference Field 機能.
前回の記事にあるサンプル・プログラムが簡単にユニコードに移行できた理由の 1 つとして、アプリケーション開発者がシステムで使用可能なツールを利用した点があります。例えば、開発者は最初にディスプレイ・ファイルを定義するときにデータベース・フィールド COMPANY、CONTACT、ADDR1、および ADDR2 を明示的に定義しませんでした。その代わり開発者は DDS の Reference Field (REFFLD) 機能を使用して物理ファイルのデータ定義を再利用し、文字からユニコードへのデータベース定義を変更させ、再コンパイル時に *DSPF に自動的にユニコードへの変更をピックアップさせました。同様に、サンプル RPG アプリケーションは、データベース・ファイル ORDER、ORDDET、および INVEN また SHIPTODSPF *DSPF についてプログラム記述定義ではなく、外部記述データを使用して作成されました。ディスプレイ・ファイルの再コンパイルと同様、SHIPTORPG プログラムを単に再コンパイルすることで、コンパイラーは自動的にユニコードへの変更をピックアップできました。
RPG プログラムの中には、使用できるサポートすべてを利用しないものもあります。REFFLD および外部記述データの話題に沿ったある例として、アプリケーション内に作業フィールドを定義する場合に RPG LIKE キーワードを使用しない場合があります。例えば、「一時」保留フィールドを利用して、コードを多少実行した後にある指定の変数の値をリストアするアプリケーションがあります。図 1 は、保留フィールドを定義する場合の非常に一般的なアプローチを示しています。この場合、データベース CONTACT フィールドの保留フィールドを示しています。TempFld を 40 バイト文字フィールドとして明示的にコーディングするこのアプローチでは、ユニコード・ソリューションに発展させたい場合、ソース・プログラムを変更する必要があります。単にプログラムを再コンパイルするだけでは、プログラムは正しく動作することもあれば、ときには誤った動作、言い換えれば、本当に頭に血が上るような動作をする場合もあります。
プログラムを再コンパイルするだけの場合に見られるこの動作には、いくつかの理由があります。1 つは CONTACT が現在 80 バイト長 (CCSID 13488 ユニコードでは 1 文字に 2 バイトが必要) であるのに対して、TempFld は 40 バイトのデータしか保持しない点です。つまり、断続的に (しかし予想どおり) CONTACT 情報が切り捨てられます。例えば、処理中の ORDER ファイル・レコードに保管するのに 40 バイトより多くのバイト数が必要な CONTACT 名が入っている場合です。この動作の 2 つ目の原因は、TempFld を CONTACT の値に設定する場合、RPG ランタイムが CONTACT をユニコードでエンコードしたデータを TempFld を EBCDIC でエンコードしたデータに変換し、CONTACT を「元の」値にリストアする場合に、TempFld を EBCDIC でエンコードしたデータを CONTACT をユニコードでエンコードしたデータに変換するためです。変換処理する場合の CONTACT フィールドの文字数により、文字が失われたり、失われなかったりします。どの文字が失われるかは、プログラムが動作しているジョブ CCSID に部分的に依存しています。
LIKE キーワード.
図 2 で、LIKE キーワードを使用して変数 TempFld を定義する、さらに優れた方法を示します。LIKE キーワードを使用することで、RPG コンパイラーは TempFld を CCSID 13488 でエンコードされた 40 文字のユニコード・フィールドとして正しく定義します。この場合、依然 SHIPTORPG アプリケーションを単に再コンパイルすることができます。さらにコメントとして、LIKE キーワードなどの関数を使用するよう RPG アプリケーションを改革すると、ユニコードを使用しなくても役に立つことがわかると思います。LIKE キーワードを使用すると、将来のビジネス要件により、「英語だけ」の CONTACT フィールドを 40 文字から 50 文字に拡張しなければならなくなった場合でもメリットがあります。再コンパイルはそれでもデータベース内のこの変更をピックアップし、プログラム内のソース定義を維持する必要性が少なくなります。
CCSID 13488 ユニコード・エンコード・データ間で、従来の EBCDIC ベース・データを自動的に変換するこの RPG 機能は、TempFld 変数が正しく定義されていなかったため、早々に問題を発生させました。しかし、この暗黙的変換機能は通常、ユニコードに移動する際には便利な支援機能です。この暗黙的な変換により、ソースコードを変更しなくても図 3 のコードは動作します。図 3 では、RPG コンパイラーは、ユニコード変数値を設定する場合に、フィールド UnicodeFld が CCSID 13488 ユニコードとして定義されており、*Blanks および *Loval などの形象定数、EBCDIC 'A' および 'ABC' などのリテラル値、EBCDIC_Fld などの変数を正しく処理することを認識しています。さらに、IF、WHEN、および DOW などの共通演算は予想どおりに動作を続けます。特に、RPG は EBCDIC 値をユニコード値に「アップグレード」します。
コンパイル時の障害.
しかし、すべての EBCDIC 変換およびユニコード変換が自動で行われるわけではありません。図 4 は、コンパイル時の障害を引き起こすいくつかの RPG 演算を示しています。特に、以下のケースがあります。
- EBCDIC リテラル ', ' をユニコード変数の City に連結しようとすると、メッセージ RNF7421-Operands are not compatible with the type of operator (オペランドと演算子のタイプに互換性がありません) が表示されます。
- ユニコード変数 AddrLine の EBCDIC 空白文字をスキャンしようとすると、メッセージ RNF0353-The first and second parameters of %SCAN are not of the same type (%SCAN の第 1 および第 2 パラメーターのタイプが同じではありません) が表示されます。
- ユニコード変数 AddrLine 内のリテラル値 Minnesota を EBCDIC リテラル値 MN と置換しようとすると、メッセージ RNF0382-The second parameter ADDRLINE for %REPLACE is not valid. ( %REPLACE の第 2 パラメーター ADDRLINE が有効ではありません) が表示されます。(RNF0353 に加えて、組み込み第 3 パラメーター %REPLACE 内で %SCAN を使用することによる)
こうした状況では、RPG ソース・プログラムを変更する必要があります。これらのケースで必要な変更は難しくありませんが、時間が掛かり、当然の結果として、ソースコードを変更することによるミスの可能性が出てきます。
これらのコンパイル時障害を解決する 1 つのアプローチは、Convert to UCS-2 Value %UCS2 組み込み関数を使用してEBCDIC からユニコードへの変換を明示的に要求することです。このソリューションを使用する場合に必要な変更を図 5 に強調表示すると同時に、%UCS2 組み込み関数がどのように図 4 に記載のソース・エディターからの誤ったエラー報告を防ぐことができるかを示しています。13488 などの UCS-2 CCSID から EBCDIC へのデータ変換という逆の演算も Convert to Character Data %CHAR 組み込み関数を使用して行うことができます。しかし、ユニコード変数の文字数が確実にわかっていない限り、この方向にデータ変換することはお勧めしません。ユニコード変数は、ユニコード規格で定義された 96,000 を超える文字数のいくつかを保管している可能性があります。一方、CCSID 37 などの一般的な 1 バイト EBCDIC エンコード方式では 192 文字しか定義されません。こうした文字セット・サイズに大きな違いがあることから、ユニコードから EBCDIC に変換するのは文字数を失う大きなリスクを負っています。繰り返しますが、使用している文字数が確実に把握できていない限り、%UCS-2 組み込み関数を使用して文字データを常にユニコードに変換します。%UCS-2 組み込み関数を使用して必要以上にソースコードを変更する必要がありますが、これらのコンパイル時障害を解決する 2 番目のアプローチを図 6 に示します。
暗黙的変換サポート
RPG は、いくつかの演算に対して暗黙的変換サポートを提供しています。
- INZ キーワードを使用した初期化
- EVAL、MOVE、MOVEL、およびフリー・フォーム = を使用した代入
- IF、IFxx、DOW、DOWxx、DOU、DOUxx、WHEN、WHENxx、CABxx、CASxx、COMPを使用した比較
暗黙的変換をサポートしていない RPG 演算は次のとおりです。
- フリー・フォーム + または CAT を使用した連結
- 組み込み関数 %CHECK、%CHECKR、%REPLACE、%SCAN、%TRIMx、%XLATE
- プロシージャー・プロトタイプ戻り値または CONST または VALUE として渡されるパラメーター
上記の 2 つのリストは本来包括的ではない点に注意してください。それらは使用する割合が高い主な RPG 関数を網羅するためだけのものです。
効果的に暗黙的変換サポートを提供している関数もありますが、それらはさらに変更が必要な場合があります。例えば、DSPLY 命令コード (これがあなたの会社の対話式表示の標準でないことを祈ります) をうまく使用して EBCDIC COMPANY 名を表示できますが、ユニコードの COMPANY 名を使用するとコンパイルに失敗します。DSPLY は変数表示に最大 52 バイト長をサポートしているためです。前述のように、CCSID 13488 ユニコードは 1 文字当たり 2 バイトを使用するため、COMPANY のユニコード・バージョンは 80 バイト長として定義されます。DSPLY 命令コードに%SUBST 組み込み関数を使用するのは、このコンパイラー・エラーを回避する 1 つの方法です。しかし、それより優れたアプローチは「改革」して、DSPLY 命令コードの使用をやめることです。
一度に 1 言語か同時に多言語
暗黙的でも明示的でも、RPG 文字変換の話題を離れる前に、ユニコードに関連した取り組みに役立つコメントをいくつか残しておきましょう。データベースをユニコードに進化させる場合に多くの理由を考えるでしょう。どのような各国語環境でも使用できる、一度に 1 つの言語という 1 つのプログラム・セットとデータベース定義を持つことが、その動機となる会社もあるでしょう。(ユニコードを使用しなくても、一度に 1 つの言語という要件を満たす 1 つのプログラム・セットを持つことができる点に注意してください。ユニコードを使用しなければならないのは、1 つのデータベース定義を持つ場合です。) SHIPTORPG プログラムで示したように使用できる 1 つのプログラム・セットとデータベース定義を持つことが動機となる会社もあるでしょう (「ユニコードと System i: 革新というより進化」2009 年 11 月を参照)。つまり、SHIPTORPG プログラムとして多言語で同時に動作するプログラムにより、英語、ロシア語、中国語のテキストを同時に使用できるようになりました。
一度に 1 言語.
暗黙的でも明示的でも RPG 文字変換サポートの使用は、一度に 1 言語の場合に管理できます。製品の特定のインストールに使用する各国語は、ユーザーが扱う文字セットを予想でき、適切なジョブ CCSID 属性および言語 ID (LANGID) 属性を、そのユーザーに設定できることがあらかじめわかるでしょう。一度に 1 言語という処理により、予測できる方法で文字変換が行われる明確な環境が提供されます。図 1 についてお話しする中で、ジョブ CCSID によっては EBCDIC に変換中にユニコード文字が失われる可能性があることを指摘しました。その話を展開して、ユーザーが中国語 (簡体字) のみ使用することがあらかじめわかっている場合、ユーザー・ジョブ CCSID を 935-中国語 (簡体字) 拡張に設定できます。(オーダー番号 2 の CONTACT 名が完全に中国語 (簡体字) 文字であるため) CONTACT および文字ベース TempFld の例を使用した場合、CONTACT 名を TempFld に変換し、後で CONTACT 値をリストアするプロセスはうまくいきます。しかし、CONTACT 名を、ロシア語、タイ語、アラビア語、中国語 (繁体字)、あるいは i でサポートされているその他多数の各国語などの別の各国語に変更する場合、各国語文字は失われる場合があります。潜在的にこうした損失があるため、文字変換を避けなければならないかどうか判断する場合に、ビジネス目標として一度に 1 言語をサポートするのか、同時に多言語をサポートするのかを判断する必要があります。これは設計上重要なポイントで、プログラムが RPG 文字変換サポートを利用できるかどうかに影響する場合があります。
同時に多言語.
複数の各国語を同時に使用している場合は、EBCDIC 変数とユニコード変数の間で、暗黙的または明示的な RPG 変換は行わないことをお勧めします。リテラル値または名前の付いた固定情報で RPG に変換させるのは、変換時にどの文字が関わっているのかあらかじめ正確にわかるため、適度に「安全な」方法です。しかし、ユニコードに関する考慮事項とは関係なく、任意の定数を使用すると、多言語アプリケーションを開発する場合に問題を引き起こす場合があることを念頭に入れておく必要があります。$ 記号などの定数やアドレス行にコンマを使用するのは、その使用方法の点から見て汎用的ではありません。しかし、変数データでは、ユニコード文字セットのサイズが巨大であるため、潜在的に文字データが失われる可能性が極めて高くなっています。また、文字を失う場合がある、DOU から早めに (または遅く) 終了する、または IF ステートメントとの比較結果が正しくないなどの点は、今後悩みの種となるのは確実です。プログラムで等しいデータ・タイプ (EBCDIC または Unicode) の変数のみ使用されるようすべての計算演算を変更するのは、既存のアプリケーションを改造しながら最初は大変な作業かもしれませんが、時間とともに作業時間も短くなります。幸運にも、ユニコードに変換する可能性が最も高いデータは本質的にテキスト形式で、もちろん例外はありますが、論理比較ではほとんど使用されません。
最終的にどの方法 (一度に 1 言語または同時に多言語) を選択しても、ユニコードを使用するよう既存のアプリケーションを進化させる前に両方の方法を検討してください。新しいアプリケーションを開発する場合は、同時に多言語のソリューションを実装することをお勧めします。最も柔軟性がある環境に向けて設計することで、将来的に著しいメリットが得られるはずです。
データベースに関する考慮事項
データベースを EBCDIC からユニコードに移行すると、RPG からのデータベース・アクセスの点でいくつか問題に遭遇するはずです。しかし正直なところ、EBCDIC 定数または EBCDIC 変数を使用して、Unicode フィールドに CHAIN できません。それでも、ユニコード定義が必要ない、定数または変数を使用したユニコード対応キーにランダムにアクセスするケースは非常にまれなはずです。前回の記事 (「ユニコードと System i: 革新というより進化」 2009 年 11 月) の、データベース内のすべてのフィールドをユニコードに変更する必要がない Order Status フィールド ORDSTS を思い出してください。変更する必要があるフィールドは、ユニコードで使用できるより大きな文字セットをサポートする必要があるフィールドです。また、アプリケーションが、例えば ORDSTS (EBCDIC として定義) および COMPANY (ユニコードとして定義) で構成されたキーなど、データ・タイプが混合している複合キーを持つレコードをランダムに読み取る必要がある場合、CHAIN (OrdSts :Company) FileName; が FileName2 のキーがユニコードに基づいた SETLL *Start FileName2; のような特殊値とともに期待どおりに動作を続けることがわかるでしょう。
EBCDIC からユニコードに移行する間に遭遇する可能性があるデータ関連の問題の 1 つは、照合またはソート・シーケンスに関連しています。図 7 は、3 つの会社名に関連付けられた EBCDIC およびユニコードの 16 進値を示しています。データベース索引は、デフォルトで 16 進ソートを使用して作成されるため、アプリケーションについて、データベースをキー順に読み取るとき、レコードが読み取られる順番に違いが見られる場合があります。特に、EBCDIC COMPANY エンコード方式を採用している図 8 では、会社「1st National」が「'XYZ Company」の後に処理されている点に注目してください。これをユニコードの COMPANY エンコード方式を採用している図 9 と比較してください。この場合、「1st National」は「ABC Company」の前に処理されています。ただ、処理順序に違いがあることが重要かどうか判断できるだけです。違いに全く関心のない会社もあるでしょう。その他の会社については、元のソート順を維持するためユーザー側でさらに作業が必要になる場合があります。
でも心配しないでください。元の照合シーケンスを再確立するのは技術的に難しくはありません。物理ファイルまたは論理ファイルを作成するときに、SRTSEQ キーワードで正しいテーブルを指定するぐらい単純です。しかし、できるだけ作業努力を減らそうとしているなら、ソート・シーケンスはそのままにしておくことをお勧めします。それは、部分的に「正しい」テーブルを判断するのが難しいためです。テキスト・データをソートするのに万人に受け入れられる方法はありません。例えば、少なくとも図 7 から図 9 で使用された文字のデフォルト・ユニコード・シーケンスは ASCII ユーザーが期待するものであり、図 8 にある EBCDIC シーケンスを使用するレポートに驚くでしょう。しかし、それより大きな問題は、ユニコード対応のさまざまな言語すべての文化的期待感を満たすソート・シーケンスは 1 つもないということです。当然、さまざまなユーザーの異なるソート・シーケンス・テーブルを指定 (つまり、各国語による異なる論理ファイル・ビューを提供する) できますが、それを始める前に、だれか意味のある方法で本当に関心があるかどうか判断するよう提案します。デフォルト・シーケンスを使用すると問題になる場合、ソリューションがあります。
上記のように、そのソリューションは正しいソート・シーケンス・テーブルを適切なファイルと関連付けている可能性があります。あるいは、より堅固なソリューションに関心があるなら、影響を受けたアプリケーションについて RPG 入出力から組み込み SQL にデータベース・アクセスをアップグレード/更新するというソリューションがあります。その多数ある機能の中で SQL は、ユーザーのニーズごとに一意の論理ファイルを作成することなく、現在のユーザーの文化的好みに基づいてデータベース・レコードを動的に再シーケンスする機能を提供します。IBM i で作業する場合に予想できるように、その他にも可能なソリューションがいくつかあります。しかし、これらの代替方法については、この記事で扱うには広範なため、取り上げません。
照合に関するこの同じ考慮事項は、RPG アプリケーションにも同様に当てはまります。プログラムで、「1st Federal」のフィールド値が「ABC Company」のフィールド値より大きいという EBCDIC に基づく想定がされている場合、RPG アプリケーションの動作を変えずにユニコードに移行するとこの想定が無効になります。このようなタイプのエンコード方式を想定するビジネス・アプリケーションは、できるなら、滅多にないのが望ましいです。しかし、ソリューションはあります。
もちろん、多言語をサポートするためにアプリケーションを変換するには、お話した*DSPF、プログラム計算、およびデータベース・アクセス以上のものが関係しています。読者のアプリケーションは、1 つまたは 2 つのレポートを生成し、本質的に現在 EBCDIC である置換テキストを含むメッセージなどを送信する可能性が高いです。しかし、システムと RPG 言語コンパイラーを使用できる準備が整っているのがわかるでしょう。また、さらに多くの資料が入手できます。IBM Information Center は以下に関する情報を提供しています。
- ユニコード対応プリンター・ファイルの生成
- どのプリンターのフォントがユニコード文字セットをサポートするか (すべての 5250 エミュレーターがユニコード文字セットを表示できるわけではないのと同様に、すべてのプリンターがユニコード文字セットを印刷できるわけではない点に注意)
- メッセージ置換テキストのユニコードとしての送信
- SQL でのユニコードの使用
- Query でのユニコードの使用
- Open Query File (OPNQRYF) でのユニコードの使用
- User Interface Manager (UIM) パネルでのユニコードの使用
- クライアント・アクセスでのユニコードの使用
- ユニコードを EBCDIC にマップするための論理ファイルの作成。Data File Utility (DFU) などのユーティリティーを使用してユニコード・フィールドにアクセスする場合に便利な機能です。DFU は、ユニコードを直接サポートしないユーティリティーの例ですが、EBCDIC 論理ファイルを使用してユニコード・エンコード・データを処理できます (データの EBCDIC ビューを処理する場合には制限がある点を覚えておいてください)。
- EBCDIC をユニコードにマップするための論理ファイルの作成。プログラムまたはシステム・ユーティリティー内でのユニコード・サポートを素早くテストするなどの分野で便利な機能です。ユニコード形式のデータを処理しようとする場合に、EBCDIC データをコピーする必要はありません。
- その他ユニコード・サポートの分野多数
この記事と前回の記事を読んだら、アプリケーションを変換して多様な言語をサポートするために使用できるシステム・サポートをいくつか使用する準備ができていることでしょう。