EBCDICからASCIIへの変換時の注意点
メインフレームで運用している業務システムをオープン環境に移行するためには、EBCDICデータをASCIIデータに変換する必要があります。この変換プロセスでは様々な問題が発生する可能性があるため、すでに知られている問題点を熟知してから、実際の作業に適用してください。
一般的にEBCDICデータをASCIIデータに変換する際の問題は、COBOLで作成されたアプリケーション・プログラムのソース・ファイルを変換するときに発生します。ソース・ファイルを変換するときに発生する問題のうち、深刻度の高いものは以下のとおりです。
-
HEX値の処理
-
文字ソート処理
-
2バイト空白の処理
本付録では、文字セットの変換時に発生する問題点の中で、深刻度の高い上記の3項目について原因を究明し、解決方法を提示します。
1. HEX値の処理
以下は、HEX値を使用して作成したロジックを含むCOBOLソース・プログラムを、dsmiginツールを使ってASCIIに変換する例です。
01 WORK06-AREA. 05 W06-KOUZA-NO. 10 FILLER PIC X(01) VALUE X'F1'. 10 W06-NO-1 PIC X(01). 10 FILLER PIC X(01) VALUE X'F2'. 10 W06-NO-2 PIC X(01). 10 FILLER PIC X(01) VALUE X'F3'. 10 W06-NO-3 PIC X(01). 10 FILLER PIC X(01) VALUE X'F4'. 10 W06-NO-4 PIC X(01). 10 FILLER PIC X(01) VALUE X'F5'. 10 W06-NO-5 PIC X(01). 10 FILLER PIC X(01) VALUE X'F6'. 10 W06-NO-6 PIC X(01). 10 FILLER PIC X(01) VALUE X'F7'. 10 W06-NO-7 PIC X(01).
上記ファイルは、COBOLで作成されたソース・ファイルについて、本書で記述した一般的な変換プロセスにより、EBCDIC文字をASCII文字に変換した状態です。上記のファイルは一見変換作業が正常に完了したように見えますが、以下のような問題を含んでいる可能性があります。
以下は、上記の例から一部を抜粋したものです。
10 FILLER PIC X(01) VALUE X'F1'.
上記では、EBCDIC文字がASCII文字に正常に変換されていますが、EBCDICで作成された顧客のCOBOLプログラムに実装された業務ロジックは正しく変換されていない可能性があります。
ソース・ファイルでX’F1’が示すのがF1という文字ではなく、EBCDIC値が1である場合を仮定してみます。一般的な文字セットの変換プロセスではEBCDIC値1が処理できないため、このような場合は手動で値を変更する必要があります。したがって、ソース・ファイルをASCIIに変換し、以下のようにASCII値1に該当する値である31に修正します。
10 FILLER PIC X(01) VALUE X'31'.
以下は、上記のサンプル・ファイルと同じソース・ファイルをdsmiginツールを使用してASCIIに変換した後、文字表現を数値に変更した例です。
01 WORK06-AREA. 05 W06-KOUZA-NO. 10 FILLER PIC X(01) VALUE X '31'. 10 W06-NO-1 PIC X(01). 10 FILLER PIC X(01) VALUE X '32'. 10 W06-NO-2 PIC X(01). 10 FILLER PIC X(01) VALUE X '33'. 10 W06-NO-3 PIC X(01). 10 FILLER PIC X(01) VALUE X '34'. 10 W06-NO-4 PIC X(01). 10 FILLER PIC X(01) VALUE X '35'. 10 W06-NO-5 PIC X(01). 10 FILLER PIC X(01) VALUE X '36'. 10 W06-NO-6 PIC X(01). 10 FILLER PIC X(01) VALUE X '37'. 10 W06-NO-7 PIC X(01).
HEX値の処理問題は、プログラム上に直接HEX値が記述されているため、文字の変換に問題が生じるのが一般的です。しかし、逆の場合もあり得ます。
01 YEAR-TABLE. 05 FILLER PIC X(12) VALUE '{{{{{{JJJJJJ'. 05 FILLER PIC X(12) VALUE '{{{{{{{JJJJJ'. 05 FILLER PIC X(12) VALUE '{{{{{{{{JJJJ'. 05 FILLER PIC X(12) VALUE '{{{{{{{{{JJJ'. 05 FILLER PIC X(12) VALUE '{{{{{{{{{{JJ'. 05 FILLER PIC X(12) VALUE '{{{{{{{{{{{J'. 05 FILLER PIC X(12) VALUE '{{{{{{{{{{{{'. 05 FILLER PIC X(12) VALUE 'A{{{{{{{{{{{'. 05 FILLER PIC X(12) VALUE 'AA{{{{{{{{{{'. 05 FILLER PIC X(12) VALUE 'AAA{{{{{{{{{'. 05 FILLER PIC X(12) VALUE 'AAAA{{{{{{{{'. 05 FILLER PIC X(12) VALUE 'AAAAA{{{{{{{'.
上記例において「{」という文字は、プログラム・ロジックで文字として使用されたのではなく、「{」文字のHEX値に該当するX’C0’文字が示すZD(Zone Decimal)値を意味します。
この場合、メインフレームのZD X’C0’に対応するASCIIのZD値がX’30’であるので、ユーザー業務をそのまま変換するためには、X’30’に対応するASCII文字の0に変更する必要があります。この際、EBCDICソース・データをASCIIデータに変換した後、ソースを修正することをお勧めします。
01 YEAR-TABLE. 05 FILLER PIC X(12) VALUE '000000qqqqqq'. 05 FILLER PIC X(12) VALUE '0000000qqqqq'. 05 FILLER PIC X(12) VALUE '00000000qqqq'. 05 FILLER PIC X(12) VALUE '000000000qqq'. 05 FILLER PIC X(12) VALUE '0000000000qq'. 05 FILLER PIC X(12) VALUE '00000000000q'. 05 FILLER PIC X(12) VALUE '000000000000'. 05 FILLER PIC X(12) VALUE '100000000000'. 05 FILLER PIC X(12) VALUE '110000000000'. 05 FILLER PIC X(12) VALUE '111000000000'. 05 FILLER PIC X(12) VALUE '111100000000'. 05 FILLER PIC X(12) VALUE '111110000000'.
前述したHEX値の問題点は、文字セットの変換プロセスにおいて、ユーザーが作成したプログラム・ソースに記述されたHEXが値を意味するのか、EBCDIC文字(あるいは逆の場合も該当する)を意味するのかが自動的に区分できないということです。
ソース・ファイルのHEX値が示す意味を把握するためには、プログラム・ソースがCOBOLで作成された場合はCOBOL文法を、PSAMフォーマット定義の場合はPSAMフォーマット定義文法を適用して分析を行う必要があります。
現在この問題を解決するために、TmaxSoftのコンサルタントがマイグレーションに参加してソース・ファイルを分析しています。今後、段階的に適用範囲を拡大していきながら、プログラム単位で自動分析できるようにツールを開発する予定です。 |
2. 文字ソート処理
EBCDIC文字をASCII文字に変換したとき、目で確認される文字には問題がないように見える場合でも、両文字コードが持つ固有の特性のため、実際にユーザー・プログラムを変換して使用するときには問題が生じる可能性があります。
本節では、文字コードの固有の特性のため発生する可能性のある代表的な問題の1つであるソート問題について説明し、その解決方法を提示します。
2.1. 文字ソート順を利用するプログラム
以下は、メインフレームで使用中のCOBOLソースをASCII文字に変換したソースの一部です。
IF W01-XX <= '99' THEN MOVE 'Y' TO W01-CC ELSE MOVE 'N' TO W01-CC END-IF.
ソース上では、EBCDIC文字からASCII文字への変換が正常に行われています。しかし、ユーザー・プログラムでは、業務ロジックにエラーが発生する可能性が存在します。 |
EBCDIC文字とASCII文字のソート順(collating sequence)は、以下のように異なります。
-
EBCDIC
a < z < A < Z < 0 < 9
-
ASCII
0 < 9 < A < Z < a < z
そのため、上記の例でW01-XX値が「AA」と仮定したとき、プログラムがメインフレーム環境で動作する場合はW01-CCに「Y」が設定され、UNIX環境で動作する場合は「N」が設定されます。すなわち、EBCDIC文字の「AA」をASCII文字の「AA」に、EBCDIC文字の「99」をASCII文字の「99」に正常に変換したとしても、既存のメインフレームでは「AA」<「99」の特性が、OpenFrameにおいては「99」<「AA」に変換されるため、このような特性を利用して作成されたアプリケーション・プログラムはマイグレーション後に従来とは異なる実行結果を見せることになります。
通常プログラム言語、あるいはソート・プログラムは、文字のソート順(collating sequence)を指定できます。これを利用すると、ASCII文字コードでEBCDICコレーティング・シーケンスを使用することができます。たとえば、UNIX用の富士通Net COBOLの場合、オプションを指定してEBCDICコレーティング・シーケンスを使用することができます。
文字ソート順を利用して作成されたアプリケーション・プログラム・ロジックがごく一部の場合は、以下のようにアプリケーション・プログラムのロジックを変更するのも1つの方法です。
IF W01-XX < 'zz' THEN MOVE 'Y' TO W01-CC ELSE MOVE 'N' TO W01-CC END-IF.
2.2. 索引化した情報(KSDS、ISAM、Index Database)のレコード順の違い
EBCDICとASCII文字コードの文字ソート順の違いは、上述したアプリケーション・プログラム・コードに存在する問題のみならず、プログラムが使用するデータセットやデータベースの索引に使われるキー・フィールド順の比較にも影響を与えるため、マイグレーション前後のシステム動作が異なる原因になります。
業務システムを開発・運用するエンジニアには、EBCDICではZZ<99、ASCIIでは99<ZZであるため、文字セットの変換時にソート順を変更する必要があることを教育を通じて十分に認識させることができます。しかし、実際に業務システムを利用する一般ユーザーには、このような環境変化を認識させることは困難です。そのため、この問題はマイグレーション・プロセスでは見過ごされやすいですが、システムを使用する一般ユーザーには使用上の混乱を引き起こす可能性があります。
たとえば、KSDSやISAMのような索引タイプのデータセット、またはOpenFrame NDBの索引データベース(Index Database)で特定の検索キーの入力を受け、レコードを1ページずつ出力する検索業務画面を変換すると仮定してみます。
メインフレームでは以下のような画面が出力されます。
[User Address List] -------------------------------------------------------------------------- ID : AAAAAAAA ID NAME ADDRESS ------------------------------------------------------------------------- AAAAAAAA KIM SEOUL BBBBBBBB LEE PUSAN CCCCCCCC PARK SEOUL HHHHHHHH AHN DAEGU LLLLLLLL CHO GWANGJU MMMMMMMM CHOI INCHEON NNNNNNNN KWAK BUPYOUNG XXXXXXXX IM SUNGNAM ZZZZZZZZ SEO GURI -------------------------------------------------------------------------- <F1> Menu <F2> Prev <F3> Next <Enter> Search
上記の業務の場合、メインフレーム環境では、ID値(英数字フィールドであると仮定します)のうち最小値であるAAAAAAAAを使用してすべてのID一覧を照会することができます。しかし、オープン環境では、AAAAAAAAを指定してもずべてのID一覧を照会することができません。
さらに、「11111111」というIDが存在すると仮定した場合、メインフレーム環境では<F3>キーを押して次の画面を照会すると「11111111」の結果が出力されますが、オープン環境では、「ZZZZZZZZ」以降のID一覧は照会されません。つまり、オープン環境に関する知識が不足し既存のメインフレーム環境に慣れているユーザーは、「11111111」というID情報が実際プログラムに存在するとしても、それを認知することが難しいです。
以下は、オープン環境においてすべてのID一覧を照会(AAAAAAAAの代わりに00000000を使用)する例です。
[User Address List] -------------------------------------------------------------------------- ID : 00000000 ID NAME ADDRESS ------------------------------------------------------------------------- 11111111 NOH SEOUL 88888888 KANG DAEJEON AAAAAAAA KIM SEOUL BBBBBBBB LEE PUSAN CCCCCCCC PARK SEOUL HHHHHHHH AHN DAEGU LLLLLLLL CHO GWANGJU MMMMMMMM CHOI INCHEON NNNNNNNN KWAK BUPYOUNG -------------------------------------------------------------------------- <F1> Menu <F2> Prev <F3> Next <Enter> Search
上記のような違いは、アプリケーション・プログラムのためではなく、アプリケーション・プログラムが使用する索引データセットのキー・フィールドのソート順において、メインフレームのEBCDIC文字とオープン環境のASCII文字のソート順が異なるために発生します。索引データセットや索引化されたデータベースを管理する製品では、文字ソート順を指定できる別途の方法を提供しているので、これを利用して問題を解決することができます。
OpenFrame TSAMのKSDSや、これを利用して実装されたOpenFrame NDBの索引データベースの場合、コピーブックにEBCタイプを定義してEBCDIC文字のソート順を使用することができます。EBCタイプの設定についての詳細は、OpenFrame Base『データセットガイド』の「OpenFrame VSAMのパフォーマンス最適化」を参照してください。 |
文字ソート順の違いによる問題もHEX値の処理と同様、プログラムの動作を直接確認した後に解決する必要があるため、熟練のコンサルタントにより問題を解決する方法を取っています。したがって、マイグレーションを行う作業者はこの問題について熟知している必要があります。
3. 2バイト空白の処理
メインフレーム環境において2バイト空白はX’4040’であり、1バイト空白のX’40’を2つ合わせた値と同じ値として認識されます。
10 W-K-00. 20 W-K-00-1 PIC X(01). 20 W-K-00-2 PIC X(01). 10 W-K-01 REDEFINES W-K-00. 20 W-K-01-1 PIC G(01). * . . . MOVE SPACE TO W-K-01-1. IF W-K-00-1 = SPACE THEN DISPLAY 'DOUBLE BYTE SPACE = SINGLE BYTE SPACE * 2' END-IF.
上記のCOBOLプログラムをメインフレーム環境で動作させると、「DOUBLE BYTE SPACE = SINGLE BYTE SPACE * 2」というメッセージが出力されますが、オープン環境で動作させるとこのメッセージは出力されません。
つまり、メインフレームで2バイト空白を処理する方式は、オープン環境に移行されたときに、ユーザー・プログラムのロジックが変更されるという結果をもたらします。
このような問題が発生する理由は、例えば、EUC-JPを使用するオープン環境へデータを変換する場合を仮定すると、EUC-JP文字セットでの2バイトの文字空白はX’8140’で、1バイトの文字空白はX’20’という値なので、メインフレーム環境とは違って「Single Byte Space + Single Byte Space = Double Byte Space」という特性が変換後に維持されないためです。
この問題を解決する方法は様々ですが、コンパイラーでサポートされる機能によって簡単に解決できる場合もあれば、解決できない場合もあります。
OpenFrameでは、オープン環境で2バイト空白を使用しない方法を解決策として提示しています。なるべく2バイト空白を使用しないようにし、どうしても必要な場合は1バイト空白2つで2バイト空白1つを代替する方法を使用しています。この方法を利用すると、ほとんどのCOBOLコンパイラーでは2バイト空白を無視するオプションを提供しているため、簡単に問題を解決することができます。
逆にOpenFrameのデータをメインフレームへ送信する状況では、2バイト空白が必要な場合なので、1バイト空白2つで代替する方法は使用できません。このような場合には、OpenFrameのCPM上で処理できるようにサポートしています。