ON ERROR phrase

The ON ERROR phrase is one of the ABL constructs used for altering the default condition handling for ABL blocks. By default, when an error occurs in a block, all the changes to persistent data (database fields) are undone. If the block is a transaction block, undo variables and temp-table fields are also undone. See OpenEdge Getting Started: ABL Essentials for more information on transaction blocks. The ON ERROR phrase can be used to modify the scope of UNDO processing, possibly widening it to an outer block. In addition, if an error occurs, the ON phrase gives you control over where execution continues.

In general, the AVM performs error handling using this precedence, from highest to lowest. The AVM only abides by one of these when a condition is raised:

Due to this precedence, the ON phrase is ignored if a local CATCH block handles the error.

Syntax

ON ERROR UNDO
  [label1]
  [     , LEAVE [ label2 ]
     |  , NEXT [ label2 ]
     |  , RETRY [ label1 ]
     |  , RETURN [ return-value |
                  ERROR [ return-value | error-object-expression ] |
                  NO-APPLY ] 
     |  , THROW 
  ]
label1
The name of the block whose processing you want to undo. If you do not name a block with label1, the AVM undoes the processing of the current block.
LEAVE [label2]
Indicates that after undoing the processing of a block, the AVM leaves the block labeled label2. If you do not name a block, the AVM leaves the current block.
NEXT [label2]
Indicates that after undoing the processing of a block, the AVM executes the next iteration of the block you name with label2. If you do not specify a label with the NEXT option, the AVM executes the next iteration of the current block.
RETRY [label1]
Indicates that after undoing the processing of a block, the AVM repeats the same iteration of the block.

Because RETRY in a block without user input results in an infinite loop, the AVM automatically checks for this possibility and converts a RETRY block into a LEAVE block, or a NEXT block if it is an iterating block. This behavior is often referred to as infinite loop protection.

RETURN ...
Returns to the calling routine, if there is one. The following table describes various RETURN options:
Option Description
return-value In procedures and VOID methods, this must be a CHARACTER string. The caller can use the RETURN-VALUE function to read the returned value. For user-defined functions, non-VOID methods and property getters, the value must match the specified return type.
ERROR Undoes the current subtransaction, and raises ERROR in the caller. You cannot specify ERROR within a user-interface trigger block or a destructor.

For user-defined functions see note below.

ERROR return-value Undoes the current subtransaction, and raises ERROR in the caller. The CHARACTER string you provide is available to the caller in the RETURN-VALUE function. The AVM also creates an AppError object and stores the return-value in the ReturnValue property.

For user-defined functions see note below.

ERROR error-object-expression Undoes the current subtransaction, and raises ERROR in the caller. The specified error object instance is thrown to the caller.

For user-defined functions see note below.

NO-APPLY In a user-interface trigger, prevents the AVM from performing the default behavior for the trigger event. Otherwise, the option is ignored.
Note: Using RETURN ERROR in a user-defined function sets the target variable of the function to the Unknown value (?) instead of raising ERROR in the caller. See OpenEdge Development: ABL Error Handling for more detail.
THROW
Use this directive to explicitly propagate an error to the enclosing block, if there is one, otherwise to the caller. You can learn more about throwing error objects in OpenEdge Development: ABL Error Handling.

Examples

In r-onerr.p, if you enter a Customer number and the FIND statement is unable to find a Customer with that number, the AVM raises an error. If an error occurs, the ON ERROR phrase tells the AVM to undo anything that was done in the current iteration and start the next iteration. Thus, you see any invalid numbers you enter, and you can continue to the next Customer number you want to enter.

r-onerr.p

REPEAT ON ERROR UNDO, NEXT:
  PROMPT-FOR Customer.CustNum.
  FIND Customer USING Customer.CustNnum.
  DISPLAY Customer.Name Customer.Address Customer.City Customer.State
    Customer.Country.
END.

In r-onErrorThrow01.p the block propagates an error from a DO block up to the main procedure block. A CATCH block on the main procedure block handles the error.

r-onErrorThrow01.p

DO ON ERROR UNDO, THROW:
  /* Raises ERROR. The normal error message is diverted to a
     Progress.Lang.SysError error object and thrown to the main block. */ 
  FIND Customer 1000.
END. /* DO */

MESSAGE "Undisplayed message because of ERROR condition"
  VIEW-AS ALERT-BOX BUTTONS OK.

/* CATCH for main (procedure) block */	
CATCH eAnyError AS Progress.Lang.ERROR:
  MESSAGE "Error message and number retrieved from error object..."
    eAnyError:GetMessage(1) eAnyError:GetMessageNum(1) 
    VIEW-AS ALERT-BOX BUTTONS OK.
END CATCH.

Notes

See also

BLOCK-LEVEL ON ERROR UNDO, THROW statement,ON ENDKEY phrase, ON QUIT phrase, ON STOP phrase, RETURN statement, RETURN-VALUE function, ROUTINE-LEVEL ON ERROR UNDO, THROW statement, UNDO statement