I do use global variables, maybe the word "a lot" is an exaggeration but the phrase "many times" springs to mind. There are just some SQL statements I build in an RPG program that does not allow me to use a local (RPG) variable. I can use the value contained within a global variable in its place.
I do have a few global variables I use for a single purpose, account number, company number, etc. There are times I just want to have somewhere to put a value into so that I can use it in a SQL statement. To accommodate this general functionality, I have created three "generic" global variables, that I can put miscellaneous values into and then use. One of the advantages of using a global variable is that the value is "local" to the job, i.e., the value in the global variable cannot be seen or used by another job. Therefore, once I have a generic global variable any job can use it, without the danger of overlaying the value from another job.
I decided to create three generic global variables.
The first is to contain any character value. I decided to make it a variable length character of 100 characters, as that would cover all of the scenarios I could think of where I would need a miscellaneous character value or values. I used the statements below to create this generic character global variable:
01 CREATE OR REPLACE VARIABLE MYLIB.GENERIC_CHARACTER 02 FOR SYSTEM NAME "GENCHAR" 03 VARCHAR(100) ; 04 LABEL ON VARIABLE MYLIB.GENERIC_CHARACTER IS 'Generic character global variable' ; |
Line 1: I always like to use the "CREATE OR REPLACE" as if the object exists this statement will replace it.
Line 2: Having given the object a long name, GENERIC_CHARACTER, I also was to give it a (short) system name too.
Line 3: The data type is VARCHAR.
I did not give a default value, therefore, the default value will be null.
Line 4: I want to give the global variable a label so that anyone looking at it will know its purpose.
The second I created to be decimal:
01 CREATE OR REPLACE VARIABLE MYLIB.GENERIC_DECIMAL 02 FOR SYSTEM NAME "GENDEC" 03 DEC(30,10) ; 04 LABEL ON VARIABLE MYLIB.GENERIC_DECIMAL IS 'Generic decimal global variable' ; |
Line 3: I deliberately made this bigger than any number I could think I would need.
Lastly is a timestamp global variable. I decided upon this data type as I could use it to contain a timestamp, date, or time value.
01 CREATE OR REPLACE VARIABLE MYLIB.GENERIC_TIMESTAMP 02 FOR SYSTEM NAME "GENTMESTP" 03 TIMESTAMP ; 04 LABEL ON VARIABLE MYLIB.GENERIC_TIMESTAMP IS 'Generic timestamp global variable' ; |
I can use the SQL SYSVARIABLES View to show the attributes of these generic global variables with the following statement:
01 SELECT VARIABLE_NAME,SYSTEM_VAR_NAME,VARIABLE_TEXT, 02 DATA_TYPE,LENGTH,NUMERIC_SCALE,DEFAULT 03 FROM QSYS2.SYSVARIABLES 04 WHERE SYSTEM_VAR_SCHEMA = 'MYLIB' |
Line 4: I only want to list the global variables in my library.
The results show the information about these new global variables.
SYSTEM
_VAR_ DATA_ NUMERIC
VARIABLE_NAME NAME VARIABLE_TEXT TYPE LENGTH _SCALE DEFAULT
----------------- ---------- -------------------- --------- ------- -------- -------
GENERIC_CHARACTER GENCHAR Generic character... VARCHAR 100 <NULL> <NULL>
GENERIC_DECIMAL GENDEC Generic decimal g... DECIMAL 30 10 <NULL>
GENERIC_TIMESTAMP GENTMESTP Generic timestamp... TIMESTAMP 10 <NULL> <NULL>
|
Using ACS's Run SQL Scripts, RSS, I can easily change and display the contents of the global variables:
01 SET MYLIB.GENCHAR = 'This is RPGPGPM.COM' ; 02 SET MYLIB.GENDEC = 12.5 ; 03 SET MYLIB.GENTMESTP = CURRENT_TIMESTAMP ; 04 VALUES(MYLIB.GENCHAR, 05 MYLIB.GENDEC, 06 MYLIB.GENTMESTP) ; |
Lines 1 – 3: I am using the SET statement to change the value of all the global variables.
Lines 4 – 6: I am using a VALUES statement to display the contents of the global variables.
The results are:
00001 00002 00003 ------------------- ------------- -------------------------- This is RPGPGPM.COM 12.5000000000 2025-11-21 18:06:44.489595 |
Playing with these in RSS does not demonstrate how I want to use them. Which is within programs, predominantly with RPG. The program below shows how I can move values in and out of the global variables:
01 **free 02 ctl-opt main(Main) option(*srcstmt) ; 03 dcl-proc Main ; 04 dcl-s CharacterValue char(50) ; 05 dcl-s DecimalValue packed(7 : 2) ; 06 dcl-s DateValue date ; 07 exec sql SET GENERIC_CHARACTER = 'This is RPGPGM.COM' ; 08 exec sql SET GENERIC_DECIMAL = 123.45 ; 09 exec sql SET GENERIC_TIMESTAMP = CURRENT_TIMESTAMP ; 10 exec sql SET :CharacterValue = GENERIC_CHARACTER ; 11 exec sql SET :DecimalValue = GENERIC_DECIMAL ; 12 exec sql SET :DateValue = DATE(GENERIC_TIMESTAMP) ; 13 dump(a) ; 14 return ; 15 end-proc ; |
Line 2: I am going to use a Main procedure as this is more efficient than using not using one, as without the Main procedure the RPG cycle is active.
Line 3: Start of the Main procedure, which ends at line 15.
Lines 4 – 6: Definition of the variables that will contain the values retrieved from the global variables. I have deliberately made them different sizes or types from the global variables.
Lines 7 – 9: I am moving values to each of the global variables using the SQL SET statement.
Lines 10 – 12: Having moved values into, these lines move the values contained in the global variables to different sized or typed variables using the SET statement. On line 12 I am retrieving the date from the timestamp in the global variable.
Line 13: I am using a DUMP operation to dump the contents of this program, including the values in all the variables.
Line 14: As I am not using the RPG cycle I can return from this program.
When I look at the generated dump spool file, QPPGMDMP, I can see the values I retrieved from the global variables:
CHARACTERVALUE CHAR(50) 'This is RPGPGM.COM DATEVALUE DATE(10) '2025-11-21' DECIMALVALUE PACKED(7,2) 00123.45 |
Let me give a more "real life" example, passing the output queue and its library to the DELETE_OLD_SPOOLED_FILES procedure. Below is the first "half" of the RPG program:
01 **free
02 ctl-opt main(Main) option(*srcstmt) ;
03 dcl-proc Main ;
04 dcl-s Library char(10) inz('QUSRSYS') ;
05 dcl-s Outq char(10) inz('MYOUTQ') ;
06 exec sql SET GENERIC_CHARACTER = :Library || :Outq ;
|
Lines 4 and 5: I have defined two variables, one for the name of the output queue and the other for the name of the library it is in. I have initialized both with the output queue name and library of the one I use.
Line 6: I am concatenating the two variables into the GENERIC_CHARACTER global variable.
If I had more than a couple of variables I would use a data structure. Below if an example of using a data structure:
04 dcl-ds DataStructure qualified ; 05 Library char(10) ; 06 Outq char(10) ; 07 end-ds ; 08 dcl-s DataVariable char(100) ; 09 DataStructure.Library = 'QUSRSYS' ; 10 DataStructure.Outq = 'MYOUTQ' ; 11 DataVariable = DataStructure ; 12 exec sql SET GENERIC_CHARACTER = :DataVariable ; |
Line 4 – 6: This is the definition of the data structure, containing subfields for the output queue name and its library.
Line 8: I cannot update global variables using a data structure. I can only use a host variable, this is the definition for it.
Lines 9 – 10: Updating the data structure subfields with the output queue and library names.
Line 11: Move the contents of the data structure to the variable. I made the variable 100 character to match the size of the global variable.
Line 12: I update the global variable with the contents of the variable.
The rest of the program is the same no matter how I loaded GENERIC_CHARACTER:
13 exec sql CALL SYSTOOLS.DELETE_OLD_SPOOLED_FILES( 14 DELETE_OLDER_THAN => CURRENT_TIMESTAMP, 15 P_OUTPUT_QUEUE_LIBRARY_NAME => SUBSTR(GENERIC_CHARACTER,1,10), 16 P_OUTPUT_QUEUE_NAME => SUBSTR(GENERIC_CHARACTER,11,10), 17 PREVIEW => 'NO') ; 18 return ; 19 end-proc ; |
Line 15: The output queue library name is substringed out of the global variable.
Line 16: The output queue name is substringed out of the global variable too.
I have found these generic global variables extremely useful, especially with SQL embedded in RPG. If you encounter the same kinds of problems with SQL statements not allowing local variables you could try this approach too.
This article was written for IBM i 7.6, and should work for some earlier releases too.



No comments:
Post a Comment
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.