Sort a Subfile with the QSort API from Cobol
by Carlos Balestrazzi
System iNetwork Programming Tips Contributor
May 22, 2007 -
In my previous article ("Reading IFS Directories in Cobol" (April, 19,
2007, article ID 54504)), I presented a technique that lets you read the
contents of an IFS directory and build a user interface that presents
the IFS directory entries in alphabetical order. I used a keyed data
queue to sort the subfile and I declared that that technique provided
"decent performance" for me. Nevertheless, there are occasions in which
you might need more than just decent performance - if you are building a
business-critical application, you need a truly fast response time. This
is where the QSORT API is helpful.
Let the User Choose the Field By Which to Sort the Subfile
Data queues require you to use the QSNDDTAQ API each time you write a
new entry. Later, when you build the subfile, you must read each data
queue entry with the QRCVDTAQ API. That's unacceptable in an environment
where you must re-sort the data each time the user selects a new field
by which the subfile must be sorted. In this environment, a technique
based on keyed data queues isn't the best option.
The solution that I present in this article demonstrates how to use the
QSORT function to sort a subfile by a field selected by the user at run
time.
The complete solution includes:
A Cobol program that reads an IFS directory (and the subdirectories
under it) and loads the obtained information in an array of data
structures.
A Cobol program that builds a "Work With" type user interface and lets
the user choose by which field the subfile will be sorted. The user can
select any field in the subfile by moving the cursor over the desired
column and pressing the F8 function key. This continues until the user
presses the F3 function key.
A series of ILE procedures (written in Cobol) that you must provide to
the QSORT function to perform the sort over each column in the subfile.
Loading the IFS Directory Entries Into An Array
Now let me explain in more detail how my first sample program works. The
core of the logic is the same as that of the sample program that I
presented in "Reading IFS Directories - Recursively" (April 23, 2007,
article ID 54562). That article explains all the Unix-type APIs the
program uses. But now, the program creates a user space that will
contain an array of data structures. This way, the second program can
easily access the loaded information. The QSORT API is flexible enough
to access a user space as if it were a conventional area of memory. My
program uses the QUSCRTUS API to create a user space and the QUSPTRUS
API to obtain the address of the newly created user space. In another
article ("Working with List APIs in Cobol" November 16, 2006, article ID
53549), I explained in detail how to use these two APIs in Cobol. The
QUSPTRUS API returns the address of the user space in a pointer
variable.
CALL "QUSPTRUS" USING qual-us-name
user-space-ptr.
Next, the program sets the address of the array with this pointer. This
causes the array to occupy the user space.
SET ADDRESS OF subfile-array TO user-space-ptr.
The array is defined in the LINKAGE SECTION in this way:
01 subfile-array.
03 number-of-entries PIC 9(9) BINARY.
03 sfl-array occurs 9999 times.
COPY dds-record2 IN dspdirinf.
Each element in the array is a data structure with the same fields as
the subfile record. For this reason, I used the DDS of the subfile
record format to describe this data structure. I defined an array of
9999 elements, but I don't worry about this. The real size of the array
is determined by the value of the number-of-entries variable. As I show
later, one of the parameters of the QSORT API is the number of entries
in the array, so we don't have to worry about free array space.
Building the Subfile from the Array
My second program carries out the following tasks:
Obtains the address of the user space
Builds the subfile from the information contained in the array
Displays the subfile and lets the user choose which field to sort it by.
Sorts the array by the selected field and rebuilds the subfile.
The user can classify the subfile by the FILENAME field, the DIRECTORY
field, or the CHGDATE field. Therefore, the program must be capable of
knowing which column the user has selected. The Return Cursor Location
(RTNCSRLOC) DDS keyword for display files can send to the Cobol program
the name of field on which the cursor is located. Therefore, the only
thing that my program has to do is check out the value returned by the
RTNCSRLOC DDS keyword.
EVALUATE csrfld IN control-i-fmt
WHEN "FILENAME"
PERFORM sort-by-filename
WHEN "DIRECTORY"
PERFORM sort-by-directory
WHEN "CHGDATE"
PERFORM sort-by-change-date
WHEN OTHER
CONTINUE
END-EVALUATE.
Each of these routines calls the QSORT API with appropriate values for
its four parameters: the offset of the array into the system space, the
number of entries in the array, the width of each element in the array,
and the entry point address of an ILE procedure that performs the
comparison between two elements in the array:
CALL PROCEDURE "qsort"
USING BY VALUE ADDRESS OF subfile-array
BY VALUE number-of-entries
BY VALUE width-each-element
BY VALUE function-pointer1
END-CALL.
It's relatively simple to set the first three parameters, so let me
explain how to set the fourth. In my program, the function-pointer1
variable is a procedure-pointer data item (i.e., a pointer to an ILE
procedure). You must use a procedure-pointer data item, defined with the
USAGE IS PROCEDURE-POINTER clause, to pass the entry address of a
program (or ILE procedure) to the QSORT API. A procedure-pointer data
item can only be set in the way that the IBM ILE Cobol manuals define as
the "Format 6 of the SET statement" (i.e., using the LINKAGE TYPE clause
in the SET statement).
SET function-pointer TO ENTRY
LINKAGE TYPE IS PROCEDURE "QSORTCBL1".
Also, you can use the LINKAGE TYPE clause in the SPECIAL-NAMES
paragraph:
SPECIAL-NAMES.
LINKAGE TYPE IS PROCEDURE FOR "QSORTCBL1"
"QSORTCBL2"
"QSORTCBL3".
Then, you do not need to specify the LINKAGE TYPE phrase in the SET
statement:
SET function-pointer1 TO entry "QSORTCBL1".
SET function-pointer2 TO entry "QSORTCBL2".
SET function-pointer3 TO entry "QSORTCBL3".
"QSORTCBL1" is a separately compiled object module. This module and the
two others that my program provides to the QSORT API reside in a service
program. They are bound by reference to the main program.
Bound-by-reference calls are stored in the main program as symbolic
references to the modules in the service program. If I wanted to, I
could have used a bound-by-copy approach to call the procedures, but
dynamic program calls would not work. You must remember that these
procedures are not called by the main program, but by the QSORT
function.
You might wonder why the QSORT API needs to use these procedures. The
answer is: It lets the programmer take absolute control over the entire
sort process. The QSORT API simply asks which of two elements in the
array is higher. The procedures provide the answer. Then, the QSORT API
applies the complex quicksort algorithm (developed by C.A.R. Hoare) over
the two array elements. This "scan and swap" process continues until the
whole array is sorted.
The logic of the procedures is very simple. See the first one (that I
called QSORTCBL1):
WORKING-STORAGE SECTION.
01 return-value PIC s9(9) BINARY.
LINKAGE SECTION.
01 key-argument.
COPY dds-record2 IN dspdirinf.
01 array-element.
COPY dds-record2 IN dspdirinf.
PROCEDURE DIVISION USING key-argument,
array-element
RETURNING return-value.
main
SECTION.
unique-paragraph.
IF filename IN key-argument > filename IN array-element
MOVE 1 TO return-value
ELSE
IF filename IN key-argument < filename IN array-element
MOVE -1 TO return-value
ELSE
MOVE 0 TO return-value
END-IF
END-IF.
That's all! The procedure receives from the QSORT API two elements in
the array and must return to it one of the following values: -1 if the
first element is less than the second element, 0 if they are equal, and
1 if the first element is greater than the second element.
You can see that the third procedure (that compares two date fields) has
a little trick: the sense of the "greater than" and "less than" return
value is reversed. This way, I sort the date column in descending order.
A Final Note
I created all the module objects using the CRTCBLMOD command.
Next, I created a service program called QSORTCBL to store the object
modules that the QSORT function will use and I used the CRTPGM command
to create the DSPDIRINF2 program object:
CRTPGM PGM(DSPDIRINF2) BNDSRVPGM(QSORTCBL) BNDDIR(QC2LE)
Compile the RECURDIR2 object program with the CRTBNDCBL command:
CRTBNDCBL PGM(RECURDIR2) SRCFILE(QLBLSRC) +
BNDDIR(QC2LE) ACTGRP(*NEW)
You can download the Cobol and DDS source code for all the modules
involved in the solution from the link provided at the end of this
article. I include a CL program that will run the Cobol programs in the
appropriate order.
If you'd like to experiment with these sample programs, please change
the value of the default-directory-name variable in the RECURDIR2 source
code to an IFS directory name that exists in your installation.
More Information
Find out more about the QSORT API at:
http://publib.boulder.ibm.com/iseries/v5r2/ic2924/books/c415607107.htm#H
DRQSORT
Code Download
You can download the sample code for this article from the following
link:
http://www.pentontech.com/IBMContent/Documents/article/54761_210_QsortCo
bol.zip
John Arnold
(301) 354-2939
-----Original Message-----
From: cobol400-l-bounces@xxxxxxxxxxxx
[
mailto:cobol400-l-bounces@xxxxxxxxxxxx] On Behalf Of
cobol400-l-request@xxxxxxxxxxxx
Sent: Wednesday, June 06, 2007 1:00 PM
To: cobol400-l@xxxxxxxxxxxx
Subject: COBOL400-L Digest, Vol 5, Issue 26
Send COBOL400-L mailing list submissions to
cobol400-l@xxxxxxxxxxxx
To subscribe or unsubscribe via the World Wide Web, visit
http://lists.midrange.com/mailman/listinfo/cobol400-l
or, via email, send a message with subject or body 'help' to
cobol400-l-request@xxxxxxxxxxxx
You can reach the person managing the list at
cobol400-l-owner@xxxxxxxxxxxx
When replying, please edit your Subject line so it is more specific than
"Re: Contents of COBOL400-L digest..."
Today's Topics:
1. Sort question (Davis, Clementina)
2. Re: Sort question (Winchester Terry)
3. Re: Sort question (Simon Coulter)
4. Re: Sort question (Davis, Clementina)
5. list of Cobol shops (Phil Kestenbaum)
----------------------------------------------------------------------
message: 1
date: Wed, 6 Jun 2007 08:26:57 -0400
from: "Davis, Clementina" <cdavis@xxxxxxxxxxxxxxxxxxxxxxx>
subject: [COBOL400-L] Sort question
Team:
I have a sub-file screen that displays by date ascending. I need to
display it by date descending. We don't want to create a new logical if
at all possible.
What would be the best option to sort the records? I am thinking the
Cobol sort but I have never used it. Your ideas and/or samples are
appreciated.
Thanks.
Clementina A. Davis
Programmer Analyst
Broward County Clerk of Courts
Clerk's Technology Department
Tel: 954-831-6943
Fax: 954-831-6380
cdavis@xxxxxxxxxxxxxxxxxxxxxxx
CONFIDENTIALITY NOTICE: This e-mail message including attachments, if
any, is intended only for the person or entity to which it is addressed
and may contain confidential and/or privileged material. Any
unauthorized review, use, disclosure or distribution is prohibited. If
you are not the intended recipient, please contact the sender by reply
e-mail and destroy all copies of the original message. Under Florida
law, e-mail addresses are public record. If you do not want your e-mail
address released in response to a public-records request, do not send
electronic mail to this entity.
------------------------------
message: 2
date: Wed, 6 Jun 2007 08:40:41 -0400
from: "Winchester Terry" <terry.winchester@xxxxxxxxxxxxxxx>
subject: Re: [COBOL400-L] Sort question
Yes, a Cobol SORT is very useful for sorting subfiles :)
I have a couple of interactive program examples but they are rather
complex. Contact me offline if your interested...
Terry Winchester
Programmer/Analyst
As an Amazon Associate we earn from qualifying purchases.