Just because RPG doesnt have native data sorting functions, it does not mean that RPG cant sort data. In fact, as soon as you learn how to use these sorting APIs with RPG, you may forget that RPG could never really sort data in the first place!
Data structures and files can be sorted on the AS/400 in different ways. One interesting method entails the use of the QLGSORT (Sort) and QLGSRTIO (Sort Input/Output) APIs. These APIs are quite efficient and can be called from any AS/400 high-level language (HLL) program, such as RPG III, RPG IV, ILE COBOL, Original Program Model (OPM) COBOL, and ILE C. Using these APIs in your programs enables you to do the following from within an HLL program:
Sort an area of memory, such as an RPG multiple-occurrence data structure (MODS), within a HLL program
Sort up to 32 input files and produce from one to 32 output files
Sort data with an alternae collating sequence
Sort data by natural language sequences (coded character set ID or CCSIDs) This article explains and demonstrates how QLGSORT and QLGSRTIO work. Read on and learn how to add these powerful sorting techniques to your programming toolbox.
Using QLGSORT and QLGSRTIO
QLGSORT makes a single dynamic call from inside your HLL to sort data stored either in an input buffer or in physical files. QLGSRTIO can be used either to provide a set of records or return a set of records that has already been sorted. To do the latter, a sort initialization call to QLGSORT must first be issued. Both of these APIs use complex data structures, so its a good idea to review IBMs documentation about them. (Documentation on using QLGSORT and QLGSRTIO is provided in the OS/400 National Language Support APIs manual.)
On my system, the data structures required by QLGSORT and QLGSRTIO are contained in the QRPGLESRC source file, located in the IBM-supplied QSYSINC library.
The IBM documentation mentioned provides no practical examples, but this article does. Because of spatial considerations, however, entire programming examples are not published. Still, critical code excerpts are illustrated thoroughly. The entire source code for the examples is available free of charge from the Midrange Computing Web site at www.midrangecomputing.com/mc/99/04.
Yes, Virginia, You Can Sort a Multiple-Occurrence Data Structure
To sort a file, you use OPNQRYF, FMTDTA, or even RGZPFM; to sort an array in RPG, use SORTA. And to sort a MODS, use QLGSORT; Ive even written an RPG IV program called SrtMODSPrn that shows you how.
Figure 1 displays the parameters used by QLGSORT. Data structures and variables used as parameters for QLGSORT are illustrated in Figure 2. The MODS that I am sorting is a simple employee list that my program calls EmpRecord (see Figure 2). The sort specified is by last name and then by first name, in ascending order. SrtMODSPrn first prints the unsorted MODS, and after QLGSORT is called, it prints the sorted MODS (see Figure 3). Now, lets take a closer look at how this is done.
First, SrtMODSPrn loads EmpRecord with five sets of arbitrary name values, all of which are printed. Next, SrtMODSPrn uses subroutine ExecSort to set up the QLGSORT Sort control block (SrtCtlBlk) and two key values, SrtKeyLst1 and SrtKeyLst2. Then, a call to QLGSORT is issued using the correct parameters. The code fragment containing the critical portions of ExecSort is depicted in Figure 4.
I developed SrtCtlBlk based on the IBM-supplied data structures in my system. All values were initially set at 0, and most will remain that way. I will focus on those values that are changed and why. The new values for those variables and reasons for their assignments are as follows:
ReqTyp, which is the requested type, is set at 5. According to IBM documentation, when an input data buffer and output data buffer are used, 5 is the value of the requested type.
RecLen, the record length, is set at 50 because that is the length of the EmpRecord MODS.
RecCount represents record count. It is assigned a value of 5 because that is the number of occurrences for the EmpRecord MODS.
OffKeyLst represents the offset of the key list and is set at 80, the length of SrtCtlBlk up to the point where SortKeyVals is declared.
NumKeys, which is the number of keys, is set at 2 (LastName and FirstName).
LenKeyEnt is length of the key entry and is assigned a value of 16, the length of SortKeyVals in data structure SrtCtlBlk.
LenSrtSeq is the length of the national sort sequence information. Its minimum length must be 290.
LenBlk is the length of the request control block. My program represents this with the sum of 80, 16, and 16. 80 is the length of my Sort control block (SrtCtlBlk), and 16 is the length of both the first (SrtKeyLst1) and second (SrtKeyLst2) keys. (Of course, I could have specified 112, but I wanted to explain how the number is derived.)
SrtMODSLen stands for the length of my EmpRecord MODS. My program represents this number as 5 multiplied by 50 because EmpRecord has a length of 50 in 5 occurrences.
KeyStrPos1 is the starting position for my first key, LastName; its value is 21.
StringSiz1 is the length of LastName and has a value of 30.
DataType1 is the key data type for LastName. Per IBM documentation, when the data type is a character, the value is 6. There are 23 different key data types, including zoned decimals, packed decimals, dates, and times.
SortOrder1 is the sort order of LastName. For ascending values, this value is 1. If it were descending, the value would be 2.
KeyStrPos2 is the starting position for my second key, FirstName. This value is
1.
StringSiz2 is the length of FirstName and has a value of 20.
DataType2 is the key data type for FirstName, with a value of 6.
SortOrder2 is the sort order of LastName. The order is ascending, so the value is Immediately after all these values are set, QLGSORT is ready to be called using the required parameter set. Once again, these parameters are Sort control block (SrtCtlBlk), Input MODS (EmpRecord), Output MODS (EmpRecord), Input MODS length (SrtMODSLen), Output MODS length (SrtMODSLen), and Standard API error data structure (APIErr). When QLGSORT is called, my sorted MODS is returned, and the results are printed (Figure 3).
Now, lets examine how QLGSRTIO is used.
Putting Sorted Data into Physical Files, QLGSRTIO Style
As previously mentioned, in order to execute QLGSRTIO properly, you must first use QLGSORT to execute a sort initialization call. My next example program, SrtMODSFil, is designed to be as close as possible to my first example program. Because it uses QLGSORT to initialize the sorting process, we continue to use SrtCtlBlk.
By the same token, because we use QLGSRTIO, we need some new variables, data structures, and parameters. The required parameter list for QLGSRTIO is displayed in Figure 5, and the additional data structures and variables to be used by the QLGSRTIO program calls are displayed in Figure 6.
The first data structure displayed in Figure 6 is named SrtIOCtl and serves as my Sort control block for QLGSRTIO. The next data structure is named EmpRecord1 and is used in conjunction with my EmpRecord MODS. The standalone variables are OutSizeLen, FillerParm, and InSizeLen. InSizeLen and OutSizeLen are used to compute record lengths, while FillerParm is used when necessary as a filler parameter value.
In my example program, after the MODS is loaded, QLGSORT is called using SrtCtlBlk, InSizeLen, and OutSizeLen as the critical parameters. This operation is performed in subroutine ExecSort, displayed in Figure 7. When QLGSORT is called, the SrtCtlBlk values are almost the same as before. The only notable difference is that the record count (RecCount) value is set at 0. Parameters InSizeLen and OutSizeLen are computed by QLGSORT and used later by QLGSRTIO during subsequent calls.
The first call to QLGSRTIO loads the MODS values into the QLGSRTIO input buffer via EmpRecord. To execute this operation, the request type value SrtIOTyp is set at
1. The value 1 represents the Put function for QLGSRTIO. After the QLGSRTIO buffer loading operation has been completed, the sort operation is ready to be executed. This is accomplished by setting the value of SrtIOTyp to 2, which represents the End Put function for QLGSRTIO. QLGSRTIO is called again, and the input buffer is sorted.
The final series of calls to QLGSRTIO is to return the data buffer to my HLL program via the output parameter (EmpRecord1). For this operation, the value of SrtIOTyp is set at 3, the Get function for QLGSRTIO. This operation is accomplished one record at a time until the process is complete. When the value of EmpRecord1 returns to SrtMODSFil, the values are moved to the physical file fields and the record is written to the file. The final result is that the output of the sorted MODS is saved in the file and the program terminates.
At this point, you can see the importance of these repetitive calls to QLGSRTIO. Especially important is setting the correct request type because data loaded into the QLGSRTIO buffers stays there until the next call. In order to clear and delete the buffers, you should specify 4 as the value of the request type when calling QLGSRTIO. This invokes QLGSRTIOs Cancel function.
Implementing Sort APIs with AS/400 Applications
1.
Some HLLs, such as COBOL, have very specialized commands that can be used for sorting data in data structures or files. Other languages, such as RPG, are not so developed in this regard. The Sort APIs are a great way to get around this limitation. Honestly, when I learned how to use these APIs, I wished that I had learned them earlier. It would have saved me quite a bit of work, and my programs would have run quicker.
I have shared this knowledge with other programmers who have found it very useful. I hope that you have found it useful as well.
Reference
OS/400 National Language Support APIs V4R2 (SC41-5863-01, CD-ROM QB3AMO01)
Required Parameter Group:
Order Description Usage Type
1 Request control block Input Char(*)
2 Input data buffer Input Char(*)
3 Output data buffer Output Char(*)
4 Length of output data buffer Input Binary(4)
5 Length of returned data Output Binary(4)
6 Error code Output Char(*)
Optional Parameter Group :
7 Returned records feedback Output Char(*)
8 Length of returned records feedback Input Binary(4)
*================================================================
* Employee List to be sorted by LastName, FirstName
D EmpRecord ds occurs(05)
D FirstName 20a
D LastName 30a
*================================================================
D SrtMODSLen s 4b 0
*================================================================
D* QLGSORT Sort Control Block
D SrtCtlBlk DS
D* Length Block
D LenBlk 1 4B 0 inz(0)
D* Request Type
D ReqTyp 5 8B 0 inz(0)
D* Reserved1
D Reserved1 9 12B 0 inz(0)
D* Options
D Options 13 16B 0 inz(0)
D* Record Length
D RecLen 17 20B 0 inz(0)
D* Record Count
D RecCount 21 24B 0 inz(0)
D* Offset Key List
D OffKeyLst 25 28B 0 inz(0)
D* Number Keys
D NumKeys 29 32B 0 inz(0)
D* Offset Lang Info
D OffLangInf 33 36B 0 inz(0)
D* Offset Input List
D OffInLst 37 40B 0 inz(0)
D* Number Input Files
D NumInFils 41 44B 0 inz(0)
D* Offset Output List
D OffOutLst 45 48B 0 inz(0)
D* Number Output Files
D NumOutFil 49 52B 0 inz(0)
D* Length Key Entry
D LenKeyEnt 53 56B 0 inz(0)
D* Length Sort Seq
D LenSrtSeq 57 60B 0 inz(0)
D* Length Infile Entry
D LenInFile 61 64B 0 inz(0)
D* Length Outfile Entry
D LenOutFile 65 68B 0 inz(0)
D* Offset Null Map
Figure 1: QLGSORT uses this parameter list.
D OffNullMap 69 72B 0 inz(0)
D* Offset Record Info
D OffRecInf 73 76B 0 inz(0)
D* Reserved2
D Reserved2 77 80B 0 inz(0)
D* Key Definition for the 2 QLGSORT keys
D SortKeyVals 16A dim(2)
*================================================================
D* First Sort Key Definition
D SrtKeyLst1 DS
D* Start Position1
D KeyStrPos1 1 4B 0
D* String Size1
D StringSiz1 5 8B 0
D* Data Type1
D DataType1 9 12B 0
D* Sort Order1
D SortOrder1 13 16B 0
*================================================================
* Second Sort Key Definition
D SrtKeyLst2 DS
D* Start Position2
D KeyStrPos2 1 4B 0
D* String Size2
D StringSiz2 5 8B 0
D* Data Type2
D DataType2 9 12B 0
D* Sort Order2
D SortOrder2 13 16B 0
*================================================================
* Subroutine ExecSort will setup the sort control block and
* sort keys. Then QLGSORT will be called.
*
C ExecSort begsr
* Setup QLGSORT Control Block
C eval ReqTyp = 5
C eval RecLen = 50
C eval RecCount= 5
C eval OffKeyLst = 80
C eval NumKeys = 2
C eval LenKeyEnt = 16
C eval LenSrtSeq = 290
C eval LenBlk = 80 + 16 + 16
C eval SrtMODSLen = 5 * 50
* Setup QLGSORT Sort Keys
C eval KeyStrPos1 = 21
C eval StringSiz1= 30
C eval DataType1 = 6
C eval SortOrder1 = 1
*
C eval KeyStrPos2 = 1
C eval StringSiz2 = 20
C eval DataType2 = 6
C eval SortOrder2 = 1
* Move keys to control block
C eval SortKeyVals(1) = SrtKeyLst1
C eval SortKeyVals(2) = SrtKeyLst2
* Execute QLGSORT
C call 'QLGSORT'
C parm SrtCtlBlk
Figure 2: The QLGSORT API requires that certain information be provided in data structures.
Personnel Listing
- Unsorted
First Name Last Name
Joseph Zimmerman
Laura Sanderson
Andrew Sanderson
Alice Sanderson
Frank Anderson Personnel Listing
- Sorted by Last, First Name
First Name Last Name
Frank Anderson
Alice Sanderson
Andrew Sanderson
Laura Sanderson
Joseph Zimmerman
Figure 3: The output of program SrtMODSPrn shows both unsorted and sorted data.
C parm EmpRecord
C parm EmpRecord
C parm SrtMODSLen
C parm SrtMODSLen
C parm APIErr Required Parameter Group:
Order Description Usage Type
1 Request control block Input Char(16)
2 Input data buffer Input Char(*)
3 Output data buffer Output Char(*)
4 Length of output data buffer Input Binary(4)
5 Output data information Output Binary(4)
6 Error code I/O Char(*)
Optional Parameter Group:
7 Returned records feedback Output Char(*)
8 Length of returned records feedback Input Binary(4)
*================================================================
D* QLGSRTIO Sort Control Block
D SrtIOCtl DS
D* Sort IO Request Type
D SrtIOTyp 1 4B 0
D* Sort IO Reserved Field
D SrtIORsrv 5 8B 0
D* Sort IO Record Length
D SrtIORLen 9 12B 0
D* Sort IO Record Count
D SrtIORCnt 13 16B 0
*================================================================
D EmpRecord1 ds
D FirstName1 20a
D LastName1 30a
* Employee List to be sorted by LastName, FirstName
D EmpRecord ds occurs(05)
D FirstName 20a
D LastName 30a
*================================================================
D SrtMODSLen s 4b 0
D OutSizelen s 9b 0
D FillerParm s 16a
D InSizelen s 9b 0
*================================================================
* Subroutine ExecSort will setup the sort control block and
* sort keys. Then QLGSORT will be called.
*
C ExecSort begsr
* Setup QLGSORT Control Block
C eval RecLen = 50
C eval RecCount= 0
C eval OffKeyLst = 80
C eval NumKeys = 2
C eval LenKeyEnt = 16
C eval LenSrtSeq = 290
C eval LenBlk = 80 + 16 + 16
C eval SrtMODSLen = 50 * 5
* Setup QLGSORT Sort Keys
C eval KeyStrPos1 = 21
C eval StringSiz1= 30
C eval DataType1 = 6
C eval SortOrder1 = 1
*
C eval KeyStrPos2 = 1
C eval StringSiz2 = 20
C eval DataType2 = 6
C eval SortOrder2 = 1
Figure 4: Setting up and calling QLGSORT is a matter of initializing data structures with the proper values.
Figure 5: The QLGSRTIO API uses this parameter list.
Figure 6: Sorting files with QLGSRTIO API requires additional data structures.
* Move keys to control block
C eval SortKeyVals(1) = SrtKeyLst1
C eval SortKeyVals(2) = SrtKeyLst2
* Execute QLGSORT initialization call
C call 'QLGSORT'
C parm SrtCtlBlk
C parm FillerParm
C parm FillerParm
C parm InSizelen
C parm OutSizelen
C parm APIErr
...
*
* Execute QLGSRTIO Call #1, by loading five records at once
C clear SrtIOCtl
C eval SrtIORLen = 50
C eval SrtIORCnt = 5
C eval SrtIOTyp = 1
*
C call 'QLGSRTIO'
C parm SrtIOCtl
C parm EmpRecord
C parm FillerParm
C parm InSizelen
C parm FillerParm
C parm APIErr
...
*
* Execute QLGSRTIO Call#2, to perform actual sort
C clear SrtIOCtl
C eval SrtIOTyp = 2
C eval SrtIORLen = 50
C eval SrtIORCnt = 5
C call 'QLGSRTIO'
C parm SrtIOCtl
C parm EmpRecord
C parm FillerParm
C parm InSizelen
C parm FillerParm
C parm APIErr
....
*
* Execute final QLGSRTIO Call #3, to return records one at a time
* After records are returned they are written to the outfile
C clear SrtIOCtl
C eval SrtIOTyp = 3
C eval SrtIORLen = 50
C eval SrtIORCnt = 1
C eval OccurIdx = 1
C do 5 OccurIdx
C call 'QLGSRTIO'
C parm SrtIOCtl
C parm FillerParm
C parm EmpRecord1
C parm SrtIORLen
C parm FillerParm
C parm APIErr
...
*
C eval SFirstNam = FirstName1
C eval SLastNam = LastName1
C write SrtOutR
C enddo
C endsr
Figure 7 : This code illustrates how you can return sorted data into a file from within RPG.
LATEST COMMENTS
MC Press Online