Wednesday, August 9, 2017

Resetting the value of a variable

using reset operation code to set value back to initialization value

One of my colleagues was reading the post about initializing variables when defining them and asked a question that I had not considered when writing that post.

"What if I change the value in the variable," he asked, "can I change it back to its original value?"

Fortunately there is in RPG an operation code that will do this. The RESET operation resets the value of any variable or record format back to the value it was at the initialization phase of the program. It is not new operation, I have used it for as long as I have programmed on the AS400 - IBM i.

Let me give some examples of using it. These are going to be in fully free format RPG, but can easily be retrofitted back to the old versions of the language.

01  dcl-s Var1 char(10) inz('Hello') ;

02  Var1 = 'Goodbye' ;

03  clear Var1 ;

04  reset Var1 ;

The above example is probably the simplest example I could create to demonstrate his operation code.

Line 1: When I define the variable I am initializing it with a value, the word "Hello".

Line 2: I change the value in the variable to "Goodbye".

Line 3: The CLEAR operation code clears the variable to blank, as this is a character field.

Line 4: When I use the RESET the value of the variable is restored to what it was at the initialization phase of the program. If I run the program in debug after this line has executed I can see the original value.

VAR1 = 'Hello     '

Let me make this a bit more complicated.

01  dcl-s Var1 char(10) inz('Hello') ;

02  Var1 = 'Goodbye' ;

03  clear Var1 ;

04  reset Var1 ;

05  begsr *inzsr ;
06    Var1 = 'Hi!' ;
07  endsr ;

This is the same program as my previous example, just with a subroutine added, lines 5 – 7. The initialization subroutine, *INZSR, is called automatically by the program at initialization time. There is never a EXSR for it. In this example I am moving the value "Hi!" to the variable.

If I run the program in debug after line 4 has executed I see:

VAR1 = 'Hi!       '

The value I initialized the variable with, in the definition, has been replaced by the value from the initialization subroutine, because the subroutine happens later in the program's initialization routines.

I can use the RESET with arrays and single occurrence data structures, if I have not initialized them with a value the reset will work like the CLEAR operation.

There is a parameter I must use to reset a multiple occurrence data structure in one statement:

01  dcl-ds MultiDs qualified occurs(2) ;
02    Subfield1 char(2) ;
03    subfield2 packed(2) inz(99) ;
04  end-ds ;

05  %occur(MultiDs) = 1 ;
06  MultiDs.Subfield1 = 'AA' ;
07  MultiDs.Subfield2 = 1 ;

08  %occur(MultiDs) = 2 ;
09  MultiDs.Subfield1 = 'BB' ;
10  MultiDs.Subfield2 = 2 ;

11  reset *all MultiDs ;

12  %occur(MultiDs) = 1 ;
13  %occur(MultiDs) = 2 ;

Lines 1 – 4: This is definition of my multiple occurrence data structure. Note this has to have an OCCURS keyword on line 1 to indicate this data structure has two occurrences. Subfield2 is initialized with the value 99.

Lines 5: In free format the OCCUR operation code has been replaced by the %OCCUR built in function. On this line I get the first occurrence of the data structure.

Lines 6 and 7: I move values to the subfields.

if I am running debug and I look at the data structure before line 8 I see:

EVAL multids
MULTIDS.SUBFIELD1 = 'AA'
MULTIDS.SUBFIELD2 = 01.

Line 8: I get the second occurrence of the data structure.

Lines 9 and 10: I move values to the subfields.

As I am running debug if I look at the data structure before line 11 I see:

EVAL multids
MULTIDS.SUBFIELD1 = 'BB'
MULTIDS.SUBFIELD2 = 02.

Line 11: This RESET has the *ALL. Without the *ALL the reset would only reinitialize the current occurrence of the data structure. The *ALL allows me to reinitialize all occurrences.

Line 12: I get the first occurrence again. After this line has executed as I am in debug when I look at the data structure is has been reinitialized.

EVAL multids
MULTIDS.SUBFIELD1 = '  '
MULTIDS.SUBFIELD2 = 99.

Line 13: I get the second occurrence and look at it in debug it contains the same as the first occurrence.

Note: I no longer use multi occurrence data structures as I believe that data structure arrays are easier to use and for other programmers to understand when working with my code.

I can all use RESET with files to reset fields back to the values they were at program initialization. In the following example I will be using a file called TESTFILE.

01  A          R TESTFILER
02  A            F1             3A
03  A            F2             3A
04  A            F3             3A
05  A            USER          10A
06  A            WRITTEN         Z
07  A          K F1

Line 2 and 7: F1 is the file's only key field.

Line 3 and 4: F2 and F3 are just other alphanumeric fields.

Line 5: USER will be the user id of the last person who wrote or updated the record.

Line 6: WRITTEN is the timestamp of when the record was written or updated.

Now I need to define this file in my RPG program.

01  dcl-s FixedUser char(10) inz(*user) ;
02  dcl-f TESTFILE usage(*output) ;


13  begsr *inzsr ;
14    F3 = 'ABC'
15    USER = FixedUser ;
16  endsr ;

Line 1: I have initialized the variable FixedUser with the user's profile.

Line 2: I have defined my file TESTFILE as output only.

Lines 13 – 16: This is another initialization subroutine. I am moving values into the file's fields F3 and USER.

Now for the first write to the file:

03  F1 = 'Y' ;
04  F2 = 'Z' ;
05  WRITTEN = %timestamp() ;

06  write TESTFILER ;

That is all straightforward and results in the following record in TESTFILE:

F1  F2  F3   USER    WRITTEN
Y   Z   ABC  SIMONH  2017-08-08-20.04.08.294000

Before the next write I am going to reset the record format.

07  reset *all TESTFILER ;
08  write TESTFILER ;

Then only two fields to contain values are the two that were used in the initialization subroutine.

F1  F2  F3   USER    WRITTEN
        ABC  SIMONH  0001-01-01-00.00.00.000000

There is another value I can use in the reset operation for files only. The *NOKEY preserves the file's key fields from being reset. For example:

09  F1 = 'A' ;
10  F2 = 'B' ;
11  reset *nokey *all TESTFILER ;
12  write TESTFILER ;

Line 11: *NOKEY must come before the *ALL for the program to compile.

After this write I can see that the file's key field, F1 was preserved as well as the fields that were set in the *INZSR.

F1  F2  F3   USER    WRITTEN
A       ABC  SIMONH  0001-01-01-00.00.00.000000

 

If I am initializing variables when defining them or in the initialization subroutine, *INZSR, the reset operation code becomes extremely useful in restoring the original values, allowing me to use them again. Rather than with a clear operation where I would have to move the default value back to the variable after it has been cleared.

 

You can learn more about the RESET operation code from the IBM website here.

 

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

5 comments:

  1. This is a great, comprehensive coverage. Thank you for putting t6his great resource together with simple to follow examples.

    ReplyDelete
  2. Another great publication. Thanks!

    One remark:
    In line 14, you probably changed F3 field (and not F2)
    13 begsr *inzsr ;
    14 F2 = 'ABC'
    15 USER = FixedUser ;
    16 endsr ;

    ReplyDelete
    Replies
    1. Good catch for finding that, and thank you for letting me know. I have made the correction.

      Delete
  3. I have used MODS to do an SQL multi-fetch. Is there a way to use an array instead?

    ReplyDelete
    Replies
    1. Using a data structure array is so much easier/simpler than using a multiple occurrence data structure.

      For more information see :

      SQL blocking fetches, getting more than one row at a time

      Creating a program to show jobs in message wait

      Delete

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.