I have been racking my brain to try to remember when I first came across Externally Described Data Structures in RPG. I think it must have been when I transitioned from being a RPG II programmer on the IBM System/36 to a RPG III programmer on an AS400 (yes, I am that old). The others I was working with at the time were all former IBM System/38 programmers and were "fluent" in RPG III. They did not use Externally Described Data Structures. and I was the "newbie" learning RPG III from them, so neither did I.
It was while I was working on a project programming in Synon/2E, and later modifing Synon generated RPG code, did I find them used everywhere. Synon uses Externally Described DS for passing parameters, saving the values of fields in files, and for the Program Status DS (PSDS).
What do I use Externally described Data Structures for?
Every program I write I insert an Externally described DS for the Program Status DS as I find that it leads to a fixed naming convention of the PSDS fields, which makes it easier for myself and others to understand at a later date.
If I was to key the PSDS into the D-spec, Definition specifications, it would look something like:
DPgmDs SDS qualified D Proc_Name *PROC D Pgm_Status *STATUS D Prv_Status 16 20S 0 D Line_Nbr 21 28 D Routine *ROUTINE D Parms *PARMS D Excp_Type 40 42 D Excp_Num 43 46 D Pgm_Lib 81 90 D Excp_Data 91 170 D Excp_Id 171 174 D Date 191 198 D Year 199 200S 0 D Last_File 201 208 D File_Info 209 243 D Job_Name 244 253 D User 254 263 D Job_Num 264 269S 0 D Job_Date 270 275S 0 D Run_Date 276 281S 0 D Run_Time 282 287S 0 D Crt_Date 288 293 D Crt_Time 294 299 D Cpl_Level 300 303 D Src_File 304 313 D Src_Lib 314 323 D Src_Mbr 324 333 D Proc_Pgm 334 343 D Proc_Mod 344 353
I created a file, called RPG4DS, that contains the subfields for the PSDS. This can be inserted as an Externally described DS into the source code like this:
D PgmDs ESDS extname(RPG4DS) qualified
As this is an Externally described DS there has to be an 'E' in position 22, and the EXTNAME keyword is used for the name of the file.
The file, RPG4DS, is just a DDS file that looks like this:
A R DUMMY A PROCNME 10A COLHDG('Procedure' 'Name') A STSCDE 5S 0 COLHDG('Status' 'Code') A PRVSTSCDE 5S 0 COLHDG('Previous' 'Status' 'Code') A SRCLINNBR 8A COLHDG('Source' 'Line' 'No,') A EXCPTSUBR 8A COLHDG('Exception' 'Subroutine') A NBRPARMS 3S 0 COLHDG('No. of' 'Parameters') A EXCPTTYP 3A COLHDG('Exception' 'Type') A EXCPTNBR 4A COLHDG('Exception' 'No.') A RESERVED01 4A COLHDG('Reserved') A MSGWRKAREA 30A COLHDG('Message' 'Work' 'Area') A LIB 10A COLHDG('Library') A RTVEXCPTDT 80A COLHDG('Retrieved' 'Exception' + 'Data') A EXCPTID 4A COLHDG('Id. of' 'Exception' + 'RNX9001') A UNUSED0001 16A COLHDG('Unused') A DTEJOBENTR 8A COLHDG('*DATE' 'Job entered' + 'System') A CNTJOBENTR 2S 0 COLHDG('Century' 'Job entered' + 'System') A LASTFILEOP 8A COLHDG('File last' 'operation' + 'Performed') A FILESTS 35A COLHDG('Status' 'of' 'file') A JOBNME 10A COLHDG('Job' 'Name') A USER 10A COLHDG('User' 'Profile') A JOBNMBR 6S 0 COLHDG('Job' 'Number') A DTEJOBENT2 6S 0 COLHDG('Date job' 'Entered' + 'System') A DTEPGMRUN 6S 0 COLHDG('Date' 'Program' 'Running') A TMEPGMRUN 6S 0 COLHDG('Time' 'Program' 'Running') A COMPILEDTE 6A COLHDG('Compile' 'Date') 'Data') A COMPILETME 6A COLHDG('Compile' 'Time') A COMPILELVL 4A COLHDG('Level' 'of' 'Compile') A SRCFILE 10A COLHDG('Source' 'File' 'Name') A SRCLIB 10A COLHDG('Source' 'Library') A SRCMBR 10A COLHDG('Source' 'Member') A MODULEPGM 10A COLHDG('Program' 'Containing' + 'Module') A MODULEPROC 10A COLHDG('Module' 'Containing' + 'Procedure') A UNUSED0002 76A COLHDG('Unused')
Another example of a good use of an Externally described DS is to save the values from a record in a file. This can be coded in just a few lines like this:
01 FORDHDRP IF E K DISK 02 D Sav E DS extname(ORDHDRP) 03 D qualified 04 D New E DS extname(ORDHDRP) 05 /free 06 read(e) ORDHDRP ; 07 Sav = New ; 08 read(e) ORDHDRP ;
On line 2 the data structure 'Sav' is defined as an Externally described DS of the file ORDHDRP. Notice that on line 3 the QUALIFIED keyword is used. This adds the name of the data structure to the front of the field name followed by a period (.), for example ORDNO becomes Sav.ORDNO .
On line 4 the data structure 'New' is defined in the same manner as 'Sav', but without the QUALIFIED, therefore, ORDNO is still ORDNO.
When the file is read, line 6, the 'New' DS is loaded with the values of the fields from the file.
Line 7 moves the entire contents of the 'New' DS to 'Sav'. Now all the subfields in 'Sav' have been updated with the values from 'New', and the file.
When the file is read again, line 8, the value of the subfields in the 'New' DS are the same as fields in the new record of the file. But the values in the 'Sav' DS are unchanged.
As this is only a brief introduction to Externally described Data Structures I am sure you can think of many other uses for them.
Warning: If you convert a RPG III program using the CVTRPGSRC command and the source member contains the PSDS as an Externally described DS the conversion will complete successfully. But as the layout of the RPGIII and RPGLE/RPGIV PSDS are different you are going to have run-time issues. You need to change the new source member to use a RPGLE/RPG IV compatible PSDS.
You can learn more about this on the IBM web site:
This article was written for IBM i 7.1, and it should work with earlier releases too.