The germ for this post comes from a question I was asked. The questioner was passing a file record as a data structure from a RPG program to a CL program, and when they looked at the data structure the CL program would "really mess up" some of the numeric data structure subfields. After further questioning I discovered the "messed up" fields we all signed numeric fields. Once I established that I knew what the problem was, and came up with a simple solution.
Let me show what the problem is, and then the solution I came up with. Let me start with the file, you will not be surprised to discover that I called it TESTFILE.
01 A R RTESTFILE 02 A FSIGNED1 7S 2 03 A FPACKED 7P 2 04 A FSIGNED2 R -2 REFFLD(FSIGNED1 *SRC) 05 A FSIGNED3 R REFFLD(FSIGNED2 *SRC) 06 A FCHAR 5A 07 A FDATE L 08 A FTIME T |
As you can see I have defined one of the numeric fields as packed numeric, FPACKED, the other numeric fields are all signed numeric. I have also included in the file date, FDATE, and time, FTIME, to show what a CL program does with those too.
Line 4: The -2 in the Length field along with the REFFLD means that this field will be two places smaller than the field referenced, i.e. this field will be 5,2.
I added one record to the file to give me data to play with:
FSIGNED1 FPACKED FSIGNED2 FSIGNED3 FCHAR FDATE FTIME 12,345.67 98,765.43 333.33 444.44 CHAR> 2017-06-30 22.30.00 |
If I write a very simple CL program to read this file and then dump I will be able to see the values and see how CL has defined the fields of the file.
01 PGM 02 DCLF FILE(TESTFILE) 03 RCVF 04 DMPCLPGM 05 ENDPGM |
If I look in the spool file produced by the dump, QPPGMDMP, and I see a number of interesting things.
Variable Type Length Value *...+....1....+....2....+ &FCHAR *CHAR 5 'CHAR>' &FDATE *CHAR 10 '2017-06-30' &FPACKED *DEC 7 2 98765.43 &FSIGNED1 *DEC 7 2 12345.67 &FSIGNED2 *DEC 5 2 333.33 &FSIGNED3 *DEC 5 2 444.44 &FTIME *CHAR 8 '22.30.00' |
All the numeric fields have been defined as *DEC, regardless of whether they were defined as packed or signed numeric in the file. The date and time field are defined as *CHAR, as CL does not support date, time, or timestamp fields.
Using what I have discovered let me create a CL program with a data structure in it to match the CL's definition of the file.
01 PGM PARM(&DS) 02 DCL VAR(&DS) TYPE(*CHAR) LEN(44) 03 DCL VAR(&SF_SIGNED1) TYPE(*DEC) STG(*DEFINED) + LEN(7 2) DEFVAR(&DS) 04 DCL VAR(&SF_PACKED) TYPE(*DEC) STG(*DEFINED) + LEN(7 2) DEFVAR(&DS 8) 05 DCL VAR(&SF_SIGNED2) TYPE(*DEC) STG(*DEFINED) + LEN(5 2) DEFVAR(&DS 12) 06 DCL VAR(&SF_SIGNED3) TYPE(*DEC) STG(*DEFINED) + LEN(5 2) DEFVAR(&DS 17) 07 DCL VAR(&SF_CHAR) TYPE(*CHAR) STG(*DEFINED) + LEN(5) DEFVAR(&DS 22) 08 DCL VAR(&SF_DATE) TYPE(*CHAR) STG(*DEFINED) + LEN(10) DEFVAR(&DS 27) 09 DCL VAR(&SF_TIME) TYPE(*CHAR) STG(*DEFINED) + LEN(8) DEFVAR(&DS 37) 10 DMPCLPGM 11 ENDPGM |
Line 2: Is the data structure.
Lines 3 – 9: These are the data structure subfields. I use the DEFVAR parameter to define that this subfields belongs to the data structure, and where in the data structure does this subfield start.
Lines 3, 4, 5, and 6: I have defined the subfield equivalents of the signed and packed numeric fields in the file as *DEC as that is what the CL compiler did in my previous CL program.
Line 10: A dump again, I am doing this as this, in my opinion, is the easiest way to see all of the program's variables in one place.
I need a RPG program to read TESTFILE, and then call this CL program and pass a data structure to it.
01 **free 02 dcl-pr TESTCL1 extpgm ; 03 *n char(44) ; 04 end-pr ; 05 dcl-f TESTFILE ; 06 dcl-ds File_DS likerec(RTESTFILE) ; 07 read RTESTFILE File_DS ; 08 TESTCL1(File_DS) ; 09 *inlr = *on ; |
Line 1: I am programming on IBM i 7.3 so I am going to use totally free RPG.
Lines 2 – 4: As I am using totally free RPG if I am going to call another program I need to define a procedure prototype to do so.
Line 5: My file definition for TESTFILE as input only.
Line 6: I am defining a file data structure using the LIKEREC, then when I read the file the entire record from the record format RTESTFILE is moved into the data.
Line 7: The read into the data structure.
Line 8: Call the program TESTCL1 and pass the data structure.
When I look at the dump produced by the CL program I notice that the signed fields are all "messed up".
Variable Type Length Value Hexadecimal *...+....1....+....2....+ * . . . + . &DS *CHAR 44 '1234567qÎè 3333344444CHAR' +26 '>2017-06-3022.30.00' &SF_CHAR *CHAR 5 'CHAR>' &SF_DATE *CHAR 10 '2017-06-30' &SF_PACKED *DEC 7 2 98765.43 &SF_SIGNED1 *DEC 7 2 ' 1 2 .3 ' F1F2F3F4 &SF_SIGNED2 *DEC 5 2 ' 3 .3 ' F3F3F3 &SF_SIGNED3 *DEC 5 2 ' 4 .4 ' F4F4F4 ¬¬&SF_TIME *CHAR 8 '22.30.00' |
I have included the value in hexadecimal column this time so that you can see that the signed fields were passed as signed. But as the subfields are defined as *DEC CL regards them as packed numeric.
After a period of playing, coming up with various ways to overcome this issue, I came up with that I consider an easy way to overcome this. What I need to do is to convert the signed numeric to packed numeric. I could define a data structure in the RPG program with packed numeric subfields and then move the signed fields from the file to the packed numeric subfields, but that could mean lots of lines added to the RPG program or the use of EVAL-CORR operation code to move the contents of one data structure to another. I think my solution is simple than that.
I create Logical file, TESTFILEL, over the Physical file that looks like:
01 A R DUMMY PFILE(TESTFILE) 02 A FSIGNED1 P 03 A FPACKED 04 A FSIGNED2 P 05 A FSIGNED3 P 06 A FCHAR 07 A FDATE 08 A FTIME |
Line 1: I need to call the record format something different to that of the Physical file. I chose DUMMY as that is a reminder to me that I will never use the Logical file in a file definition.
Lines 2, 4, and 5: By placing the P in the data type field I convert the signed fields to packed numeric in this Logical file.
I don't need any key fields.
I have change my CL program as the length of the data structure, and record, is smaller than that of the Physical file. Otherwise the program is the same as before.
01 PGM PARM(&DS) 02 DCL VAR(&DS) TYPE(*CHAR) LEN(37) 03 DCL VAR(&SF_SIGNED1) TYPE(*DEC) STG(*DEFINED) + LEN(7 2) DEFVAR(&DS) 04 DCL VAR(&SF_PACKED) TYPE(*DEC) STG(*DEFINED) + LEN(7 2) DEFVAR(&DS 5) 05 DCL VAR(&SF_SIGNED2) TYPE(*DEC) STG(*DEFINED) + LEN(5 2) DEFVAR(&DS 9) 06 DCL VAR(&SF_SIGNED3) TYPE(*DEC) STG(*DEFINED) + LEN(5 2) DEFVAR(&DS 12) 07 DCL VAR(&SF_CHAR) TYPE(*CHAR) STG(*DEFINED) + LEN(5) DEFVAR(&DS 15) 08 DCL VAR(&SF_DATE) TYPE(*CHAR) STG(*DEFINED) + LEN(10) DEFVAR(&DS 20) 09 DCL VAR(&SF_TIME) TYPE(*CHAR) STG(*DEFINED) + LEN(8) DEFVAR(&DS 30) 10 DMPCLPGM 11 ENDPGM |
Line 2: The data structure is now 37 long.
The RPG program needs to be changed too.
01 **free 02 dcl-pr TESTCL2 extpgm ; 03 *n char(37) ; 04 end-pr ; 04 dcl-f TESTFILE ; 05 dcl-ds File_DS extname('TESTFILEL') ; 06 end-ds ; 07 read RTESTFILE ; 08 TESTCL2(File_DS) ; 09 *inlr = *on ; |
Line 3: The length of the data structure will be 37.
Line 5 and 6: I am defining the file data structure using the EXTNAME keyword with the Logical file.
Line 7: I still read the Physical file.
I do not have to do any field moving as the field names in the data structure are the same as they are in the input file.
When I look in the dump produced by the CL program I can see that all the subfields contain valid data.
Variable Type Length Value *...+....1....+....2....+ &DS *CHAR 37 ' î"qÎè àà|CHAR>2017-0 +26 '6-3022.30.00' &SF_CHAR *CHAR 5 'CHAR>' &SF_DATE *CHAR 10 '2017-06-30' &SF_PACKED *DEC 7 2 98765.43 &SF_SIGNED1 *DEC 7 2 12345.67 &SF_SIGNED2 *DEC 5 2 333.33 &SF_SIGNED3 *DEC 5 2 444.44 &SF_TIME *CHAR 8 '22.30.00' |
I think that is pretty easy. Don't you too?
This article was written for IBM i 7.3, and should work for earlier releases too.
Looking forward to go to 7.3 soon. Thanks Simon for all your didactics examples thru 2017. Happy new year to you and your readers.
ReplyDeleteCarlos
Thank you, and a happy New Year to you too.
DeleteExcellent Simon.Happy New Year
ReplyDeleteA very happy New Year to you too
Delete