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

Am I missing something on "FREE DD" command ?


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

New User


Joined: 14 Jul 2020
Posts: 14
Location: Brazil

PostPosted: Fri Sep 04, 2020 6:51 am
Reply with quote

Hey guys, me again on my rexx adventure and needing some quick insight from all of you experts, hope not to bother you much this time.. so the deal is that I can't get a FREE DD command to work when to free/close a generated(last) member out of a LMDINIT command. I've tried several places already so as a last resort I really hope you allow me to bother you a little bit.

Initially whenever an empty member is generated (no more datasets are read) then it will do a free and deletion of this last empty member, now if we proceed below you will find thse:

DATAsap = cntid3//10000
IF DATAsap = 0 THEN DO
"EXECIO 0 DISKW "SRCSAP""mbn" (FINIS"
"EXECIO 0 DISKW "TGTSAP""mbn" (FINIS"
"FREE DD("SRCSAP""mbn")"
"FREE DD("TGTSAP""mbn")"
CALL REALLOC
END

and more below a QUEUE is executed to generate a job containing a few jcl rows for each new SRCSAP"mbn" and TGTSAP"mbn" that is generated.
Once all datasets are read and SRCSAP"mbn" , TGTSAP"mbn" and CLNSAP"mbn" are created the program ends and invoke LIST_DS. Problem I'm facing is that once the program completes, if I execute CLNSAP job it complains that both DB2.CLONE."SID".CNTL and DB2.CLONE."SID".JCL are still opened and last SRCSAP , TGTSAP were not freed.
Lets say when more than one STCSAP/TGTSAP are generated, the free DD works but the last one generated never gets really freed up.

I hope it does make sense what I'm trying to accomplish.

So below is the code;

Code:

ALLOC_DS:     /* This procedure will create the new dataset that will store   
                 Source / Target files and also FRRECOV jobs     */           
                                                                             
  if emptymember = 0 then do                                                 
                         "FREE DD("SRCSAP""mbn")"                             
                         "FREE DD("TGTSAP""mbn")"                             
                         delete DA(DB2.CLONE."SID".CNTL("SRCSAP""mbn"))       
                         delete DA(DB2.CLONE."SID".CNTL("TGTSAP""mbn"))       
                      end                                                     
                                                                             
  "ISPEXEC LMDLIST LISTID("ID3") OPTION(FREE)"                               

/* FETCH STEP 3: Will fetch data based on SAPSID parsed argument */             
                                                                               
 SAY "Creating members (SRCSAP and TGTSAP) to list SOURCE DB2 SAP Application ta
bles"                                                                           
 SAY                                                                           
 SAY "Loading dataset list in SRCSAP/TGTSAP members. PLEASE BE PATIENT"         
 SAY                                                                           
                                                                               
"ISPEXEC LMDINIT LISTID(ID3) LEVEL(SAP"SID".DSNDBD.*)"                         
                                                                               
mbn = 0                                                                         
                                                                               
CALL REALLOC      /* first call to allocate the first member */                 
                                                                               
/* cntid3 = 1 */ /*--> use this in case wanna change code to do forever*/       
DO cntid3=1 to 999999  /* update to do forever and init counter above */       
                                                                               
"ISPEXEC LMDLIST LISTID("ID3") OPTION(LIST) DATASET(DSNSAP)"                   
   IF RC <> 0 THEN CALL EDIT_DS                                                 
                                                                               
  CURRENTDSN.1 = DSNSAP                                                         
                                                                               
  orig = CURRENTDSN.1                                                           
  orig = strip(orig)                                                   
  lenorig = length(orig)                                               
  lenorig = lenorig - 6                                                 
  orig1 = substr(orig, 1, 7)||"DSNDBC"||substr(orig, 14, lenorig)       
  CURRENTDSN.1 = orig1                                                 
  "EXECIO 1 DISKW "SRCSAP""mbn" (STEM CURRENTDSN. "                     
                                                                       
  temp = CURRENTDSN.1                                                   
  temp = strip(temp)                                                   
  lentemp = length(temp)                                               
  lentemp = lentemp - 6                                                 
  temp1 = substr(temp, 1, 3)||"SID"||substr(temp, 7, lentemp)           
  CURRENTDSN.1 = temp1                                                 
  "EXECIO 1 DISKW "TGTSAP""mbn" (STEM CURRENTDSN. "                     
  emptymember = 1                                                       
                                                                       
   DATAsap = cntid3//10000                                             
   IF DATAsap = 0 THEN DO                                               
                        "EXECIO 0 DISKW  "SRCSAP""mbn" (FINIS"         
                        "EXECIO 0 DISKW  "TGTSAP""mbn" (FINIS"         
                        "FREE DD("SRCSAP""mbn")"                       
                        "FREE DD("TGTSAP""mbn")"                       
                        CALL REALLOC                                       
                     END                                                   
/*--> uncomment "cntid3 = cntid3 + 1" in case of use DO FOREVER */         
END                                                                         
RETURN                                                                     
REALLOC:                                                                   
  mbn = mbn + 1                                                             
  "ALLOC DD("SRCSAP""mbn") DA(DB2.CLONE."SID".CNTL("SRCSAP""mbn")) SHR REU"
  "ALLOC DD("TGTSAP""mbn") DA(DB2.CLONE."SID".CNTL("TGTSAP""mbn")) SHR REU"
                                                                           
 QUEUE "//CLNSAP"mbn"  JOB  (@HSG,BA01),DB2CLONE,CLASS=S,MSGCLASS=H,   "   
 QUEUE "//         MSGLEVEL=(1,1),NOTIFY=&SYSUID,REGION=0M,TIME=30    "     
 QUEUE "/*JOBPARM S=                                                  "     
 QUEUE "//STEP01   EXEC PGM=IKJEFT01                                  "     
 QUEUE "//SYSEXEC  DD DISP=SHR,DSN=DB2.CLONE.CLNLOAD                  "     
 QUEUE "//SYSTSPRT DD SYSOUT=*                                        "     
 QUEUE "//SYSTSIN  DD *                                               "     
 QUEUE " PROFILE NOPREFIX                                             "     
 QUEUE "%$FRRECOV +                                                   "     
 QUEUE "DB2.CLONE."SID".CNTL +                                        "     
 QUEUE "SRCSAP"mbn" +                                                 "     
 QUEUE "TGTSAP"mbn" +                                                 "     
 QUEUE "DSN$BHSAP"SID"$DB                                             "   
                                                                           
  "ALLOC DD("CLNSAP""mbn") DA(DB2.CLONE."SID".JCL("CLNSAP""mbn")) SHR REU"
  "EXECIO" QUEUED() "DISKW "CLNSAP""mbn" (FINIS"                           
  "FREE DD("CLNSAP""mbn")"                                                 
                                                                           
  emptymember = 0                                                         
RETURN                                                                     
                                                                           
/* EDIT_DS Will run macros $SID and $DSNDB located in DB2.ISPF.CLIST Librar
   These macros will update some members listed in MBR parm      */       
                                                                           
EDIT_DS:                                                                   
                                                                           
 DATASET = "DB2.CLONE."SID".CNTL"                                         
 ADDRESS 'ISPEXEC'                                                         
 "LMINIT DATAID(TGT1) DATASET('"DATASET"') ENQ(SHRW)"                     
 "LMOPEN DATAID("TGT1") OPTION(INPUT)"                                     
 MBR1 = "TGTSID"                                                           
 MBR2 = "TGTDSID"                                                         
 MBR3 = "SRCDSID"                                                         
 SAVERC = 0                                                               
 DO WHILE (SAVERC = 0) & (ENDNOW \= 'Y')                           
    "LMMLIST DATAID("TGT1") MEMBER(MBR1) OPTION(LIST) STATS (NO)"   
    "LMMLIST DATAID("TGT1") MEMBER(MBR2) OPTION(LIST) STATS (NO)"   
    SAVERC = RC                                                     
   "EDIT DATAID("TGT1") MEMBER("MBR1") MACRO(@SID)"                 
   "EDIT DATAID("TGT1") MEMBER("MBR2") MACRO(@SID)"                 
   "EDIT DATAID("TGT1") MEMBER("MBR2") MACRO(@DSNDB)"               
   "EDIT DATAID("TGT1") MEMBER("MBR3") MACRO(@DSNDB)"               
 END  /* end do */                                                 
 "LMCLOSE DATAID("TGT1")"                                           
 "LMFREE DATAID("TGT1")"                                           
                                                                   
/* LIST_DS will show on screen the new members generated           
           For Source and Target files                   */         
LIST_DS:                                                           
 SAY "LISTING NEWLY CREATED MEMBERS"                               
 ADDRESS TSO                                                       
 "LISTDS DB2.CLONE."SID".CNTL MEMBERS"                             
 "LISTDS DB2.CLONE."SID".JCL MEMBERS"                               
EXIT 0                                                             
Back to top
View user's profile Send private message
Willy Jensen

Active Member


Joined: 01 Sep 2015
Posts: 712
Location: Denmark

PostPosted: Fri Sep 04, 2020 1:31 pm
Reply with quote

I don't see a LMDFREE for listid ID3, you need that before the FREE.
Back to top
View user's profile Send private message
Nic Clouston

Global Moderator


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

PostPosted: Fri Sep 04, 2020 1:37 pm
Reply with quote

Show your trace. Check your return codes. Quotes around DELETE statements. FREE FI not FREE DD.
Back to top
View user's profile Send private message
Willy Jensen

Active Member


Joined: 01 Sep 2015
Posts: 712
Location: Denmark

PostPosted: Fri Sep 04, 2020 6:01 pm
Reply with quote

Re "FREE FI not FREE DD", I beg to differ, I have always used FREE DD. Or do you have a reason why 'FI' is the better choice?
Back to top
View user's profile Send private message
steve-myers

Active Member


Joined: 30 Nov 2013
Posts: 917
Location: The Universe

PostPosted: Fri Sep 04, 2020 8:23 pm
Reply with quote

FREE DDname(...) (as opposed to File(...)) has been valid for a long time. Like most old timers, i rarely use FREE DD, and do use FREE F. Actually I use ALLOCATE FILE(...) REUSE (rather than FREE F(...);ALLOC FILE(...) just to use one command.
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 05, 2020 1:48 am
Reply with quote

Well, I have only been working IBM computing since early 1973, which might not make me old-timer ? icon_wink.gif
Back to top
View user's profile Send private message
steve-myers

Active Member


Joined: 30 Nov 2013
Posts: 917
Location: The Universe

PostPosted: Sat Sep 05, 2020 4:40 am
Reply with quote

I forget when DDNAME(...) was added to FREE, but I suspect it was with TSO-E. The code effort was trivial; the doc change was bigger!

The parse macro definition in OS/360 would have been something like this (add continuation flags as required) -
Code:
...      IKJPARM DSECT=...
XXX      IKJKEYWD
         IKJNAME FILE,SUBFLD=AAA
YYY      IKJKEYWD
         IKJNAME DATASET,SUBFLD=BBB
AAA      IKJSUBF
ZZ1      IKJIDENT 'FILE NAME',LIST,FIRST=ALPHA,OTHER=ALPHANUM,
               MAXLNTH=8,PROMPT='FILE NAME'
BBB      IKJSUBF
ZZ2      IKJPOSIT DSNAME,LIST,PROMPT='DATA SET NAME'
         IKJENDP
The actual labels, of course, are different, but are not material to the immediate discussion. MVS (or maybe SVS) would have added USID to the ZZ2 PCE.

To add DDNAME and DSNAME, the only change would be in the parse macros -
Code:
...      IKJPARM DSECT=...
XXX      IKJKEYWD
         IKJNAME FILE,SUBFLD=AAA
         IKJNAME DDNAME,SUBFLD=AAA
YYY      IKJKEYWD
         IKJNAME DATASET,SUBFLD=BBB
         IKJNAME DSNAME,SUBFLD=BBB
AAA      IKJSUBF
ZZ1      IKJIDENT 'FILE NAME',LIST,FIRST=ALPHA,OTHER=ALPHANUM,
               MAXLNTH=8,PROMPT='FILE NAME'
BBB      IKJSUBF
ZZ2      IKJPOSIT DSNAME,LIST,PROMPT='DATA SET NAME'
         IKJENDP
The actual code only needs to look at the ZZ1 (for FILE or DDNAME) PDE, or the ZZ2 (for DATASET or DSNAME) PDE; the keyword is immaterial.

Now you may say, but doesn't the PROMPT keyword require the terminal user to enter a value? Yes, but only if the FILE/DDNAME or DATASET/DSNAME keyword is entered, so it won't prompt for a data set name when FREE DDNAME is entered by the terminal user.

Just some notes about the terminology. In the parse macros, a PCE (Parameter Code Entry) is the data in the PCL (Parameter Control List) CSECT constructed by the parse macros; a PDE (Parameter Descriptor Entry) is the data returned by IKJPARS in the PDL (Parameter Descriptor List) DSECT also constructed by the parse macros.
Back to top
View user's profile Send private message
Nic Clouston

Global Moderator


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

PostPosted: Sat Sep 05, 2020 3:16 pm
Reply with quote

I admit to not coding FREE for 5 years and my recent reading has been for MVS 3.8j on Hercules - and I haven't, yet, managed to get Rexx installed. (Struggling with that at the moment.)
Back to top
View user's profile Send private message
rodferrn

New User


Joined: 14 Jul 2020
Posts: 14
Location: Brazil

PostPosted: Mon Sep 07, 2020 12:35 am
Reply with quote

Hi Folks, first of all I'd like to say I appreciate all the feedback and valuable insights. It's weird thou that somehow I couldn't still figure this out .. whatever place I put the FREE listid :

"ISPEXEC LMDLIST LISTID("ID3") OPTION(FREE)"

even thou the datasets are not freed after they are generated, if I put LMDLIST LISTID free inside the loop the program just doesn't complete at all, if I put at the beginning of the code (as it shows in my first post) members SRCSAP1 and TGTSAP1 are kept opened just like CNTL and JCL datasets, which forces me to do a TSO ISRDDN and hit F in front of those (first I need to free members SAP1 and then the datasets).

I was thinking that perhaps, after LIST_DS function I could add a ISPEXEC to close the datasets ? One issue I had with that is that the program ends in error saying that FREE is not a valid dialog command .. I've been trying for days but still have the same outcome.. feel like I'm running out of ideas icon_sad.gif
Back to top
View user's profile Send private message
Pedro

Global Moderator


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

PostPosted: Mon Sep 07, 2020 10:05 am
Reply with quote

Quote:
error saying that FREE is not a valid dialog command


There is an ADDRESS 'ISPEXEC' statement that changes the host command environment to be for ISPF dialog stuff.

FREE is a TSO command. You have to explicitly specify the host command environment if it is mixed in with ISPEXEC commands:
Code:
Address TSO "FREE DD("SRCSAP""mbn")"
Address TSO "FREE DD("TGTSAP""mbn")"
Back to top
View user's profile Send private message
Willy Jensen

Active Member


Joined: 01 Sep 2015
Posts: 712
Location: Denmark

PostPosted: Mon Sep 07, 2020 1:39 pm
Reply with quote

I am talking about a missing LMDFREE, the companion of your ISPEXEC LMDINIT, not LMDLIST FREE.

A few more comments:

I assume that variables SRCSAP, TGTSAP and mbn has been defined prior to entering ALLOC_DS, otherwise the ddname in the free commands would be 9 byte long.
You should have quotes around the 'delete' commands.

I don't think that you need to increase the DDname qualifier like "SRCSAP""mbn", seems to me that you are allocating and freeing the ddname set in each loop iteration. And since you do ALLOCATE .. REUSE, you might get away with just using i.e.. DDname SRCSAP hardcoded.
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 RACF - Rebuild SETROPTS command which... All Other Mainframe Topics 3
No new posts Routing command Address SDSF to other... TSO/ISPF 2
No new posts DTL - how to define key with stacked ... TSO/ISPF 3
No new posts LTJ command CA Products 4
No new posts PuTTY - "User is not a surrogate... IBM Tools 5
Search our Forums:

Back to Top