DB2 REXX SQL for VM/ESA(R): Installation and Reference


Appendix F. Sample Programs with Examples of RXSQL Requests

The example programs in this section describe how to write a set of REXX programs that create a table, insert data into it, and make queries on the table.


Examples Using RXSQL Requests

The first example program shows a REXX program that can be used to create the table named RXEMP. Figure 42 shows a sample input file that can be used to create the RXEMP table. The RXEMP table consists of columns with the headings EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, PHONENO, HIREDATE, JOB, EDLEVEL, SEX, BIRTHDATE, SALARY, BONUS, and COMMISSION

Figure 42. Example of Input File EMPLOYEE INPUT

002130 GARY    M  SAMS      B12  5643  1969-10-01  MANAGER   17  M  1956-11-21  41700  900  4130
002300 JANET   L  HEDGLEY   B09  2345  1972-12-15  ANALYST   16  F  1963-06-01  37900  800  3178
001010 RON     A  LOWRY     D14  2313  1978-01-15  ANALYST   20  M  1959-09-17  38240  600  3000
000990 RANDY   M  SCHENKER  A07  1430  1983-03-22  OPERATOR  15  M  1960-12-17  30190  700  2660
002020 TERRY   A  RAINEY    D11  3243  1989-09-05  DESIGNER  20  M  1967-09-13  32560  500  2408
001840 PAUL    P  CORDON    B09  7070  1985-07-21  FILEREP   18  M  1965-03-05  28090  600  3090
002330 LES     H  FABER     A10  2119  1977-03-18  CLERK     14  M  1952-02-25  27800  400  1777
009236 HEATHER B  DOBSON    D08  3467  1979-04-03  WRITER    16  F  1964-05-31  37600  800  2900
002574 JAY     Q  MERCIER   A11  2946  1991-05-06  WRITER    15  M  1971-09-22  33400  600  2650
003567 DICK    E  SCHMIDT   C04  3847  1972-11-17  CLERK     14  M  1960-12-03  25790  500  2540
002419 HARRY   P  ATWALA    A07  9127  1980-10-28  OPERATOR  16  M  1962-10-30  37940  800  3105
003326 MARY    K  GOODBAR   B09  3943  1974-07-13  MANAGER   18  F  1959-02-25  40360  900  3980
003589 STEVE   S  GOULD     D07  3565  1976-06-12  WRITER    17  M  1956-04-25  39250  350  3050

Creating Tables and Inserting Data

Figure 43 is an example of how to use DB2 RXSQL to create a table and how to insert data rows in it.

Figure 43. Program to Create a Table and Insert Data

/* EMPCRE */
/*   5697-F42 (C) Copyright IBM Corp. 1973, 2000.                      */
/*   All rights reserved.                                              */
/*   US Government Users Restricted Rights -                           */
/*   Use, duplication or disclosure restricted by                      */
/*   GSA ADP Schedule Contract with IBM Corp.                          */
/*                                                                     */
/*   Licensed Materials - Property of IBM                              */
 
/* An exec to create a table and a view of the table in SQL to control */
/* employee information.                                               */
/* Data from a file "EMPLOYEE INPUT" is loaded into the table          */
Address 'COMMAND'(1)
 
 
/* Define the data structure of the table to create                    */
 
creat_emp = 'CREATE TABLE RXEMP (',(2)
                    'EMPNO       CHAR(6) NOT NULL,',
                    'FIRSTNME    VARCHAR(12) NOT NULL,',
                    'MIDINIT     CHAR(1) NOT NULL,',
                    'LASTNAME    VARCHAR(15) NOT NULL,',
                    'WORKDEPT    CHAR(3),',
                    'PHONENO     CHAR(4),',
                    'HIREDATE    DATE,',
                    'JOB         CHAR(8),',
                    'EDLEVEL     SMALLINT NOT NULL,',
                    'SEX         CHAR(1),',
                    'BIRTHDATE   DATE,',
                    'SALARY      DECIMAL(9,2),',
                    'BONUS       DECIMAL(9,2),',
                    'COMM        DECIMAL(9,2) )' (3)
 
'RXSQL EXEC'  creat_emp(4)            /* Create the table  */
If rc <> 0 then Signal 'ERROR' (5)
 
view = 'CREATE VIEW EMPVIEW (EMPNO, FIRSTNME, MIDINIT, LASTNAME, JOB,',
       'EDLEVEL, SALARY)',
       'AS SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, JOB, EDLEVEL,',
       'SALARY FROM RXEMP'
 
'RXSQL EXEC'  view                            /* Create the view  */
If rc <> 0 then Signal 'ERROR'
 
/* Define the insert statement to fill in rows of the table */
 
ins_emp = 'INSERT INTO RXEMP VALUES (', (6)
              ':emp,:fname,:mid,:lname,:wdpt,:ph,:hire,:job,',
              ':ed,:sex,:birth,:sal,:bon,:comm )'
 
'RXSQL PREP IEMP'  ins_emp(7)         /* Prepare the INSERT statement */
If rc <> 0 then Signal 'ERROR'
Do Forever                                    /* Input data to the table */
   'EXECIO 1 DISKR EMPLOYEE INPUT * (LIFO' (8)  /* Read from file */
   If rc <> 0 then Leave (9)
   /* Get the data into REXX variables */
   Parse Upper Pull emp fname mid lname wdpt ph hire job,
                    ed sex birth sal bon comm .(10)
   If emp = '' then Iterate (11)       /* Check for Blank record              */
   emp = "'"emp"'" (12)                /* Make sure it is a char string so    */
   fname = "'"fname"'"                 /* RXSQL does not change numeric chars */
   mid = "'"mid"'"                     /* to numeric type input type.         */
   lname = "'"lname"'"
   wdpt = "'"wdpt"'"
   ph = "'"ph"'"
   hire= "'"hire"'"
   job = "'"job"'"
   sex = "'"sex"'"
   birth = "'"birth"'"
 
   'RXSQL CALL IEMP' (13)              /* Call the prepared INSERT statement */
   If rc <> 0 then Signal 'ERROR'
End
 
 
'FINIS EMPLOYEE INPUT *'               /* Close input file         */
'RXSQL COMMIT' (14)                    /* Commit the inserted data */
'RXSQL PURGE IEMP' (15)                /* Purge prepared statement */
If rc = 0 then Exit
 

ERROR: /* A severe error occurred */
/* Forget all inserted data so far */
errrc = rc
If errrc >= 100 then Do (16)
Say ' RXSQL Error:' errrc rxsqlmsg
'RXSQL ROLLBACK'
End
Else If errrc = 4 | errrc = 8 then Do (17)
Say ' Sqlcode:' sqlcode (18)
Say ' Sqlstate:' sqlstate
Do errd = 1 to 6
If sqlerrd.errd <> 0 then Say ' Sqlerrd.'errd':' sqlerrd.errd
End
If sqlerrp <> '' then Say ' Sqlerrp:' sqlerrp
If sqlerrm <> '' then Say ' Sqlerrm:' sqlerrm
If sqlwarn <> '' then Say ' Sqlwarn:' "'"sqlwarn"'"
If sqlcode < 0 & "INDEX"('WS',"SUBSTR"(sqlwarn,7,1)) = 0 then (19)
'RXSQL ROLLBACK'
End
Exit errrc (20)

Notes for EMPCRE Program

The following notes refer to the lines in the EMPCRE program identified by reverse video numbers in Figure 43:

(1)
Address COMMAND causes REXX to pass command lines directly to a module without searching for a program of the same name. You should include Address COMMAND in your programs for performance reasons.

(2)
The comma at the end of the line causes REXX to concatenate the current line and the one that follows, replacing the comma with a blank. Using a comma for concatenation allows you to build long SQL statements.

(3)
This CREATE statement does not include an IN dbspace_name phrase. As a result, SQL chooses a PRIVATE DBSPACE for the table. To explicitly select a particular dbspace, use the IN dbspace_name phrase.

(4)
REXX expands the creat_emp variable and passes it to DB2 RXSQL as part of the command. DB2 RXSQL passes the statement to SQL for processing.

(5)
The REXX variable rc is set with the return code from DB2 RXSQL. If REXX, DB2 RXSQL, or the database manager indicates an error, this program (at label ERROR) displays all the error variables set by DB2 RXSQL, and then ends processing.

(6)
The names of the REXX variables are preceded by colons. They hold the values to be inserted into the fields of the RXEMP table.

(7)
This RXSQL PREP statement prepares the INSERT statement and gives it the name IEMP. DB2 RXSQL stores all the input variable names until the CALL request is made.

(8)
EXECIO is a CMS command to read a line from the EMPLOYEE INPUT file and put it on the program stack in last-in-first-out (LIFO) order.

(9)
The loop ends when the EXECIO command has an error (assumed to be end-of-file).

(10)
Parse Upper Pull gets the line read by EXECIO from the program stack. Each token in the line is assigned to the variables emp, fname, mid, lname, wdpt, ph, hire, job, ed, sex, birth, sal, bon, and comm respectively. The period after comm causes REXX to ignore any extra tokens on the line. Without the period, comm is set with all the characters remaining in the record, including trailing blanks.

(11)
If the record is all blank, the loop iterates and the program ignores the record.

(12)
The values emp, fname, mid, lname, wdpt, ph, hire, job, sex, and birth are put into quotation marks to ensure that DB2 RXSQL does not interpret the values as numeric. DB2 RXSQL removes the quotation marks before sending the values to the database manager on the CALL request.

(13)
The CALL request executes the IEMP statement prepared earlier. The input variables, held since the PREP statement (see line (7)), are converted from REXX variable values to SQL input data.

(14)
Processing reaches this point only if no errors occurred. The RXSQL COMMIT statement commits all data inserted in the database.

(15)
This RXSQL PURGE statement removes the prepared SQL statement named IEMP.

(16)
Processing reaches this point only if the program encounters a non-zero return code. This line checks for a DB2 RXSQL error (a number greater than 99). If the return code is greater than 99, the program displays the rxsqlmsg variable (a textual description of the error that occurred). The RXSQL ROLLBACK statement cancels any changes made to the database.

(17)
If the return code is not an RXSQL error, the program checks whether the return code is an SQL return code of 4 or 8. A return code of 4 indicates an SQL warning. A return code of 8 indicates an SQL error.

(18)
This line begins processing the SQL error indicator variables that display the following information:

sqlcode
The primary SQL error code.   You can issue the EXEC RXSQLHLP sqlcode command to determine the meaning of the displayed code.

sqlstate
Error codes common to all distributed relational databases.

sqlerrd.1 - sqlerrd.6
The secondary error codes and other information.

sqlerrp
The SQL module that detected the error.

sqlerrm
The values to be substituted into the error message text.   See the DB2 Server for VM Messages and Codes manual for full error text.

sqlwarn
Eleven characters of error indicators.   For a more detailed explanation of sqlwarn, see page ***.

(19)
When the database manager cancels a transaction, it sets the seventh character of sqlwarn to W or S. This line checks whether the database manager has canceled the transaction or not by checking the value of the seventh character of sqlwarn. If the value is not W or S, the program issues an explicit DB2 RXSQL ROLLBACK command to cancel any changes to the database.

(20)
If the program encounters an error, it finishes processing and exits to VM.
Note:You can create a more sophisticated program to handle both recoverable situations and unrecoverable situations.

Retrieving Data from a Table

Figure 44 shows a REXX program that you can use to retrieve data from the table created by the EMPCRE program.

Figure 44. Program to Select Data from an SQL Table

/* EMPSEL */
/*   5697-F42 (C) COPYRIGHT IBM CORP. 1990, 2000.   */
/*   Licensed material - Program Property of IBM    */
/*   Refer to copyright instructions form G120-2083 */
 
/* An exec to display employees with a salary less then some amount */
/* Defaults: ANALYSTs with a salary less than $38,000               */
Address 'COMMAND'
 
Parse Upper Arg job salary . (1)
If job = '' then job = 'ANALYST'(2)
Else job = "'"job"'" (3)               /* Make sure it is char type */
If salary = '' then salary = 38000 (4)
 
/* Define the select statement to pick part of the data from DB2 Server for VM */
 
sel_emp = 'SELECT * FROM EMPVIEW WHERE SALARY < :salary AND JOB = :job'(5)
 
'RXSQL PREP SELEMP' sel_emp (6)        /* Prepare the SELECT statement */
if rc<>0 then signal 'ERROR'
'RXSQL OPEN SELEMP' (7)                /* Open the SELECT statement */
if rc<>0 then signal 'ERROR'
 
If rc = 0 then Do                      /* If no errors occurred then */
   Do Forever                          /*   Get data from the table */
 
      /* Get the data into REXX variables from DB2 Server for VM */
      'RXSQL FETCH SELEMP emp fname mid lname job ed sal' (8)
      If (rc = 4 & SQLCODE = 100)  then Leave (9) /* If there is no more */
      Else If rc <> 0 then Signal 'ERROR'     /* If there is an error */
 
      /* Check for Nulls */
      If "SYMBOL"('job') <> 'VAR' then job = '?' (10)
      If "SYMBOL"('sal') <> 'VAR' then sal = '?'
 
      /* Type the data on the users terminal */
      Say 'Employee: 'emp '    ' fname mid lname
      Say 'Job:'job'    Education:'ed'     Salary:'sal
      Say '' (11)                      /* Space down one line */
   End
   'RXSQL CLOSE SELEMP'(12)            /* Close the SELECT statement */
   if rc<>0 then signal 'ERROR'
End
'RXSQL COMMIT'                         /* Commit the transaction */
'RXSQL PURGE SELEMP'(13)              /* Purge PREPed statement */
If rc=0 then Exit
ERROR:                                /* A fatal error occurred  */
                                      /* Forget all inserted data so far */
errrc = rc
If errrc >= 100 then Do
   Say '  RXSQL Error:' errrc rxsqlmsg
   'RXSQL ROLLBACK'
End
Else If errrc = 4 | errrc = 8 then Do
   Say '  Sqlcode:' sqlcode
   Say ' Sqlstate:' sqlstate
   Do errd = 1 to 6
      If sqlerrd.errd <> 0 then Say '  Sqlerrd.'errd':' sqlerrd.errd
   End
   If sqlerrp <> '' then Say '  Sqlerrp:' sqlerrp
   If sqlerrm <> '' then Say '  Sqlerrm:' sqlerrm
   If sqlwarn <> '' then Say '  Sqlwarn:' "'"sqlwarn"'"
   If sqlcode < 0 & "INDEX"('WS',"SUBSTR"(sqlwarn,7,1)) = 0 then
      'RXSQL ROLLBACK'
End
Exit errrc

Notes for EMPSEL Program

The following notes refer to the lines in the EMPSEL program identified by reverse video numbers:

(1)
This program allows two arguments to be passed to it: salary and job.

(2)
If job is null, this line causes DB2 RXSQL to set job to a value of ANALYST.

(3)
This line ensures that any value specified for job is identified to DB2 RXSQL as a character type.

(4)
If salary is null, this line causes DB2 RXSQL to set salary to a value of 38000.

(5)
This SQL SELECT statement queries the RXEMP table for for employees with a certain job who have less than a certain salary. Colons in the variable names indicate to the database manager that the REXX variables job and salary are to supply these values.

(6)
This RXSQL PREP statement prepares the SELECT statement into the database. The statement is SELEMP for DB2 RXSQL. DB2 RXSQL stores the input variables job and salary for a subsequent OPEN request.

(7)
This RXSQL OPEN statement opens a cursor (for prepared statement SELEMP) on the query, using the values of the input variables job and salary.

(8)
This RXSQL FETCH statement reads one row from the result table each time through the loop. DB2 RXSQL uses the fields of the row as values for the variables listed on the FETCH request.

(9)
This line causes the loop to end if no more rows satisfy the query. This is not a true error situation. When there is a true error situation, the error routine takes control.

(10)
The columns of the table might contain null values. The SYMBOL function tests the REXX variable to see if it is defined or not. If the column value is null, DB2 RXSQL makes the variable that is to receive the column value undefined, and the SYMBOL function returns LIT. This means that the variable does not have a value. If the column has a value, DB2 RXSQL sets the variable that is to receive the column value, and the SYMBOL function returns VAR, meaning that the variable has a value.

(11)
These three lines format the results from one row of the query and display it for the user.

(12)
This RXSQL CLOSE statement closes the cursor (for prepared statement SELEMP) on the result table. A cursor for SELEMP can be opened again with another set of input job and salary values.

(13)
This RXSQL PURGE statement deletes the prepared statement named SELEMP. After the program processes this statement, SELEMP no longer exists. A cursor cannot be opened for it with another set of input values.


Examples Using Extended Dynamic RXSQL Requests

You can use an XPREP (or Extended PREPARE) request to accomplish the same results as the PREP request in the EMPSEL program. With an XPREP request, two programs replace the EMPSEL program. One program creates and prepares a package in the database. The other allows general users to access the data.

When the XPREP statement is processed, the database manager returns a section number identifying the position in the package that the prepared statement occupies. To use this prepared statement in any run-time program, you must use the same section number returned by the XPREP, in an extended DECLARE statement.

Since the XPREP needs to be done only once and the DECLARE every time you wish to use the prepared statement, two separate programs are typically used. One contains the XPREP statement and the other, a run-time program, contains the extended DECLARE statement. The following example programs describe a method of passing the section number from the first program to the run-time program.

Creating a Package

The following programs show one method of saving the section number. The EMPPRP program (shown in Figure 45), contains the XPREP statement and generates the intermediate EMPDCL program (shown in Figure 46). The EMPSELX program (shown in Figure 47) is a run-time program that invokes the EMPDCL program to declare statement names for the appropriate SQL statement.
Note:The example generates a package with only one statement, but you can put more than one statement into a single package.

Figure 45. Program to Define Extended Prepared Package

/* EMPPRP */
/*   5697-F42 (C) Copyright IBM Corp. 1973, 2000.                      */
/*   All rights reserved.                                              */
/*   US Government Users Restricted Rights -                           */
/*   Use, duplication or disclosure restricted by                      */
/*   GSA ADP Schedule Contract with IBM Corp.                          */
/*                                                                     */
/*   Licensed Materials - Property of IBM                              */
 
/* An exec to create and prepare the SQL statements available */
/* to the users                                               */
Address 'COMMAND'
 
/* Define the select statement to pick part of the data from DB2 Server for VM */
/* Note: Use parameter markers not variable names */
/*       Variable names given on OPEN */
sel_emp = 'SELECT * FROM EMPVIEW WHERE SALARY < ? AND JOB = ?'(1)
 
/* Find out who I am */
'IDENTIFY (LIFO' (2)
Parse Upper Pull myid .(3)
 
/* Prepare to add DECLAREs to a generated exec called EMPDCL */
'ERASE EMPDCL EXEC' (4)
/* Put in comment so exec will be a REXX exec */
'EXECIO 1 DISKW EMPDCL EXEC A (STRING /* EMPDCL */' (5)
'EXECIO 1 DISKW EMPDCL EXEC A (STRING Trace "Err"'(6)
 
Trace 'Err'
Signal ON ERROR (7)                    /* Any error aborts */
 
/* Create package */
'RXSQL CREATE PACKAGE' myid'.EMPPROG USING BLOCK' (8)
 
/* Prepare the SELECT statement */
'RXSQL XPREP' myid'.EMPPROG' sel_emp (9)
 
/* Generate DECLARE with result of XPREP for EMPSELX to use */
decl ="'RXSQL DECLARE SELEMP CURSOR FOR" sqlstmtn "IN" myid".EMPPROG'" (10)
'EXECIO 1 DISKW EMPDCL EXEC A (STRING' decl (11)
 
'RXSQL COMMIT WORK' (12)               /* Commit the transaction */
 
'RXSQL EXEC GRANT RUN ON EMPPROG TO PUBLIC' (13)
 
'RXSQL COMMIT WORK'                           /* Commit the transaction */
Exit
ERROR:
Signal OFF ERROR (14)
errrc = rc
If errrc >= 100 then Do
   Say '  RXSQL Error:' errrc rxsqlmsg
   'RXSQL ROLLBACK'
End
Else If errrc = 4 | errrc = 8 then Do
   Say '  Sqlcode:' sqlcode
   Say ' Sqlstate:' sqlstate
   Do errd = 1 to 6
      If sqlerrd.errd <> 0 then Say '  Sqlerrd.'errd':' sqlerrd.errd
   End
   If sqlerrp <> '' then Say '  Sqlerrp:' sqlerrp
   If sqlerrm <> '' then Say '  Sqlerrm:' sqlerrm
   If sqlwarn <> '' then Say '  Sqlwarn:' "'"sqlwarn"'"
   If sqlcode < 0 & "INDEX"('WS',"SUBSTR"(sqlwarn,7,1)) = 0 then
      'RXSQL ROLLBACK'
End
Exit errrc

Notes for EMPPRP Program

The following notes refer to the lines in the EMPPRP program identified by reverse video numbers:

(1)
This SELECT statement is the same as the SELECT statement used in the EMPSEL program, except that the variable names are replaced by parameter markers. The OPEN request in the EMPSELX program provides the variable names to replace the parameter markers.

(2)
IDENTIFY is a CMS command that returns the current VM user ID, along with other information. The LIFO option causes IDENTIFY to stack the result in last-in-first-out order.

(3)
This statement reads the stacked result of IDENTIFY and sets the myid variable with the current user ID. This value is used as the owner ID of the package. Some other value could be used if the user has appropriate database privileges.

(4)
This line erases any existing copies of the program to be generated.

(5)
This line of the EMPPRP program writes the first line of the generated EMPDCL program. The first line of the EMPDCL program must be a REXX comment to identify the program as a REXX program.

(6)
This line causes a trace of any errors that occur when the EMPDCL program runs.

(7)
If any command after this point sets a non-zero return code, REXX immediately branches to the label ERROR.

(8)
This RXSQL CREATE statement creates the package into which the SELECT statement is prepared. The BLOCK option allows the performance improvements achieved by blocking multiple rows from the database on the DB2 RXSQL FETCH statement. If you choose not to use the BLOCK option, you do not have to change any programs that use the package.

The default options REPLACE, NOMODIFY, and KEEP are not specified on this CREATE statement. These options replace the package if it already exists, keeping the authorizations that were granted on the previous package.

(9)
This RXSQL XPREP statement prepares the SELECT statement into the package. DB2 RXSQL sets the sqlstmtn variable with the SQL statement number of the statement in the package.

(10)
This line sets the variable decl to a RXSQL DECLARE statement. The DECLARE statement declares the name SELEMP for the statement in the package identified by sqlstmtn

(11)
This line writes the DECLARE statement to the generated program.

(12)
COMMIT causes the database manager to save the package in the database.

(13)
This line processes an SQL GRANT statement to allow the public to use the package called EMPPROG. Without this GRANT statement, only the creator of the package can use the package. You do not necessarily have to authorize the public to use the package; you can use a GRANT statement that authorizes only specific users.

(14)
This line turns off the automatic signal on ERROR. Turning off the signal prevents error loops.

The Generated EMPDCL program

Figure 46 shows the program generated by the EMPPRP Program. The DB2 RXSQL DECLARE statement declares the cursor SELEMP and associates it with section 1 in the package xxx.EMPPROG. The characters xxx are replaced with the name of the user running the EMPPRP program.

Figure 46. Exec Generated by EMPPRP

/* EMPDCL */
Trace "Err"
'RXSQL DECLARE SELEMP CURSOR FOR 1 IN xxx.EMPPROG'

Selecting Data

The EMPSELX Program in Figure 47 is a slight modification of the EMPSEL program shown in Figure 44. Instead of a PREP request, the EMPSELX program has a DECLARE request that defines a statement name for a prepared statement in a package.

Figure 47. Program to Select Data from an SQL Table after Extended Prepare

/* EMPSELX version using extended dynamic SQL */
/*   5697-F42 (C) COPYRIGHT IBM CORP. 1990, 2000.   */
/*   Licensed material - Program Property of IBM    */
/*   Refer to copyright instructions form G120-2083 */
 
/* An exec to display employees with a salary less than some amount */
/* Defaults: ANALYSTs with a salary less than $38,000 */
Address 'COMMAND'
 
Parse Upper Arg job salary .
If job = '' then job = 'ANALYST'
Else job = "'"job"'"                          /* Make sure it is char type */
If salary = '' then salary = 38000
 
/* Declare name for SELECT statement prepared in EMPPRP */
'EXEC EMPDCL' (1)                      /* Exec generated by EMPPRP */
 
/* Open the SELECT statement and give the input parms */
'RXSQL OPEN SELEMP salary job' (2)
if rc<>0 then signal 'ERROR'
 
If rc = 0 then Do                             /* If no errors occurred then */
   Do Forever                                 /* Get data from the table */
 
      /* Get the data into REXX variables from DB2 Server for VM */
      'RXSQL FETCH SELEMP emp fname mid lname job ed sal'
      If (rc = 4 & SQLCODE = 100)  then Leave  /* If there is no more */
      Else If rc <> 0 then Signal 'ERROR'     /* If there is an error */
 
      /* Check for Nulls */
      If "SYMBOL"('job') <> 'VAR' then job = '?'
      If "SYMBOL"('sal') <> 'VAR' then sal = '?'
 
      /* Type the data on the users terminal */
      Say 'Employee: 'emp '    ' fname mid lname
      Say 'Job:'job'    Education:'ed'     Salary:'sal
      Say ''       /* Space down one line */
 
   End
   'RXSQL CLOSE SELEMP'                       /* Close the SELECT statement */
   if rc<>0 then signal 'ERROR'
End
'RXSQL COMMIT'                                /* Commit the transaction */
'RXSQL PURGE SELEMP'                          /* Purge Declared name */
If rc=0 then Exit
 
ERROR:                                        /* A fatal error occurred  */
                                              /* Forget all inserted data so far */
errrc = rc
If errrc >= 100 then Do
   Say '  RXSQL Error:' errrc rxsqlmsg
   'RXSQL ROLLBACK'
End
Else If errrc = 4 | errrc = 8 then Do
   Say '  Sqlcode:' sqlcode
   Say ' Sqlstate:' sqlstate
   Do errd = 1 to 6
      If sqlerrd.errd <> 0 then Say '  Sqlerrd.'errd':' sqlerrd.errd
   End
   If sqlerrp <> '' then Say '  Sqlerrp:' sqlerrp
   If sqlerrm <> '' then Say '  Sqlerrm:' sqlerrm
   If sqlwarn <> '' then Say '  Sqlwarn:' "'"sqlwarn"'"
   If sqlcode < 0 & "INDEX"('WS',"SUBSTR"(sqlwarn,7,1)) = 0 then
      'RXSQL ROLLBACK'
End
Exit errrc

Notes for EMPSELX Program

The following notes refer to the lines in the EMPSELX program identified by reverse video numbers:

(1)
This program statement invokes the generated EMPDCL program, that contains the DECLARE request.

An alternative to executing the program is to include it in the EMPSELX program after running EMPPRP. Including the EMPDCL program in the EMPSELX program requires that only one program be made available for general use instead of two.

(2)
This OPEN statement names the input variables. In the EMPSEL program, DB2 RXSQL stored the variable names given in the PREP statement until subsequent processing of the OPEN statement. This method worked because DB2 RXSQL recalled the variables in the same transaction. In the program in Figure 47, variables are not used in the same transaction. DB2 RXSQL cannot store variables between transactions.


More Examples Using Extended Dynamic RXSQL Requests

The following programs use extended dynamic SQL to interactively update entries in the table and to insert new records into the database.

Defining a Package

The EMPPRPM program shown in Figure 48 defines the package for the statements that the EMPUPD program shown in Figure 50 uses for updating, inserting, and scaling salaries. EMPPRPM program prepares the SQL statements into a different package than the one created by EMPPRP program because the statements are authorized for use by managers only. The EMPPRP program authorizes the general public to use its statements.

Figure 48. Program to Define Extended Prepare Package for Updating

/* EMPPRPM */
/*   5697-F42 (C) Copyright IBM Corp. 1973, 2000.                      */
/*   All rights reserved.                                              */
/*   US Government Users Restricted Rights -                           */
/*   Use, duplication or disclosure restricted by                      */
/*   GSA ADP Schedule Contract with IBM Corp.                          */
/*                                                                     */
/*   Licensed Materials - Property of IBM                              */
 
/* An exec to create and prepare the SQL statements available to */
/* managers to update the tables */
Address 'COMMAND'
 
/* Define the insert statement to fill in rows of the table */
ins_emp = 'INSERT INTO EMPVIEW VALUES(?,?,?,?,?,?,?)'(1)
 
/* Define the update to change a emp salary */
set_salary = 'UPDATE EMPVIEW SET SALARY = ?', (2)
             'WHERE EMPNO = ? AND LASTNAME = ?'
 
/* Define the update to mark down/up all the salaries */
scale_salary = 'UPDATE EMPVIEW SET SALARY = SALARY * ?'
 
/* Find out who I am */
'IDENTIFY (LIFO'
Parse Upper Pull myid .
 
/* Prepare to add DECLAREs to a generated exec called EMPDCLM */
'ERASE EMPDCLM EXEC'
/* Put in comment so exec will be a REXX exec */
'EXECIO 1 DISKW EMPDCLM EXEC A (STRING /* EMPDCLM */'
'EXECIO 1 DISKW EMPDCLM EXEC A (STRING Trace "Err"'
 
Trace 'Err'
Signal ON ERROR                               /* Any error aborts */
 
/* Create package */
'RXSQL CREATE PACKAGE' myid'.EMPUPD' (3)
 
/* Prepare the INSERT statement */
'RXSQL XPREP' myid'.EMPUPD' ins_emp
 
/* Generate DECLARE with result of XPREP for EMPUPD to use */
decl = "'RXSQL DECLARE INSEMP CURSOR FOR" sqlstmtn "IN" myid".EMPUPD'"
'EXECIO 1 DISKW EMPDCLM EXEC A (STRING' decl
 
/* Prepare the first UPDATE statement */
'RXSQL XPREP' myid'.EMPUPD' set_salary
decl = "'RXSQL DECLARE SETEMP CURSOR FOR" sqlstmtn "IN" myid".EMPUPD'"
'EXECIO 1 DISKW EMPDCLM EXEC A (STRING' decl
 
Trace 'Off'
Signal OFF ERROR (4)                   /* Don't signal on error */
 
/* Prepare the second UPDATE statement */
dcllist = 'F' (5)                      /* Describe one input variable, Float type */
'RXSQL XPREP' myid'.EMPUPD USING dcllist' scale_salary (6)
If rc > 4 then Signal 'ERROR' (7)      /* Ignore expected warning */
 
Trace 'Err'
Signal ON ERROR (8)                    /* Any error aborts */
 
decl ="'RXSQL DECLARE SCALEEMP CURSOR FOR" sqlstmtn "IN" myid".EMPUPD'"
'EXECIO 1 DISKW EMPDCLM EXEC A (STRING' decl
 
'RXSQL COMMIT WORK'                           /* Commit the transaction */
 
'RXSQL EXEC GRANT RUN ON EMPUPD TO MANAGER' (9)
 
'RXSQL COMMIT WORK'                           /* Commit the transaction */
Exit
 
ERROR:
Signal OFF ERROR
errrc = rc
If errrc >= 100 then Do
   Say '  RXSQL Error:' errrc rxsqlmsg
   'RXSQL ROLLBACK'
End
Else If errrc = 4 | errrc = 8 then Do
   Say '  Sqlcode:' sqlcode
   Say ' Sqlstate:' sqlstate
   Do errd = 1 to 6
      If sqlerrd.errd <> 0 then Say '  Sqlerrd.'errd':' sqlerrd.errd
   End
   If sqlerrp <> '' then Say '  Sqlerrp:' sqlerrp
   If sqlerrm <> '' then Say '  Sqlerrm:' sqlerrm
   If sqlwarn <> '' then Say '  Sqlwarn:' "'"sqlwarn"'"
   If sqlcode < 0 & "INDEX"('WS',"SUBSTR"(sqlwarn,7,1)) = 0 then
      'RXSQL ROLLBACK'
End
Exit errrc

Notes for EMPPRPM

The following notes refer to the lines in the EMPPRPM program identified by reverse video numbers:

(1)
A parameter marker represents each input value to be provided when the program calls the INSERT statement.

(2)
The expression used to scale SALARY is not a simple variable and requires a USING clause on a subsequent XPREP statement (see line (6)).

(3)
This CREATE PACKAGE statement does not specify the BLOCK option. Blocking is not appropriate here, because the EMPPRPM program is an interactive application.

(4)
This line turns off the REXX automatic branch-on-error action, because the XPREP request on the following line always generates an SQL warning, indicating that the SQL statement does not have a WHERE clause. This warning sets the fifth character of the sqlwarn variable to W.

(5)
This UPDATE statement has one input variable. The variable type is floating point. With numeric input, you should specify a data type that encompasses all possible input values so that you do not lose data when SQL translates the input value to the type you specify.

(6)
This RXSQL XPREP statement uses the name of the variable that contains the definition list dcllist. DB2 RXSQL obtains the value before preparing the statement.

(7)
If the program encounters an error more serious than the anticipated warning, this line signals the error exit routine.

(8)
This line turns on automatic error branching for the remainder of processing.

(9)
This DB2 RXSQL program statement processes the SQL statement to grant run authority to a specific SQL ID named MANAGER.

The Generated EMPDCLM program

Figure 49 shows the program generated by the EMPPRP program.

Figure 49. Program Generated by EMPPRPM

/* EMPDCLM */
Trace "Err"
'RXSQL DECLARE INSEMP CURSOR FOR 1 IN xxx.EMPUPD'
'RXSQL DECLARE SETEMP CURSOR FOR 2 IN xxx.EMPUPD'
'RXSQL DECLARE SCALEEMP CURSOR FOR 3 IN xxx.EMPUPD'

Interactive Updating

The EMPUPD program shown in Figure 50 is an example of an interactive application that waits for commands from a user who wants to update the RXEMP table. The program can insert new rows into the table, set a new salary for an existing employee in the table, or make a percentage change to all the salaries in the table.

Figure 50. Example Interactive Program to Update the EMPLOYEE Table

/* EMPUPD */
/*   5697-F42 (C) Copyright IBM Corp. 1973, 2000.        */
/*   All rights reserved.                                */
/*   US Government Users Restricted Rights -             */
/*   Use, duplication or disclosure restricted by        */
/*   GSA ADP Schedule Contract with IBM Corp.            */
/*                                                       */
/*   Licensed Materials - Property of IBM                */
/* An exec to interactively insert, set a salary, or     */
/* mark up/down all salaries                             */
trace 'Off' /*(1) */
Address 'COMMAND'
 
/* Declare INSEMP, SETEMP, SCALEEMP as cursor and   */
/* statement names by executing the exec generated  */
/* by EMPPRPM                                       */
'EXEC EMPDCLM' /*(2) */
 
Do Forever /* (3) */
   Say 'Enter command: Insert, Set, Update, COMMit, ROLLback, or Quit' /* (4) */
   Parse Upper Pull cmd .  /*(5) */
   Select /* (6) */
      When cmd = '' then Nop /* (7) */
      When ABBREV('QUIT',cmd,1) then Leave /* (8) */ /* terminate loop */
      When ABBREV('INSERT',cmd,1) then Do
         Do Forever /* (9) */
           Say 'Enter Employee number, First name, Middle initial,', /* (10) */
               'Last name, Job,'
           Say 'Education level and Salary'
           Say ' (Empty line to quit)'
 
           Parse Upper Pull employee_number first_name,
                            middle_initial last_name job ed_level salary .
 
           If employee_number = '' then Leave /* (11) */
           /* Got all input? */
           If salary <> '' then Do /* (12) */
          /* Use variable qualifiers to ensure */
          /* proper types                      */
             'EXECSQL CALL INSEMP USING',
                  ':employee_number (CHAR(6)),',
                  ':first_name   (VARCHAR(12)),',
                  ':middle_initial  (CHAR(1)),',
                  ':last_name    (VARCHAR(15)),',
                  ':job             (CHAR(8)),',
                  ':ed_level     (SMALLINT),',
                  ':salary       (DECIMAL(9,2))' /* (13) */
               If rc <> 0 then Call DSCERROR /* (14) */
               Else Say 'Inserted.'
            End  /* salary <> ''     */
         End     /* inner Do forever */
      End        /* When INSERT      */
      When ABBREV('UPDATE',cmd,1) then Do
         Say 'Enter percent salary change. (Empty line to quit)'
         Say '  5 means add 5 percent to all current salaries,'
         Say ' -4 means subtract 4 percent from all current salaries.'
         Parse Pull factor .
         If factor <> '' then Do
            factor = 1 + factor/100 /* (15) */
            /* Scale all salaries */
            'EXECSQL CALL SCALEEMP USING :factor (DECIMAL(6,3))'
            If rc >= 0, /* (16) */
               Then Say sqlerrd.3 'row(s) updated.'
            If rc <> 0 then call DSCERROR
         End /* factor <> '' */
      End    /* When UPDATE  */
      When ABBREV('SET',cmd,1) then Do
         Do Forever
            Say 'Enter Emp#, Last name, SALARY. (Empty line to quit)'
            Parse Upper Pull,
                  employee_number last_name salary .
            /* Terminate inner loop */
            If employee_number = '' then Leave
            If last_name <> '' & salary <> '' then Do
               /* Reset salary*/
               'EXECSQL CALL SETEMP',
                   ':salary     (DECIMAL(9,2)),',
                   ':employee_number (CHAR(6)),',
                   ':last_name  (VARCHAR(15))'
               If rc >= 0,
                  then Say sqlerrd.3 'row(s) updated.'
               If rc <> 0 Then Call DSCERROR
            End
         End  /* Inner Do Forever */
      End     /* When SET         */
      When ABBREV('COMMIT',cmd,4) then Do /* (17) */
         'EXECSQL COMMIT'
         If rc <> 0 then Call DSCERROR
      End
      When ABBREV('ROLLBACK',cmd,4) then Do
         'EXECSQL ROLLBACK'
         If rc <> 0 then Call DSCERROR
      End
      Otherwise Say 'Unknown command' /* (18) */
   End  /* outer Select     */
End     /* outer Do Forever */
 
/* Commit the transaction */
'EXECSQL COMMIT RELEASE' /* (19) */
If rc <> 0 then Call DSCERROR
/* Purge Declared names */
'EXECSQL PURGE INSEMP, SETEMP, SCALEEMP'
Exit
DSCERROR:
errrc = rc
 
/* Display the RXSQL request */
say 'RXSQL Request   :' rxsqlrequest
 
Select
  When errrc >=1000  then msgpart='RXSQL warning:'
  When errrc  =  10,
       then msgpart='Application Server warning:'
  When errrc  = -10,
       then msgpart='Application Server error:'
  When errrc <=-100  then msgpart='RXSQL error:'
  Otherwise msgpart='Unexpected return code from RXSQL:'
end
 
Say msgpart errrc rxsqlmsg
If errrc = 10 | errrc = -10 Then do
   Say '  Sqlcode:' sqlcode
   Say ' Sqlstate:' sqlstate
   Do errd = 1 to 6
      If sqlerrd.errd <> 0 then Say '  Sqlerrd.'errd':' sqlerrd.errd
 
   End
   If sqlerrp    <> '' then Say ' Sqlerrp :' sqlerrp
 
   If sqlerrmc   <> '' then Say ' Sqlerrmc:' sqlerrmc
   If sqlwarn.0  <> '' then Do
      warnflgs=sqlwarn.0||sqlwarn.1||sqlwarn.2||sqlwarn.3
      warnflgs= warnflgs||sqlwarn.4||sqlwarn.5||sqlwarn.6
      warnflgs= warnflgs||sqlwarn.7||sqlwarn.8||sqlwarn.9
      warnflgs= warnflgs||sqlwarn.10
      Say ' Sqlwarn : '"'"warnflgs"'"
   end
   If INDEX('WS',sqlwarn.6) <> 0, /* (20) */
      Then Exit errrc /* Terminate exec */
 
End
/* return back to interactive questions */
Return /* (21) */

Notes for EMPUPD

The following notes refer to the lines in the EMPUPD program identified by reverse video numbers:

(1)
REXX tracing is set to Off from the default of Normal. Changing the default prevents REXX from displaying the EXECSQL statement whenever DB2 RXSQL returns a negative return code to signal an error condition.

(2)
The generated program declares all three statement names. Declaring all the names at once, even if they are not used, does not affect performance.

(3)
This Do Forever loop asks for input until a REXX Leave statement breaks the loop.

(4)
This line prompts for input. The capital letters indicate the minimum abbreviation.

(5)
This line reads the command typed from the terminal. The first token is assigned to the variable cmd. Any other tokens are discarded.

(6)
This REXX SELECT statement processes the first When clause that evaluates as true. If no When clause evaluates as true, the Select statement processes the Otherwise clause in line (18).

(7)
This line tests for null input. If the input is null, the program prompts the user to type another command.

(8)
The ABBREV function tests if cmd matches the character string QUIT. The number 1 indicates the minimum number of characters needed for cmd to match the character string. If cmd is Q, QU, QUI, or QUIT, it matches. This line also contains the Leave statement which ends the Do Forever loop.

(9)
This line is another example of a Do Forever loop. This loop ends with the Leave statement in line (11).

(10)
These lines prompt the user for all the input variables needed.

(11)
This line tests for null input.

(12)
If the salary variable has a value, then the program has all the input.

(13)
When writing programs that use DB2 RXSQL statements, you must make sure that the variables named match the columns of the table. DB2 RXSQL retrieves the values for the host variables from REXX as needed.

All variables in the list have variable-qualifiers to ensure that DB2 RXSQL passes appropriate data type values to the database manager.

(14)
If an error occurs, the DSCERROR subroutine displays the error variables. The DSCERROR subroutine does not cause the program to end abnormally. The program resumes processing at the point where DSCERROR was called (see line (21)).

(15)
The program converts the user's input percentage value to a scaling factor.

(16)
If the update was successful (indicated by a return code greater than or equal to zero) the program displays the number of rows that were updated. The program uses the number returned in SQLERRD.3. Note that DB2 RXSQL may still return a warning even though the update was successful.

(17)
Note that the minimum abbreviation required for COMMIT is 4, not 1.

(18)
If none of the When clauses are true, then this program does not recognize the cmd variable as valid input. The program informs the user that it does recognize the input by issuing the message Unknown command.

(19)
The program explicitly commits any as yet uncommitted changes to the database manager and drops the connection to free up resources.

(20)
If this condition is true, a serious database error occurred and the program ends abnormally.

(21)
Return causes the program to resume processing at the line of the program that called DSCERROR.



[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]