Skip to main content

What is the importance of User Open (USROPN) in RPGLE - IBM i

User Open (USROPN)

USROPN (User Open) in RPGLE provides the flexibility for the programmer to open a file at a specific point in the program execution. In this post, let's explore what is the use of a USROPN and what is the importance of USROPN and how to use it with a simple example.

What is the use of USROPN?

By default, any file in the RPGLE (defined in F-Spec) opens as soon as the program execution is started and file is closed at the end of the program (by setting LR indicator ON).

A simple RPGLE program looks something like this on a high level with out the use of a USROPN. 

1

2

3

4

5

6

7

8

9

10

11

**Free                               

  Dcl-F TestFile;                    

                                     

  Setll *Start TestFile;             

  Read  TestFile;                    

  Dow   Not %Eof(TestFile);          

    // Operation required on a file  

    Read TestFile;                   

  EndDo;                             

                                     

  *InLr = *On;                       


In the above example, 
  • Line - 2: 'TestFile' would be opened in Read mode by default at the beginning of program execution. 
  • Line - 11: 'TestFile' would be closed at the end of the program on setting the LR indicator ON.
Defining USROPN keyword in the file definition, will avoid the file from automatic opening and closing of the file. 

So, How do we open the file? If not automatically opened. Open opcode can be used to open the file at a specific point and Close opcode can be used to close the file when required in the program. 

Let's have a look at an example using USROPN, Open and Close. 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

**Free                             

  Dcl-F TestFile USROPN;           

                                   

  If Not %Open(TestFile);          

    Open TestFile;                 

  EndIf;                           

                                   

  Setll *Start TestFile;           

  Read  TestFile;                  

  Dow   Not %Eof(TestFile);        

    // Operation required on a file

    Read TestFile;                 

  EndDo;                           

                                   

  If %Open(TestFile);              

    Close TestFile;                

  EndIf;                           

                                   

  *InLr = *On;                                          


In the above example, 
  • Line - 2: Declaring USROPN keyword against the file would prevent the file from automatically opening at the beginning. The same file has to be opened somewhere in the program, else compilation error would be thrown. 
  • Line - 5: Manually opening the file using the Open opcode. 
    • Line - 4 & 6: Enclosing the Open operation with in a if condition to check if the file is already open or not. 
    • %Open() BIF returns the status of a file, it returns Boolean '1' if the file is already open and Boolean '0' if the file is not open. 
    • This If condition would ensure Open is executed only if the file is not already open. 
    • Alternatively an extender 'E' can be used with Open followed by the if condition to check for the error (If %Error()). 
  • Line - 16: Manually closing the file using the Close opcode.
    • Line - 15 & 17: Enclosing the Close operation with in a if condition to check if the file is already open or not.  
    • This If condition would ensure Close is executed only if the file is already open. 
    • Alternatively an extender 'E' can be used with Open followed by the if condition to check for the error (If %Error()).

What is the importance of USROPN?

USROPN only prevents the file from automatically opening and nothing else. So, why is it so important? why not let the file just open automatically? Doesn't opening the file automatically make the code look better, easy to understand and maintain? 

Absolutely Yes, USROPN may not necessarily be used if all we are doing is to just open the file in the beginning of the program and close the file just before the end of the program. 

However, there are many scenarios where USROPN becomes essential. Below are a couple of scenarios to note, there could be many more.
  • If the file is a multi-member file and a specific member needs to be opened. 
  • If the file is a temporary file that get's created in the same program and is deleted in the same program. 
Let's look at each of these scenarios.

If the file is a multi-member file

Let's consider a multi-member file and we need to read records from a specific member of a file, It does not necessarily need USROPN, like in the example below. 

1

2

3

4

5

6

7

8

9

10

11

12

**Free                             

  Dcl-F TestFile ExtMbr(‘MEMBER1’);           

                      

  Setll *Start TestFile;           

  Read  TestFile;                  

  Dow   Not %Eof(TestFile);        

    // Operation required on a file

    Read TestFile;                 

  EndDo;                           

                                   

  *InLr = *On;                                          


In this case, RPGLE program opens the file (and member 'MEMBER1') at the beginning of the program with out any issue. 

Challenge is when we need to open multiple members in the same program (i.e., Open MEMBER1 and do some processing, Open MEMBER2 and do some other processing). We could compare this to something like having a transaction file with each month's data in a different member and open each month's data and process month by month. 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

**Free                              

  Dcl-F TestFile ExtMbr(MemberName)

               USROPN;

                                    

  Dcl-S MemberName Char(10);        

                       

  // Open MEMBER1             

  MemberName = 'MEMBER1';                        

  If Not %Open(TestFile);          

    Open TestFile;                 

  EndIf;                           

                                   

  Setll *Start TestFile;           

  Read  TestFile;                  

  Dow   Not %Eof(TestFile);        

    // Operation required on a file

    Read TestFile;                 

  EndDo;                           

            

// Close MEMBER1                       

  If %Open(TestFile);              

    Close TestFile;                

  EndIf;                           


// Open MEMBER2

  MemberName = 'MEMBER2';                        

  If Not %Open(TestFile);          

    Open TestFile;                 

  EndIf;                           

                                   

  Setll *Start TestFile;           

  Read  TestFile;                  

  Dow   Not %Eof(TestFile);        

    // Operation required on a file

    Read TestFile;                 

  EndDo;                           

            

// Close MEMBER2                       

  If %Open(TestFile);              

    Close TestFile;                

  EndIf;                           

                                   

  *InLr = *On;                                          


In this example, 
  • Line - 2: We have declared a file with a variable MemberName passed to the EXTMBR keyword. This variable would determine which member of the file needs to be opened when Open is issued in the program. 
  • Line - 3: USROPN keyword indicating the program to not open the file automatically. 
  • Line - 8: Populating the variable MemberName with the member that needs to be opened (i.e., MEMBER1 in this case). 
    • This is followed by the lines 9 to 24 that involves opening the file with MEMBER1, read the file and do some processing and close the file. 
  • Line - 26: Populating the variable MemberName with the member that needs to be opened (i.e., MEMBER2 in this case). 
    • This is followed by the lines 9 to 24 that involves opening the file with MEMBER2, read the file and do some processing and close the file. 
  • There is a plenty of duplicate code left like that for easier understanding, this can be better managed using sub routines. 

If the file is a temporary file

Let's consider a temporary file which gets created during the program processing. 

As an extension to the previous example, Suppose we actually don't know the member names of TESTFILE to explicitly code. We could create a temporary file that could dump all of the member names of a file and reading that file to get the member name. 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

**Free                                                

  Dcl-F AllMbrs ExtFile(FileName)                     

                USROPN;                               

                                                      

  Dcl-S FileName Char(21);                            

                                                      

  Dcl-PR ExecuteCommand ExtPgm('QCMDEXC');            

    Command Char(100);                                

    CommandLength Packed(15 : 5);                     

  End-PR;                                             

                                                      

  Dcl-S Command Char(100);                            

  Dcl-S CommandLength Packed(15 : 5);                 

           

  // Creating a temporary file                                           

  FileName = 'QTEMP/ALLMBRS';                         

  Command = 'DSPFD FILE(PANGAP/TESTFILE) TYPE(*MBR) ' 

          + 'OUTPUT(*OUTFILE) OUTFILE(QTEMP/ALLMBRS)';

  CommandLength = %Len(Command);                      

  ExecuteCommand(Command : CommandLength);            

                                                                              

  If Not %Open(AllMbrs);            

    Open AllMbrs;                   

  EndIf;                            

                                    

  Setll *Start AllMbrs;             

  Read  AllMbrs;                    

  Dow   Not %Eof(AllMbrs);          

    // Maybe plug in the logic from previous

// to populate the member name and open

// the TESTFILE, process and close for

// each member of the file.

// File declaration also to be copied.

    Read AllMbrs;                   

  EndDo;                            

                                    

  If %Open(AllMbrs);                

    Close AllMbrs;                  

  EndIf;                            

                                    

  *InLr = *On;                      



In the above example, 
  • Line - 2: File is defined by using the keyword EXTFILE and passing the variable FileName. This would let the programmer to populate the FileName that is to be opened when file is opened during the program. 
    • Please note that the file needs to be present at the time of compilation.
  • Line - 3: USROPN key on the file to indicate the file not to be automatically opened. 
  • Lines - 16 - 20: Create a temporary file and populating the file name to the variable FileName. 
  • Lines - 22 - 39: To open the file, read, process and close the file. 
These are just a couple of examples to help understand the USROPN better. There could be many more use cases. 

I hope this post has been a bit of help in understanding what is the importance of USROPN.


If you have any Suggestions or Feedback, Please leave a comment below or use Contact Form.

Comments

Popular posts from this blog

All about READ in RPGLE & Why we use it with SETLL/SETGT?

READ READ is one of the most used Opcodes in RPGLE. As the name suggests main purpose of this Opcode is to read a record from Database file. What are the different READ Opcodes? To list, Below are the five Opcodes.  READ - Read a Record READC - Read Next Changed Record READE - Read Equal Key Record READP - Read Prior Record READPE - Read Prior Equal Record We will see more about each of these later in this article. Before that, We will see a bit about SETLL/SETGT .  SETLL (Set Lower Limit) SETLL accepts Key Fields or Relative Record Number (RRN) as Search Arguments and positions the file at the Corresponding Record (or Next Record if exact match isn't found).  SETGT (Set Greater Than) SETGT accepts Key Fields or Relative Record Number (RRN) as Search Arguments and positions the file at the Next Record (Greater Than the Key value). Syntax: SETLL SEARCH-ARGUMENTS/KEYFIELDS FILENAME SETGT  SEARCH-ARGUMENTS/KEYFIELDS FILENAME One of the below can be passed as Search Arguments. Key Fiel

What we need to know about CHAIN (RPGLE) & How is it different from READ?

CHAIN READ & CHAIN, These are one of the most used (& useful) Opcodes by any RPG developer. These Opcodes are used to read a record from file. So, What's the difference between CHAIN & READ?   CHAIN operation retrieves a record based on the Key specified. It's more like Retrieving Random record from a Database file based on the Key fields.  READ operation reads the record currently pointed to from a Database file. There are multiple Opcodes that start with READ and all are used to read a record but with slight difference. We will see more about different Opcodes and How they are different from each other (and CHAIN) in another article. Few differences to note.  CHAIN requires Key fields to read a record where as READ would read the record currently pointed to (SETLL or SETGT are used to point a Record).  If there are multiple records with the same Key data, CHAIN would return the same record every time. READE can be used to read all the records with the specified Ke

Extract a portion of a Date/Time/Timestamp in RPGLE - IBM i

%SUBDT Extracting Year, Month, Day, Hour, Minutes, Seconds or Milli seconds of a given Date/Time/Timestamp is required most of the times.  This can be extracted easily by using %SUBDT. BIF name looks more similar to %SUBST which is used to extract a portion of string by passing from and two positions of the original string. Instead, We would need to pass a value (i.e., Date, Time or Timestamp ) and Unit (i.e., *YEARS, *MONTHS, *DAYS, *HOURS, *MINUTES, *SECONDS or *MSECONDS) to %SUBDT.  Valid unit should be passed for the type of the value passed. Below are the valid values for each type. Date - *DAYS, *MONTHS, *YEARS Time - *HOURS, *MINUTES, *SECONDS Timestamp - *DAYS, *MONTHS, *YEARS, *HOURS, *MINUTES, *SECONDS, *MSECONDS Syntax: %SUBDT(value : unit { : digits { : decpos} }) Value and Unit are the mandatory arguments.  Digits and Decimal positions are optional and can only be used with *SECONDS for Timestamp. We can either pass the full form for the unit or use the short form. Below i