Beruflich Dokumente
Kultur Dokumente
A sample chapter from Daniel Jacobs training SQL for RPG Programmers follows.
Learn some basic SQL terminology. Learn the syntax of the SQL statement compiler directive. Create a collection and table. Work with a simple SQL INSERT statement. Use host variables in the embedded SQL. Use the list objects system API with pointers. Compile ILE RPG modules and programs using embedded SQL. Complete a lab using an embedded SQL INSERT statement.
Files are called tables Records are called rows Fields are called columns
Thus, you have column names, not field names. You can access existing physical files, their records and fields using SQL. Just call them tables and rows and columns. Also, in a lot of AS/400 shops the term file pointer is used. A file pointer is some mysterious thing that presumably points to a particular record in an open data path. There are no file pointers in SQL. There are SQL cursors instead, which you will use in later chapters. There will probably be some more words to learn as you go along, but that is enough to get started.
The C/EXEC SQL and C/END-EXEC directives tell the RPG compiler that the lines between will be compiled by the SQL precompiler and executed at run time by the DB2 engine. The statement in between (DROP TABLE) can be any SQL statement that is allowed in the embedded RPG environment. You can have as many C+ lines as you need between the C/EXEC SQL and C/END-EXEC directives to complete your SQL statement. You can put only one SQL statement in an EXEC SQL and END-EXEC pair. However, you can use as many EXEC SQL and END-EXEC pairs as needed in your program, so you can have multiple embedded SQL statements in a program.
____ Enter the following SQL command at the SQL command line
CREATE COLLECTION RPG_SQLFOO
Note: you can enter SQL commands in upper or lower case. ____ Now go to an AS/400 command line and enter the command
WRKLIB RPG_SQLFOO
____ Enter option 12 (Work with objects) for the RPG_SQLFOO library to display the objects. ____ You should see a display similar to Figure 2. When you create a collection, SQL automatically adds the journal receiver, journal and system tables shown in the figure.
020005
Figure 2: The Work with Objects display for the RPG_SQLFOO library (collection).
____ Just for fun, start the SQL environment again (STRSQL) and enter the following SELECT statement for one of the tables in the collection:
SELECT * FROM RPG_SQLFOO/SYSCOLUMNS
Note: Before running the SELECT, you may want to press F13 from your SQL session screen, take option 1 from the menu and make sure that the second parameter (SELECT output) is set to 1. ____ You should see a screen of data, as shown in Figure 3.
020010
Figure 3: The output of the SELECT statement over the SYSCOLUMNS table.
Can you guess what is going on? Figure 2 shows the objects that were created when you ran the CREATE COLLECTION command. Along with the library named RPG_SQLFOO, the SQL engine created a journal and a journal receiver. Because commitment control (also referred to as transaction processing) is a standard part of the DB2 SQL implementation, the journal was created automatically. When you create a table in RPG_SQLFOO, you will see that it is automatically journalled to the RPG_SQLFOO journal. In addition to journal QSQJRN and its attached receiver, there are a several logical files. Those are actually SQL views. DB2 stores information about every database object in a set of tables that make up the catalog. There are tables to keep track of table names, indices, views, triggers, constraints in short, everything that can be created in SQL. In Figure 3, you see the column names that exist in every table in the RPG_SQLFOO Collection. Since you have not yet created any tables of your own, the column names belong to the catalog tables themselves.
10
____ You have just created an SQL table named TFOO in collection RPG_SQLFOO. The table has two columns, TCOL1 and TCOL2. TCOL1 is character length 5, and TCOL2 is decimal with two decimal places. TCOL2 cannot be null; if a row is created in TFOO without specifying the value of TCOL2 it will receive a default value of 0. ____ Enter the following command to view the SQL catalog view of the columns in the TFOO table:
SELECT * FROM RPG_SQLFOO/SYSCOLUMNS WHERE TABLE_NAME = 'TFOO'
020015
Figure 4: The SYSCOLUMNS table contains the names of the columns in the TFOO table.
The CREATE statement also allows for referential and check constraints. You will learn about constraints later in this manual.
11
____ Enter the following SQL statement to view the results of the INSERT statement:
SELECT * FROM RPG_SQLFOO/TFOO
020020
Figure 5: The SELECT statement displays the data that was added with the INSERT statement.
____ In a later chapter you will learn how to populate multiple rows in one table from one or more other tables with a single INSERT statement.
12
Notice the colon before the variable names. The colons inform the SQL compiler that the values are host variables. Now let's put everything together and use embedded SQL in a useful RPG program.
13
2.8 Lab 21 Use an INSERT statement and the List Objects API
Strictly speaking this book is not about OS/400 system APIs, nor about ILE RPG pointers. If those tools are not yet part of your toolset, you can still learn embedded SQL. A word of advice, however: system APIs and ILE RPG pointers should be a standard part of an advanced programmers toolset. So give it a shot! In this section youll work with an RPG program that uses embedded SQL and the List Objects system API. The program lists objects from a library name passed to it into a user space. It then loops through the list of objects in the user space and uses the SQL INSERT statement to insert some of the information retrieved by the API into an SQL table. For example, Figure 6 shows a sample of the data inserted into the table when the program is run to get the contents of the RPG_SQL library.
020025
Figure 6: The output of the POBJLIST program is data about objects in a library, inserted into the table with an SQL INSERT statement.
I adapted some code in this example from the excellent book iSeries & AS/400 APIs at Work by Doug Pence & Ron Hawkins1.
This book is available from Rochester Initiative (http://www.lab400.com) and Midrange Computing (http://www.mc-store.com). 14 Getting started: using the SQL INSERT statement
RPG_SQL/QRPGLESRC(CRTUSRSPC)
RPGLE
RPG module that contains procedure CrtUsrSpc to create a user space. RPG program that creates a user space, uses the List Objects API to write library objects to it, retrieves user space entries and uses an embedded SQL INSERT statement to enter data into a table.
RPG_SQL/QRPGLESRC(POBJLIST)
RPGLE
**************************************************************** * Local Variables **************************************************************** D UsrSpcAttr S 10 inz('LISTOBJ') D UsrSpcAuth S 10 inz('*CHANGE') D UsrSpcLen S 10I 0 inz(2048) D UsrSpcName S like(UsrSpc) D UsrSpcReplc S 10 inz('*YES') D UsrSpcText S 50 inz('For ListObjects API') D UsrSpcValue S 1 inz(x'00') D ErrorDs D BytesProvd D BytesAvail D MessageId D EReserved D EData DS 10I 0 inz(%len(EData)) 10I 0 inz(0) 7 1 40
(continues)
15
**************************************************************** * Set user space name to a variable for use on API calls. * Parms passed to APIs must be variables that can be modified. * UsrSpc is passed as "const" and cannot be modified. **************************************************************** C eval UsrSpcName = UsrSpc
**************************************************************** * Create the user space **************************************************************** C C C C C C C C C Call Parm Parm Parm Parm Parm Parm Parm Parm 'QUSCRTUS' UsrSpcName UsrSpcAttr UsrSpcLen UsrSpcValue UsrSpcAuth UsrSpcText UsrSpcReplc ErrorDs
**************************************************************** * Change user space to be extendable **************************************************************** C C C C C Call Parm Parm Parm Parm 'QUSCUSAT' Slib UsrSpcName ChgAttrDs ErrorDs
**************************************************************** * Get pointer to user space **************************************************************** C C C C P CrtUsrSpc E Call Parm Parm Return 'QUSPTRUS' UsrSpcName ListPtr ListPtr
16
QCUSCRTUS create the user space with the specified attributes QUSCUSAT change the user space attributes so that the user space is
extendable
Create the user space The QUSCRTUS API is used to create the user space. The user space is created with an initial length of 2048 bytes, initialized to the hexadecimal value x'00' (null character). Change user space attributes The QUSCUSAT API changes an attribute of the user space so it will be extendable. If the amount of data written to the user space is greater than 2048 bytes, the user space will be automatically extended. Get a pointer to the user space The QUSPTRUS API gets a pointer to the user space. The pointer points to the first byte in the user space. The pointer is returned to the caller of procedure.
17
**************************************************************** * General Header Data structure as copied from QUSGEN in * source file QSYSINC/QRPGLESRC **************************************************************** DQUSH0300 D* D QUSUA00 D* D QUSSGH00 D* D QUSSRL00 D* D QUSFN00 D* D QUSAU00 D* D QUSDTC00 D* D QUSIS00 D* D QUSSUS00 D* D QUSOIP00 D* DS 1 65 69 73 81 91 104 105 109 64 User Area 68B 0 Size Generic Header 72 Structure Release L 80 Format Name 90 Api Used 103 Date Time Created 104 Information Status 108B 0 Size User Space 112B 0 Offset Input Parame Based(GenHeaderPtr) Qus Generic Header
18
D QUSSIP00 D* D QUSOHS00 D* D QUSSHS00 D* D QUSOLD00 D* D QUSSLD00 D* D QUSNBRLE00 D* D QUSSEE00 D* D QUSSIDLE00 D* D QUSCID00 D* D QUSLID00 D* D QUSSLI00 D* D QUSRSV1 D* D QUSEPN D* D QUSRSV2 D*
113 117 121 125 129 133 137 141 145 147 150 151 193 449
116B 0 Size Input Paramete 120B 0 Offset Header Secti 124B 0 Size Header Section 128B 0 Offset List Data 132B 0 Size List Data 136B 0 Number List Entries 140B 0 Size Each Entry 144B 0 CCSID List Ent 146 Country ID 149 Language ID 150 Subset List Indicat 192 Reserved 1 448 Entry Point Name 576 Reserved 2
***************************************************************** * Type Definition for the OBJL0300 format ***************************************************************** DQUSL030000 DS Based(ListPtr) D* Qus OBJL0300 D QUSOBJNU01 1 10 D* Object Name Used D QUSOLNU01 11 20 D* Object Lib Name Used D QUSOBJTU01 21 30 D* Object Type Used D QUSIS02 31 31 D* Information Status D QUSEOA00 32 41 D* Extended Obj Attr D QUSTD07 42 91 D* Text Description D QUSUDA00 92 101 D* User Defined Attr D QUSERVED23 102 108 D* Reserved D QUSASP 109 112B 0 D* Aux Storage Pool D QUSOBJO 113 122 D* Object Owner D QUSOBJD 123 124 D* Object Domain
(continues)
19
132 Create Date Time 140 Change Date Time 150 Storage 151 Object Compress Status 152 Allow Change 153 Changed By Program 163 Object Audit Value 172
InLib
Load the list data structure eval do ListPtr = GenHeaderPtr + QUSOLD00 QUSNBRLE00
Process if the list entry has no problems, otherwise ignore it if exsr endif eval enddo eval return QUSIS02 = *blanks InsObjInf
*inlr = *on
20
INSERT INTO RPG_SQL/OBJINF VALUES ( :QUSOBJNU01, :QUSOLNU01, :QUSOBJTU01, :QUSOBJO, :QUSASP, :QUSORAGE )
endsr ***************************************************************** * Create the table, create the user space *****************************************************************
Setup
begsr
DROP
TABLE RPG_SQL/OBJINF
CREATE TABLE RPG_SQL/OBJINF (OBJNAM CHARACTER (10 ) NOT OBJLIB CHARACTER (10 ) NOT OBJTYP CHARACTER (10 ) NOT OBJOWN CHARACTER (10 ) NOT OBJSTGPL NUMERIC (5,0) NOT OBJSTG CHARACTER (10 ) NOT
C* create user space for file list information C C C eval eval eval SpaceName SpaceLib = USRSPC_NAME = USRSPC_LIB
GenHeaderPtr = CrtUsrSpc(UserSpace)
C* list objects to user space C C C C C C C** don't include C eval call parm parm parm parm parm endsr ObjNamLib = ALL + InLib 'QUSLOBJ' UserSpace ListFormat ObjNamLib ObjType QusEc
21
On the AS/400, there are two ways to refer to a table in a library when using embedded SQL. One way is shown in the program, the library/table format. This is the familiar format used in OS/400 and CL commands. It is not the way that SQL refers to the path to a table. SQL uses the syntax library.table. When you use SQL syntax, the compiler does not search the library list for tables; you must enter the complete path. However, the SQL naming syntax is what the rest of the universe, outside of the AS/400, uses. So if you are concerned about portable code and you don't need to use the library list, you may decide to use the SQL naming convention. The naming convention is specified on the CRTSQLRPGI command in the OPTION Parameter. In addition to several other values for the parameter, the default value *SYS is used to specify the system naming convention. To use the SQL naming convention, you specify *SQL in the parameter. For the purposes of this manual, I use the default of OS/400 system naming. Bottom line it's up to you. Just don't choose SQL naming and then specify library/table in your SQL code! It won't work!
Accepts an input parameter of a library name to list objects for Drops (deletes) and creates table RPG_SQL/OBJINF for use in the program Creates user space QTEMP/POBJLIST for use with the List Objects API Calls the QUSLOBJ (List Objects) API to list objects in the specified library to the user space Loops through the object list entries in the user space and inserts data from each list entry into table OBJINF
Procedure prototype The first thing the program does is declare a procedure prototype for the CrtUsrSpc procedure in the CRTUSRSPC module that you created in Section 2.8.2. Work fields and constants This section of the code is used to define work fields and constants used in the module. The constants USRSPC_NAME and USRSPC_LIB are used to set the values for the user space name and library. The actual value is set in data structure UserSpace, which is the field passed as a parameter to the CrtUsrSpc procedure.
22
Generic user space header When you use a list API like QUSLOBJ (as in this module), the API writes a data structure into the user space that contains header information. The header is followed in the user space by a repeating section containing the elements of the list. One of the elements in the header is the offset to the list element section. Thus the pointer to the user space plus the offset to the list section yields the address of the list section in the user space. Because the header information section is commonly used, IBM provides RPG source code that you can include in your programs to work with the header. The user space header is in one of two possible formats, which in RPG are described as data structures. In this program, the QUSH0300 format is used. The data structure is copied from source member QSYSINC/QRPGLESRC(QUSGEN). Note: library QSYSINC is installed as option 13 of OS/400, System Openness Includes. The keyword Based(GenHeaderPtr) at the start of the QUSH0300 data structure means that GenHeaderPtr is a pointer to the QUSH0300 data structure. You do not need to define GenHeaderPtr separately, as the compiler defines the pointer based on its usage here. The offset length is stored in subfield QUSOLD00 in QUSH0300. List format When you use a list API (for example, to list data about files, spool file, or objects), the API returns data about each object listed in a defined format. To make it easier to use the APIs, IBM provides definitions of the formats as ILE RPG data structures in source file QSYSINC/QRPGLESRC. Each API may have several different data structures associated with it. The data structure you use depends on how much information the API returns to your program. In this example, the QUSLOBJ API is used to return object information, so the data structure format used is QUSL030000. Variable ListPtr is defined as a pointer to the QUSL030000 data structure, simply by specifying Based(ListPtr) to the right of the data structure name. Main routine The program parameter InLib is used as the name of the library containing objects to be listed. The Setup subroutine is executed to create the user space and fill it with the list of objects in the specified library. Upon returning from Setup, pointer GenHeaderPtr points to the header section of the user space. By adding to it the offset to the element list section (field QUSOLD00), ListPtr will point to the first element in the list, describing the first object. QUSNBRLE00 contains the number of elements in the list. QUSIS02 has status information about the success of retrieving the list element; if the list element was retrieved successfully, its data is inserted into the table in subroutine InsObjInf. The variable QUSSEE00 contains the length of each list element. After processing the current element, ListPtr is incremented by QUSSEE00 so that it points to the next element in the list.
23
InsObjInf subroutine This subroutine contains an embedded SQL INSERT statement. The INSERT statement does not stipulate the column names because it inserts data into all the columns in the table (see the CREATE TABLE statement in subroutine Setup). The host variables contain the values being inserted. The host variable names are preceded by a colon (:). The INSERT statement is contained within the /EXEC SQL and /END-EXEC directives that delimit the SQL block. That's all there is to it. Don't forget the following! 1) The plus sign (+) after the C for each SQL continuation line. 2) The colon (:) before the name of each host variable (a host variable is any program defined field). 3) The comma between host variables. Dont put a trailing comma after the last variable, the compile fails if you do. Setup subroutine The Setup subroutine does a number of things:
Uses an SQL DROP TABLE statement to drop the existing OBJINF table, if it exists. Uses an SQL CREATE TABLE statement to create table RPG_SQL/OBJINF. Invokes the CrtUsrSpc function (in module CrtUsrSpc) to create user space QTEMP/POBJLIST. Calls the QUSLOBJ API to list objects in the specified library to the user space. User space name List format name (OBJL0300) Library containing objects to be listed Type of objects to list (*ALL)
List APIs are written very efficiently. You must tell the API how much information to return for each list element by specifying the list format name (the second parameter). You use different formats to return more or less information about the objects.
24
A word about the QUSEC standard error code data structure, which is commented out on the call to QUSLOBJ. QUSEC is an optional parameter for most APIs. In one of my tests, I left out the library name of the user space. Although the API was called with no apparent error, the objects were not being listed to the user space. Since I had included the optional error code data structure, the program did not blow up, and a status code told me the retrieval had been partially successful. I did not have any code to check the error data structure, and I couldn't figure out what was wrong. When I commented out the QUSEC parameter on the call to QUSLOBJ, recompiled and ran the program again, it immediately blew up at the offending line with a meaningful message in my job log. Moral of the story: either don't include the error code data structure at all, or check it in your code to see if there is a problem.
This command binds the modules CRTUSRSPC and POBJLIST to create program POBJLIST. The first module listed (POBJLIST) is considered to be the entry module, since the default value of the ENTMOD parameter is *FIRST. ____ Call the program to list the contents of the RPG_SQL library:
CALL PGM(RPG_SQL/POBJLIST) PARM('RPG_SQL')
____ Start the SQL environment with the STRSQL command. ____ Enter the following SQL statement in the SQL environment:
SELECT * FROM RPG_SQL/OBJINF
____ You should see a listing of objects in the library as shown in Figure 7 on page 26.
25
020045
Figure 7: The SELECT statement shows the rows in the OBJINF table.
26
6 18 30 30 18 2
____ Code an embedded SQL statement to drop table RPG_SQL/TVENDOR. ____ Code an embedded SQL statement to create table RPG_SQL/TVENDOR, defined as shown in the following table:
Name Data type Length Description
6 18 30 30 30 18 9 2
Vendor number Name Address 1 Address 2 City Country Postal code Credit rating
____ Use the eval opcode to load the following values into the host variables:
Variable Value
27
____ Code an embedded SQL INSERT statement to insert the host variables into the RPG_SQL/TVENDOR table columns. Note that because you are not inserting a value for every column (there is no value given to VAddress2 and VZip), the INSERT statement must use this syntax:
INSERT INTO RPG_SQL/TVENDOR ( :VNbr, ..., :VCreditRating) VALUES('ABCD', ..., 'A2')
Note that a list of columns is specified, then a list of values in the VALUES clause. ____ Compile the program using this command:
CRTSQLRPGI OBJ(RPG_SQL/TLAB22) SRCFILE(RPG_SQL/RPGLESRC) COMMIT(*NONE) CLOSQLCSR(*ENDMOD) DBGVIEW(*SOURCE)
Note: the CRTSQLRPGI command can create either a program or an ILE Module. The default for compiler parameter OBJTYPE is *PGM. ____ Call the program. ____ Enter the following select statement in the SQL environment (STRSQL) to view the table:
SELECT * FROM RPG_SQL/TVENDOR
____ You should see the results shown in Figure 8. Use F20 to shift the display to the right to see the remaining columns.
020035
Figure 8: The row added to the TVENDOR table (first four columns).
____ If you are uncertain what the code should look like, you can use source member RPG_SQL/QRPGLESRC(LAB22) as a guide. 28 Getting started: using the SQL INSERT statement