はじめに
ここまでで、z/OS上のVSAMファイルをDb2, Kafkaにレプリケーションするための構成の流れを見てきました。インフラ設定とVSAMファイルごとのレプリケーション設定を合わせて実施しているので、操作の位置づけが分かりにくいかもしれません。
ここでは、一旦一通りの構成が出来た後に、レプリケーションするVSAMファイルが増えた場合の追加分の手順を追ってみます。TargetとしてはKafkaを使用します。
また、CICSアプリからVSAMファイルを更新し、その更新情報がKafka Topic上ににどのようなメッセージとして伝播されるのかを確認してみます。
関連記事
VSAM on z/OS のレプリケーション - (1) 環境構築(to Db2)
VSAM on z/OS のレプリケーション - (2) レプリケーション構成(to Db2)
VSAM on z/OS のレプリケーション - (3) Kafka連携
VSAM on z/OS のレプリケーション - (4) VSAMファイルの追加(Kafka連携) / レプリケーションのテスト
全体像
ソース側設定
VSAM, LOGSTREAMの準備
レプリケーション対象のVSAM(SMS対象のVOLに保持している必要あり) を選定します。既存のものがあれば、LOGREPLICATE, LOGSTREAMIDが指定されているかどうか確認します。指定されていなければ先の例に従ってログを取得するようパラメータを設定します。
今回は、新規にVSAMファイルを作成する想定で、以下のようなJCLでVSAMファイルを新規に作成することにします。
//DEFFILET JOB CLASS=A,MSGCLASS=X,MSGLEVEL=(1,1),NOTIFY=&SYSUID
//*********************************************************************
/*
//DELETE EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
/* DELETE A FILET DATASET */
DELETE DB2P.CT56B4A1.FILET
/*
//DEFINE EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
/* DEFINE A FILET DATASET */
DEFINE CLUSTER(NAME(DB2P.CT56B4A1.FILET)-
REC(200)-
LOG(ALL) -
LOGREPLICATE -
LOGSTREAMID(CEC.RMTLRS.CECREPL) -
STORAGECLASS(SCDB2K) INDEXED) -
DATA(NAME(DB2P.CT56B4A1.FILET.DATA)-
RECSZ(200 200)-
UNIQUE -
KEYS(6 0)) -
INDEX(NAME(DB2P.CT56B4A1.FILET.INDEX)-
UNIQUE -
SHR(2 3))
//*
1レコード200bytes、キーは先頭6bytesの想定です。また、LOGSTREAMは先に作成したものを使う想定です。別のLOGSTREAMを使用する場合は適宜LOGSTREAMも作成してください。
VSAM定義登録
参考: 1.1 VSAM定義登録
Linux上のコンテナとして稼働しているVSAM Remote Source上に、レプリケーション対象のVSAMファイルの情報を登録します。
コンテナに接続してClassicInstallAndMaintenanceMenu.shスクリプトを実行します。
[root@test12 ~]# podman exec -it --workdir /classic/usr/scripts ClassicCDCVSAM2 bash
[cecuser@ff6dc51e9523 scripts]$ ./ClassicInstallAndMaintenanceMenu.sh
*---------------------------------------------------------------------*
*
* IBM Data Replication VSAM for z/OS Remote Source, V11.4
* PID: 5737-C30
*
* Menu options:
* 1. Set the job card
* 2. Set the z/OS High Level Qualifier (HLQ)
* 3. Set the z/OS Unix System Services (USS) path
* 4. Install or replace z/OS libraries with this container's maintenance level
* 5. Start a new z/OS log reader
* 6. Stop the existing z/OS log reader
* 7. Get diagnostic log for the existing z/OS log reader
* 8. Configure a z/OS VSAM cluster for the container environment
* 9. Configure VSAM IVP file
* 10. Update container scripts from the current image
* 11. Generate diagnostics tar
* 99. Exit this script
*
*---------------------------------------------------------------------*
Select an option: 8
*---------------------------------------------------------------------*
*
* Classic CDC for VSAM
* Define a VSAM cluster to Linux components for refresh/replication
*
*---------------------------------------------------------------------*
Enter a VSAM base cluster data set name:DB2P.CT56B4A1.FILET
Enter the replication log to use for this VSAM DSN: CEC.RMTLRS.CECREPL
You provided DSN: <DB2P.CT56B4A1.FILET> with replication log: <CEC.RMTLRS.CECREPL>
Is this correct? (Y or N)y
DSN: <DB2P.CT56B4A1.FILET> added to <../../shell/vsamcat/vsamcat.txt>
Do you want to generate JCL to ALTER DSN: <DB2P.CT56B4A1.FILET> for change capture? (Y or N)n
Is CICS VR installed for VSAM batch logging? (Y or N)n
Do you want to generate JCL to DEFINE LOGSTREAM for replication log: <CEC.RMTLRS.CECREPL>? (Y or N)n
Should the IDCAMS ALTER JCL be submitted to your z/OS system? (Y or N)n
...
登録したいVSAMファイル(DB2P.CT56B4A1.FILET)、および、使用するLOGSTREAM(CEC.RMTLRS.CECREPL)の情報を登録します。各種JCLの生成はしません。ここで指定した情報はvsamcat.txtファイルに保持されます。
...
VSAMDD,DB2P.CT56B4A1.FILET,32760,0,20,C,K,Y,0,32764,Y,CEC.RMTLRS.CECREPL
VSAM表作成
参考: 1.5 VSAM表の作成
Classic Data ArchitectからVSAM Remote Sourceに接続してVSAM表を作成します。
COPYBOOKのインポート
ファイルに保持するレコードのレイアウトは以下のCOPYBOOKを使用する想定ですので、これをインポートします。インポートするプロジェクトは前回作成したものをそのまま使用します。(別プロジェクトとして作成したい場合はプロジェクトから作成してください。)
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE 'ThisIsROOT'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ全角漢文'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 FILLER PIC X(15) VALUE SPACE.
Classic Data Architect - クラシック参照ファイル を選択して次へ
ローカルホストを選択し、ファイル・タイプ: COBOLコピーブック、ファイル: 上のFILET.cpy を選択して次へ
VSAM表作成
物理データ・モデルも既存のものを使う想定です。物理データ・モデル以下のデータベースを右クリック - クラシック・オブジェクトの追加 - VSAM表を選択
適当なスキーマ名を指定し、照会、変更キャプチャーを選択して次へ
表名:FILET、データセットの名前: DB2P.CT56B4A1.FILET を指定して次へ
DDLの生成/適用
上で作成したVSAM表は、WindowsのCDA上のプロジェクトとして作成しただけなので、これをVSAM Remote Source上に反映させる必要があります。VSAM Remote Source上に反映させるためにはDDL(SQL)を生成してそれを実行する必要があります。
上で生成したVSAM表(FILET)を右クリック - DDLの生成を選択
ファイル名に適当な値を指定し、サーバー上でDDLを実行にチェックを入れて次へ
参考:上で作成されたDDL
--<ScriptOptions statementTerminator=";"/>
CREATE TABLE "TEST01"."FILET" DBTYPE VSAM
DS "DB2P.CT56B4A1.FILET"
(
"RT_KEY" SOURCE DEFINITION
DATAMAP OFFSET 0 LENGTH 6
DATATYPE C
USE AS CHAR(6),
"RT_ALPHA" SOURCE DEFINITION
DATAMAP OFFSET 6 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_ALPHAKANA" SOURCE DEFINITION
DATAMAP OFFSET 16 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_MIXDBCS" SOURCE DEFINITION
DATAMAP OFFSET 26 LENGTH 32
DATATYPE C
USE AS CHAR(32),
"RT_MIXALL" SOURCE DEFINITION
DATAMAP OFFSET 58 LENGTH 40
DATATYPE C
USE AS CHAR(40),
"RT_GRAPHIC" SOURCE DEFINITION
DATAMAP OFFSET 98 LENGTH 15
DATATYPE C
USE AS GRAPHIC(15),
"RT_DECIMAL" SOURCE DEFINITION
DATAMAP OFFSET 128 LENGTH 10
DATATYPE UC
USE AS CHAR(10),
"RT_PACKED" SOURCE DEFINITION
DATAMAP OFFSET 138 LENGTH 3
DATATYPE P
USE AS DECIMAL(5 , 0),
"RT_BINHALF" SOURCE DEFINITION
DATAMAP OFFSET 141 LENGTH 2
DATATYPE H
USE AS SMALLINT,
"RT_BINFULL" SOURCE DEFINITION
DATAMAP OFFSET 143 LENGTH 4
DATATYPE F
USE AS INTEGER,
"RT_BINDBLE" SOURCE DEFINITION
DATAMAP OFFSET 147 LENGTH 8
DATATYPE D
USE AS DECIMAL(12 , 0),
"RT_GRP01" SOURCE DEFINITION
DATAMAP OFFSET 155 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_GRP02" SOURCE DEFINITION
DATAMAP OFFSET 165 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_GRP03" SOURCE DEFINITION
DATAMAP OFFSET 175 LENGTH 10
DATATYPE C
USE AS CHAR(10));
ALTER TABLE "TEST01"."FILET" DATA CAPTURE CHANGES;
データ・ソース・エクスプローラー・ビューから、VSAM Remote Source上に反映されたVSAM表が確認できます。
ターゲット側設定
参考: ターゲット環境(Kafka)構築
ターゲット側は、先に作成したKafka Brokerを使用する想定なので特に追加指定する必要はありません。
レプリケーション構成
参考: レプリケーション構成
レプリケーション設定(サブスクリプション)
Management ConsoleからAccess Serverに接続してレプリケーションの構成を行います。ソース用データストア、ターゲット用データストアは作成済みの想定なので、サブスクリプションの設定から追加していきます。
構成タブに切り替えて、サブスクリプションビューの"新規サブスクリプションの作成"アイコンをクリックします。
適当な名前を指定し、データストアにはソースとしてVsamRemoteSource01、ターゲットとしてKafka_test01を指定し、拡張設定をクリック
確認のみ。(ソースIDとして前画面の名前の先頭8文字がとられるようなので、全画面の名前も8文字にしておくとよい)
キー列としてRT_KEYを選択して右矢印をクリック (キー列にRT_KEYが表示された状態にする)
次へ
Kafkaプロパティーの設定
上に表示された警告に従って、今作成したサブスクリプションを右クリック-Kafkaプロパティーを選択
ZooKeeper Serverを指定して、ZooKeeperのアドレス、ポートを指定します。また、Schema Registryのアドレス、ポートも指定します。
レプリケーション実行
リフレッシュ
まず最初に、現時点でのVSAMデータをKafkaに反映させておきます。
この時、CICSからはVSAMをClose状態にしておきます。
サブスクリプションを右クリック - リフレッシュの開始を選択
Kafka上のTopicのリストを参照してみます。
[root@test12 ~/Kafka]# /opt/confluent-6.2.0/bin/kafka-topics --list --bootstrap-server localhost:9092 | grep -i filet
cdc_kafka_test01-FILET01-commitstream
cdc_kafka_test01.filet01.sourcedb.vsam.test01.filet
kafka-avro-console-consumer
コマンドを使って Topic cdc_kafka_test01.filet01.sourcedb.vsam.test01.filet
のメッセージを参照してみます。
[root@test12 ~/Kafka]# /opt/confluent-6.2.0/bin/kafka-avro-console-consumer --from-beginning --topic cdc_kafka_test01.filet01.sourcedb.vsam.test01.filet --bootstrap-server localhost:9092 --property print.key=true --property print.schema.ids=true
{"RT_KEY":{"string":"000001"}} 3 {"RT_KEY":{"string":"000001"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}} 4
{"RT_KEY":{"string":"000002"}} 3 {"RT_KEY":{"string":"000002"},"RT_ALPHA":{"string":"11:11:54.3"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}} 4
{"RT_KEY":{"string":"000003"}} 3 {"RT_KEY":{"string":"000003"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}} 4
{"RT_KEY":{"string":"000004"}} 3 {"RT_KEY":{"string":"000004"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}} 4
スキーマ確認
[root@test12 ~]# curl -s http://localhost:8081/schemas/ids/4 | jq .schema | sed -e 's/^"//' -e 's/"$//' -e 's/\\//g' | jq .
{
"type": "record",
"name": "FILET",
"namespace": "value.SOURCEDB.VSAM.TEST01",
"fields": [
{
"name": "RT_KEY",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_KEY",
"length": 6
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_ALPHA",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_ALPHA",
"length": 10
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_ALPHAKANA",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_ALPHAKANA",
"length": 10
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_MIXDBCS",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_MIXDBCS",
"length": 32
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_MIXALL",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_MIXALL",
"length": 40
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_GRAPHIC",
"type": [
{
"type": "string",
"logicalType": "VARCHAR",
"dbColumnName": "RT_GRAPHIC",
"length": 15
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_DECIMAL",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_DECIMAL",
"length": 10
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_PACKED",
"type": [
{
"type": "int",
"logicalType": "DECIMAL",
"dbColumnName": "RT_PACKED",
"precision": 5,
"scale": 0
},
"null"
],
"doc": "",
"default": 0
},
{
"name": "RT_BINHALF",
"type": [
{
"type": "int",
"logicalType": "SMALLINT",
"dbColumnName": "RT_BINHALF"
},
"null"
],
"doc": "",
"default": 0
},
{
"name": "RT_BINFULL",
"type": [
{
"type": "int",
"logicalType": "INTEGER",
"dbColumnName": "RT_BINFULL"
},
"null"
],
"doc": "",
"default": 0
},
{
"name": "RT_BINDBLE",
"type": [
{
"type": "long",
"logicalType": "DECIMAL",
"dbColumnName": "RT_BINDBLE",
"precision": 12,
"scale": 0
},
"null"
],
"doc": "",
"default": 0
},
{
"name": "RT_GRP01",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_GRP01",
"length": 10
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_GRP02",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_GRP02",
"length": 10
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_GRP03",
"type": [
{
"type": "string",
"logicalType": "CHARACTER",
"dbColumnName": "RT_GRP03",
"length": 10
},
"null"
],
"doc": "",
"default": ""
}
]
}
ミラーリングの開始
サブスクリプションを右クリック - ミラーリングの開始を選択
モニタータブを開いて、指定したサブスクリプションの状態が"継続ミラーリング"になっていることを確認。
レプリケーションのテスト1
上の設定で、一通りVSAMファイルのレプリケーションの設定は済んだので、CICSアプリケーションからVSAMファイルを更新してその時の状況を確認してみます。
ここでは主に、DBCSや数値などいくつかの型を含むレコードのレプリケーション状況、および、Insert, Update, Delete処理がどのようにKafkaに伝播されるか、という辺りを見ていきます。
CICSアプリケーションの準備
単純なVSAMファイルアクセス用のプログラムをいくつか用意します。基本的にはCOMMAREAベースのアプリケーションで、キー値のみ指定して単発でVSAMファイルをアクセスするものです。テスト用なのでかなり単純化しています。
※更新系の操作のみKafkaへ反映されるので参照系のものはあまり意味が無いですが、一応作成しています。
レコード追加用
COMMAREAにキー値(6バイト)を指定して呼び出すと、キー値以外は固定の文字列(ソース中に埋め込まれた文字列)がセットされたレコードがVSAM(KSDS)に追加される。
実行例: CECI LINK PROGRAM(TGFADD) COMMAREA(000005)
ソース: TGFADD
IDENTIFICATION DIVISION.
PROGRAM-ID. TGFADD.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESP1 PIC S9(08) COMP VALUE 0.
01 Z-EIBFN PIC X(15) VALUE ' '.
01 Z-EIBRESP PIC 9(4) VALUE ZERO.
01 Z-EIBRESP2 PIC 9(4) VALUE ZERO.
01 CURRENT-DATE.
03 CURRENT-YEAR PIC 9(2).
03 CURRENT-MONTH PIC 9(2).
03 CURRENT-DAY PIC 9(2).
01 CURRENT-TIME.
03 CURRENT-HOUR PIC 9(2).
03 CURRENT-MINUTE PIC 9(2).
03 CURRENT-SECOND PIC 9(2).
03 CURRENT-HNDSEC PIC 9(2).
01 WS-RAWTIME PIC S9(15) COMP-3.
01 CURRENT-DATE-CICS PIC X(8).
01 CURRENT-TIME-CICS PIC X(8).
01 TSQ-NAME PIC X(8) VALUE 'TSQTESTQ'.
01 FILE-NAME PIC X(8) VALUE 'FILET'.
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE 'ThisIsROOT'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ全角漢文'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 FILLER PIC X(15) VALUE SPACE.
01 TEMP-RECORD PIC X(200).
*---------------------------------------------------------------
LINKAGE SECTION.
01 DFHCOMMAREA.
03 COMMAREA-DATA PIC X(6).
*---------------------------------------------------------------
PROCEDURE DIVISION.
DISPLAY 'TGFADD Start-------------'
* Get Timestamp from ACCEPT
ACCEPT CURRENT-DATE FROM DATE.
ACCEPT CURRENT-TIME FROM TIME.
DISPLAY 'ACCEPT DATE = ' CURRENT-MONTH '/'
CURRENT-DAY '/' CURRENT-YEAR ' (mm/dd/yy)'.
DISPLAY ' TIME = ' CURRENT-HOUR ':'
CURRENT-MINUTE ':' CURRENT-SECOND '.' CURRENT-HNDSEC
* Display COMMAREA
DISPLAY ' Received COMMAREA: ' COMMAREA-DATA.
* Move COMMAREA-DATA to Key
IF EIBCALEN > 0 AND EIBCALEN < 7 THEN
MOVE COMMAREA-DATA TO RT-KEY
END-IF.
* WRITEQ TS
EXEC CICS WRITEQ TS QUEUE(TSQ-NAME)
FROM(RT-SEG)
LENGTH(LENGTH OF RT-SEG)
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** WRITEQ TS ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'WRITEQ TS OK'
END-IF.
* WRITE FILE (Add Record)
EXEC CICS WRITE FILE(FILE-NAME)
FROM(RT-SEG)
RIDFLD(RT-KEY)
LENGTH(LENGTH OF RT-SEG)
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** WRITE FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
IF Z-EIBRESP = DFHRESP(DUPREC) THEN
DISPLAY 'DUPLICATTE KEY!'
END-IF
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'WRITE FILE OK'
END-IF.
* Display Data
DISPLAY '*****'.
* DISPLAY 'LENGTH Total: ' LENGTH OF RT-SEG.
* DISPLAY 'LENGTH RT-PACKED: ' LENGTH OF RT-PACKED.
* DISPLAY 'LENGTH RT-BINHALF: ' LENGTH OF RT-BINHALF.
* DISPLAY 'LENGTH RT-BINFULL: ' LENGTH OF RT-BINFULL.
* DISPLAY 'LENGTH RT-BINDBLE: ' LENGTH OF RT-BINDBLE.
DISPLAY RT-SEG.
DISPLAY '*****'.
* Delay
EXEC CICS DELAY FOR SECONDS(1) END-EXEC.
* End
DISPLAY 'TGFADD End---------------'.
EXEC CICS RETURN END-EXEC.
レコード更新用
COMMAREAにキー値(6バイト)を指定して呼び出すと、指定したキー値を持つレコードの情報を上書きする。
基本的にはキー値以外は固定の文字列(ソース中に埋め込まれた文字列)がセットされたレコードがVSAM(KSDS)に追加される。
ただし、RT-ALPHAフィールドには実行時のタイムスタンプをセットし、また、RT-MIXDBCSフィールドには環境依存文字を含む文字列をセットする。
実行例: CECI LINK PROGRAM(TGFUPDT) COMMAREA(000005)
ソース: TGFUPDT
IDENTIFICATION DIVISION.
PROGRAM-ID. TGFUPDT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESP1 PIC S9(08) COMP VALUE 0.
01 Z-EIBFN PIC X(15) VALUE ' '.
01 Z-EIBRESP PIC 9(4) VALUE ZERO.
01 Z-EIBRESP2 PIC 9(4) VALUE ZERO.
01 CURRENT-DATE.
03 CURRENT-YEAR PIC 9(2).
03 CURRENT-MONTH PIC 9(2).
03 CURRENT-DAY PIC 9(2).
01 CURRENT-TIME.
03 CURRENT-HOUR PIC 9(2).
03 CURRENT-MINUTE PIC 9(2).
03 CURRENT-SECOND PIC 9(2).
03 CURRENT-HNDSEC PIC 9(2).
01 WS-RAWTIME PIC S9(15) COMP-3.
01 CURRENT-DATE-CICS PIC X(8).
01 CURRENT-TIME-CICS PIC X(8).
01 TSQ-NAME PIC X(8) VALUE 'TSQTESTQ'.
01 FILE-NAME PIC X(8) VALUE 'FILET'.
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE '00:00:00.0'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ㈱①Ⅰ鯵鰺'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 FILLER PIC X(15) VALUE SPACE.
01 TEMP-SEG.
02 TEMP-KEY PIC X(06).
02 TEMP-ALPHA PIC X(10).
02 TEMP-ALPHAKANA PIC X(10).
02 TEMP-MIXDBCS PIC X(32).
02 TEMP-MIXALL PIC X(40).
02 TEMP-GRAPHIC PIC G(15) USAGE DISPLAY-1.
02 TEMP-DECIMAL PIC 9(10) .
02 TEMP-PACKED PIC S9(05) COMP-3.
02 TEMP-BINHALF PIC S9(04) COMP.
02 TEMP-BINFULL PIC S9(08) COMP.
02 TEMP-BINDBLE PIC S9(12) COMP.
02 TEMP-GROUP.
03 TEMP-GRP01 PIC X(10).
03 TEMP-GRP02 PIC X(10).
03 TEMP-GRP03 PIC X(10).
02 FILLER PIC X(15).
01 CURRENT-TIME-STR PIC X(10) VALUE '00:00:00.0'.
*---------------------------------------------------------------
LINKAGE SECTION.
01 DFHCOMMAREA.
03 COMMAREA-DATA PIC X(6).
*---------------------------------------------------------------
PROCEDURE DIVISION.
DISPLAY 'TGFUPDT Start-------------'
* Get Timestamp from ACCEPT
ACCEPT CURRENT-DATE FROM DATE.
ACCEPT CURRENT-TIME FROM TIME.
DISPLAY 'ACCEPT DATE = ' CURRENT-MONTH '/'
CURRENT-DAY '/' CURRENT-YEAR ' (mm/dd/yy)'.
DISPLAY ' TIME = ' CURRENT-HOUR ':'
CURRENT-MINUTE ':' CURRENT-SECOND '.' CURRENT-HNDSEC
* Display COMMAREA
DISPLAY ' Received COMMAREA: ' COMMAREA-DATA.
* Move COMMAREA-DATA to Key
IF EIBCALEN > 0 AND EIBCALEN < 7 THEN
MOVE COMMAREA-DATA TO RT-KEY
MOVE COMMAREA-DATA TO TEMP-KEY
END-IF.
* READ FILE with UPDATE (Read Record)
EXEC CICS READ FILE(FILE-NAME)
INTO(TEMP-SEG)
RIDFLD(TEMP-KEY)
LENGTH(LENGTH OF TEMP-SEG)
UPDATE
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** READ FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
IF Z-EIBRESP = DFHRESP(NOTFND) THEN
DISPLAY 'NOT FOUND!'
END-IF
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'READ FILE OK'
END-IF.
* Display Data
DISPLAY 'Before Data*****'.
* DISPLAY 'LENGTH Total: ' LENGTH OF RT-SEG.
* DISPLAY 'LENGTH RT-PACKED: ' LENGTH OF RT-PACKED.
* DISPLAY 'LENGTH RT-BINHALF: ' LENGTH OF RT-BINHALF.
* DISPLAY 'LENGTH RT-BINFULL: ' LENGTH OF RT-BINFULL.
* DISPLAY 'LENGTH RT-BINDBLE: ' LENGTH OF RT-BINDBLE.
DISPLAY TEMP-SEG.
DISPLAY '*****'.
* Set Current Time to New Record
STRING CURRENT-HOUR, ':'
CURRENT-MINUTE, ':',
CURRENT-SECOND, '.'
CURRENT-HNDSEC(1:1)
DELIMITED BY SIZE INTO CURRENT-TIME-STR.
MOVE CURRENT-TIME-STR TO RT-ALPHA.
* REWRITE FILE (Update Record)
EXEC CICS REWRITE FILE(FILE-NAME)
FROM(RT-SEG)
LENGTH(LENGTH OF RT-SEG)
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** REWRITE FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'REWRITE FILE OK'
END-IF.
* Display Data
DISPLAY 'After Data*****'.
* DISPLAY 'LENGTH Total: ' LENGTH OF RT-SEG.
* DISPLAY 'LENGTH RT-PACKED: ' LENGTH OF RT-PACKED.
* DISPLAY 'LENGTH RT-BINHALF: ' LENGTH OF RT-BINHALF.
* DISPLAY 'LENGTH RT-BINFULL: ' LENGTH OF RT-BINFULL.
* DISPLAY 'LENGTH RT-BINDBLE: ' LENGTH OF RT-BINDBLE.
DISPLAY RT-SEG.
DISPLAY '*****'.
* Delay
EXEC CICS DELAY FOR SECONDS(1) END-EXEC.
* End
DISPLAY 'TGFUPDT End---------------'.
EXEC CICS RETURN END-EXEC.
レコード削除用
COMMAREAにキー値(6バイト)を指定して呼び出すと、指定したキー値を持つレコードが削除される。
実行例: CECI LINK PROGRAM(TGFDEL) COMMAREA(000005)
ソース: TGFDEL
IDENTIFICATION DIVISION.
PROGRAM-ID. TGFDEL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESP1 PIC S9(08) COMP VALUE 0.
01 Z-EIBFN PIC X(15) VALUE ' '.
01 Z-EIBRESP PIC 9(4) VALUE ZERO.
01 Z-EIBRESP2 PIC 9(4) VALUE ZERO.
01 CURRENT-DATE.
03 CURRENT-YEAR PIC 9(2).
03 CURRENT-MONTH PIC 9(2).
03 CURRENT-DAY PIC 9(2).
01 CURRENT-TIME.
03 CURRENT-HOUR PIC 9(2).
03 CURRENT-MINUTE PIC 9(2).
03 CURRENT-SECOND PIC 9(2).
03 CURRENT-HNDSEC PIC 9(2).
01 WS-RAWTIME PIC S9(15) COMP-3.
01 CURRENT-DATE-CICS PIC X(8).
01 CURRENT-TIME-CICS PIC X(8).
01 TSQ-NAME PIC X(8) VALUE 'TSQTESTQ'.
01 FILE-NAME PIC X(8) VALUE 'FILET'.
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE 'ThisIsROOT'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ全角漢文'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 FILLER PIC X(15) VALUE SPACE.
*---------------------------------------------------------------
LINKAGE SECTION.
01 DFHCOMMAREA.
03 COMMAREA-DATA PIC X(6).
*---------------------------------------------------------------
PROCEDURE DIVISION.
DISPLAY 'TGFDEL Start-------------'
* Get Timestamp from ACCEPT
ACCEPT CURRENT-DATE FROM DATE.
ACCEPT CURRENT-TIME FROM TIME.
DISPLAY 'ACCEPT DATE = ' CURRENT-MONTH '/'
CURRENT-DAY '/' CURRENT-YEAR ' (mm/dd/yy)'.
DISPLAY ' TIME = ' CURRENT-HOUR ':'
CURRENT-MINUTE ':' CURRENT-SECOND '.' CURRENT-HNDSEC
* Display COMMAREA
DISPLAY ' Received COMMAREA: ' COMMAREA-DATA.
* Move COMMAREA-DATA to Key
IF EIBCALEN > 0 AND EIBCALEN < 7 THEN
MOVE COMMAREA-DATA TO RT-KEY
END-IF.
* DELETE FILE
EXEC CICS DELETE FILE(FILE-NAME)
RIDFLD(RT-KEY)
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** DELETE FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
IF Z-EIBRESP = DFHRESP(NOTFND) THEN
DISPLAY 'NOT FOUND!'
END-IF
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'DELETE FILE OK'
END-IF.
* Display Data
* DISPLAY '*****'.
* DISPLAY 'LENGTH Total: ' LENGTH OF RT-SEG.
* DISPLAY 'LENGTH RT-PACKED: ' LENGTH OF RT-PACKED.
* DISPLAY 'LENGTH RT-BINHALF: ' LENGTH OF RT-BINHALF.
* DISPLAY 'LENGTH RT-BINFULL: ' LENGTH OF RT-BINFULL.
* DISPLAY 'LENGTH RT-BINDBLE: ' LENGTH OF RT-BINDBLE.
* DISPLAY RT-SEG.
* DISPLAY '*****'.
* Delay
EXEC CICS DELAY FOR SECONDS(1) END-EXEC.
* End
DISPLAY 'TGFDEL End---------------'.
EXEC CICS RETURN END-EXEC.
レコード参照用(1レコード)
COMMAREAにキー値(6バイト)を指定して呼び出すと、指定したキー値をもつレコード(1件)を読み、内容をDISPLAY文で出力(JOBLOGのCEEMSGで確認)。
実行例: CECI LINK PROGRAM(TGFREAD) COMMAREA(000001)
ソース: TGFREAD
IDENTIFICATION DIVISION.
PROGRAM-ID. TGFREAD.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESP1 PIC S9(08) COMP VALUE 0.
01 Z-EIBFN PIC X(15) VALUE ' '.
01 Z-EIBRESP PIC 9(4) VALUE ZERO.
01 Z-EIBRESP2 PIC 9(4) VALUE ZERO.
01 CURRENT-DATE.
03 CURRENT-YEAR PIC 9(2).
03 CURRENT-MONTH PIC 9(2).
03 CURRENT-DAY PIC 9(2).
01 CURRENT-TIME.
03 CURRENT-HOUR PIC 9(2).
03 CURRENT-MINUTE PIC 9(2).
03 CURRENT-SECOND PIC 9(2).
03 CURRENT-HNDSEC PIC 9(2).
01 WS-RAWTIME PIC S9(15) COMP-3.
01 CURRENT-DATE-CICS PIC X(8).
01 CURRENT-TIME-CICS PIC X(8).
01 TSQ-NAME PIC X(8) VALUE 'TSQTESTQ'.
01 FILE-NAME PIC X(8) VALUE 'FILET'.
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE 'ThisIsROOT'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ全角漢文'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 FILLER PIC X(15) VALUE SPACE.
01 TEMP-SEG.
02 TEMP-KEY PIC X(06).
02 TEMP-ALPHA PIC X(10).
02 TEMP-ALPHAKANA PIC X(10).
02 TEMP-MIXDBCS PIC X(32).
02 TEMP-MIXALL PIC X(40).
02 TEMP-GRAPHIC PIC G(15) USAGE DISPLAY-1.
02 TEMP-DECIMAL PIC 9(10) .
02 TEMP-PACKED PIC S9(05) COMP-3.
02 TEMP-BINHALF PIC S9(04) COMP.
02 TEMP-BINFULL PIC S9(08) COMP.
02 TEMP-BINDBLE PIC S9(12) COMP.
02 TEMP-GROUP.
03 TEMP-GRP01 PIC X(10).
03 TEMP-GRP02 PIC X(10).
03 TEMP-GRP03 PIC X(10).
02 FILLER PIC X(15).
*---------------------------------------------------------------
LINKAGE SECTION.
01 DFHCOMMAREA.
03 COMMAREA-DATA PIC X(6).
*---------------------------------------------------------------
PROCEDURE DIVISION.
DISPLAY 'TGFREAD Start-------------'
* Get Timestamp from ACCEPT
ACCEPT CURRENT-DATE FROM DATE.
ACCEPT CURRENT-TIME FROM TIME.
DISPLAY 'ACCEPT DATE = ' CURRENT-MONTH '/'
CURRENT-DAY '/' CURRENT-YEAR ' (mm/dd/yy)'.
DISPLAY ' TIME = ' CURRENT-HOUR ':'
CURRENT-MINUTE ':' CURRENT-SECOND '.' CURRENT-HNDSEC
* Display COMMAREA
DISPLAY ' Received COMMAREA: ' COMMAREA-DATA.
* Move COMMAREA-DATA to Key
IF EIBCALEN > 0 AND EIBCALEN < 7 THEN
MOVE COMMAREA-DATA TO TEMP-KEY
END-IF.
* READ FILE (Read Record)
EXEC CICS READ FILE(FILE-NAME)
INTO(TEMP-SEG)
RIDFLD(TEMP-KEY)
LENGTH(LENGTH OF TEMP-SEG)
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** READ FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
IF Z-EIBRESP = DFHRESP(NOTFND) THEN
DISPLAY 'NOT FOUND!'
END-IF
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'READ FILE OK'
END-IF.
* Display Data
DISPLAY '*****'.
* DISPLAY 'LENGTH Total: ' LENGTH OF RT-SEG.
* DISPLAY 'LENGTH RT-PACKED: ' LENGTH OF RT-PACKED.
* DISPLAY 'LENGTH RT-BINHALF: ' LENGTH OF RT-BINHALF.
* DISPLAY 'LENGTH RT-BINFULL: ' LENGTH OF RT-BINFULL.
* DISPLAY 'LENGTH RT-BINDBLE: ' LENGTH OF RT-BINDBLE.
DISPLAY TEMP-SEG.
DISPLAY '*****'.
* Delay
EXEC CICS DELAY FOR SECONDS(1) END-EXEC.
* End
DISPLAY 'TGFREAD End---------------'.
EXEC CICS RETURN END-EXEC.
レコード参照用(複数レコード)
COMMAREAにキー値(6バイト)を指定して呼び出すと、指定したキー値以降のレコードを読み、内容をDISPLAY文で出力(JOBLOGのCEEMSGで確認)。
実行例: CECI LINK PROGRAM(TGFREAD) COMMAREA(000001)
ソース: TGFLIST
IDENTIFICATION DIVISION.
PROGRAM-ID. TGFLIST.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 RESP1 PIC S9(08) COMP VALUE 0.
01 Z-EIBFN PIC X(15) VALUE ' '.
01 Z-EIBRESP PIC 9(4) VALUE ZERO.
01 Z-EIBRESP2 PIC 9(4) VALUE ZERO.
01 CURRENT-DATE.
03 CURRENT-YEAR PIC 9(2).
03 CURRENT-MONTH PIC 9(2).
03 CURRENT-DAY PIC 9(2).
01 CURRENT-TIME.
03 CURRENT-HOUR PIC 9(2).
03 CURRENT-MINUTE PIC 9(2).
03 CURRENT-SECOND PIC 9(2).
03 CURRENT-HNDSEC PIC 9(2).
01 WS-RAWTIME PIC S9(15) COMP-3.
01 CURRENT-DATE-CICS PIC X(8).
01 CURRENT-TIME-CICS PIC X(8).
01 TSQ-NAME PIC X(8) VALUE 'TSQTESTQ'.
01 FILE-NAME PIC X(8) VALUE 'FILET'.
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE 'ThisIsROOT'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ全角漢文'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 FILLER PIC X(15) VALUE SPACE.
01 TEMP-SEG.
02 TEMP-KEY PIC X(06).
02 TEMP-ALPHA PIC X(10).
02 TEMP-ALPHAKANA PIC X(10).
02 TEMP-MIXDBCS PIC X(32).
02 TEMP-MIXALL PIC X(40).
02 TEMP-GRAPHIC PIC G(15) USAGE DISPLAY-1.
02 TEMP-DECIMAL PIC 9(10) .
02 TEMP-PACKED PIC S9(05) COMP-3.
02 TEMP-BINHALF PIC S9(04) COMP.
02 TEMP-BINFULL PIC S9(08) COMP.
02 TEMP-BINDBLE PIC S9(12) COMP.
02 TEMP-GROUP.
03 TEMP-GRP01 PIC X(10).
03 TEMP-GRP02 PIC X(10).
03 TEMP-GRP03 PIC X(10).
02 FILLER PIC X(15).
01 SRCH-KEY PIC X(10).
01 LINE-CNT PIC S9(4) COMP VALUE +0.
*---------------------------------------------------------------
LINKAGE SECTION.
01 DFHCOMMAREA.
03 COMMAREA-DATA PIC X(6).
*---------------------------------------------------------------
PROCEDURE DIVISION.
DISPLAY 'TGFLIST Start-------------'
* Get Timestamp from ACCEPT
ACCEPT CURRENT-DATE FROM DATE.
ACCEPT CURRENT-TIME FROM TIME.
DISPLAY 'ACCEPT DATE = ' CURRENT-MONTH '/'
CURRENT-DAY '/' CURRENT-YEAR ' (mm/dd/yy)'.
DISPLAY ' TIME = ' CURRENT-HOUR ':'
CURRENT-MINUTE ':' CURRENT-SECOND '.' CURRENT-HNDSEC
* Display COMMAREA
DISPLAY ' Received COMMAREA: ' COMMAREA-DATA.
* Move COMMAREA-DATA to Key
IF EIBCALEN > 0 AND EIBCALEN < 7 THEN
MOVE COMMAREA-DATA TO SRCH-KEY
END-IF.
* READ All Record
SRCH-RESUME.
EXEC CICS STARTBR FILE(FILE-NAME)
RIDFLD(SRCH-KEY) GTEQ
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** STARTBR FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
IF Z-EIBRESP = DFHRESP(NOTFND) THEN
DISPLAY 'NOT FOUND!'
END-IF
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
DISPLAY 'STARTBR FILE OK'
END-IF.
SRCH-LOOP.
EXEC CICS READNEXT FILE(FILE-NAME)
INTO(TEMP-SEG)
RIDFLD(SRCH-KEY)
LENGTH(LENGTH OF TEMP-SEG)
RESP(Z-EIBRESP)
RESP2(Z-EIBRESP2)
END-EXEC.
IF Z-EIBRESP = DFHRESP(ENDFILE) THEN
DISPLAY '*****'
GO TO SRCH-DONE
END-IF.
IF Z-EIBRESP NOT = DFHRESP(NORMAL) THEN
DISPLAY '***** READNEXT FILE ERROR!'
DISPLAY 'RESP: ' Z-EIBRESP
DISPLAY 'RESP2: ' Z-EIBRESP2
IF Z-EIBRESP = DFHRESP(NOTFND) THEN
DISPLAY 'NOT FOUND!'
END-IF
EXEC CICS ABEND ABCODE('TTTT') END-EXEC
EXEC CICS RETURN END-EXEC
ELSE
ADD 1 TO LINE-CNT
DISPLAY LINE-CNT ' : *****'
DISPLAY TEMP-SEG
GO TO SRCH-LOOP
END-IF.
SRCH-DONE.
EXEC CICS ENDBR FILE(FILE-NAME) END-EXEC.
* Delay
EXEC CICS DELAY FOR SECONDS(1) END-EXEC.
* End
DISPLAY 'TGFLIST End---------------'.
EXEC CICS RETURN END-EXEC.
参考: コンパイル用JCLサンプル
コンパイル用JCLサンプル
コンパイル用JCLのテンプレートです(@ProgName@はソースのメンバー名に置き換え)。
CICS TS V5.6を使用している想定です。
データセット名等は適宜環境に合わせて変更する必要があります。
//TRANCBL JOB MSGLEVEL=(1,1),CLASS=A,MSGCLASS=X,NOTIFY=&SYSUID
//DFHYITVL PROC SUFFIX=1$, Suffix for translator module
// INDEX='CICSTS56.CICS', Qualifier(s) for CICS libraries
// PROGLIB='CICSTS56.CICS.SDFHLOAD', Name of o/p library
// DSCTLIB='CICSTS56.CICS.SDFHCOB', Private macro/dsect
// AD370HLQ='LANG.IGY.V6R1M0', Qualifier(s) for AD/Cycle compiler
// LE370HLQ='CEE', Qualifier(s) for LE/370 libraries
// OUTC=*, Class for print output
// REG=0M, Region size for all steps
// TRNPARM='COBOL3,SP,DBCS',
// COBPARM='NODYNAM,OBJECT,RENT,APOST,MAP,XREF,TRUNC(BIN)',
// LNKPARM='LIST,XREF,REUS=RENT', Link edit parameters
// STUB='DFHEILID', Lked INC. for DFHELII
// LIB='SDFHSAMP', Library
// WORK=SYSDA Unit for work datasets
//*
//* This procedure generates a COBOL module.
//*
//* This procedure contains 4 steps
//* 1. Exec the COBOL translator
//* (using the supplied suffix 1$)
//* 2. Exec the COBOL compiler
//* 3. Reblock &LIB(&STUB) for use by the linkedit step
//* 4. Linkedit the output into dataset &PROGLIB
//*
//* The following JCL should be used
//* to execute this procedure
//*
//* //APPLPROG EXEC DFHYITVL
//* //TRN.SYSIN DD *
//* .
//* . Application program
//* .
//* /*
//* //LKED.SYSIN DD *
//* NAME anyname(R)
//* /*
//*
//* Where anyname is the name of your application program.
//* (Refer to the system definition guide for full details,
//* including what to do if your program contains calls to
//* the common programming interface.)
//*
//TRN EXEC PGM=DFHECP&SUFFIX,
// PARM='&TRNPARM', @01C
// REGION=®
//STEPLIB DD DSN=&INDEX..SDFHLOAD,DISP=SHR
//SYSPRINT DD SYSOUT=&OUTC
//SYSPUNCH DD DSN=&&SYSCIN,
// DISP=(,PASS),UNIT=&WORK,
// DCB=BLKSIZE=400,
// SPACE=(400,(400,100))
//*
//COB EXEC PGM=IGYCRCTL,REGION=®,PARM='&COBPARM'
//STEPLIB DD DSN=&AD370HLQ..SIGYCOMP,DISP=SHR
//SYSLIB DD DSN=&DSCTLIB,DISP=SHR
// DD DSN=&INDEX..SDFHCOB,DISP=SHR
// DD DSN=&INDEX..SDFHMAC,DISP=SHR
// DD DSN=&INDEX..SDFHSAMP,DISP=SHR
//* DD DSN=CICSTS56.@DBDC.DSCTLIB,DISP=SHR
//SYSPRINT DD SYSOUT=&OUTC
//SYSIN DD DSN=&&SYSCIN,DISP=(OLD,DELETE)
//SYSLIN DD DSN=&&LOADSET,DISP=(MOD,PASS),
// UNIT=&WORK,SPACE=(80,(250,100))
//SYSMDECK DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT1 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT2 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT3 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT4 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT5 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT6 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT7 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT8 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT9 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT10 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT11 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT12 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT13 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT14 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT15 DD UNIT=&WORK,SPACE=(460,(350,100))
//*
//COPYLINK EXEC PGM=IEBGENER,COND=(7,LT,COB)
//SYSUT1 DD DSN=&INDEX..&LIB(&STUB),DISP=SHR
//SYSUT2 DD DSN=&©LINK,DISP=(NEW,PASS),
// DCB=(LRECL=80,BLKSIZE=400,RECFM=FB),
// UNIT=&WORK,SPACE=(400,(20,20))
//SYSPRINT DD SYSOUT=&OUTC
//SYSIN DD DUMMY
//*
//LKED EXEC PGM=IEWL,REGION=®,
// PARM='&LNKPARM',COND=(5,LT,COB)
//SYSLIB DD DSN=&INDEX..SDFHLOAD,DISP=SHR
// DD DSN=&LE370HLQ..SCEELKED,DISP=SHR
//SYSLMOD DD DSN=&PROGLIB,DISP=SHR
//SYSUT1 DD UNIT=&WORK,DCB=BLKSIZE=1024,
// SPACE=(1024,(200,20))
//SYSPRINT DD SYSOUT=&OUTC
//SYSLIN DD DSN=&©LINK,DISP=(OLD,DELETE)
// DD DSN=&&LOADSET,DISP=(OLD,DELETE)
// DD DDNAME=SYSIN
//*
// PEND
//*********************************************************************
//* RUN INSTREAM-PROCEDURE *
//*********************************************************************
//@COBOL EXEC DFHYITVL
//TRN.SYSIN DD DISP=SHR,DSN=CICSTS56.@DBDC.PGMSOR(@ProgName@)
//LKED.SYSLMOD DD DISP=SHR,DSN=CICSTS56.@DBDC.USERLIB.PDSE
//LKED.SYSIN DD *
MODE AMODE(31),RMODE(ANY)
NAME @ProgName@(R)
/*
CICS資源定義
FILE定義
CEDA View File( FILET )
File : FILET
Group : TAGGRP
DEScription :
VSAM PARAMETERS
DSNAme : DB2P.CT56B4A1.FILET
Password : PASSWORD NOT SPECIFIED
RLsaccess : No Yes | No
LSRPOOLId : 1 1-8 | None
LSRPOOLNum : 001 1-255 | None
READInteg : Uncommitted Uncommitted | Consistent | Repeatable
DSNSharing : Allreqs Allreqs | Modifyreqs
STRings : 003 1-255
Nsrgroup :
REMOTE ATTRIBUTES
REMOTESystem :
REMOTEName :
REMOTE AND CFDATATABLE PARAMETERS
...
PROGRAM定義
CEDA View PROGram( TGFADD )
PROGram : TGFADD
Group : TAGGRP
DEScription :
Language : CObol | Assembler | Le370 | C | Pli
RELoad : No No | Yes
RESident : No No | Yes
USAge : Normal Normal | Transient
USElpacopy : No No | Yes
Status : Enabled Enabled | Disabled
RSl : 00 0-24 | Public
CEdf : Yes Yes | No
DAtalocation : Any Below | Any
EXECKey : User User | Cics
COncurrency : Quasirent Quasirent | Threadsafe | Required
Api : Cicsapi Cicsapi | Openapi
REMOTE ATTRIBUTES
DYnamic : No No | Yes
同様に、TAGFUPDT、TAGFDEL、TAGFREAD、TAGFLIST についてもプログラム定義を追加。
テスト実行
リフレッシュ直後のTopicの状態確認
[root@test12 ~/Kafka]# /opt/confluent-6.2.0/bin/kafka-avro-console-consumer --from-beginning --topic cdc_kafka_test01.filet01.sourcedb.vsam.test01.filet --bootstrap-server localhost:9092 --property print.key=true
{"RT_KEY":{"string":"000001"}} {"RT_KEY":{"string":"000001"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}}
{"RT_KEY":{"string":"000002"}} {"RT_KEY":{"string":"000002"},"RT_ALPHA":{"string":"11:11:54.3"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}}
{"RT_KEY":{"string":"000003"}} {"RT_KEY":{"string":"000003"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}}
{"RT_KEY":{"string":"000004"}} {"RT_KEY":{"string":"000004"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}}
VSAM上に4つのレコードがある状態。ここからミラーリングを開始します。
レコード追加
TGFADDプログラムを動かしてKey:000005のレコードを追加してみます。
Topicに以下のメッセージが追加されました。
{"RT_KEY":{"string":"000005"}} {"RT_KEY":{"string":"000005"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}}
レコード更新
TGFUPDTプログラムを動かしてKey:000005のレコードを更新してみます。
Topicに以下のメッセージが追加されました。
{"RT_KEY":{"string":"000005"}} {"RT_KEY":{"string":"000005"},"RT_ALPHA":{"string":"16:15:20.9"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ㈱①Ⅰ鯵鰺"},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"string":"1234567890"},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"}}
レコード削除
TGFDELプログラムを動かしてKey:000005のレコードを削除してみます。
Topicに以下のメッセージが追加されました。
{"RT_KEY":{"string":"000005"}} null
補足
Kafka Consumerで結果を確認していますが、kafka-avro-console-consumerを実行しているロケールはja_JP.UTF-8を使用しています。すなわち、元々のデータはEBCDIC(1399)ですが、UTF-8に文字コード変換されていることが確認できています。
Graphicタイプ(DBCSのみ)のフィールドもきちんとコード変換できていますし、環境依存文字(㈱、①など)も変換できているようです。
その他、デフォルトでは、COBOL COPYBOOKの型と、Kafka上の型は以下の様にマッピングされていました。
COBOL COPYBOOK | Avro |
---|---|
01 RT-SEG. | - |
02 RT-KEY PIC X(06). | string |
02 RT-ALPHA PIC X(10). | string |
02 RT-ALPHAKANA PIC X(10). | string |
02 RT-MIXDBCS PIC X(32). | string |
02 RT-MIXALL PIC X(40). | string |
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1. | string |
02 RT-DECIMAL PIC 9(10). | string |
02 RT-PACKED PIC S9(05) COMP-3. | int |
02 RT-BINHALF PIC S9(04) COMP. | int |
02 RT-BINFULL PIC S9(08) COMP. | int |
02 RT-BINDBLE PIC S9(12) COMP. | long |
02 RT-GROUP. | - |
03 RT-GRP01 PIC X(10). | string |
03 RT-GRP02 PIC X(10). | string |
03 RT-GRP03 PIC X(10). | string |
02 FILLER PIC X(15). | なし |
レプリケーションのテスト2
テスト1で実行したシナリオを少し改修して試してみます。ここでは、CopyBookを元に生成されるVSAM表を一部カスタマイズしてみます。
使用するCopyBook
01 RT-SEG.
02 RT-KEY PIC X(06) VALUE '000001'.
02 RT-ALPHA PIC X(10) VALUE 'ThisIsROOT'.
02 RT-ALPHAKANA PIC X(10) VALUE 'アイウエオカキクケコ'.
02 RT-MIXDBCS PIC X(32)
VALUE 'あいうえおアイウエオ全角漢文'.
02 RT-MIXALL PIC X(40)
VALUE 'ABCDEFGHあいうabcdefgh全角漢アイウエオカキク'.
02 RT-GRAPHIC PIC G(15) USAGE DISPLAY-1
VALUE G'全角漢文字あいうえおアイウエオ'.
02 RT-DECIMAL PIC 9(10) VALUE 1234567890.
02 RT-PACKED PIC S9(05) COMP-3 VALUE 12345.
02 RT-BINHALF PIC S9(04) COMP VALUE 1234.
02 RT-BINFULL PIC S9(08) COMP VALUE 12345678.
02 RT-BINDBLE PIC S9(12) COMP VALUE 123456789012.
02 RT-GROUP.
03 RT-GRP01 PIC X(10) VALUE 'ThisIs1st!'.
03 RT-GRP02 PIC X(10) VALUE 'ThisIs2nd!'.
03 RT-GRP03 PIC X(10) VALUE 'ThisIs3rd!'.
02 RT-BIT8 PIC X(01) VALUE X'F0'.
02 RT-BIT16 PIC X(02) VALUE X'FFF0'.
02 RT-BIT32 PIC X(04) VALUE X'FFFFFFF0'.
02 FILLER PIC X(08) VALUE SPACE.
最後にバイナリのデータを保持する想定のフィールドを追加しました。型としてはPIC Xを使用していますが、ここにバイナリのデータ(コード変換対象外)のデータが含まれる想定です。
(上のCopyBookに指定してある固定の値をそのままファイルに書き込むイメージです。)
先の例だと、デフォルトでPIC Xは文字列(string)として扱われることになります。通常はこれで問題ありませんが、PIC Xのフィールドにバイナリ情報を格納して扱っているケースもあり得ますので、特定のフィールドを明示的にバイナリとして扱うよう変更してみます。
また、先の例では、PIC 9 (ゾーン10進)のフィールドも文字列として変換されていました。こちらも明示的に数値として扱うよう変更してみます。
※ここではテスト1と同じ手順でレプリケーションの設定を追加していきますが、テスト1と違うところだけ記載します。他の手順は同等です。
VSAM表のカスタマイズ
COBOLのCopyBookを取りこみ => VSAM表を作成 => DDL生成 => DDL適用 という流れでVSAM Remote Source上にVSAM表を反映させますが、生成されたDDLを用途に合わせてカスタマイズしてから適用します。
DDLのカスタマイズはマニュアルの以下の辺りを参考にします。
参考:Columns for VSAM
先にあげたCopyBookを元にClassic Data Architect上で生成させたDDLはこちらです。
--<ScriptOptions statementTerminator=";"/>
CREATE TABLE "TEST01"."FILET2" DBTYPE VSAM
DS "DB2P.CT56B4A1.FILET2"
(
"RT_KEY" SOURCE DEFINITION
DATAMAP OFFSET 0 LENGTH 6
DATATYPE C
USE AS CHAR(6),
"RT_ALPHA" SOURCE DEFINITION
DATAMAP OFFSET 6 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_ALPHAKANA" SOURCE DEFINITION
DATAMAP OFFSET 16 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_MIXDBCS" SOURCE DEFINITION
DATAMAP OFFSET 26 LENGTH 32
DATATYPE C
USE AS CHAR(32),
"RT_MIXALL" SOURCE DEFINITION
DATAMAP OFFSET 58 LENGTH 40
DATATYPE C
USE AS CHAR(40),
"RT_GRAPHIC" SOURCE DEFINITION
DATAMAP OFFSET 98 LENGTH 15
DATATYPE C
USE AS GRAPHIC(15),
"RT_DECIMAL" SOURCE DEFINITION
DATAMAP OFFSET 128 LENGTH 10
DATATYPE UC
USE AS CHAR(10),
"RT_PACKED" SOURCE DEFINITION
DATAMAP OFFSET 138 LENGTH 3
DATATYPE P
USE AS DECIMAL(5 , 0),
"RT_BINHALF" SOURCE DEFINITION
DATAMAP OFFSET 141 LENGTH 2
DATATYPE H
USE AS SMALLINT,
"RT_BINFULL" SOURCE DEFINITION
DATAMAP OFFSET 143 LENGTH 4
DATATYPE F
USE AS INTEGER,
"RT_BINDBLE" SOURCE DEFINITION
DATAMAP OFFSET 147 LENGTH 8
DATATYPE D
USE AS DECIMAL(12 , 0),
"RT_GRP01" SOURCE DEFINITION
DATAMAP OFFSET 155 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_GRP02" SOURCE DEFINITION
DATAMAP OFFSET 165 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_GRP03" SOURCE DEFINITION
DATAMAP OFFSET 175 LENGTH 10
DATATYPE C
USE AS CHAR(10),
"RT_BIT8" SOURCE DEFINITION
DATAMAP OFFSET 185 LENGTH 1
DATATYPE C
USE AS CHAR(1),
"RT_BIT16" SOURCE DEFINITION
DATAMAP OFFSET 186 LENGTH 2
DATATYPE C
USE AS CHAR(2),
"RT_BIT32" SOURCE DEFINITION
DATAMAP OFFSET 188 LENGTH 4
DATATYPE C
USE AS CHAR(4));
ALTER TABLE "TEST01"."FILET2" DATA CAPTURE CHANGES;
これを以下のように変更します。(変更箇所のみ抜粋)
...
"RT_DECIMAL" SOURCE DEFINITION
DATAMAP OFFSET 128 LENGTH 10
DATATYPE UC
USE AS DECIMAL(10 , 0),
...
"RT_BIT8" SOURCE DEFINITION
DATAMAP OFFSET 185 LENGTH 1
DATATYPE B
USE AS BINARY(1),
"RT_BIT16" SOURCE DEFINITION
DATAMAP OFFSET 186 LENGTH 2
DATATYPE B
USE AS BINARY(2),
"RT_BIT32" SOURCE DEFINITION
DATAMAP OFFSET 188 LENGTH 4
DATATYPE B
USE AS BINARY(4));
...
上のDDLを適用すると変更した箇所とは関係ない所で以下のWarningが出ました。とりあえず無視してよさそうなので放置。
SQLState=S1000 列 RT_BINDBLE について LENGTH 8 は、DECIMAL の USE AS SQL データ・タイプに基づいて無視されます。 .
テスト実行
Avro Consumerを使用してVSAMにデータを投入してKafkaのTopicを確認してみます。
{"RT_KEY":{"string":"000001"}} {"RT_KEY":{"string":"000001"},"RT_ALPHA":{"string":"ThisIsROOT"},"RT_ALPHAKANA":{"string":"アイウエオカキクケコ"},"RT_MIXDBCS":{"string":"あいうえおアイウエオ全角漢文 "},"RT_MIXALL":{"string":"ABCDEFGHあいうabcdefgh全角漢アイウエオカキク"},"RT_GRAPHIC":{"string":"全角漢文字あいうえおアイウエオ"},"RT_DECIMAL":{"long":1234567890},"RT_PACKED":{"int":12345},"RT_BINHALF":{"int":1234},"RT_BINFULL":{"int":12345678},"RT_BINDBLE":{"long":123456789012},"RT_GRP01":{"string":"ThisIs1st!"},"RT_GRP02":{"string":"ThisIs2nd!"},"RT_GRP03":{"string":"ThisIs3rd!"},"RT_BIT8":{"bytes":"d"},"RT_BIT16":{"bytes":"yd"},"RT_BIT32":{"bytes":"yyyd"}}
RT_DECIMALは意図した通り数値型(long)になっています。
一方RT_BIT8, RT_BIT16, RT_BIT32は文字列として表示されてしまっています。
スキーマを確認してみます。
{
"type": "record",
"name": "FILET2",
"namespace": "value.SOURCEDB.VSAM.TEST01",
"fields": [
...
{
"name": "RT_DECIMAL",
"type": [
{
"type": "long",
"logicalType": "DECIMAL",
"dbColumnName": "RT_DECIMAL",
"precision": 10,
"scale": 0
},
"null"
],
"doc": "",
"default": 0
},
...
{
"name": "RT_BIT8",
"type": [
{
"type": "bytes",
"logicalType": "BINARY",
"dbColumnName": "RT_BIT8",
"length": 1
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_BIT16",
"type": [
{
"type": "bytes",
"logicalType": "BINARY",
"dbColumnName": "RT_BIT16",
"length": 2
},
"null"
],
"doc": "",
"default": ""
},
{
"name": "RT_BIT32",
"type": [
{
"type": "bytes",
"logicalType": "BINARY",
"dbColumnName": "RT_BIT32",
"length": 4
},
"null"
],
"doc": "",
"default": ""
}
]
}
スキーマ上、RT_BITxxのフィールドは"type":"bytes"
になっているので、恐らく確認に使っているAvroComsumerの仕様で文字列として表示されているのではないかと思われます。
kafka-console-consumerを使用して先頭のメッセージだけ抜き出してHexダンプを出力してみます。
[root@test12 ~/Kafka]# /opt/confluent-6.2.0/bin/kafka-console-consumer --from-beginning --topic cdc_kafka_test01.filet02.sourcedb.vsam.test01.filet2 --max-messages 1 --bootstrap-server localhost:9092 | xxd > temp.txt
Processed a total of 1 messages
[root@test12 ~/Kafka]# cat temp.txt
00000000: 0000 0000 0200 0c30 3030 3030 3100 1454 .......000001..T
00000010: 6869 7349 7352 4f4f 5400 3cef bdb1 efbd hisIsROOT.<.....
00000020: b2ef bdb3 efbd b4ef bdb5 efbd b6ef bdb7 ................
00000030: efbd b8ef bdb9 efbd ba00 58e3 8182 e381 ..........X.....
00000040: 84e3 8186 e381 88e3 818a e382 a2e3 82a4 ................
00000050: e382 a6e3 82a8 e382 aae5 85a8 e8a7 92e6 ................
00000060: bca2 e696 8720 2000 7441 4243 4445 4647 ..... .tABCDEFG
00000070: 48e3 8182 e381 84e3 8186 6162 6364 6566 H.........abcdef
00000080: 6768 e585 a8e8 a792 e6bc a2ef bdb1 efbd gh..............
00000090: b2ef bdb3 efbd b4ef bdb5 efbd b6ef bdb7 ................
000000a0: efbd b800 5ae5 85a8 e8a7 92e6 bca2 e696 ....Z...........
000000b0: 87e5 ad97 e381 82e3 8184 e381 86e3 8188 ................
000000c0: e381 8ae3 82a2 e382 a4e3 82a6 e382 a8e3 ................
000000d0: 82aa 00a4 8bb0 9909 00f2 c001 00a4 1300 ................
000000e0: 9c85 e30b 00a8 e8c8 e997 0700 1454 6869 .............Thi
000000f0: 7349 7331 7374 2100 1454 6869 7349 7332 sIs1st!..ThisIs2
00000100: 6e64 2100 1454 6869 7349 7333 7264 2100 nd!..ThisIs3rd!.
00000110: 02f0 0004 fff0 0008 ffff fff0 0a .............
末尾にf0
fff0
fffffff0
というデータがあるのでバイナリデータとしてコード変換されずにデータが送信されていることが確認できました。
まとめ
- Kafkaをターゲットとして連携する場合、更新情報が1メッセージとしてTopic上に送付されます。
- Kafka Topic上のメッセージはKey + Valueで構成されますが、Key部分には更新レコードのキーとなるフィールド、Value部分には更新レコード全体が含まれます。
- メッセージ単体からはInsert, Updateの区別はつきません。Updateの場合、更新後のレコード情報がValueに含まれるだけなのでどのフィールドに変更が入ったかの判別もできません。
- Deleteの場合、DeleteされたレコードのKey情報のみが転送され、Value部分はnullとなっています。
- MixedField, DBCSのみのフィールド、数値フィールドなど上のテストで挙げた型は意図した通りに変換できているようです(Mixed FieldとDBCS Fieldそれぞれに対してCCSIDを指定するパラメータがあるので注意!)。
バイナリや一部の数値フィールドはCopyBookから生成されるDDLを手動でカスタマイズしてVSAM表を作成する必要があるので注意が必要です。 - 更新情報は、更新された各レコード単位で独立したメッセージとしてKafkaに送られます。ソース側で複数レコードの更新を1UOWで更新した場合などでも、Kafka側では別々のイベントとして捉えられてしまいます。そのため、Kafkaから先のターゲットへの反映タイミングによっては整合性の取れていない状態となり得ます(Partitionを1つにしても、同一表の異なるレコードを1UOWで更新した場合は反映タイミングによっては不整合状態が生じうる)。トランザクション性を保証する必要がある場合は、"Kafka transactionally consistent consumer"の機能を使用して、1UOWとして扱われるメッセージの塊をKafka Consumer側でハンドリングする必要があります。
参考:
Kafka transactionally consistent consumer
A Solution for Leveraging Kafka to Provide End-to-End ACID Transactions