Problem solve Get help with specific problems with your technologies, process and projects.

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.

More Information


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

  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

       CtlEvent = 'DATA';

       Dou CtlEvent = '*END';
            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;

       *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;

         RecordsInSubfile = RRN;


       // 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;

         RecordInError = 0;
         PositionAt = 1;


       // DISPLAY - Process the Screen

       BegSR Display;

         CtlEvent = 'VALD';

         If RecordInError <> 0;
           PositionAt = RecordInError;

         SFLInds = '110';

         If RecordsInSubfile = 0;
           SFLDsp = *Off;

         Write FOOTER;
         ExFmt SUBCTL;

         SFLInds = *Zeros;
         ErrInds = *Zeros;
         RecordInError = 0;
         PositionAt = AtRecord;
         If PositionAt = 0;
           PositionAt = 1;

         When F3Exit;
           CtlEvent = '*END';
         When F5Refresh;
           CtlEvent = 'LOAD';
(7)      When F10Sort;
           CtlEvent = 'SORT';


       // 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';


       // PROCESS - Process the SubFile

       BegSR Process;

         CtlEvent = 'DISP';

           // Do Subfile Stuff Here


       // SORT - Sort the subfile

(8)    BegSR SortData;
           CtlEvent = 'LOAD';

           When CsrFld = 'CCODE';
              SortA  %SubArr(ArrCode:1:RecordsInSubfile);
           When CsrFld = 'ANAME';
              SortA  %SubArr(ArrName:1:RecordsInSubfile);


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?"

Dig Deeper on RPG iSeries programming