Topic
  • 2 replies
  • Latest Post - ‏2013-02-01T14:30:41Z by barbara_morris
bogeybetsy
bogeybetsy
43 Posts

Pinned topic READE and CHAIN Gotchas

‏2013-01-24T10:50:37Z |
We have a file declared in a program as an update file with the following records :

Key Data
4 (any data)
5 (any data)
7 (any data)

And we were looking for the record whose key is 6, and the record whose key is 7 is locked. We found that the following code does not work for and EOF condition:

SetLL ( Key ) File;
DoU %EOF(File);
ReadE(E) ( Key ) File;

ExSr $$FilErr; (this subroutine contains an "If %Error" condition)

If %EOF(File);
Leave;
EndIf;

Delete FileRecordFormat;

EndDo;
What happens is the READE statement tries to acquire the record whose key is 7 (even though we are looking for the record whose key is 6) and since it is locked, a "lock error" occurs - instead of an "end-of-file" occurring! It seems that the READE has to acquire first the record whose key is 7, before it could check if the key of the acquired record is the key being searched.

Instead of an EOF condition occurring, what occurred was an error! It thought that the record being searched existed and was locked when in truth the record being searched was not really in the file. And because of the error that occurred, a rollback consequently occurred.

We have changed the code to:

SetLL ( Key ) File;
If %Equal( File );
DoU %EOF(File);
ReadE(E) ( Key ) File;

ExSr $$FilErr;

If %EOF(File);
Leave;
EndIf;

Delete FileRecordFormat;

EndDo;
EndIf;

Also, the code (for CHAIN as seen) below does not work too for the %Found condition:

C Key chain(E) File
C ExSr $$FILERR (again, this subroutine contains "If %Error" logic...)
c If %Found(File)
c (Do what's necessary here...)
c (Do what's necessary here...)
c EndIf

Like the READE, the CHAIN tries to acquire the record first before checking if it has acquired the record with the right key!

Does the READE (and the CHAIN) really behave this way? Or was the way it was coded really the culprit here?
Updated on 2013-02-01T14:30:41Z at 2013-02-01T14:30:41Z by barbara_morris
  • scott_klement
    scott_klement
    245 Posts

    Re: READE and CHAIN Gotchas

    ‏2013-02-01T13:52:07Z  
    SETLL sets %EQUAL and READE sets %EOF. So doing a SETLL and immediately checking %EOF will obviously not work right, as you point out.

    Personally, I prefer to code it like this:

    
    SETLL (key) FILE; READE (key) FILE; DOW not %EOF(); exsr DoTheWork; READE (key) FILE; ENDDO;
    


    Isn't that easier?
  • barbara_morris
    barbara_morris
    392 Posts

    Re: READE and CHAIN Gotchas

    ‏2013-02-01T14:30:41Z  
    SETLL sets %EQUAL and READE sets %EOF. So doing a SETLL and immediately checking %EOF will obviously not work right, as you point out.

    Personally, I prefer to code it like this:

    <pre class="jive-pre"> SETLL (key) FILE; READE (key) FILE; DOW not %EOF(); exsr DoTheWork; READE (key) FILE; ENDDO; </pre>

    Isn't that easier?
    SETLL does set off %EOF(filename) when it's successful. http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/topic/rzasd/sc092508839.htm#bbeof

    But there are two problems with assuming that a READE will be successful if %EOF(filename) is off after a SETLL:

    • %EOF(filename) is not changed when SETLL is not successful, so if the file was not already at %EOF before a not-found SETLL, it will still not be at %EOF after a not-found SETLL. (This scenario is probably quite rare for most applications.)

    • SETLL is considered successful when it positions the cursor at a record whose key is less than or equal to the specified key. SETLL sets %FOUND if the key is less than or equal, and %EQUAL when the key is equal. But it sets off %EOF(filename) in either case. (This scendario is quite common - if you have keys A B E F, and you do SETLL C, the file cursor will be positioned at E.)

    I usually code the way that Scott suggested too. But to avoid the record lock on the unwanted record, checking %EQUAL after the SETLL is good.

    Here's another way to code the loop that doesn't risk the record locks for unwanted records, or require the extra %EQUAL check. (But this is an unfamiliar design pattern for RPG programmers, so it might make the code less maintainable. I think that most RPG programmers would find it weird to check %STATUS instead of %FOUND or %EOF.)

    
    D IO_SUCCESSFUL    C              0   chain (key) FILE; dow %status(FILE) = IO_SUCCESSFUL; exsr DoTheWork; reade (key) FILE; enddo;