Page 1 of 1

ProcessError TI function doesn't work as expected

Posted: Tue Nov 13, 2012 1:59 am
by cdredmond
I have the following code in the Prolog for parameter input verification:

Code: Select all

IF ( DIMIX ( Dim, vVersion ) = 0 ) ;
    sMessage = 'Version ( ' | vVersion | ' ) does not exist.' ;
    ItemReject ( sMessage ) ;
    ProcessError ;
ENDIF ;
As expected, the message appears in the message log.
However, the process does not terminate, only the procedure terminates.
It then continues on to the Data procedure (no code in the Metadata procedure).
I have also tried ProcessBreak and ProcessQuit with the same result.
Anybody know of a method to reliably terminate a process from the Prolog?

Re: ProcessError TI function doesn't work as expected

Posted: Tue Nov 13, 2012 2:30 am
by Alan Kirk
cdredmond wrote:I have the following code in the Prolog for parameter input verification:

Code: Select all

IF ( DIMIX ( Dim, vVersion ) = 0 ) ;
    sMessage = 'Version ( ' | vVersion | ' ) does not exist.' ;
    ItemReject ( sMessage ) ;
    ProcessError ;
ENDIF ;
As expected, the message appears in the message log.
However, the process does not terminate, only the procedure terminates.
It then continues on to the Data procedure (no code in the Metadata procedure).
I have also tried ProcessBreak and ProcessQuit with the same result.
Anybody know of a method to reliably terminate a process from the Prolog?
Greetings to you in Portland, my favourite city of the north-west which I may never see again but retain fond memories of.

I'm afraid it is working as expected; the problem is with the ItemReject line.

Strictly speaking ItemReject has no context in the Prolog but a lot of people do use it to generate an error log. (Hi Martin!) It's a quick and easy way of achieving that result and as long as IBM never pulls this undocumented feature, there's nothing wrong with doing that.

HOWEVER... when you do that the Prolog, which only has one "item" and that of a virtual kind, stops stone motherless dead and never executes any following statements including your ProcessQuit (etc) statement. Instead it just heads straight for the next tab with code on it, if any. (Same basic behaviour as you get if you encounter the statement on the Metadata or Data tab; none of the code following the ItemReject is executed and it moves straight to the next record (if any).)

You have a couple of alternatives:
(a) (My preferred one) Instead of using an ItemReject, get the error log file by using the GetProcessErrorFilename function, manually write the output to it, THEN ProcessQuit out of the sucker inside the If block; or
(b) Set a flag variable to True if there's an error, and check that in the first line of your Data tab. ProcessQuit if the flag is set to your True value. However I'd regard this as a waste of processor cycles; option (a) is far better.

Incidentally despite the v tag at the start I'm assuming that this really is a parameter that you're checking and not a variable. Obviously none of the variables will have a value in the prolog either, so it would always error out. (I generally tag parameters with a "p" to distinguish them from variables, and I've noticed that that's not an uncommon practice. But it's not a mandatory one obviously.)

Re: ProcessError TI function doesn't work as expected

Posted: Tue Nov 13, 2012 3:35 am
by rmackenzie
Alan Kirk wrote:You have a couple of alternatives:
(a) (My preferred one) Instead of using an ItemReject, get the error log file by using the GetProcessErrorFilename function, manually write the output to it, THEN ProcessQuit out of the sucker inside the If block; or
(b) Set a flag variable to True if there's an error, and check that in the first line of your Data tab. ProcessQuit if the flag is set to your True value. However I'd regard this as a waste of processor cycles; option (a) is far better.
Just to add another one, which is similar to Alan's option (b) and sounds similar to something you tried already:
(c) Set up an error message variable and populate with any error; call ProcessBreak; do the ItemReject as the last step in the Epilog:

Code: Select all

### Prolog
sErrorMessage = '';
IF ( pVersion @= '' );
  sErrorMessage = 'pVersion was blank in ' | GetProcessName();
  ProcessBreak;
ENDIF;
# some more Prolog stuff goes here

### Epilog
# all your other Epilog comes first
IF ( sErrorMessage @<> '' );
  ItemReject ( sErrorMessage );
ENDIF;

Re: ProcessError TI function doesn't work as expected

Posted: Tue Nov 13, 2012 8:31 am
by lotsaram
Interesting that this was also discussed in some detail here just a few weeks back.

Re: ProcessError TI function doesn't work as expected

Posted: Wed Nov 14, 2012 1:43 am
by cdredmond
Thank you to all three of you for your responses! :)

lotsaram,
Thanks for linking to the other discussion which I did not find. It appears that Paul Simon is recommending what Alan Kirk calls option (b). While this does work, in this case, I am processing 10's to 100's of millions of cells and want to keep the processing time to a minimum.

rmackenzie,
Thank you for your clear explanation of the TI handling of ItemReject in Prolog and Epilog.
I use the same naming standard of 'p' for Parameters and 'v' for variables. The vVersion variable is actually inside a while loop that is extracting a values out of a comma delimited list one at a time to validate them.
I may totally lose you on this point, but at that risk: I coded MUMPS for about 8 years. One of the built-in functions it provides is $PIECE. This fuction allows you to identify a string, a delimiter (can be more than one character) and a position number. With this it will extract the 'n'th "piece" (substring) of information you want from the string. Boy how I wish TI could provide this and indirection! :idea: But I digress...
Your option (c) worked the best for this situation. Here's what I did:

Code: Select all

# PROLOG #
# Declare Global Variables
NumericGlobalVariable ( 'PrologMinorErrorCount' ) ;
PrologMinorErrorCount = 0 ;
:
:
IF ( DIMIX ( Dim, vVersion ) = 0 ) ;
    sMessage = 'Version ( ' | vVersion | ' ) does not exist.' ;
    PrologMinorErrorCount = PrologMinorErrorCount + 1 ;
    ProcessBreak ;
ENDIF ;
:
:
# EPILOG #
# Quit if parameter input verification failed. #
IF ( PrologMinorErrorCount > 0 ) ;
    ItemReject ( sMessage ) ;
ENDIF ;
:
:
I have purposely used PrologMinorErrorCount so that all Prolog generated errors are handled consistently in the epilog. At least that's the idea at this point. It may change once I complete my unit testing of the error handling.

You guys were all a great help!
Thanks! :)