Wednesday, December 27, 2017

Signed numeric in CL data structures

handling a cl data structure with signed fields in it

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.

4 comments:

  1. 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.

    Carlos

    ReplyDelete
  2. Excellent Simon.Happy New Year

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.