Error Handling 101

Posted by Jeff Ledbetter on 06-Apr-2017 10:43

Hi.

Apparently I do not understand error handling like I thought I did.

Why is this error only caught if I have an ROUTINE-LEVEL ON ERROR UNDO, THROW statement in the code?

USING PROGRESS.Lang.*.

RUN tryIt.

PROCEDURE tryIt:

  RUN doIt.
  
  CATCH a AS AppError:
    MESSAGE a:ReturnValue VIEW-AS ALERT-BOX.
  END.

END.

PROCEDURE doIt:
  UNDO, THROW NEW AppError("Jeff's error!").
END PROCEDURE.

Posted by Laura Stern on 06-Apr-2017 10:54

Yes - at first this is not intuitive.  The error you are throwing inside doIt(), is raising error inside that procedure.  Errors do not bubble out of blocks, ever, unless UNDO, THROW is in effect.  So if you'd had a CATCH block inside doIt, it would have run.  

With ROUTINE-LEVEL ON ERROR UNDO, THROW, it is saying that when error gets raised in doIt(), instead of just doing an UNDO, LEAVE, it will throw the error out of the block, up to the caller in this case.  So then error gets raised again in the caller, at the RUN statement.  So then your CATCH block will run.

Posted by Ken McIntosh on 06-Apr-2017 10:59

Hi Jeff,

There's no default error handling properties on a procedure/function block that would cause the procedure to be able to CATCH the error.  Since you added none in tryIt the application error was not passed back to the caller.

ROUTINE-LEVEL error handling is designed to impose implicit error handling at the sub-routine level for the following blocks (from the doc):

Main block of an external procedure (.p)

Internal procedures

User-defined functions

Methods of a class

Class constructors

Property accessors

ON blocks used as database triggers with CREATE, DELETE, WRITE or ASSIGN events

Note that BLOCK-LEVEL would also provide the desired behavior.

Ken Mc

Posted by Ken McIntosh on 06-Apr-2017 11:00

Yeah... What Laura said.

All Replies

Posted by Laura Stern on 06-Apr-2017 10:54

Yes - at first this is not intuitive.  The error you are throwing inside doIt(), is raising error inside that procedure.  Errors do not bubble out of blocks, ever, unless UNDO, THROW is in effect.  So if you'd had a CATCH block inside doIt, it would have run.  

With ROUTINE-LEVEL ON ERROR UNDO, THROW, it is saying that when error gets raised in doIt(), instead of just doing an UNDO, LEAVE, it will throw the error out of the block, up to the caller in this case.  So then error gets raised again in the caller, at the RUN statement.  So then your CATCH block will run.

Posted by Ken McIntosh on 06-Apr-2017 10:59

Hi Jeff,

There's no default error handling properties on a procedure/function block that would cause the procedure to be able to CATCH the error.  Since you added none in tryIt the application error was not passed back to the caller.

ROUTINE-LEVEL error handling is designed to impose implicit error handling at the sub-routine level for the following blocks (from the doc):

Main block of an external procedure (.p)

Internal procedures

User-defined functions

Methods of a class

Class constructors

Property accessors

ON blocks used as database triggers with CREATE, DELETE, WRITE or ASSIGN events

Note that BLOCK-LEVEL would also provide the desired behavior.

Ken Mc

Posted by Ken McIntosh on 06-Apr-2017 11:00

Yeah... What Laura said.

Posted by Jeff Ledbetter on 06-Apr-2017 12:22

Thank you both. That helps jog the old noggin'.

Posted by Peter Judge on 11-Apr-2017 21:30

I’d recommend ALWAYS adding the BLOCK-LEVEL directive to new code. I’d say all code but there are some things to be aware of , which Mike’s presentation at pugchallenge.org/.../272_Strucutred_Error_Handling.pdf  does an excellent job of explaining.
 

This thread is closed