During the execution flow, you may determine that there is an invalid condition (for example, when validating input) and want to communicate that to other parts of the program or to the user. To do this, you create an application error object and raise the ERROR condition by using the UNDO, THROW statement.

In addition, you can provide local CATCH blocks that provide handling for specific error numbers and throw any other condition to an outer or calling block to be handled by more generic error-handling code. The same UNDO, THROW statement can be used in a CATCH block to accomplish this.

Syntax

UNDO, THROW [error-object-expression].
error-object-expression
Any expression that results in an instance of an error or stop object.

When this statement is executed, it undoes the current block (the innermost block with error-handling capabilities) and raises ERROR or STOP on the statement. ERROR is raised if it is an error object and STOP is raised for any of the stop objects (which includes Progress.Lang.StopError). It is then up to the block directives to determine how the error is handled, as with any other condition.

Examples

In each of the following examples, ERROR is raised on the UNDO, THROW statement. If there are any updates in the block that require undoing, that is performed, though in these examples there are not. The comment in each code example describes what happens. Assume the current output device is the screen:

Example 1

This example demonstrates the use of UNDO, THROW within a block. Note that this is not the same as using the ON ERROR UNDO, THROW directive on that block. With the UNDO, THROW statement, the condition is simply raised on the current statement.

DO ON ERROR UNDO, LEAVE:
    IF CurrentTime > ClosingTime THEN
       UNDO, THROW NEW Progress.Lang.AppError("Can't take a delivery order
                                               after closing time.", 550).
END.

<next line>

/* Since there is no CATCH block and no THROW directive, the error message
   provided as the parameter to the AppError constructor is displayed. 
   Execution then continues at <next line>. 
*/

Example 2

With the ON ERROR UNDO, THROW directive, the condition, which was already raised within the context of that block, is thrown to the outer block (or caller if there is no outer block).

DO ON ERROR UNDO, THROW:
   IF CurrentTime > ClosingTime THEN
       UNDO, THROW NEW Progress.Lang.AppError("Can't take a delivery order
                                               after closing time.", 550).
END.

<next line>

/* Once error is raised, the newly created AppError object is thrown out of the DO
   block due to the ON ERROR UNDO, THROW block directive. Thus, error is raised again
   at the END of the DO block (though functionally, it is outside of this block).
   Because there is no THROW directive or CATCH block at this level, this causes
   <next line> not to execute.  Instead the error message that was provided as the
   parameter to the AppError constructor is displayed. Assuming this is the end
   of a procedure, execution continues in the caller, if there is one. 
*/

If you use the DEBUG-ALERT feature (SESSION:DEBUG-ALERT = yes, or startup parameter -debugalert) for each of the above two examples, the difference is clearer. For the first example, if you hit the Help button on the alert box when the error message is displayed, it shows line 3 (the UNDO, THROW statement). In the second example, it shows line 5 (the END statement).

Example 3

This example demonstrates what happens when the UNDO, THROW statement occurs within a CATCH block. Here the condition is raised and thrown to the outer block of the associated block (or the caller if there is no outer block). This happens because CATCH blocks have the UNDO, THROW flow-of-control directive by default.

DO ON ERROR UNDO, LEAVE:
    FIND FIRST Customer WHERE Customer.Name Begins “A”.

    CATCH err AS Progress.Lang.Error:
        IF err:GetMessageNum(1) = 565 // record not found
        THEN <do custom handling for this error>
        ELSE UNDO, THROW err.
    END.
END.

<next line>

CATCH err AS Progress.Lang.Error:
    MESSAGE err:GetMessage(1) 
        VIEW-AS ALERT-BOX.
END.

/* The caught Progress.Lang.SysError object is thrown out of the CATCH block
   and thus, out of the associated DO block.  Error is raised again in the
   outer block, <next line> does not execute, and the outer CATCH block runs.      
*/