︿
Top

2019年12月14日 星期六

[COBOL] ACUCOBOL COMP DATA TYPE 解析


0. 前言


最近的專案, 有將 ACUCOBOL 資料檔轉入至 DB 的需求.
最簡單的方式, 當然是針對每個 COBOL 資料檔, 撰寫 COBOL 程式, 各自轉為轉為固定長度的文字檔, 例如: 有 10 個資料檔, 就寫 10 支轉檔程式; 再採以下任一方案:
方案一: 撰寫 Java 或 C# 程式, 排程後, 定期轉至 DB.
方案二: 建立 SSIS Package (source: flat file, destination: ole db), 排程後, 定期轉至 DB.

但事與願違, 客戶想說, 是否可以採通用目的轉檔程式就好, 把整筆 COBOL 資料, 寫到 Binary Sequential 檔案; 由 Java 或 C# 讀取, 轉至 DB. 這樣就不需額外定義固定長度的文字檔 (即 COBOL 的 FD 檔), COBOL 的轉檔程式也變得很單純.

這是沒錯啦, COBOL 變單純了, 但 Java 或 C# 就會變複雜了.
然而並不是每一個 Java 或 C# 的程式設計師, 都了解 COBOL.
COBOL 主要有 2 種資料型態:

  • X: 字元型態.
  • 9: 數值型態.
    但因為古早的時候, 主機記憶體及磁碟空間有限, 所以有了 COMP 的壓縮方式, 以節省空間; 不只 COMP, 還有一些 SIGN LEADING, SIGN TRAILING ... 等的修飾詞.
要由 Java 或 C# 把 COMP 的內容解開, 必須理解各種 COMP 的資料壓縮方式.

筆者的第 1 份工作, 就是用 COBOL 寫醫療系統, 對 COMP 還有一些印象; 所以, 就上網查了一些資料, 並寫了一支 COBOL 程式, 作了一下驗證.
本文主要就是針對 COBOL 數值 COMP 型態的儲存格式, 進行整理.




1. 細節


1.1 編譯選項:

編譯選項, 會影響數值的編排方式.
細節可以參考 ACUCOBOL 的官方文件 (以下的參考文件1). 以下只是舉一些例子.

{編譯選項1}
COMP-4 (對應到 Java 或 C# 為 int) 會受 -D 選項的影響, 而造成 byte 數的差異. 如下圖:

(說明)
在預設的狀況, 即不作該編譯選項設定, 則:
PIC 9(1) COMP-4 ~~ PIC 9(4) COMP-4 為 2 byte unsigned integer ( 0 to 65,535 )
PIC 9(5) COMP-4 ~~ PIC 9(9) COMP-4 為 4 byte unsigned integer ( 0 to 4,294,967,295 )
PIC S9(1) COMP-4 ~~ PIC S9(4) COMP-4 為 2 byte integer ( -32,768 to 32,767 )
PIC S9(5) COMP-4 ~~ PIC S9(9) COMP-4 為 4 byte integer ( -2,147,483,648 to 2,147,483,647 )
(原理)
PIC 9(4) COMP-4 的最小值為 0, 最大值為 9999.
PIC S9(4) COMP-4 的最小值為 -9999; 最大值為 9999.
PIC 9(9) COMP-4 的最小值為 0, 最大值為 999,9999,999.
PIC S9(9) COMP-4 的最小值為 -999,999,999, 最大值為 999,999,999.
上述的 2 byte, 4 byte integer 的配置, 正好可以容納其值域.

{編譯選項2}
COMP-2, COMP-3 會受到 -Dc 選項的影響, 而造成內容的差異. 如下圖:

(說明)
COMP-2 的最後 "一個" byte 代表正負值符號. 例如: -Dca 的正值是用 0x0B, 負值是 0x0D
COMP-3 的最後 "半個" byte 代表正負值符號. 例如: -Dca 的正值是用 0xF, 負值是 0xD. 預設即是 0xF, 0xD

{編譯選項3}
SIGN LEADING, SIGN TRAILING, SIGN LEADING SEPARATE, SIGN TRAILING SEPARATE 先說明如下:
狀況一. PIC 9(n) 不論有無 SEPARATE 的, 都佔 n 個 bytes.
狀況二. PIC S9(n) 沒有 SEPARATE 的, 佔 n 個 bytes. 但它要如何表達數值呢? 就是用第1碼或最後1碼作編碼; 而其編碼原則, 會受編譯選項的影響.
狀況三. PIC S9(n) 有 SEPARATE 的, 佔 n + 1 個 bytes.
其中, 狀況二會受到 -Dc 選項的影響, 而造成內容的差異. 如下圖:

(說明) PIC S9(n) SIGN LEADING ...

[正值編碼] (沒有加 -Dci 的 compile option; 維持原值不變)
'0' -> '0'
'1' -> '1'
...
'9' -> '9'
[正值編碼] (有加 -Dci 的 compile option; 有作編碼)
'0' -> '{'
'1' -> 'A'
'2' -> 'B'
'3' -> 'C'
...
'9' -> 'I'

[負值編碼] (不論是否有加 -Dci 的 compile option, 都是如此編碼)
'0' -> '}'
'1' -> 'J'
'2' -> 'K'
'3' -> 'L'
...
'9' -> 'R'

可參考下圖.
上圖的測試程式, 可以參考 [附錄一].

1.2 官網範例:

在沒有 -Dci 的編譯選項下. 如下表格及截圖 (截圖是為了明顯標註差異)

PIC 9(3) VALUE 123.
 TRAILING            `1'   `2'   `3'   
 TRAILING SEPARATE   `1'   `2'   `3'   
 LEADING             `1'   `2'   `3'   
 LEADING SEPARATE    `1'   `2'   `3'   
 COMP-1                    00    7B   
 COMP-2              01    02    03   
 COMP-3                    12    3F   
 COMP-4                    00    7B   
 COMP-5(68000)             00    7B   
 COMP-5(8086)              7B    00   
 COMP-6                    01    23   
                        
PIC S9(3) VALUE -123.
TRAILING                 `1'   `2'   `L'    // 3 --> L 
TRAILING SEPARATE  `1'   `2'   `3'   `-'   
LEADING                  `J'   `2'   `3'    // 1 --> J
LEADING SEPARATE   `-'   `1'   `2'   `3'   
COMP-1                         FF    85   
COMP-2             01    02    03    0D   
COMP-3                         12    3D   
COMP-4                         FF    85   
COMP-5(68000)                  FF    85   
COMP-5(8086)                   85    FF   
COMP-6             illegal 
                            
                        
PIC 9(5)V9 VALUE 12345.6.
TRAILING             `1'   `2'   `3'   `4'   `5'   `6'   
TRAILING SEPARATE    `1'   `2'   `3'   `4'   `5'   `6'   
LEADING              `1'   `2'   `3'   `4'   `5'   `6'   
LEADING SEPARATE     `1'   `2'   `3'   `4'   `5'   `6'   
COMP-1               illegal   
COMP-2               01    02    03    04    05    06   
COMP-3                           01    23    45    6F   
COMP-4                           00    01    E2    40   
COMP-5(68000)                    00    01    E2    40   
COMP-5(8086)                     40    E2    01    00   
COMP-6                                 12    34    56                              
                        
PIC S9(5)V9 VALUE -12345.6.
TRAILING                `1'  `2'  `3'  `4'  `5'  `O'   // 6 --> O 
TRAILING SEPARATE  `1'  `2'  `3'  `4'  `5'  `6'  `-'   
LEADING                 `J'  `2'  `3'  `4'  `5'  `6'   // 1 --> J
LEADING SEPARATE   `-'  `1'  `2'  `3'  `4'  `5'  `6'   
COMP-1             illegal   
COMP-2             01   02   03   04   05   06   0D   
COMP-3                            01   23   45   6D   
COMP-4                            FF   FE   1D   C0   
COMP-5(68000)                     FF   FE   1D   C0   
COMP-5(8086)                      C0   1D   FE   FF   
COMP-6             illegal   
                        


2. 結論


若真的要實作客戶想要的方式, 除了要理解 COBOL 數值資料編碼要處理外, Java 或 C# 還要能夠解讀原有 COBOL FD (要計算各欄位的起始位置), 還有 BIG-5 字碼轉換 (造字) 的處理, 並不是那麼單純.
本文主要在介紹 ACUCOBOL COMP 數值的編碼方式, 有些 ANSI COBOL 並沒有明確規定. (例如: SIGN LEADING / SIGN TRAILING, 參考文件1. 第18點), 各家編譯器可能有不同的處理方式, 要留意.


3. 參考文件



4. [附錄一] 測試程式


       IDENTIFICATION DIVISION.
       PROGRAM-ID. PROGRAM1.

      * 測試 SIGN TRAILING / LEADING ... 
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
       SELECT PRINTF ASSIGN TO "SIGNTEST.TXT"
           ORGANIZATION IS LINE SEQUENTIAL.

       DATA DIVISION.
       FILE SECTION .
       FD PRINTF LABEL RECORD OMITTED.
       01  PRINT-REC.
           05  DATA-PRINT   PIC X(128).

       WORKING-STORAGE SECTION.
       01  WORK-AREA.
           05  I             PIC  9(6) VALUE 0.
           05  ANS           PIC X(01) VALUE SPACES.
       01  MY-DATA-0.
           05  CX901       PIC 9(03)  SIGN LEADING VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX902       PIC 9(03)  SIGN LEADING VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX903       PIC 9(03)  SIGN LEADING VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX904       PIC 9(03)  SIGN LEADING VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX905       PIC 9(03)  SIGN LEADING SEPARATE VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX906       PIC 9(03)  SIGN LEADING SEPARATE VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX907       PIC 9(03)  SIGN LEADING SEPARATE VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX908       PIC 9(03)  SIGN LEADING SEPARATE VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
       01  MY-DATA-1.
           05  CX911       PIC 9(03)  SIGN TRAILING VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX912       PIC 9(03)  SIGN TRAILING VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX913       PIC 9(03)  SIGN TRAILING VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX914       PIC 9(03)  SIGN TRAILING VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX915       PIC 9(03)  SIGN TRAILING SEPARATE VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX916       PIC 9(03)  SIGN TRAILING SEPARATE VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX917       PIC 9(03)  SIGN TRAILING SEPARATE VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX918       PIC 9(03)  SIGN TRAILING SEPARATE VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
       01  MY-DATA-2.
           05  CX921       PIC S9(03) SIGN LEADING VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX922       PIC S9(03) SIGN LEADING VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX923       PIC S9(03) SIGN LEADING VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX924       PIC S9(03) SIGN LEADING VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX925       PIC S9(03) SIGN LEADING SEPARATE VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX926       PIC S9(03) SIGN LEADING SEPARATE VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX927       PIC S9(03) SIGN LEADING SEPARATE VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX928       PIC S9(03) SIGN LEADING SEPARATE VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
       01  MY-DATA-3.
           05  CX931       PIC S9(03) SIGN TRAILING VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX932       PIC S9(03) SIGN TRAILING VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX933       PIC S9(03) SIGN TRAILING VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX934       PIC S9(03) SIGN TRAILING VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX935       PIC S9(03) SIGN TRAILING SEPARATE VALUE 120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX936       PIC S9(03) SIGN TRAILING SEPARATE VALUE 121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX937       PIC S9(03) SIGN TRAILING SEPARATE VALUE 123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX938       PIC S9(03) SIGN TRAILING SEPARATE VALUE 129.
           05  FILLER      PIC X(01)  VALUE X"09".
       01  MY-DATA-4.
           05  CX941       PIC S9(03) SIGN LEADING VALUE -120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX942       PIC S9(03) SIGN LEADING VALUE -121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX943       PIC S9(03) SIGN LEADING VALUE -123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX944       PIC S9(03) SIGN LEADING VALUE -129.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX945       PIC S9(03) SIGN LEADING SEPARATE VALUE -120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX946       PIC S9(03) SIGN LEADING SEPARATE VALUE -121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX947       PIC S9(03) SIGN LEADING SEPARATE VALUE -123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX948       PIC S9(03) SIGN LEADING SEPARATE VALUE -129.
           05  FILLER      PIC X(01)  VALUE X"09".
       01  MY-DATA-5.
           05  CX951       PIC S9(03) SIGN TRAILING VALUE -120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX952       PIC S9(03) SIGN TRAILING VALUE -121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX953       PIC S9(03) SIGN TRAILING VALUE -123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX954       PIC S9(03) SIGN TRAILING VALUE -129.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX955       PIC S9(03) SIGN TRAILING SEPARATE VALUE -120.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX956       PIC S9(03) SIGN TRAILING SEPARATE VALUE -121.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX957       PIC S9(03) SIGN TRAILING SEPARATE VALUE -123.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX958       PIC S9(03) SIGN TRAILING SEPARATE VALUE -129.
           05  FILLER      PIC X(01)  VALUE X"09".
       01  MY-DATA-6.
           05  CX951       PIC S9(03) SIGN TRAILING VALUE +0.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX952       PIC S9(03) SIGN TRAILING VALUE +1.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX953       PIC S9(03) SIGN TRAILING VALUE -0.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX954       PIC S9(03) SIGN TRAILING VALUE -1.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX955       PIC S9(03) SIGN TRAILING SEPARATE VALUE +0.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX956       PIC S9(03) SIGN TRAILING SEPARATE VALUE +1.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX957       PIC S9(03) SIGN TRAILING SEPARATE VALUE -0.
           05  FILLER      PIC X(01)  VALUE X"09".
           05  CX958       PIC S9(03) SIGN TRAILING SEPARATE VALUE -1.
           05  FILLER      PIC X(01)  VALUE X"09".

       PROCEDURE DIVISION.
       
       MAIN.
           OPEN OUTPUT PRINTF.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-0    TO DATA-PRINT.
           WRITE PRINT-REC.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-1    TO DATA-PRINT.
           WRITE PRINT-REC.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-2    TO DATA-PRINT.
           WRITE PRINT-REC.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-3    TO DATA-PRINT.
           WRITE PRINT-REC.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-4    TO DATA-PRINT.
           WRITE PRINT-REC.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-5    TO DATA-PRINT.
           WRITE PRINT-REC.

           MOVE SPACES       TO DATA-PRINT.
           MOVE MY-DATA-6    TO DATA-PRINT.
           WRITE PRINT-REC.

           CLOSE PRINTF.
           
           DISPLAY "Press anykey to continue ..." .
           ACCEPT ANS.
           EXIT PROGRAM.
           STOP RUN.

沒有留言:

張貼留言