Page 1 of 1

Best Practice using IO$STS with multiple IO Operations

Posted: Tue Mar 21, 2017 9:00 am
by jyoung
I am wondering what the best practice is in terms of using IO$STS when you have multiple IO operations.

For example, on the client (VLF-ONE) after the call to the save server module, I do something like this

Code: Select all

evtroutine handling(#save.Completed)
* Get server messages and issue them in the Framework
#COM_SELF.HighlightProblems( #PanelFields )

#avFrameworkManager.avRecordTraceAValue component(#COM_OWNER) event("Save Completed") avalue(#Status)

if (#Status = OK)
* Message indicating successful update
#avFrameworkManager.avIssueMessage text('Update was successful') requester(#COM_OWNER)
#SaveButton.Enabled := False
endif

if (#Status = VE)
#avFrameworkManager.avIssueMessage text('Update failed due to data validation errors') requester(#COM_OWNER)
endif

#COM_OWNER.avGotoFreeState

endroutine
The save server routine has potentially 3 write based IO operations and 3 read based IO ops (Why is beyond the scope of this topic, but suffice to say I don't think it is good database design, but there is nothing I can do about it).

Since I only return one IO$STS it is always the status of the last write (do read ops affect it?) operation.

In this specific case, my last operation I am doing a check_for and if the if_status is *EQUALKEY then I need to do an update.
Here is a snippet of the server side code.

Code: Select all

* fetch all fields for key and level 1 (was 0 before the above update)
#CMELVL := 1
fetch fields(#BF1103Fields) from_file(BF1103) with_key(#CMOFID #CMOFD #CMOCN #CMOD #CMELVL)

* get the entry from the save list, this will update the fields that we just loaded with their new values
get_entry number(1) from_list(#SaveList)

* reset the level 0 fields
#CMELVL := 0
#vEffectiveDate2 := #STD_DATEX.Now
#vNonEffectiveDate := *SQLNULL
#vLastUpdatedDate := #STD_DATEX.Now
#vLastUpdatedTime := *TIME
#CMULU := #Persistent_ApplicationString1.AsNativeString
#CMAH := 'A'

* finally do the insert
insert fields(#BF1103Fields) to_file(BF1103)

* one last thing to do, if the key exists in BF1147, update the ESI Rating
#CPOFID := #LCOFID
#CPOFD := #LCOFD
#CPOCN := #LCOCN
#CPOD := #LCOD

check_for in_file(BF1147) with_key(#CPOFID #CPOFD #CPOCN #CPOD)
if_status is(*EQUALKEY)
#CPCRE := #CMCRE
update fields(#CPCRE) in_file(BF1147) with_key(#CPOFID #CPOFD #CPOCN #CPOD)
endif
Works well enough, however the IO$STS is now 'NE' (which is to be expected) and that throws off the client status check so I don't get the "Update Successful" message.

So I am curious what others are doing with IO$STS when you have multiple IO operations.

Do you check it on the client or do you ignore it?
Do you maintain a separate status on the server and only flip it if an IO op goes wrong which means checking every IO op?

I am thinking that I should check every IO op and if_status is_not *OKAY then set a return status (aka return code separate of IO$STS) to ER and issue a message. The client can then pick up that status and receive the messages from the server.

Re: Best Practice using IO$STS with multiple IO Operations

Posted: Tue Mar 21, 2017 2:30 pm
by MarkD
I don’t know about best practice, but where server routines have multiple operations that can fail prefer to rationalize the overall result into a simple Boolean. For example:

Code: Select all

Srvroutine Name(NewTest)
Field_Map For(*Output) Field(#ServerRoutineSuccess)

Define Field(#ServerRoutineSuccess) Type(*BOOLEAN)
Define_Com Class(#io$STS) Name(#InsertIOStatus)
Define_Com Class(#io$STS) Name(#UpdateIOStatus)

Insert Fields(#xEmployeeAge) To_File(xEmployee) Io_Status(#InsertIOStatus)

Update Fields(#xEmployeeAge) In_File(xEmployee) Io_Status(#UpdateIOStatus)

#ServerRoutineSuccess := ((#InsertIOStatus = OK) And (#UpdateIOStatus = OK))

Return
Endroutine
I find that the problem with returning IO$STS (as a field) is that if you execute other subroutines or methods within the same module they can change it without you noticing because it’s globally scoped. Here #InsertIOStatus and #UpdateIOStatus are scoped within my SrvRoutine and cannot get zapped.

Re: Best Practice using IO$STS with multiple IO Operations

Posted: Wed Mar 29, 2017 4:00 am
by atostaine
Depending on whether you want to consider all of the transactions as a logical transaction, you can get out as soon as an error happens. In that case I set the status to false at the beginning.

Code: Select all

Srvroutine Name(NewTest)
Field_Map For(*Output) Field(#ServerRoutineSuccess)
Define Field(#ServerRoutineSuccess) Type(*BOOLEAN)

#serverRoutineSuccess := False

Insert Fields(#xEmployeeAge) To_File(xEmployee) Io_Status(#InsertIOStatus)
if_status is_not(*okay)
return
endIf

Update Fields(#xEmployeeAge) In_File(xEmployee) Io_Status(#UpdateIOStatus)
if_status is_not(*okay)
return
endIf

#serverRoutineSuccess := True

Endroutine