Using IBM i? Need to create Excel, CSV, HTML, JSON, PDF, SPOOL reports? Learn more about the fastest and least expensive tool for the job: SQL iQuery.
Good afternoon! I always thought that RTVMBRD would return the number of members for a physical file, but apparently it always returns 0. I need a CL command that I can include in a CLP that will return the number of members for a physical file.
Can anyone help me out?
Thanks!
I think the RTVMBRD returned value you're looking at is this one:
Specifies the name of a variable used to retrieve the number of data file members for this logical file member. In CL programs, this should be a 2-position decimal variable. If the member is a physical file member, a value of 0 is returned.
The API QDBRTVFD returns the data that you need.
I was looking thru APIs and didn't see the one you mentioned, Neil. I'll check it out. Thanks!
Chris
here is something I found on line, hope it helps
RTVMBRD: Retrieve Member De!--script--ion. Specify a file (and optionally a member) and you can find out more about that file.
Here's an example of the RTVMBRD command.
RTVMBRD FILE(your-library/your-file) MBR(*FIRSTMBR) RTNLIB(&RTNLIB) RTNMBR(&RTNMBR) SRCTYPE(&SRCTYPE) TEXT(&TEXT) NBRCURRCD(&NBRCURRCD)
The RTVMBRD command can be used in a loop to process all members of a multi-member file (physical or source). On the first execution of the command specify the MBR parameter as MBR(*FIRST *SAME) (to process in creation-date order) or MBR(*FIRSTMBR *SAME) (to process in alphabetical-name order). On subsequent executions of the command, specify MBR(&RTNMBR *NEXT). Be sure to specify parameter RTNMBR each time you execute the command so that you'll have the value for the next iteration. Alternatively you can specify MBR(*LAST *SAME) or MBR(*LASTMBR *SAME) followed by MBR(&RTNMBR *PRV) to read through the members in reverse order.
The following short example illustrates how to process all members of a file in alphabetical order.
Pgm Dcl &Member *char 10 Dcl &Position *char 10 Dcl &CurUser *char 10 Dcl &RtnMbr *char 10 RtvJobA curuser(&CurUser) /* process members in alphabetical order */ ChgVar &Member *FIRSTMBR ChgVar &Position *SAME NextMember: RtvMbrD file(SomeFile) mbr(&Member &Position) rtnmbr(&RtnMbr) MonMsg cpf3049 exec(goto EndOfFile) /* place commands to process &RtnMbr here */ SndMsg msg('Processing member' *bcat &RtnMbr *tcat '.') + tousr(&CurUser) /* move to the next member */ ChgVar &Member &RtnMbr ChgVar &Position *NEXT goto NextMember EndOfFile:
You'd need like a RTVFD, but there isn't one. [As previously noted, help for RTVMBRD says NBRDTAMBRS is for LF's, and that for PF's it always returns 0. I think it tells you how many PF members are "based on" by the current LF member name.]
I don't have access to a system right now. Try DSPFD to *OUTFILE with *ATR and *PF. If that doesn't have number of members, you can get it from *MBRLIST. In QAFDMBRL, field &MLNOMB has the number of members (so you only need to read the first record - you don't need a loop). If there are no members, you still get one record with a 0 for &MLNOMB.
If it's pure CL, the DSPFD is probably good enough. But you can also use the QUSLMBR API. MBRI0100 returns just member names. I'm not sure what you get if there are no members, so you'd have to test that. Either the number of list entries (in the header) will be zero (and you don't need to look at the list), or it will be one, and you'll need to read that first list entry to determine if it's a real member name or some special value. Of course, if the number of list entries is greater than one, then you also won't need to process the list.
I wrote a quick and dirty little RTVFD command for you. It will return the member count. You have to be on at least v5r4 to have it work for you. here's the source:
RTVFD: CMD PROMPT('Retrieve File De!--script--ion Info') + ALLOW(*IPGM *BPGM *IMOD *BMOD) PARM KWD(FILE) TYPE(QUAL1) MIN(1) PROMPT('File + name') QUAL1: QUAL TYPE(*NAME) LEN(10) EXPR(*YES) QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) + SPCVAL((*LIBL) (*CURLIB)) EXPR(*YES) + PROMPT('Library') PARM KWD(RTNMBRS) TYPE(*DEC) LEN(5 0) + RTNVAL(*YES) MIN(1) CHOICE('Type(*DEC) + Len(5 0)') PROMPT('CL var for member count')
The program I wrote is in CL, so here's the CPP for the above command:
The program calls the QDBxxx API and returns the member count. For debug purposes, I included the cozTools CLEDIT command that converts the returned value to text and then I send the message with the member count to *PRV. You can strip out that part if you want.
RTVFD: PGM PARM(&FILE &RTNMBRCNT) DCL VAR(&RTNMBRCNT) TYPE(*DEC) LEN(5) DCL VAR(&MBRCOUNT) TYPE(*CHAR) LEN(10) DCL VAR(&FILD0100) TYPE(*CHAR) LEN(400) DCL VAR(&DBFHMXM ) TYPE(*INT) STG(*DEFINED) + LEN(2) DEFVAR(&FILD0100 42) DCL VAR(&DBFHMNUM) TYPE(*INT) STG(*DEFINED) + LEN(2) DEFVAR(&FILD0100 48) DCL VAR(&DBFmxfnum) TYPE(*INT) STG(*DEFINED) + LEN(2) DEFVAR(&FILD0100 207) DCL VAR(&DBFmxrl) TYPE(*INT) STG(*DEFINED) + LEN(2) DEFVAR(&FILD0100 305) DCL VAR(&DBFgkct) TYPE(*INT) STG(*DEFINED) + LEN(2) DEFVAR(&FILD0100 315) DCL VAR(&DBFpact) TYPE(*CHAR) STG(*DEFINED) + LEN(2) DEFVAR(&FILD0100 337) DCL VAR(&DBFHRIS) TYPE(*CHAR) STG(*DEFINED) + LEN(6) DEFVAR(&FILD0100 339) DCL VAR(&RTNLEN) TYPE(*INT) LEN(4) VALUE(400) DCL VAR(&RTNFILE) TYPE(*CHAR) LEN(20) DCL VAR(&FILE) TYPE(*CHAR) LEN(20) DCL VAR(&APIERROR) TYPE(*CHAR) LEN(16) VALUE(X'0000000000000000') MONMSG MSGID(CPF0000) CALL PGM(QDBRTVFD) PARM(&FILD0100 &RTNLEN + &RTNFILE 'FILD0100' &FILE '*FIRST' '0' + '*FILETYPE' '*EXT' &APIERROR) CHGVAR VAR(&RTNMBRCNT) VALUE(&DBFHMNUM) /* Extra cozTools-enabled stuff */ CLEDIT RTNVAR(&MBRCOUNT) VALUE(&DBFHMNUM) SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA('File' + *BCAT %SST(&FILE 1 10) *BCAT 'in' *BCAT + %SST(&FILE 11 10) *BCAT 'contains' *BCAT + &MBRCOUNT *BCAT 'members.') MSGTYPE(*COMP) ENDPGM: ENDPGM
Then I wrote a little test program to "prove" it'll work, that is listed below:
TESTRTVFD: PGM DCL VAR(&MBRS) TYPE(*DEC) LEN(5 0) DCL VAR(&MBRA) TYPE(*CHAR) LEN(5) MONMSG MSGID(CPF0000) RTVFD FILE(COZTOOLS/QRPGLESRC) RTNMBRS(&MBRS) CHGVAR VAR(&MBRA) VALUE(&MBRS) SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA('Member + count' *BCAT &MBRA) ENDPGM: ENDPGM
You could also use the List Members API, but for that you need to create a UsrSpc, before you create the list. Also you don't actually need the list, you just need to read the header bit of the Data Extract for Number of Elements. But also if the list is too large to be contained in the User Space, the Number of Elements might be a inaccurate - there's a status code in the header which is set to a certain value if the list is complete, other values indicate incomlete or error.
Another option... wrap this in a Callable CL Pgm.
DLTF QTEMP/TMPMBRCNT
MONMSG CPF2105
DSPFD FILE(&YOURLIB/&YOURFILE) TYPE(*MBR) OUTPUT(*OUTFILE)
FILEATR(*PF) OUTFILE(QTEMP/TMPMBRCNT) OUTMBR(*FIRST *REPLACE)
Then RCVF file QAFDMBR Format QWHFDMBR in CL and return field MBNOMB.
Ringer
Thanks Bob! That API is nightmarish, but I missed that number of members is in the header.
Dale, like most of the APIs, this one is documented poorly and is very misleading. I sometimes leave these goofy APIs alone for years, and then revisit them only to look at it with different eyes. Then I usually have success with them. But the docs are horrible.