Q: In my CL program, I have an OPNQRYF command that I use to select certain records from a file. I know how to read the entire list of selected records in my RPG program, but how can I access them randomly, for example with a CHAIN?
A: You can access the results of an OPNQRYF randomly from RPG. The tricky part is that the file's keys need to match the external definition pulled into your RPG program when it was compiled.
When the keylist on the OPNQRYF matches that of the file, there's not much to it. You do an OPNQRYF in the CL, then chain to it from RPG. For example, suppose you have a file defined with the following DDS:
A UNIQUE
A R CUSTMASF
A CUSTNO 4S 0
A NAME 30A
A ADDRESS 30A
A CITY 13A
A STATE 2A
A ZIPCODE 5S 0
A STATUS 1A
A K CUSTNO
If you want to access a subset of this file by customer number, it's quite simple to do so using OPNQRYF and RPG. First, you need the CL program that runs the OPNQRYF command. In this case, I have it subset all active records from the customer master file, as follows:
PGM
OVRDBF FILE(CUSTMAS) SHARE(*YES)
OPNQRYF FILE((CUSTMAS)) QRYSLT('STATUS = "A"') +
KEYFLD((CUSTNO))
CALL RPGPGM
CLOF CUSTMAS
DLTOVR CUSTMAS
ENDPGM
The RPG program can access this file as it typically would. If it tries to chain to a record in which the status code isn't set to "A", the chain doesn't find the record. For example:
FCUSTMAS IF E K DISK
D Key s like(CustNo)
/free
Key = 1234;
chain Key CUSTMAS;
if %found;
. . . record was found and therefore must
be an active record . . .
endif;
/end-free
When I compile this program, it picks up the external definition of the CUSTMAS file. One of the attributes that it picks up is the keys for the file. In this case, the external key that it picks up is CUSTNO, because that's what the file is defined with. Because this same key is the one listed on the OPNQRYF statement, it works with OPNQRYF as well.
Sometimes, however, you want to use KEYFLD on OPNQRYF to change the keys that you access so that they're different from the actual file. When you do this, you have a problem because the external definition that the program picks up isn't the same as the one that OPNQRYF presents to it at runtime.
The solution is to create a "dummy" file. This is an empty file that contains the right record format and key list but has no data.
For example, let's say I want to chain to my CUSTMAS file by zip code. To do that, I create a dummy file named CUSTZIP, and it uses the following DDS:
A R CUSTMASF
A CUSTNO 4S 0
A NAME 30A
A ADDRESS 30A
A CITY 13A
A STATE 2A
A ZIPCODE 5S 0
A STATUS 1A
A K ZIPCODE
I compile this file as just an empty file with a different name from that of my CUSTMAS file. For example:
CRTPF FILE(CUSTZIP) SRCFILE(xxx/QDDSSRC)
When I write my RPG program, I use CUSTZIP on the F-spec. That way, the RPG compiler pulls its external definition and key information from the CUSTZIP file.
FCUSTZIP IF E K DISK
D Key s like(ZipCode)
/free
Key = 90120;
chain Key CUSTZIP;
if %found;
. . . hurray! Zip code found!
endif;
/end-free
In the CL program that calls this RPG program, I tell it to override the CUSTZIP file to the actual CUSTMAS file, and I run the query on that. In the query, I specify the zip code as the key field. For example:
PGM
OVRDBF FILE(CUSTZIP) TOFILE(CUSTMAS) SHARE(*YES)
OPNQRYF FILE((CUSTMAS)) FORMAT(CUSTZIP) +
QRYSLT('STATUS = "A"') KEYFLD((ZIPCODE))
CALL RPGPGM
CLOF CUSTMAS
DLTOVR CUSTMAS
ENDPGM
This way, the format in the RPG program and in the OPNQRYF match, and random access works properly.