Libraries are one level deep and do not contain other libraries. The obvious question follows: how does a program find a file if nobody tells it which library it is in?
The answer is the library list: an ordered list of libraries belonging to the job, not to the program. When an object is named without saying where it lives, the system looks through the libraries in the list, one after another, stopping at the first that contains it.
This is where the hierarchy that seemed to be missing went. It is also the origin of nearly every problem that starts with "it works in my environment".
The four parts
The list is not flat: it has up to four parts, and only the first is always there.
- System part. Holds the libraries the system needs. It comes from the system value
QSYSLIBL, which as shipped contains QSYS, QSYS2, QHLPSYS and QUSRSYS and can hold up to fifteen. For a single job it is changed withCHGSYSLIBL. - Product libraries. Up to two, managed by the system: it puts them in and takes them out when a command or menu needs them. Not yours to touch.
- Current library. Exactly one. It is where a program created without naming a library
ends up; if the job has none, QGPL is used. Changed with
CHGCURLIB. - User part. The list proper, where the application libraries sit, up to 250. Its
starting value depends on how the job is born (next section); the system value
QUSRLIBL, up to twenty-five libraries, is used when the job description says*SYSVAL.
A change to QSYSLIBL or QUSRLIBL applies to jobs started afterwards, not to those already
running.
To see your own job's:
DSPLIBL
SELECT ORDINAL_POSITION, SYSTEM_SCHEMA_NAME, TYPE, TEXT_DESCRIPTION
FROM QSYS2.LIBRARY_LIST_INFO
ORDER BY ORDINAL_POSITION
The TYPE column says which part each library belongs to: SYSTEM, PRODUCT, CURRENT or
USER.
And another job's, which is the one you need when investigating:
WRKJOB JOB(123456/MARIO/CLOSE) OPTION(*LIBL)
Only for an active job: a finished job's list is gone.
Where it comes from
And here is where the misunderstandings live, because the initial user part does not always come from the same place.
- An interactive session takes it from its job description (
INLLIBLparameter), and during the day it is often edited by hand withADDLIBLE. - A job submitted with
SBMJOB, if nothing is said, inherits the submitter's list: the default ofINLLIBLis*CURRENT. WithINLLIBL(*JOBD)it takes it from the job description the job uses instead, with*SYSVALfromQUSRLIBL. - A schedule entry (
ADDJOBSCDE) has no library list parameter: the job takes it from its job description, which by default is the user profile's.
Warning
this is the classic cause of "it works when I run it and not at night". The same
program, submitted from a session, inherits that session's list, including libraries added by
hand; scheduled, it gets the job description's, which is often shorter. The error talks about
an object not found and it looks as if something is missing: the library is there, but not in
that job's list. You check with DSPJOBD on the description the job really uses, not on your
own session.
There is a way to leave nothing to chance, and that is declaring the list on the command that submits:
SBMJOB CMD(CALL PGM(PRODLIB/CLOSE)) +
JOB(CLOSE) +
JOBD(PRODLIB/BATCHJOBD) +
INLLIBL(PRODLIB DATALIB QGPL QTEMP)
The ambiguity risk
If two libraries in the list contain an object with the same name, the first one wins. Silently: no warning, no trace in the job log, no way to notice unless you go looking.
This is how the worst incidents start, because the symptom is not an error but a wrong result. A test file left in a library put at the top of the list "just for a moment" makes the month-end close run against test data, and the program has no way of knowing.
Tip
the defence that holds up over the years is not a shorter library list but
qualifying objects in programs — writing PRODLIB/ORDERS instead of ORDERS
wherever the choice must not depend on the environment. It costs some flexibility and
removes an entire class of failures. Where flexibility genuinely is needed — because the
same program has to run against test and production — the library list is the right tool,
but then the choice is declared rather than inherited by accident.
Changing it
For the current job only:
ADDLIBLE LIB(TESTLIB) POSITION(*FIRST)
RMVLIBLE LIB(TESTLIB)
CHGCURLIB CURLIB(MYLIB)
Permanently, by changing the job description jobs take it from:
CHGJOBD JOBD(PRODLIB/BATCHJOBD) +
INLLIBL(PRODLIB DATALIB QGPL QTEMP)
Warning
a JOBD is often shared by many jobs. Removing a library from it breaks them
all at once, and the resulting error talks about a missing object: the symptom, not the
cause. Before changing a job description it is worth knowing who uses it: WRKJOBSCDE
for schedules, and user profile JOBDs with
SELECT AUTHORIZATION_NAME, JOB_DESCRIPTION_NAME, JOB_DESCRIPTION_LIBRARY_NAME FROM QSYS2.USER_INFO. The library must be asked for alongside the name: a job description without
its library is ambiguous, which is exactly the ambiguity this chapter is about.
The limit
The user part goes up to 250 libraries, QUSRLIBL up to 25, QSYSLIBL up to 15. These are not
constraints you meet in practice, and a long list is a problem in its own right: it multiplies
the chances of ambiguity.
Comments
No comments yet. Be the first to comment!
You need an account to comment. Log in · Sign up