Wednesday, July 15, 2015

Read operation code extenders

read operations reade readpe readp readc chain and operation code extenders

Operation code extenders on a Read operation in RPG are those letters that are follow the operation code in parentheses. I am sure the two most commonly known ones are:

  read(e) TESTFILE ;
  reade(n) (KeyField) TESTFILE ;

Each one provides a little bit extra functionality that compliments the Read operation. On performing research for this post I found that with free format Read operations a number of additional extenders were added, some are available with only some of the Read operations in V5R4 and later releases.

The operation codes extenders available for read operations are:

  • E – Error handling
  • N – Record is read but not locked
  • H – Half adjust is performed on the numeric value
  • M – Default precision rules for numeric values
  • R – "Result decimal position" precision rules

This table shows each of the read operations and the extenders that can be used with it. And I am including Chain, CHAIN, as a read operation as it is just the same as a Set lower limit, SETLL, and a Read equal, READE, combined into one operation.

Operation code   E     N     H     M     R  
Fixed format RPG
READ - Read Y Y
READE – Read equal Y Y
READP – Read prior Y Y
READPE – Read prior equal Y Y
READC – Read changed record Y
CHAIN - Chain Y Y
Free format RPG
READ - Read Y Y
READE – Read equal Y Y Y Y Y
READP – Read prior Y Y
READPE – Read prior equal Y Y Y Y Y
READC – Read changed record Y
CHAIN - Chain Y Y Y Y Y

 

Error (E) operation code extender

This must be the most widely used operation extender as it is available not just to the Read operations, but to many others operations codes too. By using the E when an error occurs with the read the Error flag, %ERROR, is set on. I can then use the subfields in the Program Data Structure to determine what the error was. For example:

01  dcl-ds PgmDs
02    extname('RPG4DS') psds qualified
03  end-ds ;
                                      
04  dcl-f TESTFILE usage(*update) keyed ;
                                      
05  dcl-s Key1 like(FLD1) inz(123.45) ;

06  chain(e) (Key1) TESTFILER ;

07  if (%found) ;
08    dsply ('Found = ' + FLD2) ;
09  elseif (%error) ;
10    dsply (%subst(PgmDs.RtvExcptdt:1:52)) ;
11  endif ;

Those of you who are familiar with my code know that I like to use an external file for my Program data structure. If you want to learn more about how I do this see the post Externally described Data Structures. In this example I have included this external data structure in lines 1 -3. As I am only interested in the Retrieved Exception Data I could have code it as an internal data structure like this:

01  dcl-ds PgmDs psds qualified ;
02    RtvExcptDt char(80) pos(91) ;
03  end-ds ;

On line 4 I have defined by file, TESTFILE, for update and with a key.

I have defined a variable on line 5 to be the same as the key field in TESTFILE, and initialized it with the value 123.45.

The record with the key 123.45 is locked by another job. So when I perform the chain, on line 6, as the record is locked the chain will fail and the %ERROR flag will come on. As the %FOUND flag is off, line 7, the next test is for %ERROR on line 9. As this is an error I display what is basically the error text for the lock by using the Retrieved Exception Data field, RtvExcptDt. Alas the DSPLY operation will only display 52 character of text, therefore, I use the substring built in function, %SUBST to display the first 52 characters.

  DSPLY  Record 1 in use by job 843726/SUSIEQ/QPADEV0002.

While this way works well I prefer to use the Monitor operation code in my code. You can learn about it in Monitor for errors in RPG.

 

Record is read but not locked (N) operation code extender

This is the extender I use the most with Read operations.

If the input file is coded for update any record that is read is locked until it is released, either by another read of the same file or by using the Unlock operation code, UNLOCK. If the file is read in a Do loop or a For group the last record read is locked.

If I use the operation code extender N the record I read is not locked. Why would I do this? I could have a file maintenance program. I need to write records from the file to a subfile, and when one of the subfile records is selected update that record in the file. OK, this example is a bit unreal as I am not going to add records to the file, but I am sure you will get the idea.

01  dcl-f TESTFILE usage(*update) keyed ;

02  for RRN1 = 1 to 10 ;
03    read(n) TESTFILER ;
04    if (%eof) ;
05      leave ;
06    endif ;
                        
07  endfor ;


08  chain (Key1) TESTFILER ;


09  if (UpdateRecord) ;
10    update TESTFILER ;
11  else ;
12    unlock TESTFILE ;
13  endif ;

It will to come to no surprise to regular readers that I am using TESTFILE again, line 1. It is coded for update and is keyed.

I am performing 10 reads, lines 2 – 7, using a For operation, FOR, as if I am loading a subfile. The read on line 3 has the N operation code extender so records are not locked when they are read. This is important as if I had not used the N the last record read would still be locked when I exit this For group.

When I select a record in the subfile I have to chain the file to get the record selected, line 8. This time I want the record locked as I am going to update it.

After making the changes I desire I would press Enter and the indicator variable UpdateRecord would be set on, or I would have pressed F12 to return and UpdateRecord would be off. If UpdateRecord is on, line 9, then the update is performed on line 10. If UpdateRecord is off I need to release the locked record, which I do using the UNLOCK, line 12.

 

The other operation code extenders

Using the other three operation extenders, H, M and R, sounds a little bit weird and freaky to me. I do struggle to come up with a scenario where I would consider using them, rather than move the value I want to use as a key into a variable which I would then use as the key field.

The key field in the file TESTFILE, FLD1, is a packed field, see below.

A          R TESTFILER
A            FLD1           5P 2
A            FLD2           5A
A          K FLD1

If I Chain to TESTFILE using 123.449 as the key with the half adjust operation extender it will round 123.449 to 123.45 which is the value of the one of the key fields in the file, line 1 below. As the Chain is successful, %FOUND is on, then I will display the value in FLD2.

01  chain(h) (123.449) TESTFILER ;

02  if (%found) ;
03    dsply ('Found = ' + FLD2) ;
04  endif ;

Rather than use a value as the key I could use a variable that has more decimal places than the key field instead:

01  dcl-s Key1 packed(6:3) inz(123.499) ;

02  chain(h) (Key1) TESTFILER ;

03  if (%found) ;
04    dsply ('Found = ' + FLD2) ;
05  endif ;

As I said I am not sure if I will ever use this, but it is out there for you to use if you so choose.

 

You can learn more about this on the IBM website:

 

This article was written for IBM i 7.2, and should work for earlier releases too.


Clarification

I have received several messages about how the H, M, and R operation codes go back to before V5R4. I agree these operation extenders are not new to the RPG language. I can recall using the M when RPGLE was first launched, and have used all of these with the EVAL operation code with many releases of the operating system.

What I am meaning in this post is that these operation extenders are new, since V5R4, to being used with the Read operation codes.

2 comments:

  1. I always code the (N) extender when I don't want to lock the row, even if the table is INPUT only. Now why would I do this? Because if the table ever needs to be changed to UPDATE someday in that program by me or another developer (yes, it happens), then they have to hunt down all the reads / chains and add (n) later. If they *don't* think to do this, then it will cause record lock errors soon after installing that change to production. The (N) future proofs the code.

    Chris Ringer

    ReplyDelete
  2. 1. When using the built-in-functions %Found, %Equal and %EOF without specifying a file name (in parenthesis) always the result of the last READ or CHAIN is checked. In this way you should get into the habit to always specifying the file name for which the built-in-function is checked.

    2. When performing inserts, updates or deletes under commitment control, neither the extender (N) nor the UNLOCK operation code will free a record locked under commitment control. Instead after the record wait time (default 60 seconds) an error is returned.
    In this way it would be better to read the records as input first and then try to chain (as update file) immediately before updating the record.

    Birgitta

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.