Wednesday, January 31, 2018

Getting the library list from a Job Description

using api to get library list from jobd

The germ for this post came from this question:

How can get the Library List from a Job Description?

I can use the DSPJOBD command to see the Job Description's library list, alas I can only display or print it. This does not make it easy for me to use in a program.

DSPJOBD JOBD(MYLIB/MYJOBD)


Display Job Description
  Job description:  MYJOBD         Library:  MYLIB

  Initial library list:
    Sequence
     number   Library
        10    QTEMP
        20    MYLIB
        30    ANOTHERLIB
        40    QGPL

My first thought was to look for something using Db2 for i that would allow me to do this. After checking all the possibilities on Scott Forstie's Db2 for i poster I could not find a View, Table Function, etc. that would give me what I wanted. Therefore, I would have use an API.

The QWDRJOBD API retrieves information from the Job Description, including the library list. Unfortunately the area used for the library list is variable in length, and I will be able to retrieve that information if I call the API once to get the size of the information retrieved, and a second time to get the library list information.

I am calling this API from a RPG program. Let me start with the definitions:

01  **free
02  ctl-opt option(*nodebugio:*srcstmt:*nounref) ;

03  /copy qsysinc/qrpglesrc,qusec
04  /copy qsysinc/qrpglesrc,qwdrjobd

05  dcl-pr GetJobDinfo extpgm('QWDRJOBD') ;
06    *n char(65535) options(*varsize) ; //Receiver
07    *n int(10) const ;                 //Receiver length
08    *n char(8) const ;                 //API format
09    *n char(20) const ;                //Job description
10    *n likeds(QUSEC) ;                 //Std API error DS
11   end-pr ;

12  dcl-ds JobD1 likeds(QWDD0100) ;
13  dcl-ds JobD2 likeds(QWDD0100) based(pJobd2) ;

14  dcl-s LibList char(11) based(pLibl) dim(250) ;

15  dcl-s JobDescription char(20) ;
16  dcl-s BytesAvailable int(10) ;
17  dcl-s Entries packed(3) ;

Line 1: In 2018 my RPG is always totally free format.

Line 2: My favorite control options.

Line 3: The definition of the standard API error data structure is in this source member. By using the /COPY I don't have to define it myself.

Line 4: Rather than define the data structure the results of the API are returned in I can use the data structure defined in this source member to ask as a template.

Lines 5 – 11: This is the procedure definition, parameter list, for the API. I am using my own name for the API in the program, therefore, I need to give the API's name in the EXTPGM.

Lines 6 – 10: I do not see the point in giving the API's parameters names if I am not going to use those names. If I do not give these subfields names I have to give *N instead.

Lines 12 and 13: I have defined the same data structure twice, using the data structure in the member QWDRJOBD as the template. I have defined the second one with a pointer, more about that later.

Line 14: This is the array that will contain the list of libraries in. Notice that is has a pointer.

Lines 15 – 17: This is the definition of various variables I will be using.

And now onto the part of the program that get the library list.

18  JobDescription = 'MYJOBD    MYLIB' ;
19  JobD1 = *allx'00' ;

20  BytesAvailable = %size(JobD1) ;
21  dsply ('Size 1 = ' + %char(BytesAvailable)) ;

22  GetJobDInfo(JobD1:%size(JobD1):'JOBD0100':JobDescription:QUSEC) ;

23  BytesAvailable = JobD1.QWDBAVL ;
24  dsply ('Size 2 = ' + %char(BytesAvailable)) ; //test

25  pJobd2 = %alloc(JobD1.QWDBAVL) ;
26  JobD2 = *allx'00' ;

27  GetJobDInfo(JobD2:BytesAvailable:'JOBD0100':JobDescription:QUSEC) ;

28  Entries = JobD2.QWDNLILL ;
29  pLibl = pJobd2 + JobD2.QWDOILL ;

30  *inlr = *on ;

Line 18: The API requires that the qualified Job Description name is passed to it. It must be Job Description name, in positions 1 – 10, followed by the library name, starting at position 11.

Line 19: I am initializing the data structure that will contain the results from the API data structure with hexadecimal '00'. This is the equivalent of null.

Lines 20 and 21: These two lines are only here to show you, later, how the size of the returned information is different depending upon the Job Description.

Line 22: This first call of the API is only to get the number of bytes that could be retrieved in the result. The parameters I have used are:

  1. Data structure to contain the results.
  2. I have to give a length for the results. The first time I call this API I have no idea how long the results, including the library list will be. I can only use the length of the data structure, knowing that the library list is not included.
  3. Result format. For this API there is only one value that can be used.
  4. Qualified Job Description name.
  5. Standard API error data structure.

Line 23: Now I have the length of all the results, in the data structure subfield QWDBAVL.

Line 24: This is only here for testing, to show that the value of the bytes available is larger than the length of the data structure.

Line 25: The %ALLOC operation code allocates a space in memory that I will use for the results when we call the API again.

Line 26: The second results data structure in initialized with nulls.

Line 27: This time I call the API with the second result data structure, JobD2, to contain my results.

Line 28: The subfield QWDNLILL contains the number libraries in the library list.

Line 29: The pointer for the library list array is set to start at the memory space starting at the start of the pointer plus the offset to the library list information, subfield QWOFILL.

When I run this for the same Job Description I used with the DSPJOBD command, MYJOBD in MYLIB I get the following:

DSPLY  Size 1 = 452
DSPLY  Size 2 = 502

EVAL LibList
LIBLIST(1) = 'QTEMP      '
LIBLIST(2) = 'MYLIB      '
LIBLIST(3) = 'ANOTHERLIB '
LIBLIST(4) = 'QGPL       '
LIBLIST(5) = '*NONE      '
LIBLIST(6) = '           '
LIBLIST(7) = '           '

> EVAL Entries
ENTRIES = 004.

The DSPLY operations show how the size of the results for all the data, including the library list, is bigger than the result data structure.

If I run the program for the Job Description QDFTJOBD in my library list I can see the get:

DSPLY  Size 1 = 452
DSPLY  Size 2 = 469

> EVAL LibList
  LIBLIST(1) = '*SYSVAL    '
  LIBLIST(2) = '*NONE      '
  LIBLIST(3) = '           '
  LIBLIST(4) = '           '
  LIBLIST(5) = '           '
  LIBLIST(6) = '           '
  LIBLIST(7) = '           '

> EVAL Entries
ENTRIES = 001.

Even though it is cumbersome to have to call the API twice this shows how easy it is to get the library list from the Job Description.

 

You can learn more about the QWDRJOBD API from the IBM website here.

 

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

10 comments:

  1. Simon, what about QSYS2/LIBLIST? This is on my 7.1 system.

    Ken

    ReplyDelete
    Replies
    1. LIBLIST is the same as LIBRARY_LIST_INFO. This only lists the library of a current running job. Not the library list contained within a job description. I could assume that the library list of the job is the same as the library list that it started with, but sometimes programs add or remove libraries from the list. Or perhaps I want a list of all job descriptions that contain a certain library.

      Delete
  2. Use a pgm submitted with the JOBD, you could do this command DSPLIBL OUTPUT(*PRINT) and read the spool that generated.

    Claude

    ReplyDelete
    Replies
    1. Strikes me as an over complicated and inefficient way to get the library list. Not even using the DSPJOBD command.

      If I wanted to get this library list from an active job I would use the SQL LIBRARY LIST_INFO View. Which is much more efficient than reading a spool file.

      Delete
    2. SQL is very nice for any process that doesn't with normal program. I use SQL as a last resort.

      Claude

      Delete
    3. Alas, this is the attitude that makes non-IBM i folks think that all IBM i programmers are old fuddy duddies.

      It is a good job that some of us do not hold that attitude to progress.

      Delete
    4. You should avoid getting information from spool files where there is an alternative. IBM guarantee APIs are always backward compatible, spool file output they do not...and yes it does change...and also can be different between language versions.

      Delete
  3. I would go for (Existing code so sorry not all in free)

    D RtvJobInf PR ExtPgm('QUSRJOBI')
    D RcvVar 32766A options(*varsize)
    D RcvVarLen 10I 0 CONST
    D Format 8A CONST
    D JobName 26A CONST
    D IntJobID 16A CONST
    D ErrorCode 32766A options(*varsize)

    D dsJOBI0700 DS qualified
    D ByteRtn 10I 0
    D ByteAvl 10I 0
    D JobName 10A
    D UserID 10A
    D JobNbr 6A
    D IntJob 16A
    D Status 51 60
    D JobType 61 61
    D JobSubType 62 62
    D reserved 63 64
    D systemLibs 65 68B 0
    D ProductLibs 69 72B 0
    D CurrentLibs 73 76B 0
    D UserLibs 77 80B 0
    D Libraries 81 3240

    RtvJobInf(dsJOBI0700: %size(dsJOBI0700):'JOBI0700': '*':*BLANKS: dsEC);

    dsjobi0700 will contain the library list

    ReplyDelete
    Replies
    1. The QUSRJOBI API get the information for the job. And rather than mess with all that API malarkey I think you'll find it easier to get a job's library list using the LIBRARY_LIST_INFO SQL View.

      It does NOT get the library list from a job description.

      Delete
  4. Good to see qsysinc being used. Too many code examples on the web dpnt use it which is (I think) poor coding as its reinventing the wheel.

    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.