Wednesday, July 2, 2025

SQL table function to list all imports for ILE program or service program

This is one of the IBM i enhancements that was released in version 7.6, but not in 7.5 TR6. This new table function, PROGRAM_RESOLVED_IMPORTS, allows me to get a list of all the imports for an ILE program or service program.

This Table function has four parameters:

  1. PROGRAM_LIBRARY:  Library that contains the ILE program or service program. "*LIBL" is not supported.
  2. PROGRAM_NAME:  Name of the ILE program or service program.
  3. OBJECT_TYPE*PGM for ILE program, *SRVPGM for ILE service program.
  4. IGNORE_ERRORS:  Optional. NO when an error is encounter an error is returned. YES a warning is returned, this is the default.

This looks like:

01  SELECT * 
02    FROM TABLE(QSYS2.PROGRAM_RESOLVED_IMPORTS( 
03                 PROGRAM_LIBRARY => < program_library_name >,
04                 PROGRAM_NAME    => < program_name >,
05                 OBJECT_TYPE     => < *PGM or *SRVPGM >))

In my first example I have a program, TESTPGM1, that calls various procedures in a service program, SRVPGM1.

TESTPGM1 looks like:

01  **free                                      
02  ctl-opt main(Main) bnddir('TESTPGM1') ;
03  /copy devsrc,copybook ;

04  dcl-proc Main ;
05    dcl-s Returned char(10) ;

06    Returned = First() ;                      
07    Returned = Second('X') ;
08    Returned = Third() ;

09    return ;
10  end-proc ;

Line 2: I am using a Main procedure called Main. And I will be using a binding directory for the list of objects to bind to this program.

Line 3: Copy the contents of the member copybook into this program. This will copy all the procedure definitions, DCL-PR, into the source.

Line 4: Start of the Main procedure.

Line 5: Defining a variable to contain what is returned from the service program's procedures.

Lines 6 - 8: Calling procedures in the service programs. Second needs to be passed a parameter, others do not. The result is placed in the variable Returned. For this example what those values are is immaterial.

I can the see the contents the of the TESTPGM1 binding directory using the BINDING_DIRESTORY_INFO View:

01  SELECT ENTRY_LIBRARY,ENTRY,ENTRY_TYPE, 
02         ENTRY_ACTIVATION
03    FROM QSYS2.BINDING_DIRECTORY_INFO 
04   WHERE BINDING_DIRECTORY_LIBRARY = 'MYLIB'
05     AND BINDING_DIRECTORY = 'TESTPGM1'

I am only interested in the same columns that appear using the Work with Binding Directory Entries command, WRKBNDDIRE.

The result is:

ENTRY_            ENTRY_   ENTRY_
LIBRARY  ENTRY    TYPE     ACTIVATION
-------  -------  -------  ----------
*LIBL    SRVPGM1  *SRVPGM  *IMMED

There is only the service program SRVPGM1 in the binding directory that will be bound to TESTPGM1 when it is created.

The procedures in the procedure look like:

01  **free
02  ctl-opt nomain reqprexp(*no) ;

03  dcl-proc First export ;
     | 
04  end-proc ;

05  dcl-proc Second export ;
     |
06  end-proc ;

07  dcl-proc Third export ;
     |
08  end-proc ;

Line 2: The module for the service program's module does not have a main procedure. The REQPREXP(*NO) means that I do not need procedure prototypes for these procedures.

What happens within the procedures is not needed. All the procedures have been marked as EXPORT, therefore, I can call them from TESTPGM1.

Now I can use the PROGRAM_RESOLVED_IMPORTS Table function to which exports TESTPGM1 uses. My statement is:

01  SELECT * 
02    FROM TABLE(QSYS2.PROGRAM_RESOLVED_IMPORTS( 
03                 PROGRAM_LIBRARY => 'MYLIB',
04                 PROGRAM_NAME    => 'TESTPGM1',
05                 OBJECT_TYPE     => '*PGM'))

Line 3: My program is in the library MYLIB.

Line 4: The program's name is TESTPGM1.

Line 5: And it is a program.

I have not given the IGNORE_ERRORS parameter as the default is 'YES'.

The results are:

BOUND_              RESOLVED
SERVICE_  BOUND_    SERVICE_                         RESOLVED_
PROGRAM_  SERVICE   PROGRAM_  RESOLVED_              SYMBOL_
LIBRARY   PROGRAM   LIBRARY   SYMBOL_NAME            USAGE
--------  --------  --------  ---------------------  --------
*LIBL     SRVPGM1   MYLIB     THIRD                  *PROCEXP
*LIBL     SRVPGM1   MYLIB     SECOND                 *PROCEXP
*LIBL     SRVPGM1   MYLIB     FIRST                  *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_G_CANCEL_H       *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_G_FC_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_G_INFSR_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_CALL_FC_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_CALL_EN_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_TERM_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_CAN_EXC_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_DFT_ERROR        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT             *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_SIGNAL_EXCP      *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leDefaultEh2      *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leBdyCh2          *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leBdyEpilog2      *PROCEXP
QSYS      QRNXUTIL  QSYS      _QRNX_GET_ASSOC_CCSID  *PROCEXP

The first three results are from the SRVPGM1 service program. The rest of the exports were included into the program by the compiler.

When I use PROGRAM_RESOLVED_IMPORTS with SRVPGM1:

01  SELECT * 
02    FROM TABLE(QSYS2.PROGRAM_RESOLVED_IMPORTS( 
03                 PROGRAM_LIBRARY => 'MYLIB',
04                 PROGRAM_NAME    => 'SRVPGM1',
05                 OBJECT_TYPE     => '*SRVPGM'))

Line 3: The service program is in the library MYLIB.

Line 4: The service program's name is SRVPGM1.

Line 5: And it is a service program.

The results returned are:

BOUND_              RESOLVED
SERVICE_  BOUND_    SERVICE_                         RESOLVED_
PROGRAM_  SERVICE   PROGRAM_  RESOLVED_              SYMBOL_
LIBRARY   PROGRAM   LIBRARY   SYMBOL_NAME            USAGE
--------  --------  --------  ---------------------  --------
QSYS      QRNXIE    QSYS      _QRNX_INIT_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT             *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leDefaultEh2      *PROCEXP
QSYS      QRNXUTIL  QSYS      _QRNX_GET_ASSOC_CCSID  *PROCEXP

These are the imported procedures included into the service program when it is created.

In my next example the service program, SRVPGM2, has an import to another services program.

The program's, TESTPGM2, source looks like:

01  **free
02  ctl-opt main(Main) bnddir('TESTPGM2') ;

03  dcl-pr Another char(10) ;
04  end-pr ;

05  dcl-proc Main ;
06    dcl-s Returned char(10) ;
07    Returned = Another() ;
08    return ;
09  end-proc ;

Line 2: This program also has a Main procedure. It also uses a binding directory, which is different from the one used by the previous program.

Lines 3 and 4: The procedure prototype for the procedure, Another, I will be calling.

Line 5: The start of the Main procedure.

Line 6: Definition of the variable to contain what is returned from the Another procedure.

Line 7: The Another procedure is called, and what is returned is placed in the variable Returned.

I can check for the contents of the binding directory using the BINDING_DIRECTORY_INFO again:

01  SELECT ENTRY_LIBRARY,ENTRY,ENTRY_TYPE, 
02         ENTRY_ACTIVATION
03    FROM QSYS2.BINDING_DIRECTORY_INFO 
04   WHERE BINDING_DIRECTORY_LIBRARY = 'MYLIB'
05     AND BINDING_DIRECTORY = 'TESTPGM2'

This shows that there is just one entry, for the service program SRVPGM2.

ENTRY_            ENTRY_   ENTRY_
LIBRARY  ENTRY    TYPE     ACTIVATION
-------  -------  -------  ----------
*LIBL    SRVPGM2  *SRVPGM  *IMMED

The source of the service program look like:

01  **free                                                   
02  ctl-opt nomain reqprexp(*no) bnddir('SRVPGM3') ;

03  dcl-pr Four char(10) ;
04  end-pr ;

05  dcl-proc Another export ;
06    dcl-pi *n char(10) ;
07    end-pi ;
08    dcl-s Var char(10) ;
09    Var = Fourth() ;
10    return Var ;
11  end-proc ;

Line 2: Along with the NOMAIN and REQPREXP(*NO) I now have a binding directory. When the module is created this service program will be bound to it.

Lines 5: The procedure Another is for export.

Line 6 and 7: The procedure interface, which is just to return a ten character value to whatever called it.

Line 9: Call the procedure Fourth, that is in the service program, SRVPGM3.

The binding directory SRVPGM3 contains the following entry:

ENTRY_            ENTRY_   ENTRY_
LIBRARY  ENTRY    TYPE     ACTIVATION
-------  -------  -------  ----------
*LIBL    SRVPGM3  *SRVPGM  *IMMED

Using PROGRAM_RESOLVED_IMPORTS for TESTPGM2:

01  SELECT * 
02    FROM TABLE(QSYS2.PROGRAM_RESOLVED_IMPORTS( 
03                 PROGRAM_LIBRARY => 'MYLIB',
04                 PROGRAM_NAME    => 'TESTPGM2',
05                 OBJECT_TYPE     => '*PGM'))

The results are:

BOUND_              RESOLVED
SERVICE_  BOUND_    SERVICE_                         RESOLVED_
PROGRAM_  SERVICE   PROGRAM_  RESOLVED_              SYMBOL_
LIBRARY   PROGRAM   LIBRARY   SYMBOL_NAME            USAGE
--------  --------  --------  ---------------------  --------
*LIBL     SRVPGM2   MYLIB     ANOTHER                *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_G_CANCEL_H       *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_G_FC_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_G_INFSR_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_CALL_FC_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_CALL_EN_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_TERM_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_CAN_EXC_H        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_DFT_ERROR        *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT             *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_SIGNAL_EXCP      *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leDefaultEh2      *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leBdyCh2          *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leBdyEpilog2      *PROCEXP
QSYS      QRNXUTIL  QSYS      _QRNX_GET_ASSOC_CCSID  *PROCEXP

The first result is for the Another procedure in SRVPGM2.

When I use PROGRAM_RESOLVED_IMPORTS for SRVPGM2:

01  SELECT * 
02    FROM TABLE(QSYS2.PROGRAM_RESOLVED_IMPORTS( 
03                 PROGRAM_LIBRARY => 'MYLIB',
04                 PROGRAM_NAME    => 'SRVPGM2',
05                 OBJECT_TYPE     => '*SRVPGM'))

The first result is for the procedure Fourth in SRVPGM3:

BOUND_              RESOLVED
SERVICE_  BOUND_    SERVICE_                         RESOLVED_
PROGRAM_  SERVICE   PROGRAM_  RESOLVED_              SYMBOL_
LIBRARY   PROGRAM   LIBRARY   SYMBOL_NAME            USAGE
--------  --------  --------  ---------------------  --------
*LIBL     SRVPGM3   MYLIB     FOURTH                 *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT_H           *PROCEXP
QSYS      QRNXIE    QSYS      _QRNX_INIT             *PROCEXP
QSYS      QLEAWI    QSYS      Q LE leDefaultEh2      *PROCEXP
QSYS      QRNXUTIL  QSYS      _QRNX_GET_ASSOC_CCSID  *PROCEXP

PROGRAM_RESOLVED_IMPORTS Table function is going to prove a useful too for determining which procedures a program or service program uses in another service program.

You can learn more about the PROGRAM_RESOLVED_IMPORTS Table function from the IBM website here.

 

This article was written for IBM i 7.6.

No comments:

Post a Comment

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.