IBM Books

Embedded SQL Programming Guide


Example Output-SQLDA Programs

Following is a sample program demonstrating the use of an output SQLDA structure. The client application invokes a stored procedure that determines the median salary for employees in the SAMPLE database. (The definition of the median is that half the values lie above it, and half below it.) The median salary is then passed back to the client application using an output SQLDA structure.

This sample program calculates the median salary of all employees in the SAMPLE database. Since there is no existing SQL column function to calculate medians, the median salary can be found iteratively by the following algorithm:

  1. Determine the number of records, n, in the table.
  2. Order the records based upon salary.
  3. Fetch records until the record in row position n/2+1 is found.
  4. Read the median salary from this record.

An application that uses neither the stored procedures technique, nor blocking cursors must FETCH each salary across the network as shown in Figure 20.

Figure 20. Median Sample Without a Stored Procedure


* Figure SQLA0F15 not displayed.

Since only the salary at row n/2+1 is needed, the application discards all the additional data, but only after it is transmitted across the network.

An application using the stored procedures technique can be designed to allow the stored procedure to process and discard the unnecessary data, returning only the median salary to the client application. Figure 21 shows this feature.

Figure 21. Median Sample Using a Stored Procedure


* Figure SQLA0F16 not displayed.

"How the Example Output-SQLDA Client Application Works" shows a sample output-SQLDA client application and sample output-SQLDA stored procedure in some of the supported languages.

How the Example Output-SQLDA Client Application Works

  1. Include Files. The program begins with the following include files:
    SQL
    Defines the symbol SQL_TYP_FLOAT
    SQLDA
    Defines the descriptor area
    SQLCA
    Defines the communication area for error handling

  2. Allocate the output SQLDA. This step declares and allocates an SQLDA structure. One SQLVAR element is used to return data from the server procedure.

  3. Declare local variables. The SQLVAR element of the SQLDA is initialized to point to these variables. These variables contain the data returned by the server procedure.

  4. Initialize the Output SQLDA. The following fields of the output SQLDA are initialized:

  5. Connect to Database. The application executes the CONNECT TO statement requesting shared access. This must be done before invoking the server procedure.

  6. Invoke the Server Procedure. The application invokes the procedure outsrv at the location of the database, sample, using:
    1. CALL statement with host variables
    2. CALL statement with an SQLDA.

  7. Disconnect from Database.

The CHECKERR macro/function is an error checking utility which is external to the program. The location of this error checking utility depends upon the programming language used:

C
check_error is redefined as CHECKERR and is located in the util.c file.

COBOL
CHECKERR is an external program named checkerr.cbl.

FORTRAN
CHECKERR is a subroutine located in the util.f file.

REXX
CHECKERR is a procedure located at bottom of the current program.

See "Using GET ERROR MESSAGE in Example Programs" for the source code for this error checking utility.

C Example: OUTCLI.SQC

#include <stdio.h>
#include <stdlib.h>
#include <sql.h> (1)
#include <sqlda.h>
#include <sqlca.h>
#include <string.h>
#include "util.h"
 
#define  CHECKERR(CE_STR)   if (check_error (CE_STR, &sqlca) != 0) return 1;
 
int main(int argc, char *argv[]) {
 
   EXEC SQL BEGIN DECLARE SECTION;
     char database[9];
     char userid[9];
     char passwd[19];
     /* Declare a Local Variable for Holding the Procedure's Name */
     char procname[255] = "outsrv";
 
     /* Declare Local Variables for Holding Returned Data */
     double sal     = 0.0;  (3)
     short  salind  = 0;
   EXEC SQL END DECLARE SECTION;
 
 
   /* Declare the output SQLDA */
   struct sqlda *inout_sqlda = (struct sqlda *)
   malloc(SQLDASIZE(1)); (2)
 
   /* Declare the SQLCA */
   struct sqlca sqlca;
 
   if (argc != 4) {
      printf ("\nUSAGE: outcli remote_database userid passwd\n\n");
      return 1;
   }
   strcpy (database, argv[1]);
   strcpy (userid, argv[2]);
   strcpy (passwd, argv[3]);
   /* Connect to Remote Database */
   printf("CONNECT TO Remote Database.\n");
   EXEC SQL CONNECT TO :database USER :userid USING :passwd; (5)
   CHECKERR ("CONNECT TO RSAMPLE");
 
   /********************************************************\
   * Call the Remote Procedure via CALL with Host Variables *
   \********************************************************/
   printf("Use CALL with Host Variable to invoke the Server Procedure "
      "named outsrv\n");
   salind = -1;                  /* Sal has no input, so set to null */
   EXEC SQL CALL :procname (:sal :salind);  (6a)
   CHECKERR ("CALL WITH HOST VARIABLES");
   printf("Server Procedure Complete.\n");
 
   /* Print Salary Returned in The Host Variables */
   printf("Median Salary = %.2f\n\n", sal );
 
   /***********************************************\
   * Call the Remote Procedure via CALL with SQLDA *
   \***********************************************/
   /* Initialize the output SQLDA */  (4)
   inout_sqlda->sqln = 1;
   inout_sqlda->sqld = 1;
   inout_sqlda->sqlvar[0].sqltype = SQL_TYP_NFLOAT;
   inout_sqlda->sqlvar[0].sqllen  = sizeof( double );
   inout_sqlda->sqlvar[0].sqldata = (char *)&sal;
   inout_sqlda->sqlvar[0].sqlind  = (short *)&salind;
 
   printf("Use CALL with SQLDA to invoke the Server Procedure "
      "named outsrv\n");
   salind = -1;                  /* Sal has no input, so set to null */
   EXEC SQL CALL :procname USING DESCRIPTOR :*inout_sqlda;  (6b)
   CHECKERR ("CALL WITH SQLDA");
   printf("Server Procedure Complete.\n");
 
   /* Print Salary Returned in The Host Variables */
   printf("Median Salary = %.2f\n\n", sal );
 
   /* Free allocated memory */
   free( inout_sqlda );
 
   /* Disconnect from Remote Database */
   EXEC SQL CONNECT RESET; (7)
   CHECKERR ("CONNECT RESET");
   return 0;
}
/* end of program : outcli.sqc */

COBOL Example: OUTCLI.SQB

 Identification Division.
 Program-ID. "outcli".
 
 Data Division.
 Working-Storage Section.
 
* Copy Files for Constants and Structures.
 copy "sql.cbl". (1)
 copy "sqlenv.cbl".
 copy "sqlca.cbl".
 
 01 decimal-sqllen     pic s9(4) comp-5.
 01 decimal-parts      redefines decimal-sqllen.
     05 precision      pic x.
     05 scale          pic x.
 
* Declare an Output SQLDA Structure.
 01  io-sqlda sync. (2)
     05 io-sqldaid     pic x(8) value "O-DA   ".
     05 io-sqldabc     pic s9(9) comp-5.
     05 io-sqln        pic s9(4) comp-5.
     05 io-sqld        pic s9(4) comp-5.
     05 io-sqlvar occurs 1 to 99 times
        depending on io-sqld.
        10 io-sqltype  pic s9(4) comp-5.
        10 io-sqllen   pic s9(4) comp-5.
        10 io-sqldata  usage is pointer.
        10 io-sqlind   usage is pointer.
        10 io-sqlname.
           15 io-sqlnamel   pic s9(4) comp-5.
           15 io-sqlnamec   pic x(30).
 
 EXEC SQL BEGIN DECLARE SECTION END-EXEC.
 01 dbname            pic x(8). (3)
 01 userid            pic x(8).
 01 passwd.
   49 passwd-length   pic s9(4) comp-5 value 0.
   49 passwd-name     pic x(18).
 
* Declare Variables for the SQL CALL.
 77  prog-name       pic x(19)        value "outsrv".
 
* Declare Local Variables for Holding Actual Data.
 77  salary          pic s9(5)v99  comp-3.
 77  sal-ind         pic s9(4)     comp-5.
 
 EXEC SQL END DECLARE SECTION END-EXEC.
 
* Declare Output Mask for Salary
 77  sal-out         pic z9(5).99-.
 
* Declare a Null Pointer Variable.
 77  null-ptr-int    pic s9(9)     comp-5.
 77  null-ptr redefines null-ptr-int pointer.
 
 77 errloc pic x(80).
 
 Procedure Division.
 Main Section.
 
* Initialize the Input/Output SQLDA Structure
     move 1 to io-sqln. (4)
     move 1 to io-sqld.
     move sql-typ-ndecimal to io-sqltype(1).
* Length = 7 digits precision and 2 digits scale
     move x"07" to precision.
     move x"02" to scale.
     move decimal-sqllen to io-sqllen(1).
     set io-sqldata(1) to address of salary.
     set io-sqlind(1)  to address of sal-ind.
 
* CONNECT TO DATABASE
     display "Enter in the database name : " with no advancing.
     accept dbname.
 
     display "Enter your user id (default none): " 
          with no advancing.
     accept userid.
 
     if userid = spaces
       EXEC SQL CONNECT TO sample END-EXEC
     else
       display "Enter your password : " with no advancing
       accept passwd-name.
 
* Passwords in a CONNECT statement must be entered in a VARCHAR format
* with the length of the input string.
     inspect passwd-name tallying passwd-length for characters
        before initial " ".
 
     EXEC SQL CONNECT TO :dbname USER :userid USING :pa(5)
        END-EXEC.
     move "CONNECT TO" to errloc.
     call "checkerr" using SQLCA errloc.
 
* Call the Remote Procedure.
     display "Use CALL with Host Var. to invoke Server Procedure."
     EXEC SQL CALL :prog-name (:SALARY:SAL-IND) END-EXE(6a)
     move "CALL HV" to errloc.
     call "checkerr" using SQLCA errloc.
     display "Server Procedure Complete.".
 
* Print Salary Returned in the host variable.
     move salary to sal-out.
     display "Median Salary = " sal-out.
     display " ".
 
* Call the Remote Procedure.
     display "Use CALL with SQLDA to invoke Server Procedure."
     EXEC SQL CALL :prog-name USING DESCRIPTOR (6b)
                              :IO-SQLDA END-EXEC.
     move "CALL DA" to errloc.
     call "checkerr" using SQLCA errloc.
     DISPLAY "Server Procedure Complete.".
 
* Print Salary Returned in IO-SQLDA.
     move salary to sal-out.
     display "Median Salary = " sal-out.
 
* Disconnect from Remote Database.
     EXEC SQL CONNECT RESET END-EXEC. (7)
     stop run.
     exit.

FORTRAN UNIX Example: OUTCLI.SQF

 
      program outcli
      implicit none
 
*     Copy Files for Constants and Structures
      include 'sql.f'
      include 'sqlenv.f' (1)
      include 'sqlutil.f'
      include 'sqldact.f'
 
      EXEC SQL INCLUDE SQLCA
 
      EXEC SQL BEGIN DECLARE SECTION (3)
        character*8    dbname
        character*8    userid
        character*18   passwd
        real*8         salary
        integer*2      sal_ind
        character*19   prog_name
      EXEC SQL END DECLARE SECTION
 
      integer*4        rc
      character*80     errloc
 
      integer*2        sqlvar1
      parameter        (sqlvar1 = sqlda_header_sz + 0*sqlvar_struct_sz)
 
      character        io_sqlda(sqlda_header_sz + 1*sqlvar_struct_sz) (2)
      character*8      io_sqldaid
      integer*4        io_sqldabc
      integer*2        io_sqln
      integer*2        io_sqld
 
      integer*2        io_sqltype1    ! First Variable
      integer*2        io_sqllen1
      integer*4        io_sqldata1
      integer*4        io_sqlind1
      integer*2        io_sqlnamelen1
      character*30     io_sqlnamedata1
 
      equivalence (io_sqlda(sqlda_sqldaid_ofs), io_sqldaid)
      equivalence (io_sqlda(sqlda_sqldabc_ofs), io_sqldabc)
      equivalence (io_sqlda(sqlda_sqln_ofs), io_sqln)
      equivalence (io_sqlda(sqlda_sqld_ofs), io_sqld)
 
      equivalence (io_sqlda(sqlvar1+sqlvar_type_ofs), io_sqltype1)
      equivalence (io_sqlda(sqlvar1+sqlvar_len_ofs), io_sqllen1)
      equivalence (io_sqlda(sqlvar1+sqlvar_data_ofs), io_sqldata1)
      equivalence (io_sqlda(sqlvar1+sqlvar_ind_ofs), io_sqlind1)
      equivalence (io_sqlda(sqlvar1+sqlvar_name_length_ofs),
     +             io_sqlnamelen1)
      equivalence (io_sqlda(sqlvar1+sqlvar_name_data_ofs),
     +             io_sqlnamedata1)
 
      io_sqldaid = 'O_SQLDA' (4)
      io_sqldabc = sqlda_header_sz + 1*sqlvar_struct_sz
      io_sqln    = 1
      io_sqld    = 1
      io_sqltype1 = sql_typ_nfloat
      io_sqllen1  = 8
      rc = sqlgaddr (%ref(salary), %ref(io_sqldata1))
      rc = sqlgaddr (%ref(sal_ind), %ref(io_sqlind1))
 
 
*     Program Logic
 
      print *, 'Enter in the remote database to attach to:'
      read 100, dbname
100   format (a8)      
 
      print *, 'Enter your user id (default none):'
      read 100, userid
 
      if( userid(1:1) .eq. ' ' ) then
	EXEC SQL CONNECT TO :dbname 
      else
	print *, 'Enter your password :'
	read 100, passwd
 
        print *, 'CONNECT TO Remote Database.'
	EXEC SQL CONNECT TO :dbname USER :userid USING :passwd
      end if (5)
      errloc = 'CONNECT'
      call checkerr (sqlca, errloc, *999)
 
      prog_name = 'outsrv'
 
      print *, ' '
      print *, 'Use CALL with Host Variable to invoke the Server Procedu
     cre named outsrv.'
      EXEC SQL CALL :prog_name (:salary:sal_ind) (6)
      errloc = 'CALL HV'
      call checkerr (sqlca, errloc, *999)
      print *, 'Server Procedure Complete.'
 
*     Print Salary Returned in OUTPUT SQLDA
      print *, 'Median Salary = ', salary
 
      print *, ' '
      print *, 'Use CALL with SQLDA to invoke the Server Procedure named
     c outsrv.'
      EXEC SQL CALL :prog_name USING DESCRIPTOR :io_sqlda (6)
      errloc = 'CALL DA'
      call checkerr (sqlca, errloc, *999)
      print *, 'Server Procedure Complete.'
 
*     Print Salary Returned in OUTPUT SQLDA
      print *, 'Median Salary = ', salary
 
*     Disconnect from Remote Database.
      EXEC SQL CONNECT RESET (7)
      errloc = 'CONNECT RESET'
      call checkerr (sqlca, errloc, *999)
 
999   stop
      end

REXX Example: OUTCLI.CMD

/* REXX OUTput CLIent  */
 
/* this variable (SYSTEM) must be user defined */
SYSTEM = OS2
if SYSTEM = OS2 then do
  if rxfuncquery('SQLDBS') <> 0 then
     rcy = rxfuncadd( 'SQLDBS',  'DB2AR', 'SQLDBS'  )
 
  if rxfuncquery('SQLEXEC') <> 0 then
     rcy = rxfuncadd( 'SQLEXEC', 'DB2AR', 'SQLEXEC' )
end
 
if SYSTEM = AIX then
  rcy = SysAddFuncPkg("/usr/lpp/db2_05_00/lib/db2rexx")
 
/* pull in command line arguments */
parse arg dbname userid passwd .
 
/* check to see if the proper number of arguments have been passed in */
if passwd = '' then
do
  say 'USAGE : outcli dbname userid passwd'
  exit
end
 
procname = 'outsrv.cmd'
/* INITIALIZE ONE ELEMENT OF OUTPUT SQLDA */  (4)
io_sqlda.sqld = 1
io_sqlda.1.sqltype = 485           /* DECIMAL DATA TYPE */
io_sqlda.1.sqllen.scale  = 2       /* DIGITS RIGHT OF DECIMAL POINT */
io_sqlda.1.sqllen.precision  = 7   /* WIDTH OF DECIMAL  */
io_sqlda.1.sqldata = 00000.00      /* HELPS DEFINE DATA FORMAT */
io_sqlda.1.sqlind = -1             /* NO INPUT DATA */
 
/* CONNECT TO REMOTE DATABASE */
say 'Connect to Remote Database.'
call SQLEXEC 'CONNECT TO' dbname 'USER' userid 'USING' passwd (5)
call CHECKERR 'CONNECT'
 
/* CALL THE REMOTE PROCEDURE USING CALL AND HOST VARIABLES */
say "Use CALL with Host Variables to invoke the Stored Procedure outsrv"
sal=00000.00 /* To force precision 7, scale 2 */
salind=0
call SQLEXEC 'CALL :procname (:sal :salind)'  (6a)
call CHECKERR 'CALL USING HV'
say 'Median Salary = ' sal
 
/* CALL THE REMOTE PROCEDURE USING CALL AND SQLDA */
say "Use the CALL with SQLDA to invoke the Stored Procedure outsrv"
call SQLEXEC 'CALL :procname USING DESCRIPTOR :io_sqlda'  (6b)
call CHECKERR 'CALL USING SQLDA'
say 'Median Salary = ' io_sqlda.1.sqldata
 
/* DISCONNECT FROM REMOTE DATABASE */
call SQLEXEC 'CONNECT RESET'  (7)
call CHECKERR 'CONNECT RESET'
 
exit 0
 
 
CHECKERR:
  arg errloc
 
  if  ( SQLCA.SQLCODE = 0 ) then
    return 0
  else
    say '--- error report ---'
    say 'ERROR occured :' errloc
    say 'SQLCODE :' SQLCA.SQLCODE
 
    /******************************\
    * GET ERROR MESSAGE API called *
    \******************************/
    call SQLDBS 'GET MESSAGE INTO :errmsg LINEWIDTH 80'
    say errmsg
    say '--- end error report ---'
 
    if (SQLCA.SQLCODE < 0 ) then
      exit
    else
      say 'WARNING - CONTINUING PROGRAM WITH ERRORS'
      return 0
    end
  end
return 0

How the Example Output-SQLDA Stored Procedure Works

  1. Include Files. The SQL include file defines the symbol SQLZ_DISCONNECT_PROC.

  2. Declare Server Procedure. The server procedure, outsrv, is declared.

    The procedure accepts pointers to SQLDA and SQLCA structures.

  3. Determine Median Position. The row at position cnt/2+1 of the cursor declared previously is assumed to contain the median value.

  4. Fetch Median. The server procedure issues FETCH statements until the row containing the median salary is reached. The FETCH statement uses the SQLDA provided by the client application.

  5. Return to the Client Application. Copy the SQLCA to the SQLCA of the client application and return the value SQLZ_DISCONNECT_PROC, indicating that no further calls to the server procedure will be made.

    If an error occurs, the SQLCA containing the error information is copied to the SQLCA of the client application and a ROLLBACK statement is issued.

Note:Server procedures cannot be written in REXX on AIX systems.

C Example: OUTSRV.SQC

#include <memory.h>
#include <string.h>
#include <sqlenv.h>    (1)
#include <sql.h>
#include <sqlda.h>
 
SQL_API_RC SQL_API_FN outsrv (   (2)
    void *reserved1,
    void *reserved2,
    struct sqlda   *inout_sqlda,
    struct sqlca   *ca) {
 
   /* Declare a local SQLCA */
   EXEC SQL INCLUDE SQLCA;
 
   /* Declare Host Variables */
   EXEC SQL BEGIN DECLARE SECTION;
      short num_records;
      char  stmt[512];
   EXEC SQL END DECLARE SECTION;
 
   /* Declare Miscellaneous Variables */
   int counter = 0;
   EXEC SQL WHENEVER SQLERROR   GOTO error_exit;
   EXEC SQL WHENEVER SQLWARNING CONTINUE;
   EXEC SQL DECLARE c1 CURSOR FOR s1;
 
   /* Prepare a Statement to Obtain and Order all Salaries */
   strcpy( stmt, "SELECT salary FROM STAFF ORDER BY salary" );
   EXEC SQL PREPARE s1 FROM :stmt;
   /*Determine the Total Number of Records */
   EXEC SQL SELECT COUNT(*) INTO :num_records FROM STAFF; (3)
 
   /* Fetch Salaries until the Median Salary is Obtained */
   EXEC SQL OPEN c1;
   while ( counter++ < num_records/2 + 1 )  (4)
      EXEC SQL FETCH c1 USING DESCRIPTOR :*inout_sqlda;
   EXEC SQL CLOSE c1;
   EXEC SQL COMMIT;
 
   /* Return the SQLCA to the Calling Program */ (5)
   memcpy( ca, &sqlca, sizeof( struct sqlca ) );
   return(SQLZ_DISCONNECT_PROC);
 
error_exit:
   /* An Error has occurred -- ROLLBACK and return to Calling Program */
   EXEC SQL WHENEVER SQLERROR CONTINUE;
   memcpy( ca, &sqlca, sizeof( struct sqlca ) );
   EXEC SQL ROLLBACK;
 
   return(SQLZ_DISCONNECT_PROC);
}

COBOL Example: OUTSRV.SQB

 Identification Division.
 Program-ID. "outsrv".
 
 Data Division.
 Working-Storage Section.
 
* Copy Files for Constants and Structures
 copy "sql.cbl".
 copy "sqlenv.cbl". (1)
 copy "sqlca.cbl".
 
* Declare Host Variables
 EXEC SQL BEGIN DECLARE SECTION END-EXEC.
   77  num-records  pic s9(9) comp-5 value 0.
   01  stmt.
       49 stmt-len pic s9(4) comp-5.
       49 stmt-str pic x(50).
 EXEC SQL END DECLARE SECTION END-EXEC.
 
* Declare Miscellaneous Variables
 77  cntr1 pic s9(9) comp-5 value 0.
 77  cntr2 pic s9(9) comp-5 value 0.
 
 Linkage Section.
 
* Declare Parameters
 77  reserved1   pointer.
 77  reserved2   pointer.
 77  inout-sqlda pointer.
 
 01 O-SQLCA SYNC.
    05 SQLCAID PIC X(8).
    05 SQLCABC PIC S9(9) COMP-5.
    05 SQLCODE PIC S9(9) COMP-5.
    05 SQLERRM.
       49 SQLERRML PIC S9(4) COMP-5.
       49 SQLERRMC PIC X(70).
    05 SQLERRP PIC X(8).
    05 SQLERRD OCCURS 6 TIMES PIC S9(9) COMP-5.
    05 SQLWARN.
       10 SQLWARN0 PIC X.
       10 SQLWARN1 PIC X.
       10 SQLWARN2 PIC X.
       10 SQLWARN3 PIC X.
       10 SQLWARN4 PIC X.
       10 SQLWARN5 PIC X.
       10 SQLWARN6 PIC X.
       10 SQLWARN7 PIC X.
       10 SQLWARN8 PIC X.
       10 SQLWARN9 PIC X.
       10 SQLWARNA PIC X.
    05 SQLSTATE PIC X(5).
 
 Procedure Division using reserved1 reserved2 inout-sqlda O-SQLCA.(2)
 
 Main Section.
     EXEC SQL WHENEVER SQLERROR GOTO ERROR-EXIT END-EXEC.
     EXEC SQL WHENEVER SQLWARNING CONTINUE END-EXEC.
 
     EXEC SQL DECLARE C1 CURSOR FOR S1 END-EXEC.
 
* Prepare a Statement to Obtain and Order all Salaries.
     move 50 to stmt-len.
     move "SELECT salary FROM staff ORDER BY salary" to stmt-str.
     EXEC SQL PREPARE S1 FROM :stmt END-EXEC.
 
* Determine Total Number of Records.
     EXEC SQL SELECT COUNT(*) INTO :num-records (3)
              FROM staff END-EXEC.
 
     EXEC SQL OPEN C1 END-EXEC.
 
* Fetch Salaries until the Median Salary is Obtained.
     compute cntr2 = 1 + num-records / 2.
     perform Fetch-Row until cntr1 = cntr2.(4)
 
     EXEC SQL CLOSE C1 END-EXEC.
 
     EXEC SQL COMMIT END-EXEC.
 
* Return the SQLCA Information to the Calling Program.
     move SQLCA to O-SQLCA.
     EXEC SQL COMMIT END-EXEC.
     move SQLZ-DISCONNECT-PROC to return-code
     goback. (5)
 
 Fetch-Row.
     add 1 to cntr1.
     EXEC SQL FETCH C1 USING DESCRIPTOR :inout-sqlda END-EXEC.
 
 ERROR-EXIT.
* An Error has Occurred -- ROLLBACK and Return to Calling Program.
     EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC.
     move SQLCA to O-SQLCA.
     EXEC SQL ROLLBACK END-EXEC.
     move SQLZ-DISCONNECT-PROC to return-code
     goback.

FORTRAN UNIX Example: OUTSRV.SQF

 
      integer*4 function outsrv( reserved1, (2)
     +                           reserved2,
     +                           io_sqlda,
     +                           ca )
      implicit none
 
*     Include Files for Constants and Structures
      include 'sql.f' (1)
      include 'sqlenv.f'
      include 'sqlutil.f'
      include 'sqldact.f'
 
*     Declare Input Parameters
      integer*4  reserved1
      integer*4  reserved2
      character  io_sqlda(sqlda_header_sz + 1*sqlvar_struct_sz)
      character  ca(sqlca_size)
 
*     Declare a Local SQLCA
      EXEC SQL INCLUDE SQLCA
 
*     Declare Host Variables
      EXEC SQL BEGIN DECLARE SECTION
        integer*4      num_records
        character*50   stmt
      EXEC SQL END DECLARE SECTION
 
*     Declare Miscellaneous Variables
      integer*2    cntr
 
*     Program Logic
 
      EXEC SQL WHENEVER SQLERROR GOTO 100
 
      EXEC SQL DECLARE c1 CURSOR FOR s1
 
*     Prepare a Statement to Obtain and Order all Salaries
      stmt = 'SELECT SALARY FROM STAFF ORDER BY SALARY'
      EXEC SQL PREPARE s1 FROM :stmt
 
*     Determine the Total Number of Records
      EXEC SQL SELECT COUNT(*) INTO :num_records FROM STAFF (3)
 
*     Fetch Salaries until the Median Salary is Obtained
      EXEC SQL OPEN c1
      cntr = 0
      do 10 while ( cntr .lt. (num_records/2 + 1) )
        cntr = cntr + 1
        EXEC SQL FETCH c1 USING DESCRIPTOR :io_sqlda (4)
10    end do
      EXEC SQL CLOSE c1
 
      EXEC SQL COMMIT
 
*     Copy Local Variables into Dummy Output Variables
*     Copy the sqlca to the ca
      cntr = 0
      do 20 while ( cntr .lt. sqlca_size )
        cntr = cntr + 1
        ca(cntr) = sqlca(cntr)
20    end do
 
      goto 200
 
100   continue                                ! An Error has Occurred
*     Copy Local Variables into Dummy Output Variables
*     Copy the sqlca to the ca
      EXEC SQL WHENEVER SQLERROR CONTINUE
      cntr = 0
      do 30 while ( cntr .lt. sqlca_size )
        cntr = cntr + 1
        ca(cntr) = sqlca(cntr)
30    end do
 
      EXEC SQL ROLLBACK
 
200   continue                                 ! Exit Program
      outsrv = sqlz_disconnect_proc
      return (5)
      end
 

REXX OS/2 Example: OUTSRV.CMD

/* REXX OUTput SeRVer */
 
/* this variable (SYSTEM) must be user defined */
SYSTEM = OS2
if SYSTEM = OS2 then do
  if rxfuncquery('SQLDBS') <> 0 then
     rcy = rxfuncadd( 'SQLDBS',  'DB2AR', 'SQLDBS'  )
 
  if rxfuncquery('SQLEXEC') <> 0 then
     rcy = rxfuncadd( 'SQLEXEC', 'DB2AR', 'SQLEXEC' )
end
 
if SYSTEM = AIX then
rcy = SysAddFuncPkg("/usr/lpp/db2_05_00/lib/db2rexx")
 
call SQLEXEC 'DECLARE c1 CURSOR FOR s1'
call CHECKERR 'DECLARE'
 
/* DETERMINE TOTAL NUMBER OF RECORDS */
stmt = 'SELECT COUNT(*) FROM STAFF'  (3)
call SQLEXEC 'PREPARE s1 FROM :stmt'
call CHECKERR 'PREPARE count statement'
 
call SQLEXEC 'OPEN c1'
call CHECKERR 'OPEN count statement'
 
call SQLEXEC 'FETCH c1 INTO :num_records'
call CHECKERR 'FETCH'
 
call SQLEXEC 'CLOSE c1'
call CHECKERR 'CLOSE c1 after FETCH of num_records'
 
/* PREPARE A STATEMENT TO OBTAIN AND ORDER ALL SALARIES */
stmt = 'SELECT salary FROM STAFF ORDER BY salary'
call SQLEXEC 'PREPARE s1 FROM :stmt'
call CHECKERR 'PREPARE order statement'
 
call SQLEXEC 'OPEN c1'
call CHECKERR 'OPEN order statement'
 
/* FETCH SALARIES UNTIL THE MEDIAN SALARY IS OBTAINED */
i = 0
do while ( i < (num_records/2) )  (4)
  call SQLEXEC 'FETCH c1 USING DESCRIPTOR :SQLRODA'
  call CHECKERR 'FETCH'
  i = i + 1
end
call SQLEXEC 'CLOSE c1'
call CHECKERR 'CLOSE c1 after FETCH of median'
 
call SQLEXEC 'COMMIT'
call CHECKERR 'COMMIT'
 
exit 0 /* Normal exit */
 
 
CHECKERR:
  arg errloc
 
  if  ( SQLCA.SQLCODE = 0 ) then
    return 0
  else
    say '--- error report ---'
    say 'ERROR occured :' errloc
    say 'SQLCODE :' SQLCA.SQLCODE
 
    /******************************\
    * GET ERROR MESSAGE API called *
    \******************************/
    call SQLDBS 'GET MESSAGE INTO :errmsg LINEWIDTH 80'
    say errmsg
    say '--- end error report ---'
 
    if (SQLCA.SQLCODE < 0 ) then
      exit
    else
      say 'WARNING - CONTINUING PROGRAM WITH ERRORS'
      return 0
    end
  end
return 0


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

[ DB2 List of Books | Search the DB2 Books ]