Synon/2E Magic and Potential Gotchas
The magic: when an external function is called, 2E generates the call with an indicator to trap any errors on the call such as the program not being there, or some other condition that causes the program to fail such as the user turning the power off or canceling the session for some reason. Who knows, maybe Windows crashed or a remote connection was lost?
This little gotcha happens when a session is lost inadvertently, and the Synon program on the display is called from within a REPEAT WHILE block.
> Loop thru check select and distribution functions until CMD 3. .=REPEAT WHILE |-PGM.*Return code is *Normal | Display list of checks with unapplied cash. | WRK.Create date = CON.*ZERO | WRK.Create time = CON.*ZERO | WRK.Bill mast code = DTL.Bill mast code | A/R Chk Unapplied Select - A/R receipt chk/adj * | > Quit if error on call | .-CASE | ¦-PGM.*Return code is *Error occured on CALL... | ¦ <-- *QUIT | '-ENDCASE | AR:RTV Batch Post Date - A/R receipt batch * | .-CASE | ¦-PGM.*Return code is *Normal | ¦ AR:RTV Uncash Post Rcpt - A/R receipt * | ¦ ...If create date and time not found use 0 to drive audit report | ¦ WRK.Create date = JOB.*Job date | ¦ WRK.Create time = JOB.*Job time | ¦ .-CASE | ¦ |-DTL.Primary chk bill mast cde is *ZERO | ¦ | DTL.Primary chk bill mast cde = DTL.Bill mast code | ¦ '-ENDCASE | ¦ WRK.A/R chk amount = DTL.A/R chk amount | ¦ AR:EDT Check Posting-Inv - A/R invoice * | ¦ > Quit if error on call | ¦ .-CASE | ¦ |-PGM.*Return code is *Error occured on CALL... | ¦ | Rollback | ¦ | <-- *QUIT | ¦ '-ENDCASE | ¦ AR:RTV To Update Status - A/R receipt chk/adj * | ¦ .-CASE | ¦ |-DTL.A/R chk primary/secondary is Secondary | ¦ | AR:CHG Chk Amt If ICT - A/R receipt chk/adj * | ¦ '-ENDCASE | ¦ AR:PRT Post Uncash Audit - A/R receipt * | ¦ ...Loop while request for Display Zero invoices. | '-ENDCASE '-ENDWHILE
This piece of code was found in a Prompt & validate record type function in the User defined action edit point. The function type and edit point are not nearly as important as the fact that there is no guarantee of being able to break out of the REPEAT WHILE block when a call to one of the external functions (Big bold text) fails. The code in italics was added to prevent looping when an external program call fails.
When functioning normally, this piece of code displays a list of checks with unapplied cash A/R Chk Unapplied Select - A/R receipt chk/adj * and requires the operator to select a check to work with or press F3. If F3 is pressed, the batch number returned is a *ZERO by virtue of being initialized in the parameter passing process. Since batch *ZERO cannot be found by AR:RTV Batch Post Date - A/R receipt batch * it returns a non *Normal return code causing the whole loop to end. If a check is selected to work with, a valid batch number is returned allowing the posing process to continue. The next thing the user sees is a list of invoices with unpaid balances against which the unapplied cash can be posted AR:EDT Check Posting-Inv - A/R invoice *. Cash amounts are applied, and accepted, the user presses F3, the program exits, and an audit report is printed AR:PRT Post Uncash Audit - A/R receipt *. Because the report will print normally without problems, PGM.*Return Code is set to *Normal, and the program will loop back to the check selection function for another try at another check.
When the display session is lost during this process, unexpected but predictable events occur. An external function call is generated by 2E with an error indicator which is tested after the function returns. If an error on the call is detected, PGM.*Return Code is set to Y2U0032, and the message *Error occurred on CALL… (Y2U0032) is sent, then the program goes on it's merry way as if nothing had happened. Unfortunately just about every function call internal or external resets PGM.*Return Code back to *Normal as its first priority. This does not mean that PGM.*Return Code is not reliable as a looping condition, but that you must be just as careful when using it as you would with a variable whose value is set withing the program.
This piece of code is affected by a lost session in the following way. If the display session is lost when A/R Chk Unapplied Select - A/R receipt chk/adj * is on the screen, output parameters are left unchanged, and PGM.*Return Code is set to Y2U0032. AR:RTV Batch Post Date - A/R receipt batch * sets PGM.*Return Code to *Normal if the batch is found, and something else if it is not. The first time through, the batch will not be found because it hasen't yet been set to a valid batch number. The second and later times through, after a check has been selected, the batch of the previously processed check will be found! If the code in red was not present to check for a failed call, this would result in an infinite loop due to the retrieve object setting PGM.*Return Code back to *Normal. If the display session is lost when AR:EDT Check Posting-Inv - A/R invoice * is on the screen, output parameters are left unchanged, and PGM.*Return Code is set to Y2U0032. The successful print of the audit report indicating the checks that were posted, or even that no checks were posted leaves PGM.*Return Code set to *Normal. If the red code was not present to check for a failed call, this would cause an infinite loop.
Synon provides message Y2U0032 in the *Messages file, but not as a possible PGM.*Return Code condition. To test for the failed call, create a new PGM.*Return Code condition from the message file using F9 from the Edit Field Conditions screen for *Return Code. Select the message *Error occurred on CALL…. When calling an external function from inside a loop, always check the return code for this new condition. This way you can break out of the loop or take other actions if necessary when the session goes down.
As was stated earlier, this is not dependent on the function type or edit point. This can happen anywhere that external functions are called from within a loop. The symptoms are not always as dramatic as the ones in this case (the loop produced thousands of spool files, one every couple of seconds until the job was really ended on the AS/400). I have seen this cause hard disks to fill up simply due to the hung jobs creating massive job logs on a small system. In any case the job remains looping until it is ended by the operator, or the system when the job log reaches maximum size.