Make the most of arrays
In this tip Paul Tuohy examines some of the features of defining and using arrays in RPG IV.
![]() |
|
![]() |
![]() |
Paul Tuohy | ![]() |
![]() |
Historically, arrays have become an under utilized commodity in RPG. They are usually used to store small "lists" such as month or day names. This was understandable when the amount of space occupied by an array was a concern and when the means of defining and using arrays was restrictive. But this is no longer the case in RPG IV; we can now define very large arrays, and we are no longer preoccupied with the amount of storage reserved by a program (maybe concerned, but no longer preoccupied).
In this tip, I want to examine some of the features of defining and using arrays in RPG IV.
|
![]() |
Basics
Figure one shows an alternative to defining compile time arrays. The compile data is placed in a named data structure and the array overlays the data. This method has the enormous benefit of having the array data alongside the definition of the array as opposed to having to page to the end of the program to view the data. There are two interesting points to note: you can define storage in a data structure without providing a DS sub-field name, and you can specify the name of the data structure on the Overlay keyword.
D CompileData DS D 27a Inz('January February March ') D 27a Inz('April May June ') D 27a Inz('July August September') D 27a Inz('October November December ') D MonthNames 9a Overlay(CompileData) Dim(12)
Figure 1: An alternative to compile time arrays
Figure two shows another feature of defining arrays in a data structure. The Address array is defined as having 100 elements, each element being 87 characters in length. The rest of the data structure appears to define subfields that overlay the first element of the array (i.e. the combined length of the subfields is 87 characters). But such is not the case; since the subfields overlay an array they are themselves arrays. That means operations (such as SortA) executed on a sub field actually affects the overlaid array. In the example shown in Figure 2, the SortA of City results in the Address array being sorted based on the 61 to 80 character of each element. Or the SortA of State results in the Address array being sorted based on the 81 and 82 character of each element. The %SubArr BIF is used to ensure that only the elements that have been loaded are sorted (you do not want blank elements being sorted to the start of the array).
D DS D Address 87a Dim(100) Ascend D Street1 30a Overlay(Address) D Street2 30a Overlay(Address:*Next) D City 20a Overlay(Address:*Next) D State 2a Overlay(Address:*Next) D Zip 5a Overlay(Address:*Next) D noLoaded S 10i 0 /Free SortA %SubArr(City:1:NoLoaded); // Sort into City sequence SortA %SubArr(State:1:NoLoaded); // Sort in State sequence
Figure 2: Overlaying an array
Now let's look at a way of putting some of these features to work.
Sorting a subfile
We will look at a sample program that allows the user to sort a subfile by placing the cursor on a column and pressing F10. The program is a simple load all subfile with the added proviso that the required data is loaded to an array and that the subfile is, in turn, loaded from the array.
Figure three shows the DDS for the display file containing the load all subfile. The main points to note are (numbers correspond to the numbers in the figure):
1. CA10 is the function key used for sorting. The user positions the cursor on a column and presses F10 to sort based on that column.
2. The Return Cursor Location (RTNCSRLOC) keyword is used to determine which record (CSRREC) and field (CSRFLD) the cursor is positioned on when the screen is returned. For example, the names of the screen format and the field are returned in CSRREC and CSRFLD.
3. CSRREC and CSRFLD are defined as hidden fields.
*---------------------------------------------------------------- * * Paul Tuohy * * ComCon * *---------------------------------------------------------------- * * SUBSORT:- This is an example of sorting a subfile * *---------------------------------------------------------------- A DSPSIZ(24 80 *DS3) A INDARA A REF(*LIBL/CUST) A CA03(03 'Exit') A CA05(05 'Refresh') (1) A CA10(10 'Sort') * A R SUBREC SFL A 54 SFLNXTCHG A OPTION 1A B 7 3 A 31 DSPATR(RI PC) A CCODE R O 7 11 A ANAME R O 7 22REFFLD(ANAME ADDR) A R SUBCTL SFLCTL(SUBREC) A OVERLAY A 51 SFLDSP A 52 SFLDSPCTL A 53 SFLCLR A 51 SFLEND(*MORE) A SFLSIZ(0050) A SFLPAG(0014) (2) A RTNCSRLOC(*RECNAME &CSRREC &CSRFLD) A POSITIONAT 4S 0H SFLRCDNBR A RRN 4S 0H A ATRECORD 5S 0H (3) A CSRREC 10 H A CSRFLD 10 H A 1 28'Work with Customers' A 3 2'Type Option, Press Enter' A 4 2'5=View' A COLOR(BLU) A 6 2'Opt' A DSPATR(HI) A 6 10'Customer' A DSPATR(HI) A 6 23'Name' A DSPATR(HI) A R FOOTER A 23 2'F3=Exit F5=Refresh F10=Sort' A DSPATR(HI) A COLOR(BLU)
Figure 3: DDS for sorting a subfile.
Figure four shows the source of the RPG IV subfile program. The main points to note are numbers correspond to the numbers in the figure:
1. The F10 key is mapped to the indicator F10Sort in the indicator data structure for the display file.
2. An externally defined data structure (SubRecData) is used to store an image of a subfile record. The field names used in the subfile correspond to those inputs from the database files (CCODE and ANAME).
3. AllSubRec is a 9999 (the maximum number of records in a subfile) element array where each element is an image of the SubRecData data structure.
4. Subfields that correspond to the fields in the subfile record overlay the AllSubRec array; so each of these is, in turn, an array. Note how there are no hard-coded lengths or data types in this data structure; all of the components of the data structure are defined using the Like keyword and the use of *Next in the Overlay keyword means you need only be concerned with the sequence of the fields in the subfile record.
5. The LoadDataArray routine reads all required records from the customer and address files and adds them to the AllSubRec array. When records are input the data is placed in the CCODE and ANAME fields in the SubRecData data structure; the data structure is then copied to the next array element. At the end of the routine, the field RecordsInSubfile indicates the number of elements loaded in the array.
6. The subfile is loaded directly from the AllSubRec array; an element is moved to the SubRecData data structure and the subfile record corresponding to the array element is written. The important point to note is that each element of the array is loaded to the corresponding subfile record.
7. F10 results in the execution of a sort routine.
8. Based on the value of the CSRFLD field set on the RTNCSRLOC keyword, the corresponding subfield is used to sort the AllSubRec array. The %SubArr BIF and the RecordsInSubfile field are used to ensure that only the loaded elements are sorted. Processing continues with the subfile being reloaded.
H Option(*SrcStmt:*NoDebugIO) //---------------------------------------------------------------- // // Paul Tuohy // ComCon // //---------------------------------------------------------------- // // SUBSORTR:- Customer Enquiry, Subfile Select with Sorting. // // //---------------------------------------------------------------- FSubSortD CF E WorkStn IndDS(WorkStnInf) F SFile(SubRec:RRN) F IndDS(WorkStnInd) FCust IF E K DISK FAddr IF E K DISK D WorkStnInf DS D AtRecord 378 379i 0 D WorkStnInd DS D FunctionKeys 30 Overlay(WorkStnInd:1) D ErrInds 10 Overlay(WorkStnInd:31) D SFLInds 3 Overlay(WorkStnInd:51) D F3Exit N Overlay(WorkStnInd:3) D F5Refresh N Overlay(WorkStnInd:5) (1) D F10Sort N Overlay(WorkStnInd:10) D F12Cancel N Overlay(WorkStnInd:12) D BadOption N Overlay(WorkStnInd:31) D SFLDsp N Overlay(WorkStnInd:51) D SFLDspCtl N Overlay(WorkStnInd:52) D SFLClr N Overlay(WorkStnInd:53) D SFLNxtChg N Overlay(WorkStnInd:54) D SetMsgSfl N Overlay(WorkStnInd:91) // Info for storing subfile data and sorting it (2) D SubRecData E Ds ExtName(SUBSORTD:SUBREC) D Ds (3) D AllSubRec Like(SubRecData) D Dim(9999) Ascend D ArrOption Like(Option) OverLay(AllSubRec) (4) D ArrCode Like(CCode) OverLay(AllSubRec:*Next) D ArrName Like(AName) OverLay(AllSubRec:*Next) // Program Fields D CtlEvent S 4 D RecordsInSubfile... D S Like(RRN) D RecordInError S Like(RRN) //---------------------------------------------------------------- // MAINLINE // /FREE CtlEvent = 'DATA'; Dou CtlEvent = '*END'; Select; When CtlEvent = 'DATA'; ExSR LoadDataArray; When CtlEvent = 'LOAD'; ExSR LoadSubFile; When CtlEvent = 'DISP'; ExSR Display; When CtlEvent = 'VALD'; ExSR Validate; When CtlEvent = 'PROC'; ExSR Process; When CtlEvent = 'SORT'; ExSR SortData; EndSl; EndDo; *InLR = *On; //================================================================ // // DATA - Load all records to the array. (5) BegSR LoadDataArray; CtlEvent = 'LOAD'; RRN = 0; Option = *Blanks; AType = 'C'; SetLL *Start Cust; Read Cust; Dow Not %EOF(Cust); RRN += 1; Chain (Atype:CCode) Addr; AllSubRec(RRN) = SubRecData; Read Cust; EndDo; RecordsInSubfile = RRN; EndSR; //================================================================ // // LOAD - Load all records to the SubFile. BegSR LoadSubFile; CtlEvent = 'DISP'; SFLInds = '001'; Write SUBCTL; SFLInds = *Zeros; RRN = 0; Option = *Blanks; (6) For RRN = 1 To RecordsInSubfile; SubRecData = AllSubRec(RRN); Write SubRec; EndFor; RecordInError = 0; PositionAt = 1; EndSR; //================================================================ // // DISPLAY - Process the Screen BegSR Display; CtlEvent = 'VALD'; If RecordInError <> 0; PositionAt = RecordInError; EndIf; SFLInds = '110'; If RecordsInSubfile = 0; SFLDsp = *Off; EndIf; Write FOOTER; ExFmt SUBCTL; SFLInds = *Zeros; ErrInds = *Zeros; RecordInError = 0; PositionAt = AtRecord; If PositionAt = 0; PositionAt = 1; EndIf; Select; When F3Exit; CtlEvent = '*END'; When F5Refresh; CtlEvent = 'LOAD'; (7) When F10Sort; CtlEvent = 'SORT'; EndSl; EndSR; //================================================================ // // VALIDATE - Validate the SubFile BegSR Validate; CtlEvent = 'PROC'; RecordInError = 0; SFLNxtChg = *On; RRN = 1; // Validate all subfile records here SFLNxtChg = *Off; If RecordInError <> 0; CtlEvent = 'DISP'; EndIf; EndSR; //================================================================ // // PROCESS - Process the SubFile BegSR Process; CtlEvent = 'DISP'; // Do Subfile Stuff Here EndSR; //================================================================ // // SORT - Sort the subfile (8) BegSR SortData; CtlEvent = 'LOAD'; Select; When CsrFld = 'CCODE'; SortA %SubArr(ArrCode:1:RecordsInSubfile); When CsrFld = 'ANAME'; SortA %SubArr(ArrName:1:RecordsInSubfile); EndSl; EndSR; /END-FREE
Figure 4: Load all subfile program that sorts a subfile.
Although this technique is not suitable for volatile data, it does provide a very easy means to quickly re-sequence data for presentation purposes (a subfile in this case, but it could just as easily be for a Web page).xc
And finally
Given that the limits in RPG IV have been extended way beyond anything we could have imagined back in the RPG III days, it only makes sense to make use of all these new capabilities.
We have an historical tendency to refrain from loading a lot of information into memory. When we break the habit we discover there are a lot of neat things we can get our programs to do with little or no performance overhead.
-----------------------------------
About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company. He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"