Handling Oversized Numbers Gracefully
October 13, 2004 Hey, Ted
These MCH1210 errors are driving me nuts. We run packaged software and a lot of the database fields are bigger than we need them to be. I often use smaller fields on displays and reports in order to save room. Then one day, for some reason, a field has a bigger value than I expected and an EVAL command blows up with MCH1210 (the target for a numeric operation is too small to hold the result). Is there any way in all this new-fangled RPG stuff to tell the system to print hash marks and keep on trucking?
RPG has no such logic, but you can handle this situation yourself with little trouble. Since you want to display or print hash marks, you must define output fields as character data rather than as numeric data. You’ll have to use the %EDITC and %EDITW functions within your programs to edit the fields (that is, apply decimal points, currency symbols, minus signs, commas, and the like). And you need a routine that can decide whether an edited number can fit into the space you’ve allowed for it.
The following example contains such a routine, which I call FmtNum (Format Numeric). It requires two parameters: an edited numeric value and the number of bytes into which the edited numeric value is to fit.
H dftactgrp(*no) actgrp(*new) D FmtNum pr 256 varying D EditedNum 256 varying value D Size 10u 0 value D Column01 s 6a D Column02 s 4a D OrderQty s 7p 0 D Balance s 11p 2 /free evalr Column01 = FmtNum(%editc(Balance: 'J'): %size(Column01)); evalr Column02 = FmtNum(%editc(OrderQty: '4'): %size(Column02)); *inlr = *on; /end-free * =========================================================== P FmtNum b D FmtNum pi 256 varying D EditedNum 256 varying value D Size 10u 0 value D * local variables D TrimmedNum s 256 varying D FillChar s 256 inz(*all'#') /free if Size = *zero; return *blanks; endif; if Size > %size(FillChar); return *blanks; endif; TrimmedNum = %triml(EditedNum); if %len(TrimmedNum) <= Size; return TrimmedNum; endif; return %subst(FillChar:1:Size); /end-free P FmtNum e
In this example, OrderQty and Balance represent database fields and/or calculated variables. Column01 and Column02 represent fields on a display or report. Since there are two values to be copied into output fields, the main routine calls FmtNum twice, each time passing the edited numeric value and the size of the variable into which the edited value is to be placed. If the receiving variable is too small to hold the significant portion of the edited numeric value (that is, the portion of the edited numeric value without leading blanks), FmtNum returns enough hash marks to fill up the receiving variable. Notice that I used the EVALR op code in the main calculations in order to right-adjust the numeric values.
You could use the MONITOR, ON-ERROR, and ENDMON op codes to handle arithmetic overflow, but you would have to place such a structure around every EVAL. I much prefer the FmtNum subprocedure.