Defines a CATCH block, which allows you to trap an error or stop object and write code to handle it.
A CATCH block can be referred to as an end block because it defines end-of-block processing for the block that encloses it. End blocks are always part of another block called the associated block. End blocks must appear in the associated block after the last executable statement and before the END statement. The other type of end block is the FINALLY block.
The CATCH statement defines the start of an end block that only executes if a condition is raised in its associated block and the object type of the condition raised matches the class specified in the CATCH statement (or a subclass of that class). The CATCH block thus executes when an object of the specified error or stop type is caught by the CATCH statement, at which point the object can then be handled in the CATCH block.
When the condition is raised, if there is an active transaction for the associated block, the transaction is undone before the AVM begins executing the statements within the CATCH block.
The CATCH block executes once for each iteration of its associated block that raises a compatible error. A block can have multiple CATCH blocks, and all must come at the end of the associated block.
There can only be one CATCH block for each specific condition type in a block. However, the block also handles objects for its subtypes. So, it is possible there can be more than one CATCH block that is compatible with a particular condition’s type. In this case, the AVM executes the first CATCH block it encounters that is compatible. For this reason, CATCH blocks should be arranged from the most specific type to the most general.
CATCH blocks are covered in greater depth in ABL Error Handling.
The variable name that references the object caught by this block. It is not necessary to define the object-variable ahead of time with the DEFINE VARIABLE statement. The AVM recognizes a new variable name on the CATCH statement as a new object-variable definition within the current scope. Each CATCH in an associated block must have a unique object-variable. You can reuse an object-variable name in a different associated block, if its type is the same as the previous use. For all blocks with their own variable scope, such as object methods or internal procedures, a CATCH statement inside that context may reuse the same variable name as a CATCH statement outside of that context even if the type is different.
Example 1
In the following example, the CATCH block handles any ABL system error.
FIND Customer WHERE CustNum = 5000. /* Will fail */ /* Won't execute because FIND fails */ MESSAGE "Customer found" VIEW-AS ALERT-BOX. /* The associated block for this CATCH block is the main block of the .p */ CATCH eSysError AS Progress.Lang.SysError: MESSAGE "From CATCH block..." SKIP eSysError:GetMessage(1) VIEW-AS ALERT-BOX. END CATCH. |
Example 2
The following example illustrates how object-variable names can be reused.
DEFINE VARIABLE oneError AS CLASS Progress.Lang.SysError. /* This definition is not necessary. */ DO ON ERROR UNDO, LEAVE: FIND FIRST Customer WHERE CustNum = 5000. CATCH oneError AS Progress.Lang.SysError: MESSAGE oneError:GetMessage(1) VIEW-AS ALERT-BOX. END CATCH. CATCH twoError AS Progress.Lang.AppError: MESSAGE twoError:GetMessage(1) VIEW-AS ALERT-BOX. END CATCH. END. /* FIRST DO */ DO ON ERROR UNDO, LEAVE: FIND FIRST Customer WHERE CustNum = 6000. /* You can reuse an object-variable from a different associated block as long as it’s the same type. */ CATCH oneError AS Progress.Lang.SysError: MESSAGE oneError:GetMessage(1) VIEW-AS ALERT-BOX. END CATCH. /* NOT LEGAL: You cannot reuse an object variable name if its type is different than the variable's previous use within the same scope. */ CATCH oneError AS Progress.Lang.AppError: MESSAGE oneError:GetMessage(1) VIEW-AS ALERT-BOX. END CATCH. END. /* SECOND DO */ PROCEDURE foo: FIND FIRST Customer WHERE CustNum = 7000. /* This IS LEGAL because a new oneError variable will be defined within the scope of this subprocedure so its type does not have to match. */ CATCH oneError AS Progress.Lang.AppError: MESSAGE oneError:GetMessage(1) VIEW-AS ALERT-BOX. END CATCH. END. |
Example 3
The following example illustrates using multiple CATCH blocks to handle specific conditions.The CATCH block for the more specialized error classes should come first.
FOR EACH Customer: < Code body of the associated block > /* This CATCH specifies the most specialized user-defined error class. It will catch only myAppError error objects or objects derived from myAppError. */ CATCH eMyAppError AS Acme.Error.myAppError: /*Handler code for Acme.Error.myAppError condition. */ END CATCH. /* This CATCH will handle Progress.Lang.AppError or any user-defined application error type, except for eMyAppError which is handled by the preceding CATCH block. */ CATCH eAppError AS Progress.Lang.AppError: /* Handler code for AppError condition. */ END CATCH. /* This CATCH will handle any error raised by an ABL statement. Since it is not in the class hierarchy of AppError, this CATCH could come before or after the CATCH for AppError */ CATCH eSysError AS Progress.Lang.SysError: /* Handler code for SysError condition. */ END CATCH. /* This is compatible with any condition object that implements the Progress.Lang.Error interface. All the above classes qualify, as well as a StopError object which is a SysError. So, in this context, this CATCH block will only run for a .NET Exception. */ CATCH eError AS Progress.Lang.Error: /* Handler code for any error condition. */ END CATCH. END. /* Associated Block */ |