Wednesday, April 2, 2025

Easier way to check if member exists

Amended April 23, 2025:  To use CHKOBJ command.


I was asked: What is the easiest way to check if a member exists in a file?

They had been recommended to perform the check in a CL program, but wondered if there was a way to do the same in a RPG program.

In a "pre-SQL" world I would have used the Check Object command, CHKOBJ, in a CL program to check if the member exists. My program would look something like this:

01  PGM PARM(&LIB &FILE &MBR &RTNCODE)

02  DCL VAR(&LIB) TYPE(*CHAR) LEN(10)
03  DCL VAR(&FILE) TYPE(*CHAR) LEN(10)
04  DCL VAR(&MBR) TYPE(*CHAR) LEN(10)
05  DCL VAR(&RTNCODE) TYPE(*CHAR) LEN(3)

06  CHGVAR VAR(&RTNCDE) VALUE('OK')

07  CHKOBJ OBJ(&LIB/&FILE) OBJTYPE(*FILE) MBR(&MBR)
08  MONMSG MSGID(CPF0000) +
             EXEC(CHGVAR VAR(&RTNCDE) VALUE('ERR'))

09  ENDPGM

Line 1: The CL program is passed four parameters:

  1. &LIB:  Library name
  2. &FILE:  File name
  3. &MBR:  Member name
  4. &RTNCODE:  Return code returned to the calling program

Lines 2 – 5: Definitions of the passed parameters.

Line 6: Change the Return Code to 'OK', which means.. you get it everything is OK.

Line 7: Use the CHKOBJ to check if the member is found in the file and library passed.

Line 8: I am using the Monitor Message command, MONMSG, to monitor for CPF0000 to capture any error encountered: member not found, file not found, library not found, not authorized to object, etc. And the value 'ERR' is moved to the return code.

Below is an example program of how I could call the above program:

01  **free
02  dcl-s ReturnCode char(3) ;

03  dcl-pr CheckForMember extpgm('TESTCL') ;
04    *n char(10) const ;   // Library
05    *n char(10) const ;   // File
06    *n char(10) const ;   // Member
07    *n char(3) ;          // Return code
08  end-pr ;

09  CheckForMember('MYLIB' : 'DEVSRC' : 'TESTCL' : ReturnCode) ;

10  dsply ('Return code =  ' + ReturnCode) ;

11  *inlr = *on ;

Line 2: Defining the variable for the return code.

Lines 3 – 8: The procedure prototype that allows me to call the CL program. I am using the more descriptive procedure name CheckForMember rather than the name of the program, TESTCL. The first three parameters are defined as constants, CONST, which allows me to give the parameter as a string, rather than a variable. The exception is the fourth parameter, this is the return code which needs to be returned from the called program.

Line 9: Call the CL program passing to it the library, file, and member names, and having returned the return code.

Line 10: Using the Display operation code, DSPLY, display the value in the return code.

When I call this program the following is displayed:

DSPLY  Return code =  OK

Which confirms that the member TESTCL in the file DEVSRC in the library MYLIB exists.

If I wanted to do all of this in one RPG program I would use the SQL View SYSMEMBERSTAT to check if the member exists.

My new RPG program comes in two parts. The main section and the procedure that checks for the member. Below is the main section:

01  **free
02  ctl-opt dftactgrp(*no) ;

03  dcl-s ReturnCode char(3) ;

04  dcl-pr CheckForMember char(3) ;
05    *n char(10) const ;   // Library
06    *n char(10) const ;   // File
07    *n char(10) const ;   // Member
08  end-pr ;

09  ReturnCode = CheckForMember('MYLIB' : 'DEVSRC' : 'TESTCL') ;
10  dsply ('Return code 1 =  ' + ReturnCode) ;

11  ReturnCode = CheckForMember('MYLIB' : 'DEVSRC' : 'NOT_EXIST') ;
12  dsply ('Return code 2 =  ' + ReturnCode) ;

13  *inlr = *on ;

Line 2: I need the DFTACTGRP(*NO) as I am going to call a procedure.

Line 3: Definition for the return code variable used in the main part of the program.

Lines 4 – 8: This is the procedure prototype for the procedure that will be called. It has three input parameters. The CHAR(3) on line 4 means that a character parameter of three long is returned from the procedure.

Line 9: The procedure is called with the names of the library, files, and member. The value returned from the procedure is placed in the return code variable.

Line 10: Display the return code.

Line 11: This call to the procedure is for a member does not exist, hence its name.

Line 12: The return code is displayed.

Below is the procedure that validates if the library, file, and member exists:

14  dcl-proc CheckForMember ;
15    dcl-pi *n char(3) ;
16      inLibrary char(10) const ;
17      inFile char(10) const ;
18      inMember char(10) const ;
19    end-pi ;
                                                    
20    dcl-s ReturnCode char(3) ;

21    ReturnCode = 'ERR' ;

22    exec sql SELECT 'OK ' INTO :ReturnCode
23               FROM QSYS2.SYSMEMBERSTAT
24              WHERE SYSTEM_TABLE_SCHEMA = :InLibrary
25                AND SYSTEM_TABLE_NAME = :InFile
26                AND SYSTEM_TABLE_MEMBER = :InMember ;

27    return ReturnCode ;
28  end-proc ;

Lines 15 – 19: Procedure interface for this procedure.

Line 20: Definition of the return code variable, that is local to this procedure only.

Line 21: Change the return code to 'ERR'.

Lines 22 – 26: Look up in the SYSMEMBERSTAT View the row for the library, file, and member. If it is found the value of 'OK' is moved to the return code.

Line 27: The value in the return code is returned to what called this procedure.

When this program is executed the following is displayed:

DSPLY  Return code 1 =  OK
DSPLY  Return code 2 =  ERR

The first return code is 'OK' as the member TESTCL does exist.

The second return code is 'ERR' as the member NOT_EXIST does not exist.

This is another of where using a SQL statement is easier and simpler than the CL alternative.

 

This article was written for IBM i 7.5, and should work for some earlier releases too.

4 comments:

  1. Using the allocate object doesn't seem like a good idea at all. It might be locked by something else and you're monitoring isn't differentiating between the member's existence and any other error. If using CL, CHKOBJ seems the obvious choice.

    ReplyDelete
    Replies
    1. Would be nice changing it to a decent CHKOBJ example. This website is source to so much people (and even more programs), beginners might think it's a good idea to do it the ALCOBJ *EXCL way.

      Delete
    2. I have amended the post to use CHKOBJ.

      Delete
  2. Another way in RPG would be to define the file with user open, override the file to the member you want, and monitor for an error when trying to open it.

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.