The idea for this post came from a discussion I saw on Facebook. Someone asked:
- In your RPG how can you read from a particular member of a file?
- By default which member is read?
- How can you read all the members of your PF in your RPG program?
- How can you find out which member is being read?
The answer for the first question is to use the EXTMBR in the File specifications. I will not go into details about this as it is covered in Useful keywords for your F-specs.
The answer for the second question is that when a program opens a file with more than one member, by default, it opens the first member, which is the oldest member as that was the one created first.
The third and fourth questions I combined into my own scenario: I want to have a program that reads all the members in a multi member file to find a particular record and identify which member this record is in.
I created a file, TESTPF, with two members, ONE and TWO (I know I will not win any awards for giving things in my posts interesting names).
A R TESTPFR A FLD1 10A A K FLD1
I added data to the file to allow me to track which member was being read:
|Value of FLD1|
You could use the OVRDBF command in CL to override the member parameter to all members, MBR(*ALL), see below. I have set the override scope to *CALLLVL, therefore, only programs called by this program will have the override, and when this program ends the override no longer exists.
OVRDBF FILE(TESTPF) MBR(*ALL) OVRSCOPE(*CALLLVL)
Or you could use the EXTMBR keyword in the File specification of the RPGLE/RPG IV program, see below.
FTESTPF IF E K DISK extmbr('*ALL')
In both cases the members are processed in order. In other words when all of the records from the first member have been read the program will start reading then the records in the second member.
This answers the third question posed at the start of this post.
Before I show program RDALLMBR1 I want to explain the File Information Data Structure. It is a data structure that contains feedback information associated with a file. I like to use it as an externally described data structure. i have this data structures in Externally described Data Structures. Below is the DDS for my File Information Data Structure.
A R DUMMY A FILLER1 8A A FILEOPEN 1A TEXT('File open') A ENDOFFILE 1A TEXT('End of file') A FILESTATUS 5A TEXT('File status code') A OPCODE 6A TEXT('Last operation code') A ROUTINE 8A TEXT('Routine name') A SRCSTMTNBR 8A TEXT('Source statement No.') A FILLER2 8A A ERRMSGID 7A TEXT('Error message id') A FILLER3 30A A FILE 10A TEXT('File name') A LIBRARY 10A TEXT('Library name') A FILLER4 26A A MEMBER 10A TEXT('Member name') A FILLER5 122A A RCDFORMAT 10A TEXT('Record format') A FILLER6 258A
The data structure is 528 characters long, therefore, the parts I am not concerned about here by I have coded as Filler fields, FILLER1 - FILLER6.
|ENDOFFILE||1=End of file encountered.|
|FILESTATUS||File status code, I am not going to lilst them here but I am going to refer you to the IBM web site here.|
|OPCODE||Last operation code performed to file.|
|ROUTINE||Routine last operation occured in.|
|SRCSTMNBR||Useful if you compile you RPGLE with OPTION(*SRCSTMT) as it will give the source statement line number the last operation to the file was performed.|
|ERRMSGID||Error mention encountered when last operation was performed. Blank = no error.|
|FILE||Name of file.|
|LIBRARY||Library file is in.|
|MEMBER||File member name.|
Now we can look at the RPGLE/RPG IV code:
01 FTESTPF IF E K DISK extmbr('*ALL') 02 F infds(FileDs) 03 D FileDs E DS extname(FILEDS) D qualified /free 04 dow (1 = 1) ; 05 read TESTPFR ; 06 if (%eof) ; 07 leave ; 08 endif ; 09 post TESTPF ; . . 10 enddo ; 11 *inlr = *on ;
In the F-spec, line 1, is where I used the EXTMBR to define that I want to read all members. And on line 2, I have defined the File Information Data Structure for this file will be FileDs using the INFDS keyword.
By using the external data structure for the File Information Data Structure definition it can be simply be added by defining the file name of the file containing the external data structure definition in the EXTNAME keyword, see line 3. I have also QUALIFIED the data structure sub fields.
Line 4 - 8 are straight forward and I am not going to explain.
To load information into the File Information Data Structure I need to use the POST operation code, line 9. It is followed by the file name so that it knows which file's information to load into which data structure.
So what happens when this program runs:
If I ran RDMBRALL1 in debug and looked at the values in FileDs after the first read of TESTPF it would look like this (I am excluding the Filler fields):
> EVAL fileds FILEDS.FILEOPEN = '1' FILEDS.ENDOFFILE = '0' FILEDS.FILESTATUS = '00000' FILEDS.OPCODE = 'POST F' FILEDS.ROUTINE = '*DETC ' FILEDS.SRCSTMTNBR = '00001500' FILEDS.ERRMSGID = ' ' FILEDS.FILE = 'TESTPF ' FILEDS.LIBRARY = 'MYLIB ' FILEDS.MEMBER = 'ONE ' FILEDS.RCDFORMAT = 'TESTPFR '
From this simple example you can see how easy it would be to identify which member is being read, answering the fourth question posted at the start of this post.
More information about these commands, operation codes, etc. can be found on the IBM website.
- OVRDBF command
- EXTMBR RPGLE File specification keyword
- File information data structure
- INFDS file feedback example
- RPGLE POST operation code
In my post about Externally described Data Structures someone asked why I did not use just a /COPY or /INCLUDE to insert that data structure into the program's source. For that situation that was a valid question and either way would have worked.
I believe that in the scenario of wanting the File Information Data Structure on two files in the same program then the external data structure is easier, as shown below:
01 FTESTPF1 IF E K DISK infds(File1Ds) 02 FTESTPF2 IF E K DISK infds(File2Ds) 03 D File1Ds E DS extname(FILEDS) qualified 04 D File2Ds E DS extname(FILEDS) qualified
If I was to use the /COPY or /INCLUDE would I need two pieces of code to copy, one for each data structure?
This article was written for IBM i 7.1, and it should work with earlier releases too.