There appears to be some contradiction in the documentation on ‘ON ERROR’ here:
On the one hand, it states:
“When the ON ERROR statement block is entered for execution, the normal flow of program execution has been interrupted and cannot be resumed …” AND “Only one ON ERROR statement is permitted in a Natural object.”
On the other hand:
"When a subroutine structure is built by using CALLNAT, PERFORM or FETCH RETURN, each module may contain an ON ERROR statement.
When an error occurs, Natural will automatically trace back the subroutine structure and select the first ON ERROR statement encountered in a subroutine for execution."
“Exiting from an ON ERROR Block:
An ON ERROR block may be exited by using a FETCH, STOP, TERMINATE, RETRY or ESCAPE ROUTINE statement. If the block is not exited using one of these statements, standard error message processing is performed and program execution is terminated.”
I am trying to trap a duplicate key on STORE error in a PERFORMed subroutine and continue processing. Is that possible ?
Thanks for your help.
Is it possible to continue an application after an ON ERROR? Technically, yes. But scenarios in which this procedure would apply are so rare that I don’t even consider it. Few applications are simple enough to allow you to determine where you were, logically, at the time of the error. You need to know the values of all variables and globals, the contents of all views, which code to execute, which code to circumvent, …
Since you’re in a subroutine at the time, I’d say this is a lost cause.
I would suggest a subprogram containing the store statement
and then an On ERROR that sets an error msg in the parm area.
Remember to have an escape routine in the ON-EROR block or the standard errorhandling of the caller or the standard *ERROR-TA wil take control.
move ‘DUPLICATE KEY’ to ERR-MSG
move 99 to ERR-NO
How about simply placing a FIND NUMBER before the STORE? If *NUMBER is already GT zero, you know you have a problem. You could write a workfile with all sorts of data to find the bug. Then, your program could, perhaps, simply continue without doing the STORE.
Of course, program logic may still be a problem. Proceed with caution.
It makes sence to continue an application in case of a NAT3145. For this you got the statement RETRY. All other statements to leave the ON ERROR Block leave the module as well.
Of course you can consider a FETCH-FETCH technique for this. But I think this is not a proper way. For example program1 reads:
Thanks all for your responses.
The program copies tens of thousands of records from an archive. There may be less than 1 duplicate per 10,000 records. I wanted to avoid the overhead of reading before writing every record but that’s what I went with as the simplest and cleanest way.
"I wanted to avoid the overhead of reading before writing every record "
Trivial point, but, HISTOGRAM and FIND NUMBER for a single value of a single key, do not read records. And, if you are doing this in sequence by the key, i/o to the inverted tables is minimized since Adabas will often find the appropriate info in memory.
Trivial is as trivial does.
True, only the indeces are being read. But it’s unclear how many will end up being read since there are 100s of thousands of records already on the output file and the records being stored are interspersed by key.
Then pack your store into a Subprogram. There you can put an ON ERROR Block which returns the NAT-Error-Number to the calling program.
With a ESCAPE ROUTINE in a ON ERROR clause you can intercept any Natural errors. Only if the program flow reaches the END-ERROR the error is percolated to the program caller.
Here is a sample how you can continue your processing:
0010 READ TONS OF RECORDS
0020 CALLNAT 'STOREREC' #RECORD #ERROR-NR
0030 IF #ERROR-NR NE 0
0040 IF #ERROR-NR = 3145 ESCAPE TOP END-IF
and the subprogram
0010 DEFINE DATA PARAMETER
0020 1 #RECORD
0030 1 #E_NUMBER(P4)
0050 ON ERROR
0060 #E_NUMBER := *ERROR-NR
0070 ESCAPE ROUTINE
0100 STORE RECORD
I hope this helps
What a great group of people!