Run statement error not caught

Posted by Admin on 08-Apr-2008 20:06

Message was edited by: Miles Klettke

All Replies

Posted by svi on 09-Apr-2008 12:38

It seems the issue has been addressed on PEG

http://www.peg.com/lists/peg/web/msg14404.html

Posted by Thomas Mercer-Hursh on 09-Apr-2008 12:57

Addressed, yes, in the sense of having explained that there is a difference between an ERROR condition and a STOP condition, but what it doesn't explain is why PSC didn't implement CATCH to cover both. It seems to me that one of the potentially desirable uses of CATCH is to provide a hierarchy of error handling in which local blocks handle simple errors and pass more complex issues up the chain, eventually reaching a top level block in which all errors are handled in some graceful fashion, even if "graceful" is little more than doing some logging, giving the user a polite message, and then quitting or restarting. By not handling STOP conditions with CATCH, we can't really use this approach fully.

Posted by Admin on 09-Apr-2008 16:25

No I couldn't get that suggestion to work. Have you tried it yourself? While in RETRY you don't get a message but as soon as you return or leave you get the message. On a retry you sit in a infinite loop so you have to leave or return and as soon as you do you get the message.

I had ON STOP UNDO, LEAVE and you get the message on the leave. Try the following.

DO ON ERROR UNDO, LEAVE

ON STOP UNDO, LEAVE:

RUN IDoNotExist.p.

message 1 view-as alert-box.

CATCH eSysError AS Progress.Lang.SysError:

MESSAGE 2 eSysError:getMessage(1)

VIEW-AS ALERT-BOX INFO BUTTONS OK.

DELETE OBJECT eSysError.

END CATCH.

CATCH eproError AS Progress.Lang.ProError:

MESSAGE 3 eproError:getMessage(1)

VIEW-AS ALERT-BOX INFO BUTTONS OK.

DELETE OBJECT eproError.

END CATCH.

END.

message 4 view-as alert-box.

I had code a message 1 when the run was successful. When it wasn't it was to just drop out of the block to message 4.

It seems that CATCH traps ERROR messages but doesn't trap STOP messages as I think Tim pointed out.

Posted by Thomas Mercer-Hursh on 09-Apr-2008 16:34

I'm a little unclear on your current status ... and what the second catch block is supposed to be there for.

Are you saying that coded as it stands, the CATCH block(s) do nothing for you, but if the intent was to attempt the run and proceed silently without a message that this is what you are achieving?

Posted by svi on 09-Apr-2008 16:40

As Sébastien has pointed out in his reply to PEG, the RUN in the code sample from Miles returns an unhandled STOP. In 10.1C, which introduces ABL THROW-CATCH structured error handling, we focused on error conditions and created an error object hierarchy in the ABL. We are looking into adding exception (STOP) objects and handling for upcoming releases.

Salvador

Posted by svi on 09-Apr-2008 16:48

No, I have not tried. It's best that you get back to Sébastien.

Posted by Admin on 09-Apr-2008 16:58

An example was posted to the peg with the two CATCH's, and I just left it in there. Neither catch traps any of the messages.

Peter van Dam has just posted an example to the peg that stops the progress message and display his own. His example without the CATCH's, that again don't seem to do anything.

ROUTINE-LEVEL ON ERROR UNDO, THROW.

DO ON STOP UNDO, RETRY:

IF RETRY THEN

UNDO, THROW NEW Progress.Lang.AppError("Program not found",1).

RUN nonexistent.p.

END. /* ON STOP... */

This works ok but I want no message and will have to investigate this method further and I haven't seen the THROW.

Posted by Thomas Mercer-Hursh on 09-Apr-2008 17:09

Peter's full example has two catch blocks at the end,

The message is coming from those. Presumably, you could avoid the message by simply discarding the message instead of displaying it, e.g., putting it to a log file or something ... or nothing at all.

But, isn't this leaping from the bad run immediately down to the CATCH? If there are other statements below the run which you want to execute even if the run fails, then I think those are going to be missed.

Posted by Admin on 09-Apr-2008 17:33

No the CATCH has no effect. The message comes from the THROW. I can remove both CATCH's and still get the same result. I've just had my breakfast and will now see if I can get anything from Peter's example.

Posted by Admin on 09-Apr-2008 17:58

I was wrong on the CATCH at least the AppError one. It's the one that picks up the THROW as pointed out by Jeff Ledbetter. So removing the message from that CATCH stops the message.

A modified version of Jeff's code is below

DO ON ERROR UNDO, LEAVE

ON STOP UNDO, RETRY:

IF RETRY THEN

UNDO, THROW NEW Progress.Lang.AppError().

RUN nonexistent.p.

message 1 view-as alert-box.

CATCH eAppError AS Progress.Lang.AppError:

DELETE OBJECT eAppError.

END CATCH.

END. /* ON STOP... */

message 2 view-as alert-box.

Even with the code above you could get caught as I will have code instead of message 1. If this produces an application error then you won't see it. I could throw a specific error and check for that in the catch, but again I am assuming that the RETRY occurs from the RUN failure.

So still some things to think about.

Posted by Thomas Mercer-Hursh on 09-Apr-2008 17:59

THROW is a UI statement?????

Posted by Admin on 09-Apr-2008 18:18

From help -

You can only THROW error objects, and an error object is an object derived from the built-in interface Progress.Lang.Error. It is a compile-time error to THROW an object that is not derived from Progress.Lang.Error.

When the THROW occurs, execution stops, and the specified error is raised. The error should then be handled by the NO-ERROR qualifier, a CATCH block, or by an explicit or implicit ON ERROR phrase.

The following notes describe restrictions on using UNDO, THROW:

If the action on the UNDO statement is THROW, the UNDO cannot have a . 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 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 error in the destructor block and be caught by the ON ERROR directive of the destructor block (which can only be UNDO, LEAVE).

UNDO, THROW is not allowed in a CATCH block of a user interface trigger. The ABL does not you to raise or RETURN error out of a user interface trigger. To do so will result in a compile-time error.

The UNDO, THROW statement can itself raise error or THROW a SysError object if it fails. For example, if the statement cannot find the specified error object. In this case, the SysError will be trapped by the same block that would have trapped the successfully thrown error object.

Posted by Admin on 09-Apr-2008 18:33

In my case these are my options so far

DO ON ERROR UNDO, LEAVE ON STOP UNDO, RETRY:

IF RETRY THEN

UNDO, THROW NEW Progress.Lang.AppError().

RUN nonexistent.p.

CATCH eAppError AS Progress.Lang.AppError:

DELETE OBJECT eAppError.

END CATCH.

END.

DO ON ERROR UNDO, LEAVE ON STOP UNDO, LEAVE:

OUTPUT TO "NUL:" KEEP-MESSAGES.

RUN nonexistent.p.

OUTPUT CLOSE.

END.

The latter has less code and I can safely insert code after the output close. In the first the safest way is to add code after the do block to avoid retries being fired by other reasons or other application errors occuring. In the case of other application error I can set a specific message and or message number e.g UNDO, THROW NEW Progress.Lang.AppError('Retry Error',123456) and test for that in the catch by eAppError:GetMessage(1) or eAppError:GetMessageNum(1). But again that is more code. Probably the simplest way is to only have the run in the DO block and set a flag when it's successful and test for that after the block.

For my current purpose the old way seems simplest.

Posted by Thomas Mercer-Hursh on 09-Apr-2008 18:41

I would think that something like:

With the procedure in a utility super would allow you to write the code once and give you the option of logging the event.

Not that I've tried it yet, of course.

BTW., enclosing code in ... blocks, no spaces, helps preserve the indentation.

Posted by Admin on 09-Apr-2008 18:50

That's good for a straight run with no parameters but in this first case I am passing two dataset parameters by reference.

Thanks for the heads up on the code indentation. I was wondering about that.

Posted by Admin on 09-Apr-2008 19:04

The other thought that I had was what if the run procedure produced a system or application error. Would it be caught?

I did some tests and any system or application errors in the run procedure got reported as usual. The only time I didn't get a message when I made a change to the run procedure so that it didn't compile. I think that is an acceptable result.

Posted by Thomas Mercer-Hursh on 09-Apr-2008 19:11

in this first case I am passing two dataset parameters by reference.

Well, you could always pass them as shared!

I have to say that there is something peculiar to me about the notion of running something that deserves two dataset parameters and yet you aren't sure it is going to be there and you don't actually seem to care if it runs.

Sounds like an environment for PUB/SUB or Sonic rather than RUN.

Posted by Admin on 09-Apr-2008 19:58

We are now looking at the reason for this and perhaps there is a better reason. In this instance it is actually a service for a dataview that provide the link between ADM2 and our version of OERA that uses dataset.

The service receives input from ADM2 and I setup some contexts that are required by our service. Our context is held in a context dataset. These context's may be fine for most services but we may want to add or alter the standard context for a particular business instance.

So to allow for this I run a procedure based on the business object name passing the context dataset by reference (I dropped 1 dataset). I don't know how often there will be a procedure there and while I realized I could use SEARCH, I was originally just trying a run no-error and that's how I started exploring CATCH.

Posted by Thomas Mercer-Hursh on 10-Apr-2008 11:03

It does sound like a context which would call for something more structured than a RUN NO-ERROR.

Posted by Admin on 10-Apr-2008 15:45

I'm not sure what your thinking. But, you have prompted me to rethink about varying the context. I receive some basic info from ADM2 that I use to setup context for our service e.g. batch size, restartrowid. I thought that we may need to add other context and was passing to a procedure for the object. However, I believe that this is the wrong placement. If we're going to add context then it's going to be on specific information resolved from user input. So the application will have to set context and I will have to resolve at what point we are starting context and clearing context.

Posted by rbf on 11-Apr-2008 02:25

Some commments from my side:

- In the example I posted one CATCH would be enough (ProError) and

the ROUTINE LEVEL statement is unnecessary in the example as well

(I am already getting used on including that statement almost

everywhere).

- The bottom line is indeed that structured error handling does not

catch as STOP condition and until it does is has little value here.

Both the traditional and SEH way do not address the issue properly.

Having said that, Salvador indicated that it will be supported in the future

and that is a good reason to prepare your code for it.

Posted by Admin on 11-Apr-2008 03:51

Thanks Peter, after you initial message I did discover those things but it is good to clarify it for all readers. I appreciated your input and you were the first to provide a solution that did work.

Thanks to Thomas I have reviewed my approach and while this method is not required for this issue I will be useful in the future.

Posted by svi on 11-Apr-2008 08:50

We are looking into it, however we have not final plans for a specific release yet. Just want to make sure the expectations are right. If you are going to Exchange we may have a group discussion at the Info Exchange ...

Salvador

Posted by Thomas Mercer-Hursh on 11-Apr-2008 11:30

I would think this was an area where you had pretty clear sailing. All we have now is either these kludgy little tricks, checking before we try, or accepting an aborted session. I can't see how anything you do would break the kludgy tricks, there is nothing wrong with checking (albeit tedious), and anyone willing to accept an aborted session from an uncaught stop is no worse off. So, adding the ability to catch it is a one-sided plus.

Posted by svi on 11-Apr-2008 14:12

Agreed. Just being cautious because the plans are not final. You've seen me do this before.

Salvador

Posted by Tim Kuehn on 13-Apr-2008 17:20

Agreed. Just being cautious because the plans are not

final. You've seen me do this before.

Right before we turned the burners up a bit.

Posted by agent_008_nl on 17-Apr-2008 06:49

A way to catch the error is:

_msg = 0.

run a.

IF _msg(1) <> 0 THEN message 'error catched'.

Regards,

Stefan.

Posted by agent_008_nl on 18-Apr-2008 02:47

Ah, excuse me, my answer is not relevant in this interesting thread. I'm new here, sorry.

Stefan.

Posted by agent_008_nl on 21-Apr-2008 05:10

Not going to exchange, but I do have some questions and remarks (posting this to the peglist too for those wanting to react there).

If a run statement fails it can either result in a STOP firing or in an ERROR firing. See the code below.

DEFINE TEMP-TABLE s

FIELD a AS INTEGER.

DEFINE VARIABLE cMes AS CHARACTER NO-UNDO.

a:

DO ON ERROR UNDO, RETRY:

IF RETRY THEN UNDO a, LEAVE a.

DO TRANSACTION:

CREATE s.

RUN k NO-ERROR.

IF ERROR-STATUS:ERROR THEN UNDO a, RETRY a.

END.

END.

MESSAGE 'retval after a, avail s: ' avail s ' catched: ' RETURN-VALUE.

b:

DO ON ERROR UNDO, RETRY:

IF RETRY THEN UNDO b, LEAVE b.

DO TRANSACTION:

CREATE s.

RUN l NO-ERROR.

IF ERROR-STATUS:ERROR THEN UNDO b, RETRY b.

END.

END.

MESSAGE 'retval after b, avail s: ' avail s ' catched: ' RETURN-VALUE.

PROCEDURE k:

DO ON STOP UNDO , RETRY:

IF RETRY THEN RETURN ERROR 'stop catched in k'.

RUN nonexistent.

END.

END PROCEDURE.

PROCEDURE l:

DO ON ERROR UNDO, RETRY:

IF RETRY THEN RETURN ERROR 'error catched in l'.

RUN nonexistent IN THIS-PROCEDURE.

END.

END PROCEDURE.

Wouldn't it be desirable to have an ERROR firing in both cases? It would simplify programmatic errorhandling. The help says about the stop firing (stop conditions, run statement): "The STOP condition, in this case, is supported for backward compatibility.", well, if this is desirable then maybe a possibility to change this behaviour with a startup-parameter would help us?

Furthermore I keep finding handling unexpected errors cumbersome, although programmatic choices are desirable. Shouldn't an unexpected error during a running transaction result in undoing all active transactions by default (f.e. in the folowing example)?

Regards,

Stefan.

DEFINE TEMP-TABLE s

FIELD a AS INTEGER.

DEFINE VARIABLE iResult AS INTEGER NO-UNDO.

DO TRANSACTION:

CREATE s.

RUN k (OUTPUT iResult).

s.a = iResult.

END.

MESSAGE AVAIL s.

PROCEDURE k:

DEFINE OUTPUT PARAMETER poiResult AS INTEGER NO-UNDO.

poiResult = INT('a').

END PROCEDURE.

Posted by Admin on 21-Apr-2008 16:13

When I posted my original message I had forgotten about this one. There is a difference when running an internal procedure i.e. it appears to raise an error rather than a stop condition. If you place no-error after both runs progress still troughs an error on the first but on the second no progress error is displayed. You can trap that error by adding "IF ERROR-STATUS:ERROR THEN RETURN 'Error in ..'.".

Like you I don't know the reason for the difference a missing IP is as bad as an external procedure. Why should the former raise an ERROR while the latter raises a STOP.

An issue in your code is the use of RETURN-VALUE. If the first run has a return-value and the second is successful then you still get the return-value from the first. If you are going to use return-value ensure that there is always a return-value - so in the second if it runs ok return "".

Posted by agent_008_nl on 22-Apr-2008 01:57

Thanks for pointing me at the return-value problem. I wrote the snippet without attention on that point because I wanted to demonstrate other problems.

No one else on my remarks?

Posted by jmls on 09-Feb-2011 14:27

I've just been bitten by this, by invoking a static event in a class which needs a database connected (and there isn't)

I'm trying to write a unit test for this, but for the life of me, can't catch the damned error (lib.Config Database foo not connected (1006) Static instance failed to load. Cannot reference class lib.Config)

I've tried all the options in here, to no avail.

    DO ON ERROR UNDO, LEAVE

      ON STOP UNDO, RETRY:

    IF RETRY THEN UNDO, THROW NEW Progress.Lang.AppError().

      lib.Config:Quit() NO-ERROR .

    END.

I still get the errors and cannot catch / trap them.

Seeing as I'm using 10.2B03, and this thread is nearly three years old, am I missing something, or didn't you guys (Progress) get round to fixing this ?

Julian

This thread is closed