I have a couple of communications asking about how to "correctly" code a data structure to receive the data from and update a data area in the latest, all free, RPG. One of person even sent me their code, which I will be using for the basis for my examples.
While I am not sure if there is just one "correct" way to do this I will be giving my version of the following three scenarios:
- Receive data from a data area into a data structure
- Update the data area with data from a data structure
- Equivalent of UDS
I am not going to describe the basics of how to code Data Structures in free format in this post, as I covered this in Defining variables in RPG all free.
In this example the data area is called PPZ500D and I am creating it in QTEMP using the CRTDTAARA command:
CRTDTAARA DTAARA(QTEMP/PPZ500D) TYPE(*CHAR) LEN(100) + VALUE('abcdefghijklmnopqrstuvwxyz01234567890') |
I can use the DSPDTAARA to display the contents of the data area:
DSPDTAARA DTAARA(QTEMP/PPZ500D) |
And this is the command's output:
Data area . . . . . . . : PPZ500D Library . . . . . . . : QTEMP Type . . . . . . . . . : *CHAR Length . . . . . . . . : 100 Text . . . . . . . . . : Value Offset *...+....1....+....2....+....3....+....4....+....5 0 'abcdefghijklmnopqrstuvwxyz01234567890 ' 50 ' ' |
Receive data from a data area into a data structure
As you all know I like to things simple and uncomplicated, therefore, I would code the data structure like below:
01 dcl-ds PPZ500D dtaara len(100) ; 02 Char25 char(1) pos(25) ; 03 end-ds ; 04 in PPZ500D ; |
On line 1 I use the data area name, PPZ500D, as the name of my data structure and define it 100 characters long.
I just need to code one subfield, Char25, that is one character (= 1A) and starts at position 25.
On line 3 I code the end-ds to mark the end of the data structure.
To receive the data from the data area I just use the IN operation code followed by the data structure name, which is the same as the data structure's name as I used its name as the data structure name.
I could have made it a bit more complicated by coding it as:
01 dcl-ds DataArea1 dtaara('QTEMP/PPZ500D') ; 02 Char100 char(100) ; 03 Char25 char(1) overlay(Char100:25) ; 04 end-ds ; 05 in DataArea1 ; |
On line 1 I have decided not to use the data area's name as the data structure's name. Therefore, I have to give the name of the data structure in the dtaara keyword, I have also chosen to qualify it with the library name but I could have used '*LIBL' or just not give the library name for it to use the library list.
Update the data area with data from a data structure
This time I am only going to give an example with my preferred format of data structure. In this example I am going to increment part of the data area, positions 60-62, by one:
01 dcl-ds PPZ500D dtaara len(100) ; 02 Char60 char(3) pos(60) ; 03 end-ds ; 04 dcl-s Nbr60 uns(3) ; 05 in *lock PPZ500D ; 06 if ((Char60 = ' ') or (Char60 = '999')) ; 07 Nbr60 = 0 ; 08 else ; 09 Nbr60 = %dec(Char60:3:0) ; 10 endif ; 11 Nbr60 += 1 ; 12 Char60 = %editc(Nbr60:'X') ; 13 out PPZ500D ; |
The only difference from the data structure in previous examples is that this time I have defined a alphanumeric subfield, Char60, which is 3 long. On line 6 I have defined a stand alone variable, Nbr60, which is an unsigned integer that is 3 long with (inferred) 0 decimal places. I have to admit that I am surprised that IBM insists that you have to have decimal places with integer and unsigned integer variables as, by their nature, they cannot have decimals.
On line 5 I "in" the contents of the data area. As I am going to update it I need to lock it, with *LOCK.
In lines 5 – 10 I convert the value in the alphanumeric subfield Char60 into a number in the unsigned integer Nbr60.
On line 11 I increment Nbr60 by 1. I use the %EDITC built in function with the edit code 'X' to convert Nbr60 to character on line 12. Then I update the data area using OUT on line 13.
After this program has completed if I look at the data structure I see that the 60-62 characters have been incremented.
Data area . . . . . . . : PPZ500D Library . . . . . . . : QTEMP Type . . . . . . . . . : *CHAR Length . . . . . . . . : 100 Text . . . . . . . . . : Value Offset *...+....1....+....2....+....3....+....4....+....5 0 'abcdefghijklmnopqrstuvwxyz01234567890 ' 50 ' 001 ' |
Equivalent of UDS
What is an "UDS" data area/structure?
D Data_Area_1 UDS 100 dtaara('MYLIB/TESTDA') D Char1 1 10 |
In fixed format RPG by defining a data structure as "UDS" the following happens without any additional programming:
- The data in the data area is brought into the data structure at program initialization, and the data area is locked. This makes it unavailable to other jobs.
- When the program ends the data in the data structure is used to update the data area, and the data area is unlocked/released.
You could use the UNLOCK operation code to unlock the data area during the program, but that runs counter to the whole idea of wanting the data area to be brought in at initialization and update at termination. I only use the "UDS" for the LDA, Local Data Area, as that is unique to each job.
In the example below I want to update the printer name in the first 10 characters of the LDA:
01 dcl-ds *n dtaara(*auto) ; 02 Printer char(10) pos(1) ; 03 end-ds ; 04 Printer = 'PRT02' ; 05 *inlr = *on ; |
On line 1 by not giving the data structure a name, *N, and using *AUTO in the DTAARA keyword denotes that this data structure will get the data from LDA at program initialization. I define the subfield Printer on line 2.
I change the value of the subfield Printer on line 4, and when the program ends that value updates the LDA.
Data area . . . . . . . : *LDA Type . . . . . . . . . : *CHAR Length . . . . . . . . : 1024 Text . . . . . . . . . : *LDA for Job 999999/SIMONH/DSP001 Value Offset *...+....1....+....2....+....3....+....4....+....5 0 'PRT02 ' 50 ' ' |
You can learn more about these on the IBM website:
This article was written for IBM i 7.2, and it should work with 7.1 TR7 and greater too.
"...I am surprised that IBM insists that you have to have decimal places with integer and unsigned integer variables as, by their nature, they cannot have decimals."
ReplyDeleteI'm not sure what you mean by this, but if it's in reference to this line of code:
Nbr60 = %dec(Char60:3:0);
then the decimal place is specified to define the intermediate result of the %DEC function, not the target field of the assignment statement.
Also, the highest number that can be assigned to an unsigned integer with a length of 3 is 255. If you want up to 999 to be assigned, then a signed or packed numeric with a length of 3 should be used.
I was referring to the DCL-S statement for the unsigned integer. I now I have not given the number of decimals in that as it is optional and inferred. But I could have code:
Deletedcl-s Nbr60 uns(3:0) ;
I just wonder why we have to code for the number of decimal when we declare the variable.
I fully understand that when a %DEC is used the number of decimal places need to be given.
As for the maximum value allowed in an unsigned variable I thank you for bringing that to my attention. I have to put that down for to trying to get the post done quickly
My apologies, Simon. I didn't know that decimal positions could even be specified for an integer or unsigned integer data type (even though it must be 0), which is why I was confused.
DeleteNo need to apologize. We are still learning this stuff :)
DeleteHello,
ReplyDeleteIs there a CLLE to check if a data area exist?
The command 'DSPDTAARA DTAARA(DATEST)'
Displays the data area which in not what is needed.
I want to see if the 'DTAARA' exist.
Thank you,
Got it,
ReplyDeletethe CHKOBJ OBJ(DATEST) OBJTYPE(*DTAARA)
MONMSG MSGID(CPF9801) EXEC(GOTO CMDLBL(NEXTLIVE))
- - - - -
Resolved the issue from using the DSPDTAATA command in the CLLE
Thank you,
MR
I am glad you worked it out. My example of how to use the CHKOBJ command looks just like yours.
DeleteHello,
ReplyDeletejust a question: When I use a dtaara with char length 60 and want to get it in a datastructure with a 20 numeric values and length of 3/0 how can I do it in free?
for example: the dtaara is 'DMS' and contains the values '105200210005012018017020000000000000000000000000000000000000'
dcl-ds DMS dtaara len(60);
num3 zoned(3:0) dim(20);
end-ds;
would this be correct?
Personally I would define the data area as character.
DeleteFYI if you are like me and just needed a data area with a numeric control value say 10, 0
ReplyDeleteuse:
dcl-s waitSeconds packed(10:0) dtaara('MYWAITCTL');
then in your code pull in the value using:
in waitSeconds;
*all free etc etc.
Thank you! I've been looking for this for hours! This worked for me!
Delete