Processing a GDG in Any Order Using IGGCSI00 in COBOL

By | September 7, 2013

We know we can process an entire set of GDG datasets by allocating the GDG base name in the JCL So, for example, if we have a GDG with three generations,

GDG Base:  XXXXXXXX.TEST.GDG        Generations: XXXXXXXX.TEST.GDG.G0001V00
                                                 XXXXXXXX.TEST.GDG.G0002V00
                                                 XXXXXXXX.TEST.GDG.G0003V00

We can refer to the most current generation with XXXXXXXX.TEST.GDG(0) or XXXXXXXX.TEST.GDG.G0003V00, the second with XXXXXXXX.TEST.GDG(-1), the third with XXXXXXXX.TEST.GDG(-2), etc. So we could put all three in the JCL, concatenated together:

//FILE1 DD DISP=SHR,DSN=XXXXXXXX.TEST.GDG(-2)
//      DD DISP=SHR,DSN=XXXXXXXX.TEST.GDG(-1)
//      DD DISP=SHR,DSN=XXXXXXXX.TEST.GDG(0)

and in this way, process the oldest first and the newest last. But, often we don’t know how many generations there are to process from run to run and we certainly don’t want to recode the JCL every time, so instead we use:

//FILE1 DD DISP=SHR,DSN=XXXXXXXX.TEST.GDG

that is, we leave off the generation qualifier. This gives us all of the extant generations concatenated together automatically, but it gives them to us in reverse order with the (0) most current generation first and the (-2) oldest last.

Can we make use of our previous IGGCSI00 example to get the dataset names  for all of the generations and process them in any order we’d like?  Yes. Yes, we can.

In addition to using the Catalog Search Interface (CSI) routine, we will use COBOL’s dynamic allocation capability and to facilitate the dynamic allocation, we’ll use the POSIX setenv() function although there are other ways to set environment variables, including the Language Environment CEEENV function, which does not require a POSIX environment.

The demonstration program will take the GDG base name from a PARM, lookup the generation datasets associated with the base and put the dataset names into an array.  Then the program will open, read a record and close each dataset in the array in turn.

Some notes:

  • POSIX functions are called statically, so the program must be compiled with the NODYNAM option.  I kept the IGGCSI00 call as dynamic, however.
  • POSIX functions in general can be long, mixed-case names, so compile with PGMNAME(LONGMIXED).
  • The Language Environment option POSIX(ON) must be on, so include that in the PARM or use a CEEUOPT. Or perhaps POSIX(ON) could be set as the default in your shop.
  • The load module must be in a PDSE (or hfs).  In my testing, I use the Compile-Link-Go PROC IGYWCLG and override the SYSLMOD with DSNTYPE=LIBRARY.
  • The dynamic allocation is accomplished by setting an environment variable the name of which matches that of an ASSIGN clause (and not a DD name) and has the value “DSN(xxxx) SHR” where xxxx is the dataset name.  This has to be done before the OPEN. We use setenv() for this.

So, PROCESS statements at the front of the source:

PROCESS LIST,LIB,TEST(NOHOOK,SEP),OPT,MAP,RENT
PROCESS NODYNAM,PGMNAME(LONGMIXED)

and JCL like:

// JCLLIB ORDER=(IGY.SIGYPROC)
//CEEUOPT  EXEC ASMAC
//C.SYSLIB DD  DSN=CEE.SCEEMAC
//C.SYSIN  DD  *
CEEUOPT CSECT
CEEUOPT AMODE ANY
CEEUOPT RMODE ANY
CEEXOPT POSIX=ON
END   CEEUOPT
//C.SYSLIN DD  DSN=&&LOADSET
//COBGDG    EXEC IGYWCLG,LNGPRFX='IGY',PARM.LKED=MAP,
// PARM.GO='XXXXXXXX.TEST.GDG'
//COBOL.SYSIN  DD DISP=SHR,DSN=XXXXXXXX.SRC.COB(COBGDG)
//COBOL.SYSLIB DD DISP=SHR,DSN=XXXXXXXX.SRC.COB
//COBOL.SYSDEBUG DD DISP=SHR,DSN=XXXXXXXX.SYSDEBUG(COBGDG)
//LKED.SYSLMOD DD DSNTYPE=LIBRARY
//LKED.SYSIN   DD *
ENTRY COBGDG
//GO.SYSOUT    DD SYSOUT=*

Here’s the source:  cobgdg.cob

Look for the copybooks in the earlier post.

For a non-POSIX version, which does not require the use of a PDSE and can be compiled DYNAM (a standard in many shops), use CEEENV,

       77  ws-ceeenv                   pic x(8)  value 'CEEENV  '.
       77  ws-ceeenv-funccode          pic 9(9) binary.
       77  ws-ceeenv-namelen           pic 9(9) binary.
       77  ws-ceeenv-name              pic x(8).
       77  ws-ceeenv-valuelen          pic 9(9) binary.
       77  ws-ceeenv-valptr            pointer.
       01  ws-ceeenv-fc.
           02  CONDITION-TOKEN-VALUE.
           COPY  CEEIGZCT.
               03  CASE-1-CONDITION-ID.
                  04  SEVERITY         PIC S9(4) BINARY.
                  04  MSG-NO           PIC S9(4) BINARY.
               03  CASE-SEV-CTL        PIC X.
               03  FACILITY-ID         PIC XXX.
           02  I-S-INFO                PIC S9(9) BINARY.

           string
             'DSN('                     delimited by size
             ws-ggt-name (ws-ggt-index) delimited by space
             ') SHR'                    delimited by size
             into ws-environment-string

           move 5                       to ws-ceeenv-funccode
           move 6                       to ws-ceeenv-namelen
           move 'GDGGEN'                to ws-ceeenv-name
           move length of ws-environment-string
                                        to ws-ceeenv-valuelen
           set  ws-ceeenv-valptr
                             to address of ws-environment-string

           call ws-ceeenv using ws-ceeenv-funccode
                                ws-ceeenv-namelen
                                ws-ceeenv-name
                                ws-ceeenv-valuelen
                                ws-ceeenv-valptr
                                ws-ceeenv-fc

           if severity not = 0 then
             display 'ceeenv    return-code ' severity ' ' msg-no
             move 16                    to return-code
             goback
           end-if

and compile and test with,

// JCLLIB ORDER=(IGY.SIGYPROC)
//COBGDG2   EXEC IGYWCLG,LNGPRFX='IGY',PARM.LKED=MAP,
// PARM.GO='XXXXXXXX.TEST.GDG'
//COBOL.SYSIN  DD DISP=SHR,DSN=XXXXXXXX.SRC.COBOL(COBGDG2)
//COBOL.SYSLIB DD DISP=SHR,DSN=XXXXXXXX.SRC.COBOL
//             DD DISP=SHR,DSN=CEE.SCEESAMP
//LKED.SYSIN   DD *
  ENTRY COBGDG2
//GO.SYSOUT    DD SYSOUT=*

Here is the source for this: cobgdg2.cob

Now, if we could process these datasets in parallel we might get some performance gains.  Hmm.  Perhaps a later post.

Leave a Reply

Your email address will not be published. Required fields are marked *