May OpenEdge classes set the error-status?

Posted by Richard.Kelters on 05-Feb-2018 05:04

I'm wondering what the views are on what we may or may not expect from classes provided bij Progress?

After calling the OpenEdge.Net.HTTP.RequestBuilder the ERROR-STATUS is set and the GET-MESSAGE method returns error ConfigOption record not on file. (138).

When the builded request object is deleted the ERROR-STATUS is set and the GET-MESSAGE method returns error pbHeader record not on file. (138).

OpenEdge 11.7.2 64-bit Windows.

Posted by Peter Judge on 26-Feb-2018 03:48

We (PSC) will patch the code to use the CAN-FIND+FIND or FIND+RELEASE pattern (usually the former) which will prevent this issue. In the short term you may be able to work around it - ugly, I know - by checking for message number 138 and ignoring it.  You can use the errObj:GetMessageNumber(n) method.

All Replies

Posted by bronco on 05-Feb-2018 06:50

Well, I for one would not mind if ERROR-STATUS or GET-MESSAGEs are "leaked". I would expect any relevant error to be returned as structured error-handling (as an exception, a child of Progress.Lang.Error). Furthermore, if I have code that depends on ERROR-STATUS etc I would make sure that it would be reset before I rely on it.

Just my 2c

Posted by marian.edu on 05-Feb-2018 07:02

I think it’s also stated in the documentation, you should only check/rely on error status/message right after a statement that uses No-ERROR.

 
Marian Edu

Acorn IT 
+40 740 036 212

Posted by Peter Judge on 05-Feb-2018 07:58

Those errors will be coming from a FIND FIRST ConfigOption NO-ERROR. One couls make that case that every time you have code that checks for NO-ERROR that there’s a ASSIGN ERROR-STATUS:ERROR = FALSE after it, but I’ve rarely if ever seen that .
 
The expected error ‘process’ for the OpenEdge.Net (and .Web and some others) classes is to use structured error handling (CATCH).

Richard, where are you seeing/reading  the ERROR-STATUS handle?

Posted by Richard.Kelters on 05-Feb-2018 08:53

I copied an existing batch procedure for a new batch. I kept getting a questionmark in my logfile with this:

   IF ERROR-STATUS:ERROR OR RETURN-VALUE > "":U THEN DO:

       MESSAGE "Error: ":U RETURN-VALUE .

       RETURN "1":U .

   END.

I'm using classes and structured error handling so I removed this code.

Posted by Mike Fechner on 05-Feb-2018 10:32

I must admit I find it bad practice that an API leave an ERROR-STATUS:ERROR or messages behind…
 
A CAN-FIND before the FIND resolves that issue.

Posted by Peter Judge on 05-Feb-2018 10:56

Do you – as a general rule – clear the ERROR-STATUS:ERROR flag ?
 
And what do you consider an API?

Posted by Mike Fechner on 05-Feb-2018 11:06

An API is a tool provided to other developers as a black box. Like the Http client.

I tend to program in a way that errors are thrown or handled. But not left behind unhandled.

NO-ERROR is a bad thing. I have even requested a SonarCobe rule against it.

FIND is an exception. I prefer to do the CAN-FIND/FIND thingie or the IF AVAILABLE ... ELSE ERROR-STATUS:ERROR NO-ERROR.

When it's really a huge problem, when the record is not there I don't use NO-ERROR at all and use a CATCH block.

Sent from Nine

Von: Peter Judge <bounce-pjudge@community.progress.com>
Gesendet: Montag, 5. Februar 2018 17:58
An: TU.OE.Development@community.progress.com
Betreff: RE: [Technical Users - OE Development] May OpenEdge classes set the error-status?

Update from Progress Community
Peter Judge

Do you – as a general rule – clear the ERROR-STATUS:ERROR flag ?
 
And what do you consider an API?

View online

 

You received this notification because you subscribed to the forum.  To unsubscribe from only this thread, go here.

Flag this post as spam/abuse.

Posted by Peter Judge on 05-Feb-2018 11:40

Thanks … I’m not arguing against the HTTP client being an API; was more curious as to where people see the boundaries of their systems and components.
 
I think that treating more things as more APIs is a good approach (and then coding to that is better still). In general I follow - or try to - your rule (but without the FIND/NO-ERROR) but it is often easy to be lazy and DELETE OBEJCT myClientPrincipal NO-ERROR (for example) without checking validity (mea culpa).
 
Do you have a rule that says “you must have a CAN-FIND before a FIND” ?
 
FWIW the example Richard brought up was in a ‘config setter method’ (like the link below). In this case you always want a record available so the style is
 
FIND <table> NO-ERROR
IF NOT AVAILABLE <table>
                CREATE
ASSIGN <field value> =
 
 
 
 
 

Posted by Tim Kuehn on 05-Feb-2018 11:54

The "FIND / IF NOT Avail / CREATE" pattern is so prevalent that I think it'd be worth considering as an addition to the language. 

Posted by Rick Terrell on 05-Feb-2018 12:02

Someone once suggested a MISSING clause that would automatically create the record and assign the fields specified in the WHERE to the values used  


Sounds like an interesting addition. Maybe the auto assign of the fields could be optional. 

Rick Terrell 
Principle Consultant, Professional Services 
Progress

Sent from my iPhone

Posted by Mike Fechner on 05-Feb-2018 12:04

An API should be a black box and should not leave an error state behind when there is no error tob e handled by the caller.
 
Either do CAN-FIND or ERROR-STATUS:ERROR = FALSE NO-ERROR .
 
We do that most of the time &#128521; The SonarCube rule that reports all NO-ERROR’s as a bad habit really helps.
 
In case of that FIND ELSE CREATE we’d do
 
FIND record WHERE record.keyvalue = …. NO-ERROR /* it’s a temp-table, so no locking */.
 
IF NOT AVAILALBE record THEN DO:
    Consultingwerk.Util.ErrorHelper:ResetErrorStatus (). /* does ERROR-STATUS:ERROR = FALSE NO-ERROR */
 
   CREATE record.
  ASSIGN record.keyvalue = …
END.
 

Posted by Tim Kuehn on 05-Feb-2018 12:08

or a MISSING *block* which would auto-create the record with the WHERE field values and contain follow-on code to do other business logic. 

FIND x WHERE x.field1 = value1 
   MISSING: /* record's created with x.field1 = value1 */
     /* do other stuff */
   END MISSING.



Posted by Ken Ward on 05-Feb-2018 12:31

Or what about

DO TRANSACTION:

  CREATE x IF-MISSING WHERE [where- clause].

  /* if the query fails, it creates a new record, if the query succeeds, then the x buffer is set to that record. */

  ASSIGN x.field1 = value1 ....

END. /* transaction */

Posted by Tim Kuehn on 05-Feb-2018 12:44

If standard field lookups could be added to the schema to change this:

FIND OrderLine
WHERE OrderLine.OrderNo = iOrderNo 
AND  OrderLine.LineNo = iLineNo
NO-LOCK NO-ERROR.

IF NOT AVAIL OrderLine THEN 
DO:
CREATE OrderLine.
/* etc */
END.

to this:

FIND OrderLine
FOR OrderLineLookup(iOrderNo, iLineNo)
ADD-MISSING
MISSING:   /* optional "missing" block */
   /* Extra BL code */
END MISSING.

Where " OrderLineLookup" is the lookup field set specified in the schema for a given record lookup structure.


Posted by marian.edu on 05-Feb-2018 13:04

This is what we usually call UPSERT, or INSERT ON DUPLICATE KEY UPDATE. Either way there is no need for WHERE clause there, something along the line of…


CREATE xxx
ASSIGN … 
ON DUPLICATE KEY UPDATE.

This means the CREATE/ASSIGN is a single statement like the SQL INSERT, I would use MERGE instead of ON DUPLICATE KEY UPDATE or just make an UPSERT statement since we have a 4GL (I’m a slow typer).

Otherwise  fail to see how

FIND WHERE …
MISSING:
END MISSING.

is so much better than what we have

FIND WHERE …
IF NOT AVAILABLE DO:
END.

I mean, even for a slow typer like me this isn’t really a big improvement :)

If you imply that inside the MISSING block there should be an automatic creation of the buffer record and assignment of fields used in where clause then at least there will be some indication about this processing like a ON MISSING CREATE. The missing block will be a transaction block, with error handling and we can have any 4gl code there? (like starting a new dialog maybe) :)

 
Marian Edu

Acorn IT 
+40 740 036 212

Posted by CMI on 20-Feb-2018 17:15

I too, today just got this message. 

Here is a snipe of the code I'm using to get there above error.

/** This conforms the SOAP 1.2 specification **/
ContentTypeHeader = SUBSTITUTE('application/soap+xml; action="&1"; charset=UTF-8':U,
SOAPAction).

AuthorizationHeader = SUBSTITUTE('&1 &2',
Classes.OAuth.OAuthAccessToken:AccessTokenType,
Classes.OAuth.OAuthAccessToken:AccessToken).

DEFINE VARIABLE oRequestBody AS String no-undo.

oRequestBody = NEW STRING(SOAPPayloadXML).

oRequest = RequestBuilder:Post(SOAPEndPointURL, oRequestBody)
:AddHeader('Authorization':U, AuthorizationHeader )
:HttpVersion ("HTTP/1.0")
:ContentType(ContentTypeHeader)
:Request.

oResponse = ClientBuilder:Build():Client:Execute(oRequest).

/** 200 OK Successful **/
IF oResponse:StatusCode EQ 200 AND
oResponse:ContentType EQ "application/soap+xml":U THEN
DO:

SOAPResponseXML = oResponse:Entity:ToString().

MESSAGE "SOAPResponseXML" SKIP
LENGTH(SOAPResponseXML).

ERROR-STATUS:ERROR = FALSE.

RETURN.
END.
ELSE
RETURN ERROR SUBSTITUTE("&1 &2", oResponse:StatusCode, oResponse:StatusReason).

Posted by marian.edu on 20-Feb-2018 23:56

Not that I’m arguing wether or not framework components should/could ‘pollute’ the error status or anything but the question is why do you even check the error-status if you don’t have any statement with NO-ERROR in that piece of code?


The documentation is pretty clear on that one (imho)… “ERROR-STATUS - A handle to error information on the last statement executed with the NO-ERROR option.”

If you have framework components that might throw errors (please add the throws options to methods) then either use catch block (the new way) or stick to NO-ERROR/ERROR-STATUS but what you try there is probably not what you want anyway, if one of the methods throws an error you don’t even get to the point where you check ERROR-STATUS.

Marian Edu

Acorn IT 
+40 740 036 212

Posted by CMI on 22-Feb-2018 17:33

So.... what is the soultion to not getting this error message of pbHead not found?

Posted by Peter Judge on 26-Feb-2018 03:48

We (PSC) will patch the code to use the CAN-FIND+FIND or FIND+RELEASE pattern (usually the former) which will prevent this issue. In the short term you may be able to work around it - ugly, I know - by checking for message number 138 and ignoring it.  You can use the errObj:GetMessageNumber(n) method.

Posted by gus bjorklund on 02-Mar-2018 14:16

> On Feb 5, 2018, at 12:55 PM, Tim Kuehn wrote:

>

> The "FIND / IF NOT Avail / CREATE" pattern is so prevalent that I think it'd be worth considering as an addition to the language.

>

in SQL, this is known as an UPSERT - update if it exists, insert if it doesn’t.

This thread is closed