How to undo procedure

NewB

New Member
Hello,

Open Edge 10.1C

I would like to know how to undo a procedure, not only the last call but all calls.

Here a basic exemple.

Code:
PROCEDURE upd_customer:
define input parameter in-numCust like client.clecli.
 
FIND FIRST customer  WHERE customer.numCust = in-numCust.
 
/* Update customer FIELD */
 
END.
 
def var list-numCust as int extent 3.
def var i as int.
 
list-numCust=54.
list-numCust=55.
list-numCust=56.
 
do i = 1 to 3 :
    run upd_customer(input list-numCust).
end.

for exemple : if the 3rd customer is not found i would like to undo all the modifications done to all
customers ( custNum 54, 55 and 56).

Thanks for you help.
 
You can't undo a procedure run - you can only undo ( rollback ) a transaction. Therefore you can only undo the database changes that were caused by a run of a procedure if you extend the transaction scope so that it encloses the run statement and undo it on purpose. You can achieve this in explicitly using the DO TRANSACTION statement in conjunction with UNDO, LEAVE.

But - you need to be careful when you do something like this because you might end up having a never ending, very big transaction blowing up the lock table or the before image - whichever comes first ...

BTW: You code is not good practice:

The variable list-numCust is an extent variable and you should use individual extents for assigning 'em ...
You don't specify exclusive-lock on your find statement - therefore you will have a share lock possibly causing a dead lock ...
Do you know where your transaction scope is?


Regards, RealHeavyDude.
 
Thx for your answer,

sorry for the code, i have write it too fast, its just an exemple in order to understand how its works.

Code:
PROCEDURE upd_customer:
define input parameter in-numCust as int.
 
FIND FIRST customer  WHERE customer.numCust = in-numCust.
 
/* Update customer FIELD */
 
END.
 
def var list-numCust as int extent 3.
def var i as int.
 
list-numCust[1]=54.
list-numCust[2]=55.
list-numCust[3]=56.
 
do i = 1 to 3 :
    run upd_customer(input list-numCust[i]).
end.

Il would like to have a transaction on the "do i = 1 to 3 :"

but i don't know how to do.

I know basic transaction, but here with a procedure i'm lost
 
l:
do transaction:
do i = 1 to 3:
run upd_customer(input list-numCust).
if return-value = "ERROR" then
UNDO l, leave l.
end.
end.
 
Just a remark:

A transaction is caused by every statement that directly changes the database - which would your update customer logic code. The transaction scope is then extended to the next outer block with transaction capabilities - which would be your internal procedure upd_customer.

Therefore, if you specify DO TRANSACTION within the transaction scope you will create a sub-transaction. Such sub-transactions will not be known to the database since it will only know THE transaction. Thus the client will have to undo the sub-transactions whereas THE transaction will or will not go through on the database, depending on the fact whether an error is encountered or not. Working with sub-transactions on purpose is not bad practice but you should know what you do.

Regards, RealHeavyDude.
 
thank you, its working now :)

Code:
PROCEDURE upd_customer:
define input parameter in-numCust as int.
 
FIND FIRST customer  WHERE customer.numCust = in-numCust.
/* Update customer FIELD */
 
/* In order to catch any error during the procedure 
in this exemple the error is to not find the customer 56 */
 
CATCH procError AS Progress.Lang.Error:
RETURN "ERROR".
END CATCH.

END.
 
def var list-numCust as int extent 3.
def var i as int.
 
list-numCust[1]=54.
list-numCust[2]=55.
list-numCust[3]=56.
 
l:
do transaction:
do i = 1 to 3  :
    run upd_customer(input list-numCust[i]) .
    if return-value="ERROR" then undo l, leave l.
end.
end.

Is it the good way to write this ?
 
It is ok

other way you can use
DO Transaction ON ERROR UNDO l, LEAVE l
ON END-KEY UNDO l, LEAVE l
ON STOP UNDO l, LEAVE l:
do i = 1 to 3: run procedure.p (). end.
END.
 
I'd say you're making it far too complicated! :)

Code:
PROCEDURE upd_customer:
define input parameter in-numCust as int.
 
FIND FIRST customer EXCLUSIVE-LOCK WHERE customer.numCust = in-numCust NO-ERROR.

if not available customer then return "error". 

/* Update customer FIELD */
 
END.
 
def var list-numCust as int extent 3.
def var i as int.
 
list-numCust[1]=54.
list-numCust[2]=55.
list-numCust[3]=56.
 
l:
do transaction:
do i = 1 to 3  :
    run upd_customer(input list-numCust[i]) .
    if return-value="ERROR" then undo l, leave l.
end.
end.
 
Cringer : it's just a basic exemple. I haven't use the "not available customer " in order to generate an error.

I would like to be able to catch any error during the procedure, send the error to the do transaction block and undo all modification. My explanation wasn't clear in my first post :/

here the final code

Code:
PROCEDURE upd_customer:
define input parameter in-numCust as int.
 
FIND FIRST customer  WHERE customer.numCust = in-numCust.
/* Update customer FIELD */
 
/* In order to catch any error during the procedure 
in this exemple the error is to not find the customer 56 */
 
CATCH procError AS Progress.Lang.Error:
RETURN ERROR.
END CATCH.

END.
 
def var list-numCust as int extent 3.
def var i as int.
 
list-numCust[1]=54.
list-numCust[2]=55.
list-numCust[3]=56.
 
do transaction on error undo , leave  :
do i = 1 to 3  :
run upd_customer(input list-numCust[i]) .
end.
end.

if error-status:error then message "Error during do transaction block".

Thank MaximMonin and RealHeavyDude
 
Back
Top