Search code examples
jcldfsort

Select files by size in JCL


In a job I will treat two types of files. I need to select files by size because whichever is go to one program or another.

Currently, I am getting every day a file of a length of 200 positions (LREC=200,FB) by EDITRAN , but now I can get a 200 or 400 positions. I want to make a difference in my chain if one size or another , to use it as usual or new programs.

The selection should be with jcl. Does anyone know how to do this ?

Thanks for your help


Solution

  • OK, has to be done, so make it secure...

    First step:

    //GETSYSL  EXEC PGM=SORT 
    //SORTOUT  DD DUMMY 
    //SYSOUT   DD DISP=(,PASS),DSN=&&SOUT, 
    // UNIT=SYSDA,SPACE=(TRK,1) 
    //SORTIN   DD DISP=SHR,DSN=yourinputdsn
    //SYSIN    DD * 
      OPTION COPY,STOPAFT=1 
    

    This copies the first record of your input dataset to SORTOUT, which is set to DUMMY in the JCL. One record due to the STOPAFTer.

    The point of the step is that in the SYSOUT, DFSORT will list the LRECL of the input file.

    So output the SYSOUT to a dataset (can be permanent, I used a temporary for testing).

    Then process the sysout in the dataset:

    I have coded using DFSORT symbols/SYMNAMES, to make it easier to understand. In your JCL you need:

    //SYMNAMES DD DISP=SHR,DSN=yourpdsforsymnames(yourmem)
    //SYMNOUT DD SYSOUT=yoursitestandard
    

    The member contains the source symbols, the output list shows the source symbols for reference, and how DFSORT has normalised them prior to applying them.

    There are four output datasets, SORTOUT will contain a copy of the SYSOUT from the previous step (the input file to this step) and a message if something bad has happened. The other three can all be set to DUMMY, as it is only the RC which is relevant: RC=0 means Record-length of 400, RC=4 means record-length of 200, RC=16 means something bad, perhaps an error in the control cards, perhaps an error with the file (not 200 or 400), and you should halt the process and investigate.

    Here's the code, using DD * for SYMNAMES and SORTIN and SYSOUT=* instead of dummy for my testing:

    //DETLEN   EXEC PGM=SORT                  
    //SYSOUT   DD SYSOUT=* 
    //SORTOUT  DD SYSOUT=* 
    //SYMNAMES DD * 
    INP-RECORD,*,129,CH 
    INP-CC,=,1,CH 
    INP-DATA,*,120,CH 
    EXTENDED-INPUT-RECORD,*,1 
    EXT-LENGTH,=,4,CH 
    EXT-PUSH-LENGTH,*,4,CH 
    POSITION,INP-DATA 
    INP-MESSAGE-CODE,=,8,CH 
    POSITION,INP-DATA 
    SKIP,119 
    LAST-OF-DATA,*,1,CH 
    ICE088I-WITH-LENGTH,C'ICE088I ' 
    ICE088I-END-MESSAGE,C'ICE052I ' 
    EQUALS-BLANK-BEFORE-LEN,C'= ' 
    COMMA-AFTER-LENGTH,C',' 
    LENGTH-200,C'200 ' 
    LENGTH-400,C'400 ' 
    EXTRACTED-LENGTH,%00 
    HEADING-FOR-SYSOUT,C'SYSOUT FROM STEP TO DETERMINE LENGTH' 
    //SYMNOUT DD SYSOUT=* 
    //IS200 DD SYSOUT=* 
    //IS400 DD SYSOUT=* 
    //CHECK DD SYSOUT=* 
    //SORTIN   DD DSN=&&SOUT,DISP=(OLD,PASS) 
    //SYSIN    DD * 
      OPTION COPY 
      INREC IFTHEN=(WHEN=INIT, 
          PARSE=(EXTRACTED-LENGTH=(STARTAFT=EQUALS-BLANK-BEFORE-LEN,
                                 ENDBEFR=COMMA-AFTER-LENGTH, 
                                 FIXLEN=4)), 
                     OVERLAY=(EXT-LENGTH: 
                               EXTRACTED-LENGTH)), 
            IFTHEN=(WHEN=GROUP, 
                     BEGIN=(INP-MESSAGE-CODE, 
                           EQ, 
                          ICE088I-WITH-LENGTH), 
                     PUSH=(EXT-PUSH-LENGTH:EXT-LENGTH)), 
            IFTHEN=(WHEN=(INP-MESSAGE-CODE, 
                           NE, 
                          ICE088I-WITH-LENGTH), 
                     OVERLAY=(EXT-LENGTH:4X)) 
    
      OUTFIL HEADER1=(HEADING-FOR-SYSOUT), 
            IFTHEN=(WHEN=(INP-MESSAGE-CODE, 
                           EQ, 
                          ICE088I-END-MESSAGE, 
                       AND, 
                      (EXT-PUSH-LENGTH,NE,LENGTH-200, 
                        AND, 
                       EXT-PUSH-LENGTH,NE,LENGTH-400)), 
                   BUILD=(INP-RECORD, 
                          /, 
                          C'SOMETHING WICKED THIS WAY COMES', 
                          EXT-PUSH-LENGTH, 
                          LAST-OF-DATA:X)) 
    
      OUTFIL FNAMES=IS200, 
             INCLUDE=(EXT-LENGTH,EQ,LENGTH-200), 
             NULLOFL=RC4 
    
      OUTFIL FNAMES=IS400, 
             INCLUDE=(EXT-LENGTH,EQ,LENGTH-400), 
             NULLOFL=RC0 
    
      OUTFIL FNAMES=CHECK, 
             INCLUDE=(INP-MESSAGE-CODE,EQ,ICE088I-END-MESSAGE,
                       AND, 
                      (EXT-PUSH-LENGTH,EQ,LENGTH-200, 
                        OR, 
                       EXT-PUSH-LENGTH,EQ,LENGTH-400)), 
             NULLOFL=RC16 
    

    PARSEs for the record-length, even though the current record may not contain the information.

    Uses WHEN=GROUP, with a BEGIN identifying the message containing the length, so that each subsequent record contains the length (important for the final record).

    Clobbers the original length field if not a length record (the PARSEd value is still separate).

    Then the OUTFILs swing into action, using INCLUDE= on the extracted record-length (could also be the PUSHed record-length, it would not matter).

    SORTOUT copies the input, and, when the final record arrives (by message number) checks that a valid length on a correct record was found, otherwise puts out a message as well (you may change the text).

    CHECK does the same as the checking in SORTOUT, except ensures an RC=16 by writing no data.

    With SORT, the only way to set the RC other than by error is with empty output datasets (SORTOUT empty uses OPTION NULLOUT... and an OUTFIL uses NULLOFL).

    Note, a simple error in the control cards of the second step will also get an RC=16.


    The method is wrong.

    A produces a file with 200-byte records. B produces a file with 400-byte records. (A and B could be the same program, it doesn't matter).

    If A has run, that fact should be used to determine which program processes the file. Equally if B has run.

    If you just look at the file, and decide based on the record-length, then you leave yourself open to processing a bad file, just because you found a 200-byte-record file, even though B actually ran.

    The best way to do this is to have a Header record on the file. The header record should contain a unique identifier, the data-date (effective business date for the file), the environment it is from (PROD, for instance, or SYST for System Testing or whatever) and a logical name for the file, which is different for the two types of records, or a further indicator of the difference. It may contain other information as well. Anything that is useful.

    The header should be written as part of the process of A or B producing the data, not added later (unless allowing similar checking that the header being added actually belongs to the data).

    All information on the header should be checked, and the file processed, by the correct receiving program, if all the information is as expected.

    If you need an interim solution before that can be implemented:

    Using DFSORT, do a COPY with OPTION STOPAFT=1; send the SYSOUT for that step to a dataset; in a second step process the sysout to identify the ICE088I message, and extract the LRECL, which will be 200 or 400; use three OUTFILs, one to copy the input to a SYSOUT dataset (so that you can see it in the JOB output, although a step later); another OUTFIL where the message is written if it is 200; the third OUTFIL where the record is written if it is 400; use NULLOFL=RC4 for one of the "length" OUTFILs; the step will terminate with RC=0 for one length and RC=4 for the other; you should further code to give an RC=16 if the file is neither 200 or 400; so four OUTFILs - use the ICE052I message for that test.