Try OpenEdge Now
skip to main content
Error Handling
Handling Errors with CATCH Blocks : CATCH statement syntax
 

CATCH statement syntax

Here is the syntax for the CATCH statement:

Syntax

CATCH error-variable AS [ CLASS ]error-class:
    .
    .
    .
END [ CATCH ] .
error-variable
The variable name that references an error object derived from the built-in class Progress.Lang.ProError. Typically, you do not define the error-variable ahead of time with the DEFINE VARIABLE statement. The AVM recognizes a new variable name on the CATCH statement as a new error-variable definition. Each CATCH in an associated block must have a unique error-variable. You can reuse an error-variable name in a different associated block, as long as its type is compatible with the new definition. For example:
DEFINE VARIABLE oneError AS CLASS Progress.Lang.SysError.
/* This definition 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 BUTTONS OK.
    END CATCH.

CATCH twoError AS Progress.Lang.ProError:
MESSAGE twoError:GetMessage(1) VIEW-AS ALERT-BOX BUTTONS OK.
    END CATCH.
END. /* FIRST DO */

DO ON ERROR UNDO, LEAVE:
FIND FIRST Customer WHERE CustNum = 6000.

/* You can reuse an error-variable from a different
associated block */
CATCH oneError AS Progress.Lang.SysError:
MESSAGE oneError:GetMessage(1) VIEW-AS ALERT-BOX BUTTONS OK.
    END CATCH.

/* NOT LEGAL: Each CATCH block in an associated block must have
a unique error-variable. */
CATCH oneError AS Progress.Lang.ProError:
MESSAGE oneError:GetMessage(1) VIEW-AS ALERT-BOX BUTTONS OK.
    END CATCH.
END. /* SECOND DO */
[ CLASS ] error-class
Typically Progress.Lang.SysError for system errors or Progress.Lang.AppError (or your subclass) for application errors. Optionally, you can provide the CLASS keyword.
ABL issues a compile-time error if a CATCH block is present in a simple DO block, since simple DO blocks do not have error handling capabilities. DO blocks must have either a TRANSACTION or an ON ERROR directive in order to have a CATCH. For example:
DO TRANSACTION
    . . .
    CATCH . . . :
        . . .
    END CATCH.
END.
The code within a CATCH block is only executed if an ERROR of type error-class (or a sub-type) is raised within the body of the associated block. This behavior is also true if any sub-routine called by the associated block returns or raises an error of type error-class. When ERROR 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. If there are variables or temp-table fields with the UNDO property (defined without the NO-UNDO option) and there is no active transaction, then these variables and fields are undone before the CATCH block executes. For more information, see the reference entries for the DEFINE VARIABLE statement and the TRANSACTION option in the DO statement in OpenEdge Development: ABL Reference.
In the following example, the CATCH block handles any ABL system error:
DEFINE VARIABLE iCust AS INTEGER.

ASSIGN iCust = 5000.

FIND Customer WHERE CustNum = iCust. /* Will fail */

/* Won't execute because FIND fails */
MESSAGE "Customer found" VIEW-AS ALERT-BOX BUTTONS OK.

/* 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 BUTTONS OK.
END CATCH.
An associated block may have multiple CATCH blocks, each of which handles a different error class. If an error type satisfies multiple CATCH statements, the AVM will execute the code in the first CATCH block that matches the error type. It will not execute multiple CATCH blocks. Therefore, if multiple CATCH blocks are specified, the CATCH block for the more specialized error classes should come first, as shown:
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 inherits from the same object as AppError in the class
        hierarchy, 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 will catch any possible error raised in ABL. */

    CATCH eError AS Progress.Lang.Error:
        /* Handler code for any error condition. */
    END CATCH.

END. /* Associated Block */
The compiler will issue a warning message if a block contains a CATCH block that is not reachable. For example, the following code will cause the compiler to issue a warning, since the CATCH of myAppError can never be executed:
FOR EACH Customer:
    /* Code body of the associated block */

    /* This will catch all application errors */

    CATCH eAppError AS Progress.Lang.AppError:
        /* Handler code for AppError condition */
    END CATCH.

    /* Never get here, because myAppError is a subtype of
       Progress.Lang.AppError */

    CATCH eMyAppError AS Acme.Error.myAppError:
        /* Handler code for myAppError condition */
    END CATCH.

END. /* Associated Block */
If error is raised in a block and is not handled by a CATCH block, then the error is handled by the ON ERROR directive of the associated block. This could be an explicit ON ERROR phrase, or the implicit (default) ON ERROR phrase for the block type.
It is valid to have both an explicit ON ERROR phrase for the associated block and a CATCH on the same associated block. You might want to CATCH certain error types and handle them directly, and have all other error types handled by the ON ERROR phrase of the associated block.