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

Logic issue in writing JCL statements


IBM Mainframe Forums -> TSO/ISPF
Post new topic   Reply to topic
View previous topic :: View next topic  
Author Message
balaji81_k

Active User


Joined: 29 Jun 2005
Posts: 155

PostPosted: Fri Mar 06, 2015 8:29 am
Reply with quote

Hi ,

I have written Rexx routine to create JCL statements which does delete datasets using IEFBR14 utlity . Rexx routine reads the input file which has list of datasets needs to be deleted . Problem is , i couldn't able to see the JCL statements which i coded under iterative loop condition in output file . Can any one help me in correcting the logic issue .
Code:

address tso
user =  userid()
fi   = user || "." ||dslist ||"."||output
fo   = user || "." ||jcljob ||"."||output
address tso
"alloc da('"fi"') fi(myindd) shr reuse"
say  'alloc rc indd ->'  rc
"execio * diskr myindd (stem indata. finis"
say  'read indd rc->'  rc
"free fi(myindd)"
say 'free indd rc->' rc
final = indata.0
last_str = strip(indata.final)
y    = msg('off')
x    = sysdsn("'"fo"'")
if x =  ok  then
do
address tso "delete"   "'"fo"'"
say  rc
end
address tso
"allocate fi(jclx) da('"fo"') new tracks",
"reuse space(5,5) dir(0) dsorg(ps) recfm(f,b) lrecl(80) blksize(0)"
say rc
/*  writing jcl */
jclx.1 = "//"user"DL" "JOB (XXXX),'DELJCL',NOTIFY=&SYSUID,"
jclx.2 = "//        CLASS=B,MSGCLASS=R,MSGLEVEL=(1,1),"
jclx.3 = "//        TIME=NOLIMIT"
jclx.4 = "//*"

if final  <=  10 then
do
     call  cr_single_Step_jcl
end

cr_single_step_jcl:
stepno  =  1
jclx.5   =  "//STEP"stepno "EXEC PGM=IEFBR14"
i    = 0
cnt  =   5
cnt  =  cnt +  1
done    = "NO"
do while done  = "NO"
cnt     =  cnt +  1
  do  i  =  1    to final
      jclx.cnt = "//DD"i "DD DSN="indata.i","  ,   -> Not written in output file
                 "//      DISP=(MOD,DELETE,DELETE)," , -> Not written
                 "//      SPACE=(0,0)"  ->  not written in output file
      say jclx.cnt
      cnt =  cnt  +  1
      say 'i->'   i
  end
  if   i >= final then
      done  = "YES"
  else
      done  = "NO"
end
cnt =  cnt +  1
jcl.cnt = "//*"
trace i
address tso "execio * diskw jclx (stem jclx. finis"
if rc  > 0  then
do
  say 'error in updating  file '
  exit 4
end
exit 0
Back to top
View user's profile Send private message
prino

Senior Member


Joined: 07 Feb 2009
Posts: 1314
Location: Vilnius, Lithuania

PostPosted: Fri Mar 06, 2015 12:39 pm
Reply with quote

If you had traced ("TRACE ?R") your exec you would have immediately seen what's wrong!
Back to top
View user's profile Send private message
don.leahy

Active Member


Joined: 06 Jul 2010
Posts: 765
Location: Whitby, ON, Canada

PostPosted: Fri Mar 06, 2015 7:49 pm
Reply with quote

My preferred approach for this type of task would be to use File Tailoring services rather than writing the JCL using Rexx code. Generating JCL is what File Tailoring was designed for.
Back to top
View user's profile Send private message
Pedro

Global Moderator


Joined: 01 Sep 2006
Posts: 2593
Location: Silicon Valley

PostPosted: Fri Mar 06, 2015 10:33 pm
Reply with quote

Note: I did not actually test your code.

There are multiple logic problems in the code:

Here, you have what should be three lines of JCL put into one line of the stem variable. The result will be only one line of JCL.
Code:
jclx.cnt = "//DD"i "DD DSN="indata.i","  ,   -> Not written in output file
                 "//      DISP=(MOD,DELETE,DELETE)," , -> Not written
                 "//      SPACE=(0,0)"  ->  not written in output file


Here, you have a different stem variable than used elsewhere.
Code:
jcl.cnt = "//*"


Here, I do not think you need the DO WHILE statement. The nested DO will process all of your input records. You only need to process them once.
Code:
do while done  = "NO"
cnt     =  cnt +  1
  do  i  =  1    to final


But your question is about missing records...

Here, you increment the counter twice without saving any records. That might result in a null record.
Code:
cnt  =  cnt +  1
done    = "NO"
do while done  = "NO"
cnt     =  cnt +  1

Later, when you issue EXECIO *, it will stop at the first null record

Prino's suggestion was to run with a TRACE... what were the results?
Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10886
Location: italy

PostPosted: Fri Mar 06, 2015 11:18 pm
Reply with quote

read here why using EXECIO * DISKW is dangerous/improper

www.ibmmainframes.com/viewtopic.php?t=60269&highlight=execio

here are two snippets which achieve the same in a better IMHO way

stem handling with a work variable
Code:

/* REXX */
/* arbitrary setting for the number of input things */
data.0 = 24
/* arbitrary setting for number of deletes in each coun */
coun   = 10

do  i  = 1 to data.0
    data.i = "some.dataset.s"i
end

jclx.1 = "//JOBNAME JOB (XXXX),'DELJCL',NOTIFY=&SYSUID,"
jclx.2 = "//            CLASS=B,MSGCLASS=R,MSGLEVEL=(1,1),"
jclx.3 = "//            TIME=NOLIMIT"
jclx.4 = "//* - - - - - - - - - - - - - - - - - - - - - - - - - - -"
jclx.0 = 4

if  coun = 0 then do
    j = jclx.0 + 1
    jclx.j = "//*"
    j = j + 1
    jclx.j = "//DELETE EXEC PGM=IEFBR14"
    jclx.0  = j
end

do  i = 1 to data.0
    if coun \= 0 then do
        if  i // coun = 1 then do
            stepno = i % coun + 1
            j = jclx.0 + 1
            jclx.j   = "//*"
            j = j + 1
            jclx.j   =  "//STEP"stepno "EXEC PGM=IEFBR14"
            jclx.0 = j
        end
    end

    j = jclx.0 + 1
    jclx.j  = "//DD"i "DD DSN="data.i","
    j = j + 1
    jclx.j  = "//      DISP=(MOD,DELETE,DELETE),"
    j = j + 1
    jclx.j  = "//      SPACE=(0,0)"
    jclx.0 = j
                     ,
end
do i = 1 to jclx.0
    say  jclx.i
end

return




stem handling without a work variable using INTERPRET
Code:

/* REXX */
/* arbitrary setting for the number of input things */
data.0 = 24
/* arbitrary setting for number of deletes in each step */
coun   = 10

do  i  = 1 to data.0
    data.i = "some.dataset.s"i
end

/* THE JOBCARD */
jclx.0 = 0
interpret "jclx."jclx.0+1"  = '//JOBNAME JOB (XXXX),'DELJCL',NOTIFY=&SYSUID,'"
interpret "jclx."jclx.0+2"  = '//            CLASS=B,MSGCLASS=R,MSGLEVEL=(1,1),'"
interpret "jclx."jclx.0+3"  = '//            TIME=NOLIMIT'"
interpret "jclx."jclx.0+4"  = '//* - - - - - - - - - - - - - - - - - - - - - - - - - - -'"
jclx.0 = jclx.0 + 4

if  coun = 0 then do
    interpret "jclx."jclx.0+1"  = '//*'"
    interpret "jclx."jclx.0+2"  = '//DELETE EXEC PGM=IEFBR14'"
    jclx.0  = jclx.0 + 2
end

do  i = 1 to data.0
    if coun \= 0 then do
        if  i // coun = 1 then do
            stepno = i % coun + 1
            interpret "jclx."jclx.0+1"  = '//*'"
            interpret "jclx."jclx.0+2"  = '//STEP"stepno "EXEC PGM=IEFBR14'"
            jclx.0  = jclx.0 + 2
        end
    end
    interpret "jclx."jclx.0+1"  = '//DD"i "DD DSN="data.i",'"
    interpret "jclx."jclx.0+2"  = '//      DISP=(MOD,DELETE,DELETE),'"
    interpret "jclx."jclx.0+3"  = '//      SPACE=(0,0)'"
    jclx.0 = jclx.0+3

end
do i = 1 to jclx.0
    say  jclx.i
end

return

Back to top
View user's profile Send private message
balaji81_k

Active User


Joined: 29 Jun 2005
Posts: 155

PostPosted: Sat Mar 07, 2015 6:38 am
Reply with quote

Thanks Enrico for your valuable advise on EXECIO * DISKW . Now i am able to understand what was the issue in my logic .
Back to top
View user's profile Send private message
Pedro

Global Moderator


Joined: 01 Sep 2006
Posts: 2593
Location: Silicon Valley

PostPosted: Mon Mar 09, 2015 11:22 pm
Reply with quote

I prefer this other approach:
Code:
J = 0                                                                   
                                                                         
Call AddLine "//JOBNAME JOB (XXXX),'DELJCL',NOTIFY=&SYSUID,"             
Call AddLine "//        CLASS=B,MSGCLASS=R,MSGLEVEL=(1,1),"             
Call AddLine "//        TIME=NOLIMIT"                                   
Call AddLine "//* - - - - - - - - - - - - - - - - - - - - - - - - - - -"
                                                                         
If  coun = 0 Then Do                                                     
    Call AddLine "//*"                                                   
    Call AddLine "//DELETE EXEC PGM=IEFBR14"                             
End                                                                     
                                                                         
. . .                                                                   
                                                                         
/* add a line to the the output stem*/                                   
AddLine:                                                                 
 Parse arg newline                                                       
 j      = j + 1                                                         
 jclx.j = newline                                                       
 jclx.0 = j                                                             
Return                                                                   


By moving the repetitive index logic to a subroutine, the main routine looks more simple. It will be easier to understand when you revisit the program in the future.
Back to top
View user's profile Send private message
balaji81_k

Active User


Joined: 29 Jun 2005
Posts: 155

PostPosted: Thu Mar 12, 2015 8:33 am
Reply with quote

Hi Pedro,
Thanks for your code. Now i am working on logic to split steps based on the no of input files available for delete. for example if i have 50 files to be deleted then i am creating 5 steps to do it .10 files for each step .I am facing the issue when the no of input files is multiples of 10 and i have marked arrow where is the problem.Can you please help me to overcome this issue.
Here is the code sample that i have written for the same.
Code:

/* rexx  */
trace ?r
tot_no_files = X
div_by_10 = 10
integer_quot =  tot_no_files %  div_by_10
remainder    =  tot_no_files // div_by_10
say 'integer_quot'  integer_quot
say 'remainder'  remainder
if remainder > 0   then
do
   step_cnt =  integer_quot +  1
end
else
do
   step_cnt =  integer_quot
end
say 'step_cnt'   step_cnt
total_steps =  0
total_ddcnt = 0
do  i  =   1 to  step_cnt
     total_steps = total_steps  +   1
     if total_steps =   step_cnt then
        if remainder >  0 then
           remain_ddstps = remainder
        else
           remain_ddstps = integer_quot * 10  <-
     else
        remain_ddstps = 10
       say "//STEP" total_steps "statement = IEFBR14 "
     do j   =  1 to  remain_ddstps
       total_ddcnt  =    total_ddcnt  +   1
       say "DD"total_ddcnt "=file" total_ddcnt
     end
  end
exit 0
Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10886
Location: italy

PostPosted: Thu Mar 12, 2015 10:25 am
Reply with quote

if You look at my snippets You will see that they implement the logic You are asking for ...

the variable coun tells how many deletes for each step
Back to top
View user's profile Send private message
Pedro

Global Moderator


Joined: 01 Sep 2006
Posts: 2593
Location: Silicon Valley

PostPosted: Thu Mar 12, 2015 9:52 pm
Reply with quote

I do not think you should care that the first step name is DELETE and others are named STEPnnn. Not caring simplifies then coding:
Code:
step# = 0                                     
Do  i = 1 To 35                               
  If (I // 10) = 1 Then                       
    Do                                       
      step# = step# + 1                       
      Say  '//*'                             
      Say  '//STEP'step# 'EXEC PGM=IEFBR14'   
    End                                       
  Say '//DD'i 'DD DSN='i                     
End                                           

per Enrico's example, you use the remainder function (//) to determine when a new EXEC statement is needed.
Back to top
View user's profile Send private message
balaji81_k

Active User


Joined: 29 Jun 2005
Posts: 155

PostPosted: Fri Mar 13, 2015 10:39 pm
Reply with quote

enrico-sorichetti wrote:
if You look at my snippets You will see that they implement the logic You are asking for ...

the variable coun tells how many deletes for each step


Thanks Enrico . Now i have logic to limit delete only for the files whose creation date is more than / equal = 90 days (>= 90). I have written logic to handle this difference. I have a doubt on this ,because i am not sure whether it will handle leap year logic also.
Code:

/* rexx  */
/*  to find difference between current time and sys creat time */
dsn =  "'xxx.yyy.zzz'"
dsinfo =  listdsi(dsn)
say 'syscreate '   syscreate
parse var syscreate 1 cc 3 yy '/' ddd .
jdate = yy||ddd
say jdate
gdate = date('u',jdate,'j')
say gdate
gdateb = date('base',gdate,'u')
today = Date('Base')
say 'gdate-base format->>'    gdateb
say 'today-base format->>' today
ISOdate = Date('Standard', today, 'Base')
date1   = ISOdate
say 'date1->>>'  date1
ISOdate = Date('Standard', gdateb, 'Base')
date2   = ISOdate
say 'date2->>>'  date2
days_diff =  date1 - date2
say 'days_diff'  days_diff
exit 0
Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10886
Location: italy

PostPosted: Fri Mar 13, 2015 11:01 pm
Reply with quote

I guess I had a brain check ...

what is the exact format of the input list ?

an adrdssu dump delete with a dummy dump dataset might be the most practical solution


Code:

//jobname  JOB ..........
//DSS     EXEC PGM=ADRDSSU,REGION=0M,
//             PARM='TYPRUN=NORUN'
//SYSPRINT  DD  SYSOUT=*                             
//DUMMYDS   DD  DUMMY,
//              DCB=(RECFM=VB,LRECL=27994,BLKSIZE=27998)
//SYSIN    DD    *                                     
  DUMP DATASET( -
        INCLUDE( -
                 dataset.one -
                 dataset.two -
                 ...
                 dataset.umpteen -
                 ) -
      BY( REFDT LT (*,-xxx) ) -
       OUTDDNAME(DUMMYDS) -                               
       DELETE PURGE                                   
/*                                         
 
Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10886
Location: italy

PostPosted: Sat Mar 14, 2015 2:14 am
Reply with quote

IMHO the date difference code is too much ...

why not use a simpler approach ???

something along the lines of ...

Code:

000009 ...
000010 dsirc = listdsi("some.existing.dataset")
000011 crtdt = substr(syscreate,3,2) || substr(syscreate,6,3)
000012 refdt = substr(sysrefdate,3,2) || substr(sysrefdate,6,3)
000013 crtage = date("b") - date("b",crtdt,"j")
000014 refage = date("b") - date("b",refdt,"j")
000015 say "crtage = "crtage
000016 say "refage = "refage
000017 ...
Back to top
View user's profile Send private message
enrico-sorichetti

Superior Member


Joined: 14 Mar 2007
Posts: 10886
Location: italy

PostPosted: Sat Mar 14, 2015 12:30 pm
Reply with quote

and here is a nice snippet which shows how to use translate
to reorder/select part of a string

Code:

 000010 dsirc = listdsi("some.dataset")
 000011 crtdt1 = substr(syscreate,3,2) || substr(syscreate,6,3)
 000012 refdt1 = substr(sysrefdate,3,2) || substr(sysrefdate,6,3)
 - - -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  4 Line(s) not Displayed
 000017 crtdt2 = translate(34678,syscreate,"12345678")
 000018 refdt2 = translate(34678,sysrefdate,"12345678")
 000019 say "crtdt1 / refdt1 => "crtdt1 "/" refdt1
 000020 say "crtdt2 / refdt2 => "crtdt2 "/" refdt2
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 -> TSO/ISPF

 


Similar Topics
Topic Forum Replies
No new posts XML Generate issue COBOL Programming 0
No new posts How to Login in to cics region and is... CICS 9
No new posts Dynamically build sort control statem... SYNCSORT 18
No new posts SFTP Issue - destination file record ... All Other Mainframe Topics 2
No new posts Calling DFSORT from Cobol, using OUTF... DFSORT/ICETOOL 5
Search our Forums:

Back to Top