Try OpenEdge Now
skip to main content
ABL Reference
ABL Syntax Reference : UNDO statement
 

UNDO statement

Backs out all modifications to fields and variables made during the current iteration of a block, and indicates what action to take next.

Syntax

UNDO
[ label ]
[ , LEAVE [ label2 ]
| , NEXT [ label2 ]
| , RETRY [ label1 ]
     | , RETURN [ return-value |
                 ERROR [ return-value | error-object-expression ] |
                 NO-APPLY ]
     | , THROW error-or-stop-object-expression
]
label
The name of the block whose processing you want to undo. If you do not name a block with label1, UNDO undoes the processing of the closest transaction or subtransaction block. In determining the closest transaction or subtransaction block, the AVM disregards DO ON ENDKEY blocks that do not have the ON ERROR or TRANSACTION option.
LEAVE label2
Indicates that after undoing the processing of a block, the AVM leaves the block you name with label2. If you do not name a block with the LEAVE option, the AVM leaves the block that was undone. After leaving a block, the AVM continues on with any remaining processing in a routine.
NEXT label2
Indicates that after undoing the processing of a block, the AVM does the next iteration of the block you name with label2. If you do not name a block, the AVM does the next iteration of the block that was undone.
RETRY label1
Indicates that after undoing the processing of a block, the AVM repeats the same iteration of the block you name with label1. If you name a block with label1 it must be the name of the block that was undone.
RETRY is the default processing if you do not use LEAVE, NEXT, RETRY, or RETURN. When a block is retried, any frames scoped to that block are not advanced or cleared.
RETURN ...
Returns to the calling routine, or if there is no calling routine, returns to the OpenEdge Editor. The following table describes various RETURN cases:
Option
Description
return-value
The CHARACTER string you provide is passed to the caller. The caller can use the RETURN-VALUE function to read the returned value.
ERROR
Raises ERROR in the caller and undoes the current subtransaction.
ERROR return-value
Raises ERROR in the caller and undoes the current subtransaction. The CHARACTER string you provide is passed to the caller. The caller can use the RETURN-VALUE function to read the returned value.
The AVM also creates an Progress.Lang.AppError object and stores the return-value in the ReturnValue property.
Note: User-defined functions have different behavior since they must return the data type specified in the definition. See the FUNCTION statement for more information.
ERROR error-object-expression
Raises ERROR in the caller and undoes the current subtransaction.
The specified error object is created and populated according to your code. If this is an Progress.Lang.AppError object, the caller can use the RETURN-VALUE function to read the setting of the ReturnValue property.
NO-APPLY
In a user-interface trigger, prevents the AVM from performing the default behavior for that event.
You cannot specify ERROR within a user-interface trigger block or a destructor. You can specify the NO-APPLY option only within a user-interface trigger block.
THROW error-or-stop-object-expression
The THROW directive stops the execution of the current block of ABL code, or the current iteration of an ABL iterating block, and raises the ERROR or STOP condition specified in error-or-stop-object-expression. The value of error-or-stop-object-expression must be an error or stop object type.
Note: Stop object support is available as a Technology Preview only in OpenEdge Release 11.7.
In this example, the THROW directive creates an instance of Progress.Lang.AppError using one of the default object constructors:
UNDO, THROW NEW Progress.Lang.AppError("Can't find this customer", 550)
You can only THROW error or stop objects. An error object is an object that implements the built-in interface, Progress.Lang.Error. A stop object can be an instance of the built-in class Progress.Lang.Stop or one of its built-in subclasses, or it can be an instance of Progress.Lang.StopError, which is a built-in subclass of Progress.Lang.SysError and also implements the Progress.Lang.Error interface. It is a compile-time error to THROW an object that does not implement Progress.Lang.Error or that is not Progress.Lang.Stop or one of its subclasses.
Note: Although Progress.Lang.StopError is a subclass of Progress.Lang.SysError, throwing a Progress.Lang.StopError object raises a STOP condition, not an ERROR condition as when throwing a Progress.Lang.SysError.
When the THROW occurs, execution stops, and the specified ERROR or STOP condition is raised. An ERROR condition should then be handled by the NO-ERROR qualifier, a CATCH block, or by an explicit or implicit ON ERROR phrase. A STOP condition should then be handled by a CATCH block or by an explicit or implicit ON STOP phrase; otherwise the STOP condition is thrown all the way to the top of the call stack.
The following notes describe restrictions on using UNDO, THROW:
*If the action on the UNDO statement is THROW, the UNDO cannot have a [label]. To do so will result in a compile-time error.
*UNDO, THROW is not allowed in a CATCH block associated with the main block of an object destructor method. You cannot raise or RETURN an ERROR or STOP condition from a destructor. To do so will result in a compile-time error. You can use UNDO, THROW within the code of the destructor itself. In this case, the statement will raise the condition in the destructor block and be caught by the ON ERROR or ON STOP directive of the destructor block (which can only be UNDO, LEAVE).
*A RETURN ERROR is not allowed in a CATCH block of a user interface trigger. ABL does not allow you to RETURN an ERROR out of a user interface trigger. To do so results in a compile-time error.
*The UNDO, THROW statement can itself raise an ERROR condition, or THROW a Progress.Lang.SysError object if it fails, for example, if the statement cannot find the specified error or stop object. In this case, the SysError will be trapped by the same block that would have trapped the successfully thrown error or stop object.

Examples

The r-undo.p procedure prompts you for the initials of a sales representative. If the initials match those of an existing sales representative, the procedure displays that sales representative's record. Otherwise, it prompts you to add another sales representative with the initials you supplied. If you enter no, the UNDO statement undoes the work you have done since the start of the REPEAT block and lets you enter another set of initials.
r-undo.p
DEFINE VARIABLE ans AS LOGICAL NO-UNDO.

REPEAT FOR SalesRep WITH ROW 7 1 COLUMN 1 DOWN CENTERED ON ENDKEY UNDO, LEAVE:
PROMPT-FOR SalesRep.SalesRep.
FIND SalesRep USING SalesRep.SalesRep NO-ERROR.
IF NOT AVAILABLE salesrep THEN DO:
ans = TRUE.
MESSAGE "SalesRep record does not exist.".
MESSAGE "Do you want to add a SalesRep?" UPDATE ans.
IF ans THEN DO:
CREATE SalesRep.
ASSIGN SalesRep.SalesRep.
UPDATE SalesRep.RepName SalesRep.Region SalesRep.MonthQuota.
END.
ELSE UNDO, RETRY.
END.
ELSE DISPLAY SalesRep.
END.
This example shows how the UNDO, THROW statement specifies and populates an error object, and how the CATCH block handles it:
r-undothrow1.p
FIND Customer 1000 NO-ERROR.
/* Raises error on current block (main block of .p); execution goes to CATCH
   below */
IF ERROR-STATUS:ERROR THEN
  UNDO, THROW NEW Progress.Lang.AppError("Can't find this customer", 550).

MESSAGE Customer.CustNum. /* This code does not execute if FIND fails */

/* This CATCH is on the main block of r-undothrow1.p */
CATCH eAppError AS Progress.Lang.AppError:
  MESSAGE eAppError:GetMessage(1) eAppError:GetMessageNum(1).
END CATCH.

Notes

*You can also specify UNDO processing for a block by using the ON ERROR, , ON STOP and ON ENDKEY phrases with a block statement.
*An UNDO statement that specifies a block that encompasses the current system transaction block has no effect on changes made prior to the start of the system transaction. This includes changes made to variables prior to the beginning of the system transaction.
*If nothing changes during a RETRY of a block, then the RETRY is treated as a NEXT or a LEAVE. This default action provides protection against infinite loops.
*For more information on the UNDO statement, see OpenEdge Getting Started: ABL Essentials.
*Class-based error or stop objects can be thrown from an OpenEdge application server and handled by a CATCH block on an ABL client. To be throwable from an OpenEdge application server to an ABL client, any user-defined error classes must be defined on both the server and client sides, and the classes must be defined as SERIALIZABLE. Otherwise, ERROR and STOP conditions from the server are handled on the client as provided for handling any ERROR and STOP. In addition, note that any STOP condition messages are written to the server log file, even if a stop object with the messages is caught on the client. For the full list of restrictions on class-based objects that are passed between server and client, see the Parameter passing syntax entry. For more information on error and stop handling in general, see OpenEdge Development: Error Handling.

See also

ON ENDKEY phrase, ON ERROR phrase, RETRY function, RETURN statement, ROUTINE-LEVEL ON ERROR UNDO, THROW statement