IBM Mainframe Forum Index
 
Log In
 
IBM Mainframe Forum Index Mainframe: Search IBM Mainframe Forum: FAQ Register
 

Dynamically split large DSN list into different PDS-E member


IBM Mainframe Forums -> CLIST & REXX
Post new topic   Reply to topic
View previous topic :: View next topic  
Author Message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Tue Sep 17, 2019 8:24 pm
Reply with quote

Good morning,

I would have a problem to submit.
I have a member of a PDS-E library that contains a large list of dataset names, I would like to be able to dynamically create, in the same PDS-E libraries, output members that contain 5 datasets each.
I want to create everything with a REXX, and not use Sort or Icetool.
The Rexx I created works, but it creates 1 member for each line read from the Input file, so it creates me 15 Run, I would like to be able to create 3 Runs from 5 datasets each.

Below I attach the input member with 15 dataset name: INP
Of course I also attach the Rexx I created.

Thanks for any support



Member used as INPUT in the PDS-E library: INP

Code:

***************************** Top of Data ******************************
XA1MVS.REC.D12214.DOC.001
XB1MPS.REC.D12214.DOC.002
XC1MVS.REC.D12214.DOC.003
XD1MVS.REC.D12214.DOC.004
XE1MVS.REC.D12214.DOC.005
XF1MVS.REC.D12214.DOC.006
XG1MVS.REC.D12214.DOC.007
XH1MVS.REC.D12214.DOC.008
XI1MVS.REC.D12214.DOC.009
XL1MVS.REC.D12214.DOC.010
XM1MVS.REC.D12214.DOC.011
XN1MVS.REC.D12214.DOC.012
XO1MVS.REC.D12214.DOC.013
XP1MVS.REC.D12214.DOC.014
XQ1MVS.REC.D12214.DOC.015
**************************** Bottom of Data ****************************



REXX, attention to try it, the INPUT and OUTPUT must be replaced:
Code:

inpdset = 'name.pdse ('Inp')'
outdset = 'name.pdse'




Full REXX:
Code:

/* REXX  -----------------------------------------------------------*\
\*------------------------------------------------------------------*/

inpdset = 'name.pdse('Inp')'
outdset = 'name.pdse'

count   = 1
temp    = 1

"ALLOC DDN(INFILE) DSN('"inpdset"') SHR"
"EXECIO * DISKR INFILE(STEM Record. FINIS)"
"FREE DDN(INFILE)"

/*-------------------------------------------------------------------*/
Do RowX=1 to Record.0
   Load_Rec = Record.0
   Out.Temp = Record.RowX
   NextRow  = RowX + 1
   NextRecd = Record.NextRow
   Dsname   = Word(NextRecd,1)

If Dsname ^= '' and NextRow <= 5 then
   Do
     OutDS = outdset!!'('!!'Run'!!count!!')'
     OutDS = strip(OutDS)
       say 'OutDS----->' OutDS
   /*---------------------------------------------*/
      "ALLOC DDN(OFILE) DSN('"OutDS"')NEW ",
      "LIKE('"inpdset"')"
      "FREE DDN(OFILE)"

      "ALLOC DDN(OFILE) DSN('"OutDS"') SHR"
      "EXECIO * DISKW OFILE(STEM OUT. FINIS)"
      "FREE DDN(OFILE)"
     Drop Out.
     Temp = 0
     Count = Count + 1
   /*---------------------------------------------*/
   End
   Temp = Temp + 1
End

   say 'End Process'
Exit

/*---------------------------------------------------------------*/ 
Back to top
View user's profile Send private message
Nic Clouston

Global Moderator


Joined: 10 May 2007
Posts: 2455
Location: Hampshire, UK

PostPosted: Tue Sep 17, 2019 8:42 pm
Reply with quote

Why do you write out when your counter is <= 5? You surely want it to write out when you have reached 5.
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Tue Sep 17, 2019 8:47 pm
Reply with quote

Hi Nic,

you're right, I tried so many versions that I probably missed the typing error.
Sorry
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Tue Sep 17, 2019 8:55 pm
Reply with quote

My wish would be to get to this:

Member into Library:
Code:

Command ===>
           Name     Prompt       Size   Created
_________ INP                      15  2019/09/17
_________ RUN1                      5  2019/09/17
_________ RUN2                      5  2019/09/17
_________ RUN3                      5  2019/09/17
          **End**



Member: RUN1
Code:

***************************** Top of Data *
XA1MVS.REC.D12214.DOC.001
XB1MPS.REC.D12214.DOC.002
XC1MVS.REC.D12214.DOC.003
XD1MVS.REC.D12214.DOC.004
XE1MVS.REC.D12214.DOC.005
**************************** Bottom of Data



Member: RUN2
Code:

***************************** Top of Data *
XF1MVS.REC.D12214.DOC.006
XG1MVS.REC.D12214.DOC.007
XH1MVS.REC.D12214.DOC.008
XI1MVS.REC.D12214.DOC.009
XL1MVS.REC.D12214.DOC.010
**************************** Bottom of Data



Member: RUN3
Code:

***************************** Top of Data *
XM1MVS.REC.D12214.DOC.011
XN1MVS.REC.D12214.DOC.012
XO1MVS.REC.D12214.DOC.013
XP1MVS.REC.D12214.DOC.014
XQ1MVS.REC.D12214.DOC.015
**************************** Bottom of Data
Back to top
View user's profile Send private message
Willy Jensen

Active Member


Joined: 01 Sep 2015
Posts: 712
Location: Denmark

PostPosted: Tue Sep 17, 2019 10:32 pm
Reply with quote

I will suggest a slightly different approach, using the stack and using BPXWDYN for allocate and free:
Code:
 lib='xx.test.lib'                                                     
 cc=bpxwdyn('alloc da('lib'(zdslist)) shr rtddn(dd1)')                 
 "execio * diskr" dd1 "(stem dsl. finis)"                             
 cc=bpxwdyn('free dd('dd1')')                                         
                                                                       
 "newstack"                                                           
 outn=0                                                               
 do dsn=1 to dsl.0                                                     
   queue dsl.dsn                                                       
   if queued()//5=0 then call write  /* recno divisible by 5 */
 end                                                                   
 if queued()>0 then call write                                         
 cc=bpxwdyn('free dd('dd1')')                                         
 "delstack"                                                           
 exit 0                                                               
                                                                       
Write:                                                                 
 outn=outn+1                                                           
 say 'new ds' outn 'at record' dsn 'will contain' queued() 'records'   
 cc=bpxwdyn('alloc da('lib'(run'outn')) shr dd('dd1') reuse')         
 "execio" queued() "diskw" dd1 "(finis)"                               
 return 0                                                             

I understood it so that the new members are written to the same library as the datasetlist.
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Wed Sep 18, 2019 12:33 pm
Reply with quote

Hi Willy, the method you proposed is fantastic, it works very well.
I had never tried the bpxwdyn method, so thank you for making me new methods.

How can I put [Solved] in this discussion?

Thanks again Willy for the support.
Back to top
View user's profile Send private message
Willy Jensen

Active Member


Joined: 01 Sep 2015
Posts: 712
Location: Denmark

PostPosted: Wed Sep 18, 2019 1:17 pm
Reply with quote

You are welcome. I prefer the BPXWDYN command to ALLOC as it has some very usefull features, plus it is a function so can be placed in an expression.
BPXWDYN is described in the 'Using REXX and z/OS UNIX System Services' manual.
I dont think that you can 'solve' a discussion, but your latest entry should make it clear.
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Wed Sep 18, 2019 1:51 pm
Reply with quote

Hi Willy thanks for the explanations.
I have already downloaded the 'Using REXX and z / OS UNIX System Services' manual.

Thanks again Willy for the support.
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Thu Sep 26, 2019 6:11 pm
Reply with quote

Thanks to the help and support of Willy I managed to complete REXX as I wanted.
I make it available to everyone if it can be used by some other user.
REXX can also be modified to launch other HSM commands, such as Recall, Recover, Migration.

Kind regards
Ghellar

Code:

/* REXX ______________________________________________________________
|                                                                     |
| This REXX takes INPUT a member of a Library in which it is          |
| a List of Datasets has been inserted (taken from a query).          |
| The dataset names MUST be in column 1, these DSNAMEs are read       |
| one by one and a Backup Delete HSM command will be created:         |
|                                                                     |
|       Queue ' HSEND BDELETE ('!!DsName!!') ALL'                     |
|                                                                     |
| These command lists will then be dynamically saved to a series      |
| of members (in the same library where the member of INPUT), with    |
| names chosen a priori before launching the REXX.                    |
| There are indeed variables that necessarily go valued before        |
| ANY LAUNCH, and are reported by following:                          |
| | | | | |                                                           |
| V V V V V                                                           |
|____________________________________________________________________*/
/*-------------------------------------------------------------------*/
/*Preparatory variables to be modified by hand before EEXEC launch   */
/*-------------------------------------------------------------------*/
 InpLib  = pds.library.name        /* Extended name of the library   */
 ZDSLIST = INP                     /* Member of INPUT in the library */
 NameRun = RUN$                    /* Partial name member: OUTPUT    */
 N$Split = 5                       /* Number DSN that will be split  */
/*********************************************************************/

/*-------------------------------------------------------------------*/
 CC=BPXWDYN('ALLOC DA('InpLib'('ZDSLIST')) SHR RTDDN(DD1)')
 "EXECIO * DISKR" DD1 "(STEM DSL. FINIS)"
 CC=BPXWDYN('FREE DD('DD1')')
/*-------------------------------------------------------------------*/
 "newstack"                        /*                                */
 Outn=0                            /* Clear the variable  OutNumber  */
 JobN=0                            /* Clear the variable: JobNumber  */
/*--------------------------------*/
 do dsn=1 to dsl.0                 /*                                */
    DsnName = WORD(DSL.dsn,1)      /*                                */

    QUEUE ' HSEND BDELETE ('!!DsnName!!') ALL'

    if queued()//N_Split=0 then call Write
 end                               /*                                */
    if queued()>0 then call write  /*                                */
      cc=bpxwdyn('free dd('dd1')') /*                                */
 "delstack"                        /*                                */
 exit 0                            /*                                */
/*-------------------------------------------------------------------*/
/* ---  Start call Write      -------------------------------------- */
/*-------------------------------------------------------------------*/
Write:
 Outn=Outn+1                       /*Add +1 to the OutNumber variable*/
 Jobn=Jobn+1                       /*Add +1 to the JobNumber variable*/

 say 'new ds' Outn 'at record' dsn 'will contain' queued() 'records'
 CC=BPXWDYN('ALLOC DA('InpLib'('NameRun''Outn')) SHR DD('DD1') REUSE')
 call JobCard                      /* CALL JobCard insert jcl card   */
 "EXECIO" QUEUED() "DISKW" DD1 "(FINIS)"
 Return 0
/*-------------------------------------------------------------------*/
/* ---  End   call Write      -------------------------------------- */
/*-------------------------------------------------------------------*/


/*-------------------------------------------------------------------*/
/* ---  Start call JobCard    -------------------------------------- */
/*-------------------------------------------------------------------*/
JobCard:

If Jobn>=1 or Jobn<=9 then         /*                                */
   do                              /*                                */
     Jobn='0'!!Jobn                /*                                */
   end                             /*                                */

jcl.1='//TMPJCL'Jobn' JOB MSGCLASS=8,CLASS=E,NOTIFY=&SYSUID        '
jcl.2='//*---------------------------------------------------------'!!,
        '------------'
jcl.3='//* JOB that deletes ALL obsolete files with alias: xxxxxx  '
jcl.4='//*---------------------------------------------------------'!!,
        '------------'
jcl.5='//BKDELETE EXEC PGM=IKJEFT01,DYNAMNBR=20                    '
jcl.6='//*        ----------------                                 '
jcl.7='//SYSPRINT DD SYSOUT=*                                      '
jcl.8='//SYSTSPRT DD SYSOUT=*                                      '
jcl.9='//SYSTSIN  DD *                                            '
jcl.0=9
                                   /*                                */
do n=jcl.0 to 1 by -1              /*                                */
   push jcl.n                      /*                                */
end                                /*                                */

Return
/*-------------------------------------------------------------------*/
/*----  End   call JobCard    ---------------------------------------*/
/*-------------------------------------------------------------------*/
 
Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10873
Location: italy

PostPosted: Thu Sep 26, 2019 7:16 pm
Reply with quote

unfortunately the snippet posted is unreadable , too much clutter
the noise outsizes the info

do not over-comment
spaces are much much better than a bunch of "---...---"
space properly the lines for readability ( a blank line is better that an irrelevant comment, or a <comment box>

Code:
Outn=Outn+1                       /*Add +1 to the OutNumber variable*/

how does the comment help ??? do not comment the obvious
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Thu Sep 26, 2019 7:29 pm
Reply with quote

Hi Enrico,

unfortunately I do not work all the days with the REXX, so I always comment on the projects being realized, because I might need to modify them after months or years, this explains the reason for the comments.
I will take your comment as a suggestion for future projects.
Many thanks
Back to top
View user's profile Send private message
sergeyken

Senior Member


Joined: 29 Apr 2008
Posts: 2022
Location: USA

PostPosted: Sat Sep 28, 2019 12:38 am
Reply with quote

Ghellar wrote:
Hi Enrico,

unfortunately I do not work all the days with the REXX, so I always comment on the projects being realized, because I might need to modify them after months or years, this explains the reason for the comments.
I will take your comment as a suggestion for future projects.
Many thanks

Enrico is absolutely right.
Comments must clarify some non-obvious ideas, but not just repeat obvious things in other words! It makes the code even less understandable, and impossible to read.
Code:
 A = A + 1 /* this REXX arithmetic statement is supposed to perform
              very critical operation. It takes the previous value
              of variable A, then performs arithmetic addition
              with value of 1, and places the result back
              to variable A.
              Before any change to this code please, consult with
              the author. */

Whenever I met comments of this style, my first desire was: how to kill the author?

Also endless use of '---------------------------------------------', or even '******************************' makes it much worse compared to simple blank lines.
Back to top
View user's profile Send private message
Willy Jensen

Active Member


Joined: 01 Sep 2015
Posts: 712
Location: Denmark

PostPosted: Sat Sep 28, 2019 2:12 am
Reply with quote

Guys, he got his problem solved and was kind enough to share his solution with us. He uses more comments than you (and I) like to, but that does not neccessarily make it wrong. I have been been accused of using too few comments and writing much too compact code. At the end of the day it works for him.
If in the future someone faces a similar issue they can copy the program, stripping away what they deem superflous. Still easier that starting from scratch.
Just my 2 cents.
Back to top
View user's profile Send private message
Ghellar

New User


Joined: 01 Sep 2005
Posts: 22

PostPosted: Sat Sep 28, 2019 9:18 pm
Reply with quote

Goodmorning everyone,

thank you for your opinions, sorry but I'm not as expert as you, I'm here to try to learn that's all. If you were an expert you know here in this forum to help others, and instead I am here asking for help from all of you for my lack of knowledge.
But I wouldn't want to have created a problem with these excessive comments, so to try to fix it, I simply attach the code without comments.

Thanks again to everyone.

Code:

/* REXX ______________________________________________________________
|                                                                     |
| This REXX takes INPUT a member of a Library in which it is          |
| a List of Datasets has been inserted (taken from a query).          |
| The dataset names MUST be in column 1, these DSNAMEs are read       |
| one by one and a Backup Delete HSM command will be created:         |
|                                                                     |
|       Queue ' HSEND BDELETE ('!!DsName!!') ALL'                     |
|                                                                     |
| These command lists will then be dynamically saved to a series      |
| of members (in the same library where the member of INPUT), with    |
| names chosen a priori before launching the REXX.                    |
| There are indeed variables that necessarily go valued before        |
| ANY LAUNCH, and are reported by following:                          |
| | | | | |                                                           |
| V V V V V                                                           |
|____________________________________________________________________*/

 InpLib  = pds.library.name       
 ZDSLIST = INP                     
 NameRun = RUN$                   
 N$Split = 5                       

 CC=BPXWDYN('ALLOC DA('InpLib'('ZDSLIST')) SHR RTDDN(DD1)')
 "EXECIO * DISKR" DD1 "(STEM DSL. FINIS)"
 CC=BPXWDYN('FREE DD('DD1')')

 "newstack"                       
 Outn=0                           
 JobN=0                           

 do dsn=1 to dsl.0                 
    DsnName = WORD(DSL.dsn,1)     

    QUEUE ' HSEND BDELETE ('!!DsnName!!') ALL'

    if queued()//N_Split=0 then call Write
 end                               
    if queued()>0 then call write 
      cc=bpxwdyn('free dd('dd1')')
 "delstack"                       
 exit 0                           

Write:
 Outn=Outn+1                       
 Jobn=Jobn+1                       

 say 'new ds' Outn 'at record' dsn 'will contain' queued() 'records'
 CC=BPXWDYN('ALLOC DA('InpLib'('NameRun''Outn')) SHR DD('DD1') REUSE')
 call JobCard                      /* CALL JobCard insert jcl card   */
 "EXECIO" QUEUED() "DISKW" DD1 "(FINIS)"
 Return 0


JobCard:
If Jobn>=1 or Jobn<=9 then         
   do                             
     Jobn='0'!!Jobn               
   end                             

jcl.1='//TMPJCL'Jobn' JOB MSGCLASS=8,CLASS=E,NOTIFY=&SYSUID        '
jcl.2='//*---------------------------------------------------------'!!,
        '------------'
jcl.3='//* JOB that deletes ALL obsolete files with alias: xxxxxx  '
jcl.4='//*---------------------------------------------------------'!!,
        '------------'
jcl.5='//BKDELETE EXEC PGM=IKJEFT01,DYNAMNBR=20                    '
jcl.6='//*        ----------------                                 '
jcl.7='//SYSPRINT DD SYSOUT=*                                      '
jcl.8='//SYSTSPRT DD SYSOUT=*                                      '
jcl.9='//SYSTSIN  DD *                                             '
jcl.0=9
                                   
do n=jcl.0 to 1 by -1             
   push jcl.n                     
end                               

Return

Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10873
Location: italy

PostPosted: Sat Sep 28, 2019 9:58 pm
Reply with quote

Quote:
But I wouldn't want to have created a problem with these excessive comments,


You have not created any problem...
I was just suggesting to keep things simple for better visual navigation of the sources
Back to top
View user's profile Send private message
View previous topic :: :: View next topic  
Post new topic   Reply to topic View Bookmarks
All times are GMT + 6 Hours
Forum Index -> CLIST & REXX

 


Similar Topics
Topic Forum Replies
No new posts How to split large record length file... DFSORT/ICETOOL 10
No new posts How to create a list of SAR jobs with... CA Products 3
No new posts Dynamically pass table name to a sele... DB2 2
No new posts Parsing Large JSON file using COBOL COBOL Programming 4
No new posts JCL/SORT to Split Records SYNCSORT 28
Search our Forums:

Back to Top