Scratch Message Files? Why Not?!
October 6, 2015 Ted Holt
If you read this august publication, you probably know what a scratch file is. (For those of you who know nothing about computers and read this publication solely for its sterling literary merit, a scratch file is a database table or stream file that is used temporarily within a job.) Today I invite you to consider that the advantages of scratch files also extend to scratch message files. Consider superb RPG program SUPERBPGM2: ctl-opt dftactgrp(*no); dcl-pr SuperbPgm2 extpgm('SUPERBPGM2'); ouStatus likeds(Status_t); inPlant char(12); end-pr; dcl-pi SuperbPgm2; ouStatus likeds(Status_t); inPlant char(12); end-pi; dcl-ds Status_t qualified template; MsgID char( 7); ProgramName char(10); Plant char(12); Additional char(99); end-ds; dcl-ds PSDS qualified PSDS; ProcedureName char(10) pos(1); end-ds; dcl-c CONST_SQL_EOF const('02000'); dcl-s Balance packed(7:2); *inlr = *on; monitor; clear ouStatus.MsgID; ouStatus.ProgramName = PSDS.ProcedureName; ouStatus.Plant = inPlant; clear ouStatus.Additional; exec sql select balance into :Balance from statusdata where key = :inPlant; select; when SqlState > CONST_SQL_EOF; ouStatus.MsgID = 'USR1001'; ouStatus.Additional = SqlState; when SqlState = CONST_SQL_EOF; ouStatus.MsgID = 'USR1002'; when Balance <> *zero; ouStatus.MsgID = 'USR1003'; ouStatus.Additional = %char(Balance); endsl; on-error; ouStatus.MsgID = 'USR1099'; endmon; return; This program verifies that some balance column (field) has a zero value for a factory (referred to here as a plant). The plant ID is passed to the program in the second positional parameter, inPlant. What can go wrong?
This program uses messages USR1001, USR1002 and USR1003 respectively to report these errors to the caller. The program references catch-all error message USR1099, just in case. SUPERBPGM2 uses the first positional parameter–a data structure named ouStatus–to inform the caller of success or failure. Now consider the caller, CL program SUPERBPGM1. Pgm parm(&inPlant) DclPrcOpt AlwRtvSrc(*yes) DftActGrp(*no) ActGrp(*new) Dcl &inPlant *char 12 Dcl &Status *char 128 MonMsg cpf0000 exec(goto Abend) /* Create a temporary message file if it does not exist */ ChkObj obj(qtemp/TempMsgF) ObjType(*MsgF) MonMsg cpf9801 exec( CallSubr CrtMsgF) call SuperbPgm2 (&Status &inPlant) if (%sst(&Status 1 7) *eq ' ') do call SuperbPgm3 (&Status) enddo if (%sst(&Status 1 7) *ne ' ') do SndPgmMsg MsgID(%sst(&Status 1 7)) MsgF(qtemp/TempMsgF) + MsgDta(&Status) MsgType(*escape) enddo Abend: MovPgmMsg MsgType(*diag) RsnEscMsg Subr CrtMsgf CrtMsgF MsgF(qtemp/TempMsgF) AddMsgD MsgID(USR1001) MsgF(qtemp/TempMsgF) + Msg('Program &2 for plant &3 canceled with message &1.') + SecLvl('SQL state is &4. Contact IT.') + Fmt((*char 7) (*char 10) (*char 12) (*char 5)) AddMsgD MsgID(USR1002) MsgF(qtemp/TempMsgF) + Msg('Balance for plant &3 was not on file.') + SecLvl('No additional information. Contact IT.') + Fmt((*char 7) (*char 10) (*char 12)) AddMsgD MsgID(USR1003) MsgF(qtemp/TempMsgF) + Msg('Invalid balance &4 found for plant &3.') + SecLvl('No additional information. Contact IT.') + Fmt((*char 7) (*char 10) (*char 12) (*char 10)) AddMsgD MsgID(USR1099) MsgF(qtemp/TempMsgF) + Msg('Program &2 canceled with an unexpected error.') + SecLvl('No additional information. Contact IT.') + Fmt((*char 7) (*char 10)) EndSubr EndPgm This CL program calls two RPG programs. You can assume that SUPERBPGM3 is similar to SUPERBPGM2. If either program ends in error, the first seven characters of the &STATUS variable will not be blank. The CL program sends an escape message to cancel the program and relay the bad news to the program that called it. So, what’s all this got to do with scratch message files? Notice where the message file resides. It’s in QTEMP, which means it only exists for the duration of the job. The CL program creates the message file unless the message file is there already. I prefer permanent message files, but I have found that temporary message files usually work just as well. If many programs use the same messages, then creating and maintaining a permanent message file is worth the effort. But in many cases only one program sends a certain message. Using temporary message files may mean that two or more programs may send the same message ID (e.g. USR1001), but the text of and data format of that message may vary widely from program to program. This is not usually a problem. The caller must deal with a message in the proper format, regardless of whether that message comes from a permanent or temporary message file. I find I tend to use temporary message files in utilities and permanent message files in production applications, but that’s by no means a hard and fast rule. Like many other features of IBM i, message files are underused and unappreciated. If you’re not using messaging support in your programs, using a temporary message file may be a good way to start. RELATED STORIES Structures Make Good Status Parameters
|