Subtransactions
- Last Updated: April 29, 2024
- 3 minute read
- OpenEdge
- Version 12.8
- Documentation
You separated the Order update and the
OrderLine updates out into two separate
transactions by moving the end of the DO TRANSACTION
block up after the Order block. Let us see what
happens if you combine the Order and OrderLine updates into a single transaction.
To combine the Order and OrderLine updates into a single transaction:
- Define a new label for the
DO TRANSACTIONblock in thesaveOrderprocedure in h-OrderLogic.p:TransBlock: DO TRANSACTION ON ERROR UNDO, LEAVE: FIND ttOrder WHERE ttOrder.TransType = "" NO-ERROR. - Move this block's
ENDstatement back all the way down to the end of theFOR EACHblock, then change theUNDO, LEAVEstatement to undo and leave that entire block:IF bUpdateOline.ExtendedPrice > (ttOline.ExtendedPrice * 1.2) THEN DO: cMessage = cMessage + "Line " + STRING(OrderLine.LineNum) + ": Can't increase price by more than 20%." + CHR(10). UNDO TransBlock, LEAVE TransBlock. END. END. /* ELSE DO If we updated the OrderLine */ END. /* DO FOR EACH ttOline */ END. /* DO TRANSACTION */
Now the transaction structure looks like the diagram in the following figure.

If there is an error on any OrderLine, then the whole transaction is backed out, including any change to the Order.
To test what happens when an error occurs during an OrderLine update:
- Edit one of the fields in the Order, such as the PO, and then make an invalid change to one of its OrderLines.
- Click Save. You see an error message.
- Click Fetch to refresh the Order.
The changes you made to the Order have been undone along with changes to the OrderLines. (Note that the code is not set up to refresh the Order display if the transaction fails. This is an exercise you can do yourself.)
But what if you want to undo a portion of a transaction? ABL supports the capability to do this. If your application has multiple nested blocks, each of which would be a transaction block if it stood on its own, then the outermost block is the transaction and all nested transaction blocks within it become subtransactions. A subtransaction block can be:
- A procedure block that is run from a transaction block in another procedure
- Each iteration of a
FOR EACHblock nested within a transaction block - Each iteration of a
REPEATblock nested within a transaction block - Each iteration of a
DO TRANSACTION,DO ON ERROR, orDO ON ENDKEYblock inside a transaction block
If an application error occurs during a subtransaction, all the
work done since the beginning of the subtransaction is undone. You
can nest subtransactions within other subtransactions. You can use
the UNDO statement to programmatically undo a subtransaction.
In the sample logic procedure, for example, with the END statement
moved to the end, the FOR EACH block is really
a subtransaction within the main transaction. An error inside this
inner block undoes only the change made in that block. Likewise,
if you change the UNDO statement back to UNDO, NEXT,
then the Order changes are saved and only
the current OrderLine changes are undone,
as shown in the following figure.

Note that a FOR EACH, REPEAT, or
procedure block that does not directly contain statements that either
modify the database or read records using an EXCLUSIVE-LOCK does not start
a transaction on its own. However, if contained inside a transaction
block, it does start a subtransaction.