ON ERROR UNDO, RETURN ERROR question

Posted by Admin on 28-May-2008 03:35

Hello,

Can anyone tell me the difference between:

DO TRANSACTION ON ERROR UNDO, RETURN ERROR:

END.

and

DO ON ERROR UNDO, RETURN ERROR:

END.

Both seem to undo the current block and return error, so both seem to be transactions... or not?

Hope this isn't a silly question

Edit: Solved it myself I think, a DO ON ERROR can cause an active transaction to be rolled back, or when a transaction is active the DO itself can be undone. If there is no active transaction the UNDO does not work!

All Replies

Posted by Admin on 28-May-2008 04:37

Perhaps someone wants to share other ideas or opinions, so I'm reopening this question for a while...

Posted by jtownsen on 28-May-2008 08:18

You're certainly on the right track. A DO block doesn't have transaction scoping capabilities by default. Adding the TRANSACTION keyword will force the DO block to start a transaction if there isn't one going yet. Adding the ON ERROR phrase will give the DO block transaction scoping capabilities. As a result, if a database update is done somewhere directly in the DO block (and not in a nested transaction scoping block), the DO block will start a transaction.

You pointed out a little know fact: that the UNDO keyword does not actually undo anything if there is no active transaction. Particularly for the client side of N-tier applications, this can have a significant impact on what the code actually does.

This was indeed not a silly question

Posted by rstanciu on 28-May-2008 08:39

When you write code to create, modify, or delete a record, OpenEdge groups changes

to the database into a unit of work called a transaction. A transaction is a unit of work

performed against a database that is either done completely or not done at all.

The scope of a transaction is from the starting point to the ending point of a unit of

work.

To know more about the scope of a transaction you can use the listing option.

COMPILE test.p LISTING listing.lst.

You may decide that, because of certain business requirements, you want the

transaction to encompass a different unit of work than what OpenEdge uses for the

default transaction size. The OpenEdge 4GL provides you with the TRANSACTION

option to override the default transaction scope, making the scope either larger or

smaller. The TRANSACTION option acts to blocks type: FOR, REPEAT, DO.

this example NON transacted:

DEF VAR li AS INTE NO-UNDO.

FOR EACH Customer NO-LOCK:

li = li + 1.

END.

In this case the transaction scope is the simple iteration.

FOR EACH Customer SHARE-LOCK:

UPDATE Name.

END.

UPDATE Name. AAAA ... commit

UPDATE Name. BBBB ... commit

UPDATE Name. CCCC ... system error ... then we loose only the last update.

In this case we force the transaction scope to all updates:

(ALL OR NOTHING)

FOR EACH Customer SHARE-LOCK TRANSACTION:

UPDATE Name.

END.

UPDATE Name. AAAA

UPDATE Name. BBBB

UPDATE Name. CCCC ... system error ... then we loose all modifications

Posted by jtownsen on 28-May-2008 08:52

To know more about the scope of a transaction you can

use the listing option.

COMPILE test.p LISTING listing.lst.

This is a very good place to start and I'm glad you mentioned it, but make sure you understand what it's saying. Even procedure (x.p) that doesn't start a transaction (ie. COMPILE x.p LISTING x.txt) shows all No's the the Tran column, it doesn't mean that it's not part of a transaction at runtime. If another program starts a transaction and then calls x.p, everything in x.p is part of the transaction.

Linking back into the original post, that means that x.p might behave differently when it comes to any UNDO's, depending on whether one of it's runtime ancestors started a transaction.

Posted by jtownsen on 28-May-2008 09:04

In this case the transaction scope is the simple

iteration.

FOR EACH Customer SHARE-LOCK:

UPDATE Name.

ND.

UPDATE Name. AAAA ... commit

UPDATE Name. BBBB ... commit

UPDATE Name. CCCC ... system error ... then we

loose only the last update.

This is correct as a FOR EACH block is inherently transaction scoping. The UPDATE directly inside the FOR EACH block automatically creates a transaction scoped to the FOR EACH block. Each iteration is a separate transaction.

In this case we force the transaction scope to all

updates:

(ALL OR NOTHING)

FOR EACH Customer SHARE-LOCK TRANSACTION:

UPDATE Name.

ND.

UPDATE Name. AAAA

UPDATE Name. BBBB

UPDATE Name. CCCC ... system error ... then we

loose all modifications

This is incorrect. In this particular example, the TRANSACTION keyword serves only to show the developer that the intent is to scope a transaction to each iteration of the FOR EACH block. The behaviour is identical to the previous example. (You can also see this in the LISTING.)

To achieve a situation where a system error will cause all record updates to be rolled-back, you could do the following:

Posted by rstanciu on 28-May-2008 09:29

Yes this is true.

At the runtime the transaction scope can be changed.

RUN procA.p -> RUN procB.p -> RUN procC.p

The procC.p is a not transacted procedure.

He will becomes transacted if procA.p starts the transaction.

At the runtime we can investigate the transaction state using the

TRANSACTION function.

MESSAGE TRANSACTION

VIEW-AS ALERT-BOX INFO BUTTONS OK.

Posted by rstanciu on 28-May-2008 10:04

I want to say that we can change the default scope which is the iteration.

Your example show this beter.

In this case the system commits each time , for each repeat iteration, and

we can loose only the last modification if a error occurs.

REPEAT:

CREATE Customer.

.... RUN something.

CREATE Order.

Update something ...

IF error THEN UNDO, LEAVE.

END.

and in this case the commit is at the end of big transaction,

and if a error occurs, the system roll-back all modifications.

_tr:

DO li = 1 TO 10 TRANSACTION:

REPEAT:

CREATE Customer.

.... RUN something.

CREATE Order.

Update something ...

IF error THEN UNDO _tr, LEAVE tr.

END.

END.

Posted by Admin on 11-Jun-2008 08:16

Thanks for the information guys, I'll mark this question as answered.

This thread is closed