Another Way to Skin a Cat
The article Running S/36 Applications in the Next Millenium (MC, February
1998) covered the basics pretty well. Every article I have ever read about this problem covers the same issues and offers the same solutions.
I have a different, very simple solution to the Year 2000 date problem for S/36 code. My solution does not involve expanding date fields in files; adding century flags, fields, or screen rewrites; or changing file specs, data structures, the local data area, or any operation control language (OCL) date sorts on YYMMDD fields. My solution does not require me to change a single screen, a single sort, or a single file spec. It does, however, require the Value Added Software Package (VASP) or called program support.
I have been using this technique for years and do not suffer from the same recoding problems many other people do. Maybe my method can help people solve this problem more quickly and more safely.
My solution is to replace six-digit dates with a number indicating the number of elapsed days since 1900. I have two subprograms to convert dates between the encoded format and the MMDDYY and YYMMDD formats needed by my programs.
Figure 1 contains RPG II program TODAYS, which accepts a date in MMDDYY format and returns the number of elapsed days, the date in YYMMDD format, and the two-digit century indicator, 19 or 20.
Figure 2 shows the program that reverses the process, FRDAYS. It accepts a number of elapsed days and returns dates in MMDDYY and YYMMDD format, and the two-digit century indicator.
My applications call FRDAYS after reading from disk and TODAYS before writing to disk. I have been using this technique for years and do not have to recode for the Year 2000.
If you choose to change your applications to use this technique, you may have to make some modifications. Sorts that sort on dates in MMDDYY or DDMMYY format must be changed as if they were sorting on dates in YYMMDD format. For record selection, you will have to convert the dates users key in to prompt screens into the days format before they can be used.
One disadvantage of this approach is that Query and DFU users will not see the actual dates.
Jay J. Falconer Bitwise Software International, Inc. Phoenix, AZ
Yet Another Way to Skin a Cat
A common method of converting code to handle dates of 2000 and beyond is to check out one or more files and all the programs that use them, change the files and programs, test, and place everything back into production.
The company I work for used another method in certain situations, and we found it helpful. Rather than starting with files, we started with programs. We changed programs so that they could use dates of different formats. We built a control file that describes how dates are described in the data files.
When a program begins to run, it calls a program that checks the control file to find out whether or not the data files have been converted. When the program reads from or writes to disk, it converts the dates according to the control information. The RPG III code fragments in Figure 3 on page 58 illustrate this process.
We found this approach to have certain advantages:
The programmer changes a program only once and is finished with it, except for recompiles. (Most methods require recompilation when a file layout changes. The difference here is that the program is modified only once. With this method, there is no modification before subsequent recompiles.)
We could coordinate changes more easily, since we did not have to wait for developers to release objects they were working on.
This method gave us a repository and checklist for the files as they were being changed.
There are disadvantages, too, however:
Programs are left with extra code that may add to maintenance confusion later.
This method may require more total effort than simply stopping all other work to change everything at one time because of adding and testing all that code. Otherwise, in many programs, you could simply revise a few lines of code to handle the new date format and recompile.
We do not feel that this is the best method or the only method for Year 2000 preparation. We do think it can be helpful in certain situations.
Skip Forster
Should Missed Jobs Run or Not?
When you add entries to the AS/400 Job Scheduler, the default recovery action (parm RCYACN) is *SBMRLS, which means that if the job cant run because the machine is off (power outage, maintenance, etc.), the job will be submitted as soon as possible after the machine is restarted. Sometimes thats fine, but sometimes it can be disastrous.
The company I work for had to backdate our machine after one of our rare snow days down here (northeast Alabama) so we could recover December 29, 1997, as a
1997 date for accounting purposes. We ran one whole day with the system backdated, and everything worked fine that day.
The next day, however, when we reset the system date value, we had major problems. Job scheduler jobs that should have run on 1/1/98, but didnt because of the backdating, fired up immediately and simultaneously!
Needless to say, system response went to zilch, and conflicting jobs were at cross purposes right and left until we could safely shut them down.
To save ourselves future grief, we set recovery action to *NOSBM on all job scheduler jobs. In the future, we will manually submit any missed jobs that need rerunning after restart.
This may be appropriate for some or all scheduled jobs in your shop, but, if you use it, be sure you have a way to know if a job was not submitted.
Barry Jones
Put the Qualified Program Name in Report Headings
As a rule, you probably include report date and page numbers in report headings. Several years ago, I added the qualified program name to that list. Printing the qualified program name in page headings is helpful.
I can determine at a glance exactly which program created a report. This is handy when a user shows me a report and asks me to modify it.
I can tell at a glance whether a report was built by a program in production or an experimental version in a test library. This is especially handy when I have both production and experimental versions lying side by side on my desk for comparison.
Including the qualified program name on a report is easy, thanks to two copybook members I created. The first defines the RPG program status data structure. Figure 4 on page 58 shows an abbreviated version of this data structure. You can find the complete version in my article Error Recovery in RPG Programs in the November 1994 issue of Midrange Computing.
The second copybook member, shown in Figure 5 on page 58, builds the qualified program name. Figure 6 illustrates how I typically include these copy members in an RPG III program.
The only other requirement is to include field PGMNAM in the printer file DDS or output specs.
Ted Holt Senior Technical Editor Midrange Computing
Automatically Reply to Printer Messages In our data center, we print hundreds of spool files with thousands of pages each day. Our operators rely on messages CPA3394 (load a certain form) and CPA4002 (verify alignment).
Our users, however, use virtual printers. These messages dont apply to them and only confuse them.
We use the system reply list to automatically answer these inquiry messages when they are sent from virtual printers. Entries in the system reply list are easily added using the Add Reply List Entry (ADDRPYLE) command. Required parameters for this command are sequence number, message ID, and reply.
The sequence number is a unique reply list number between 1 and 9999. Message ID is the inquiry message we want the system to intercept. The reply parameter is how the system will reply to the intercepted inquiry message.
ADDRPYLE also has an optional Compare data (CMPDTA) parameter, which has two fields. In the first field, you may enter up to 32 characters of message text. In the second field, you can specify at what starting position within the message to look for the compare data text. When you use this parameter, each message is searched for the compare data text at the designated starting point.
Figure 7 shows the commands to add system reply list entries for one of our virtual printers.
We wrote the CL program in Figure 8 to add all virtual printers (about 150 of them) to the system reply list. We run this program through the job scheduler. It updates our reply list for all added and deleted printers since the last time it was run. We randomly selected the 3xxx series of sequence numbers in the system reply list to be used only for virtual printers, and we will not manually add any entries within that range that we wouldnt want the CL program to remove.
Its not enough to create these reply list entries. Users jobs must be instructed to use the system reply list. One way to do this is with the Change Job (CHGJOB) command:
CHGJOB INQMSGRPY(*SYSRPYL)
Another way is to change the job descriptions that the users use.
CHGJOBD JOBD(USRJOBD) + INQMSGRPY(*SYSPLYL)
One note of caution: Before changing users jobs or job descriptions, make sure there are no reply list entries you wouldnt want them to have. We had an entry of MSGID(RPG0000) RPY(D) in our reply list. This caused all RPG messages, even those the calling program was monitoring for, to get dumped!
Try using the system reply list to intercept printer messages. It might just intercept messages that are headed for your help desk as well!
Gordon Brucks
Runtime Record Selection for a Batch Query
Q: Is there a way to prompt the record selection screen in Query/400 that will allow the user to key in selection criteria and then submit the job to batch? The RCDSLT parameter of the Run Query (RUNQRY) command lets me select records at runtime, but I have to run the command interactively for it to work.
A: We use OPNQRYF to perform the record selection that the query used to perform. In the query, locate the names of the files you are selecting data from in the Specify File Selections prompt and the way youre selecting data in the Select Records prompt (Figure 9). You will need to decide whether to let OPNQRYF select all the data or to let Query/400 select some data and let OPNQRYF select the rest. Modify the Select Records prompt appropriately.
In library QTEMP, create duplicates of the files you will be using OPNQRYF to select the data from. You need to change the name of the file to avoid getting an error on the copy you will be doing later. I usually just add a Q to the end of the file name. Change the library parameter on the file selection prompt in Query/400 to point to the files in QTEMP. Save the query definition, and delete the QTEMP files you just created.
Create a prompt screen that will allow the users to enter their selections (Figure 10). The DDS for this screen is shown in Figure 11. This prompt will run from a CL program (like the one in Figure 12) that uses the OPNQRYF to select the records from the file based on the user input. In your CL program, right after the OPNQRYF, add the Copy From Query File (CPYFRMQRYF) command to copy the selected data to a duplicate of the queried files in library QTEMP. The CPY-FRMQRYF will create the file for you in QTEMP if you want it to.
Finally, use the RUNQRY to run the original query. You will need to pass the temporary files to the query in the QRYFILE parameter on the RUNQRY command.
Now, the original query will run, using the data extracted with the OPNQRYF and any additional selections you may have defined in the Query/400 definition.
This technique has the advantage that it reuses the existing report the user is familiar with, without requiring a programmer to rewrite it in RPG, and its a very quick way to create a user-selectable report that can be easily added to a menu.
Shannon ODonnell
Dont Call the Main Procedure of a C Program
A couple of recent posts to the MC Web Forums mention calling the main function of a C module directly. That might work as long as you have only one C module in a program, but I dont think the C folks would recommend it.
Let me review a bit about ILE. A module can either have a program entry procedure (PEP) or not. A C module with a procedure called main has a PEP. An RPG module that doesnt have NOMAIN in the H-spec has a PEP. A program with several modules has one that is designated the PEP module. This is the one that is called when you first call the program.
C and RPG both have a concept of a main procedure, but they are slightly different. C allows only one main() function in a program, and its expected to be in the PEP module. RPG allows one main procedure per module. Since they have different names (the name given to the main procedure is the name of the module when it was created), you can freely call between the main procedures.
Heres how C was always intended to be used: The program would be broken up into logical units (modules), and any procedures within the modules that were useful outside the module were exported. The rest were kept private to the module. No C programmer would ever code with only one procedure per module.
The classic RPG way was one procedure per module, because a module was equivalent to a program. When you first migrated from OPM, it was convenient to continue this, just using CALLB instead of CALL, and basically calling your source- member name.
You can still do that, but you can also group your procedures together. This can be awkward at first because you dont know where your procedures are, but this isnt hard to get used to.
Barbara Morris
IBM Toronto Lab RPG Compiler Development
No-cost RPG Indenter
One of RPGs features that I see as a shortcoming is its fixed columnar nature. If you have a series of nested structures (such as an IF/ELSE/ENDIF block nested within a DOW/ENDDO block), RPGs fixed columns make it difficult to make sure which statements fall within the IF group, which fall within the DO group, and which fall outside both. Things get worse as the number of nested structures increases.
Fortunately, RPG has offered a solution for quite some time: the INDENT parameter of the compiler commands Create RPG Program (CRTRPGPGM), Create RPG Module (CRTRPGMOD), and Create Bound RPG (CRTBNDRPG).
INDENT lets you specify one or two characters to be used for indentation purposeson the printed compiler listing only. Ive found that specifying a period, or a vertical line and a space, does the trick pretty well. Next time you compile an RPG program or module, specify INDENT(.) and look at the compiler listing. Youll see a world of difference.
If you like INDENT and want to use it all the time, you should change the default value for this parameter in all three compiler commands. To make sure you dont alter IBM-supplied commands, however, you should clone all three commands into a library that is higher than QSYS in the system portion of the library list (create one if you dont have it) and then change the default parameter values of the clones, using the Change Command Default (CHGCMDDFT) command. For instance, I have a library named ALTQSYS for that very purpose. Heres what Id do to change the default for the CRTRPGPGM command: CHGCMDDFT +
CMD(ALTQSYS/CRTRPGPGM) +
NEWDFT(INDENT(.))
Ernie Malaga Senior Technical Editor Midrange Computing
H B 64 B 1
***************************************************************
** TITLE......... CONVERTS MMDDYY DATE TO YYMMDD AND #DAYS
** AUTHOR........ JAY J. FALCONER, BITWISE SOFTWARE INTL
** COPYRIGHT ..... (C) 1988-98, ALL RIGHTS RESERVED
** DESCRIPTION... CALLED BY S/36 PROGRAMS TO RETURN $DAYS AND
** YYMMDD FORMAT FOR MMDDYY $$MDY PASSED IN
**** 04/09/88 - INITIAL CODE
***************************************************************
I$$MDYP DS
I 1 60$$MDY
I 1 20$$MM1
I 3 40$$DD1
I 5 60$$YY1
I$$YMDP DS
I 1 60$$YMD
I 1 20$$YY2
I 3 40$$MM2
I 5 60$$DD2
C** CALLED PROGRAM RECEPTION
C *ENTRY PLIST
C PARM CALLOK 1
C PARM $$MDYP
C PARM $$YMDP
C PARM $$DAYS 60
C PARM $$CENT 20
C** RESET RETURN VALUES - DEFAULTS NEED TO BE PRESET
C MOVE N CALLOK
C Z-ADD0 $$DAYS
C Z-ADD0 $$CENT
C Z-ADD0 $$YMD
C** IF $$MDY 0 - NOTHING TO CONVERT - RETURN ERROR - CALLOK = N
C $$MDY IFEQ 0
C RETRN
C END
C** FIRST LOAD $$YMD (YYMMDD) FROM $$MDY (MMDDYY) PASSED IN
C Z-ADD$$MM1 $$MM2
C Z-ADD$$DD1 $$DD2
C Z-ADD$$YY1 $$YY2
C** NOW CONVERT $$MDY FROM MMDDYY TO # DAYS SINCE 1900 ($DAYS)
C Z-ADD$$MM1 G$MM 20
C Z-ADD$$DD1 G$DD 20
C** ASSUME WHAT CENTURY? (THIS CAN BE CHANGED)
C $$YY1 IFGT 50
C Z-ADD19 $$CENT
C Z-ADD1900 G$YYYY 40
C ELSE
C Z-ADD20 $$CENT
C Z-ADD2000 G$YYYY 40
C END
C** NOW ADD YEAR PASSED IN TO END OF 19XX OR 20XX PRE-LOADED
C ADD $$YY1 G$YYYY 40
C** CALC DAYS FROM MM DD YYYY FIELDS NOW LOADED
C EXSR GTOJ$
C MOVE Y CALLOK
C Z-ADDG$JD $$DAYS
C** RETURN RESULTS OF WORK DONE HERE
C RETRN
C*******************************************
C GTOJ$ BEGSR
C*******************************************
C Z-ADD0 G$JD
C G$MM SUB 3 G$MMWK 20
C Z-ADDG$MMWK G$WKSV 20
C G$MMWK IFLT 0
C ADD 12 G$MMWK
C END
C G$WKSV IFNE 0
C G$MMWK MULT 30.6 G$JD H
C END
C ADD G$DD G$JD 50
C G$YYYY SUB 1900 G$YYWK 30
C G$YYWK IFNE 0
C G$WKSV IFLT 0
C SUB 1 G$YYWK
C END
C END
C G$YYWK MULT 365.25 G$JYD 70
C ADD G$JYD G$JD
C G$JD DIV 7 G$WK7 70
C MVR G$DW 10
C ENDSR
H B 64 B 1
***************************************************************
** TITLE......... CONVERTS DAYS FORMAT TO MMDDYY FORMAT
** AUTHOR........ JAY J. FALCONER, BITWISE SOFTWARE INTL
** COPYRIGHT..... (C) 1988-98, ALL RIGHTS RESERVED
** DESCRIPTION... CALLED BY S/36 PROGRAMS TO RETURN MMDDYY &
** YYMMDD DATE FROM A VALUE PASSED IN AS DAYS
** 04/09/88 - INITIAL CODE
***************************************************************
I$$MDYP DS
I 1 60$$MDY
I 1 20$$MM1
I 3 40$$DD1
I 5 60$$YY1
I$$YMDP DS
I 1 60$$YMD
I 1 20$$YY2
I 3 40$$MM2
I 5 60$$DD2
C** CALLED PROGRAM RECEPTION
Figure 1: RPG II program TODAYS converts a date to a number of elapsed days
C *ENTRY PLIST
C PARM CALLOK 1
C PARM $$DAYS 60
C PARM $$MDYP
C PARM $$YMDP
C PARM $$CENT 20
C** RESET RETURN VALUES - DEFAULT
C MOVE N CALLOK
C Z-ADD0 $$MDY
C Z-ADD0 $$YMD
C Z-ADD0 $$CENT
C** ONLY DO CALC WHEN $$DAYS NOT 0
C $$DAYS IFEQ 0
C RETRN
C END
C** CALC MMDDYY FROM #DAYS PASSED IN
C Z-ADD$$DAYS J$DAYS 50
C EXSR JTOG$
C** NOW PREPARE FOR RETURN TO PARENT PROGRAM
C MOVE Y CALLOK
C** LOAD MMDDYY
C Z-ADDJ$MM $$MM1
C Z-ADDJ$DD $$DD1
C MOVE J$YYYY $$YY1
C** LOAD YYMMDD
C Z-ADDJ$MM $$MM2
C Z-ADDJ$DD $$DD2
C MOVE J$YYYY $$YY2
C** LOAD CENTURY FLAG
C MOVELJ$YYYY $$CENT
C**
C RETRN
C*******************************************
C JTOG$ BEGSR
C*******************************************
C J$DAYS DIV 365.25 J$YYWK 30
C J$DAYS DIV 365.25 J$TST 99
C J$TST IFEQ 0
C SUB 1 J$YYWK
C END
C J$YYWK MULT 365.25 J$YD 70
C J$DAYS SUB J$YD J$YD
C J$YD IFGT 306
C ADD 1 J$YYWK
C END
C Z-ADD0 J$X 20
C J$YD DOULEJ$MD
C ADD 1 J$X
C J$X MULT 30.6 J$MD 30H
C END
C SUB 1 J$X
C J$X MULT 30.6 J$MD H
C J$YD SUB J$MD J$DD 20
C J$X ADD 3 J$MM 20
C J$MM IFGT 12
C SUB 12 J$MM
C END
C J$YYWK ADD 1900 J$YYYY 40
C ENDSR C READ FILEA 90
* If FILEA has not been converted, convert date to ymd8
* original date fmt was mmddyy
C @ FAFLG IFEQ N Not convrtd
... include calcs here to convert six-digit date FADATE
... to eight-digit date @DATOT
C Z-ADD@DATOT FADAT8
C ELSE
C Z-ADDFADATE FADAT8
C ENDIF
... Replace FADATE with FADAT8 throughout program, except file operations.
...
C SCDATE IFGT FADAT8
C @FAFLG IFEQ N
... include calcs here to convert eight-digit date FADAT8
... to six-digit date @DATM6
Figure 2: RPG II program FRDAYS converts a number of elapsed days to dates
C Z-ADD@DATM6 FADATE
C ELSE
C Z-ADDFADAT8 FADATE
C ENDIF
C UPDATFILEA
C ENDIF ... more code
C *INZSR BEGSR *
C CALL YRCHKFIL
C PARM FILEA @FILNM
C PARM @FAFLG 1 FA Status
C CALL YRCHKFIL
C PARM FILEB @FILNM
C PARM @FBFLG 1 FB Status ... etc.
I* Program status data structure for RPG III
I* full definition is on page 100, Midrange Computing, November 1994
I SDS
I 1 10 S#PGM
I 81 90 S#LIB
C S#LIB CAT /:0 PGMNAM 21
C PGMNAM CAT S#PGM:0 PGMNAM FSOMERPT O E 88 PRINTER
I/COPY XXX/QRPGSRC ,PSDS
C WRITEPAGEHDR
*** record format PAGEHDR has 21-byte variable PGMNAM
C MOVE *ON *INLR
C***********
C *INZSR BEGSR
C*
C/COPY XXX/QRPGSRC,PGMNAME
C*
C ENDSR ADDRPYLE SEQNBR(3001) MSGID(CPA3394) CMPDTA(ACCT_HP5SI 41) RPY(I)
ADDRPYLE SEQNBR(3002) MSGID(CPA4002) CMPDTA(ACCT_HP5SI 41) RPY(G) /*==================================================================*/
/* To compile: */
/* */
/* CRTCLPGM PGM(XXX/RPY001CL) SRCFILE(XXX/QCLSRC) */
/* */
/*==================================================================*/
PGM
DCLF FILE(QADSPOBJ)
DCL VAR(&SEQNBR) TYPE(*DEC) LEN(4 0)
DCL VAR(&BGNSEQNBR) TYPE(*DEC) LEN(4 0) VALUE(3000)
DCL VAR(&ENDSEQNBR) TYPE(*DEC) LEN(4 0)
CHGVAR VAR(&ENDSEQNBR) VALUE(&BGNSEQNBR + 999)
/* Clear existing reply list entries for virtual printers */
CHGVAR VAR(&SEQNBR) VALUE(&BGNSEQNBR)
Figure 3: This program adapts to different date formats
Figure 4: An abbreviated program status data structure copybook member
Figure 5: Building the qualified program name
Figure 6: Putting it all together
Figure 7: These commands eliminate unneeded operator messages for a virtual printer
LOOP1:
IF COND(&SEQNBR *GT &ENDSEQNBR) THEN(DO)
GOTO CMDLBL(MAKEDEVLST)
ENDDO
RMVRPYLE SEQNBR(&SEQNBR)
MONMSG MSGID(CPF2556)
CHGVAR VAR(&SEQNBR) VALUE(&SEQNBR + 1)
GOTO CMDLBL(LOOP1)
/* Create file of all device descriptions */
MAKEDEVLST:
DSPOBJD OBJ(*ALL) OBJTYPE(*DEVD) OUTPUT(*OUTFILE) +
OUTFILE(QTEMP/QADSPOBJ)
/* Reset reply list sequence number */
CHGVAR VAR(&SEQNBR) VALUE(&BGNSEQNBR)
/* Receive list of virtual printers & add each to system reply list */
OVRDBF FILE(QADSPOBJ) TOFILE(QTEMP/QADSPOBJ)
LOOP2:
RCVF
MONMSG MSGID(CPF0864) EXEC(DO) /* End of file */
GOTO CMDLBL(FINISH)
ENDDO
IF COND(&ODOBAT *EQ PRTVRT) THEN(DO) /* Virtual +
printer */
CHGVAR VAR(&SEQNBR) VALUE(&SEQNBR + 1)
ADDRPYLE SEQNBR(&SEQNBR) MSGID(CPA3394) +
CMPDTA(&ODOBNM 41) RPY(I) /* Ignore load +
forms messages */
CHGVAR VAR(&SEQNBR) VALUE(&SEQNBR + 1)
ADDRPYLE SEQNBR(&SEQNBR) MSGID(CPA4002) +
CMPDTA(&ODOBNM 41) RPY(G) /* Take GO to +
verify alignment messages */
ENDDO
GOTO CMDLBL(LOOP2)
FINISH:
DLTOVR FILE(QADSPOBJ)
ENDPGM
Figure 8: This program creates system reply list entries for all virtual printers
Figure 10: The prompt screen to allow user input for selecting records
*================================================
===============
* To compile:
*
* CRTDSPF FILE(XXX/QRY001DF) SRCFILE(XXX/QDDSSRC)
*
*=====================================================
==========
A DSPSIZ(24 80 *DS3)
A CA03(03 Exit)
A PRINT
A R QRY00001
A 1 3USER
A 1 26Customer Master Report
A DSPATR(HI)
A DSPATR(UL)
A 1 57DATE
A EDTCDE(Y)
A 1 68TIME
A 6 17Select Customer Number Range For
R-
A eport
A 8 21From:
A DSPATR(HI)
A FCUST 8 B 8 27
A CHECK(FE RB)
A 8 39To:
A DSPATR(HI)
A TCUST 8 B 8 43
A CHECK(FE RB)
A 23 4F3=Exit
A COLOR(BLU)
Figure 11: The DDS for the prompt screen.
/*==================================================================*/
/* To compile: */
/* */
/* CRTCLPGM PGM(XXX/QRY001CL) SRCFILE(XXX/QCLSRC) */
/* */
/*==================================================================*/
PGM
DCLF FILE(QRY001DF)
DCL VAR(&QRYSLT) TYPE(*CHAR) LEN(2000)
/* Display Prompt Screen */
PROMPT:
SNDRCVF
/* User Requests Exit */
IF COND(&IN03 *EQ 1) THEN(GOTO CMDLBL(ENDPGM))
/* Edit Check Input Fields */
IF COND(&FCUST *EQ *BLANKS *OR &TCUST *EQ +
*BLANKS) THEN(GOTO CMDLBL(PROMPT))
/* Build Query Select Variable */
CHGVAR VAR(&QRYSLT) VALUE(&QRYSLT *BCAT CMNBR +
*GE || &FCUST || *AND CMNBR *LE +
|| &TCUST)
/* Override File To Query and Run Open Query Command */
OVRDBF FILE(CSTMST) TOFILE(*LIBL/CSTMST) SHARE(*YES)
OPNQRYF FILE((*LIBL/CSTMST)) QRYSLT(&QRYSLT)
/* Copy Records Selected In Open Query To Temporary Member */
CPYFRMQRYF FROMOPNID(CSTMST) TOFILE(QTEMP/CSTMSTQ) +
MBROPT(*ADD) CRTFILE(*YES)
/* Run OS/400 Query Program Using Copied Data As Input */
RUNQRY QRY(*LIBL/CUSTQRY) QRYFILE((QTEMP/CSTMSTQ +
*FIRST))
/* Close Files and Delete Temporary File */
DLTOVR FILE(CSTMST)
CLOF OPNID(CSTMST)
DLTF FILE(QTEMP/CSTMSTQ)
ENDPGM:
ENDPGM
Figure 12: The CLP program that performs the OPNQRYF and runs the Query/400 report.
LATEST COMMENTS
MC Press Online