Because the CATCH block only executes when ERROR or STOP is raised in the associated block, any transaction within the associated block is already undone. In other words, changes made within the associated block to persistent data, undo variables, and undo temp-table fields have been discarded. In addition, buffers scoped to the associated block of the CATCH block are not available when the CATCH block executes. This is because either the buffer was undone and released, or committed and released. If a buffer referenced in a CATCH block is referenced outside of the associated block, then the scope of that buffer is the smallest enclosing block outside of the associated block that encompasses all references to the buffer. Therefore, these buffers are available to the CATCH block.

The CATCH block itself is an undoable block with implicit ON ERROR UNDO, THROW error handling. You cannot explicitly override the ON ERROR directive for a CATCH block.

A statement that raises ERROR or STOP within a CATCH block causes the following to occur, unless the condition is handled within the block:

  1. UNDO the CATCH block if it contains a transaction.
  2. LEAVE the associated block.
  3. THROW the condition to the block enclosing the associated block, or to the caller if there is no outer block.

The following example demonstrates these availability rules:

/* Defines an undoable variable (the NO-UNDO option is not specified). */
DEFINE VARIABLE TargetCustNum AS INTEGER.

/* The last valid value before the beginning of the DO block */ 
ASSIGN TargetCustNum = 1.

/* This block is a transaction block because it makes updates to the database */
DO ON ERROR UNDO, LEAVE: 

    /* This value is undone on ERROR. */ 
    ASSIGN TargetCustNum = 15.

    /* Find a Customer */
    FIND Customer WHERE Customer.CustNum = TargetCustNum.

    /* Here’s where we update the database. */
    ASSIGN Customer.Name = Customer.NAME + " And Much More".

    /* Confirm change to persistent field. */
    MESSAGE "Customer Name changed to: " Customer.Name 
        VIEW-AS ALERT-BOX BUTTONS OK.

    /* ERROR raised. Control passes to CATCH block. */ 
    FIND Order OF Customer WHERE OrderNum = 1234.

    /* Statement does not execute. */ 
    DISPLAY Customer.CustNum SKIP
            Customer.Name SKIP 
            OrderNum SKIP 
            OrderStatus
                VIEW-AS TEXT WITH FRAME b SIDE-LABELS.

    CATCH eSysError AS Progress.Lang.SysError:

        /* Confirm if Customer record is available in CATCH.
           In this case it is not available because the customer
           record is released from the buffer when the associated
           block is undone, since it was never referenced in a
           higher block. */ 
        IF AVAILABLE (Customer) THEN DO:
            MESSAGE "Customer record is still available." 
                VIEW-AS ALERT-BOX BUTTONS OK.
        END.
        ELSE DO:
            MESSAGE "No Customer record is currently available." 
                VIEW-AS ALERT-BOX BUTTONS OK.

            /* Re-Find the Customer. Cannot rely on value of TargetCustNum! */
            FIND Customer WHERE Customer.CustNum = 15.

            /* Confirm that change to database field was not committed
               and UNDO variable was rolled back to 1. */
            MESSAGE "TargetCustNum = " TargetCustNum SKIP
                    "Customer name is now: " Customer.Name
                VIEW-AS ALERT-BOX BUTTONS OK.
        END. /* ELSE */

     END CATCH.
END. /* DO */