DSN8ED1

Pass Db2 commands received from standard input to stored procedure DSN8ED2 for execution.

 /********************************************************************/         
 /*   Module name = DSN8ED1 (sample program)                         */         
 /*                                                                  */         
 /*   DESCRIPTIVE NAME = Stored procedure result set requester pgm   */         
 /*                                                                  */         
 /*    LICENSED MATERIALS - PROPERTY OF IBM                          */         
 /*    5645-DB2                                                      */         
 /*    (C) COPYRIGHT 1998 IBM CORP.  ALL RIGHTS RESERVED.            */         
 /*                                                                  */         
 /*    STATUS = VERSION 6                                            */         
 /*                                                                  */         
 /*   Function =                                                     */         
 /*                                                                  */         
 /*      Pass DB2 commands received from standard input to           */         
 /*      stored procedure DSN8ED2 for execution.  Receive the        */         
 /*      command results from DSN8ED2 as result set.  Unload the     */         
 /*      result set and print the contents to standard output.       */         
 /*                                                                  */         
 /*      Dependencies = None                                         */         
 /*                                                                  */         
 /*      Restrictions =                                              */         
 /*                                                                  */         
 /*         1. DB2 commands must be preceded by a hyphen and         */         
 /*            followed by a semicolon. Lines with an asterisk       */         
 /*            in the first column or two hyphens as the first       */         
 /*            nonblank characters are interpreted as comment        */         
 /*            lines.  Two hyphens placed after the command text in  */         
 /*            in a line indicate that the rest of the line is       */         
 /*            comments only.                                        */         
 /*                                                                  */         
 /*         2. A command may be no more than 4096 bytes.             */         
 /*                                                                  */         
 /*      Input =                                                     */         
 /*         1. A single input parameter that indicates the location  */         
 /*            of the stored procedure. The contents must be a       */         
 /*            valid DB2 location name of at most 16 characters.     */         
 /*                                                                  */         
 /*         2. Lines of length INPUTL from standard input.           */         
 /*            Only the first INPUSED bytes are used. Lines are      */         
 /*            considered to be either command text or comments.     */         
 /*            Command text begins with a hyphen and ends with a     */         
 /*            semicolon. Comments begin with an asterisk in         */         
 /*            column one or two hyphens as the first two nonblank   */         
 /*            characters. Command text may span lines, but comment  */         
 /*            text may not.                                         */         
 /*                                                                  */         
 /*      Output =                                                    */         
 /*            Lines of length OUTLEN to standard output.            */         
 /*            Each line contains one of the following:              */         
 /*            a. Command text.                                      */         
 /*            b. Results returned by the DB2 for MVS/ESA command    */         
 /*               processor after the command is issued.             */         
 /*                                                                  */         
 /*   Module type  = C program                                       */         
 /*      Processor =                                                 */         
 /*         ADMF Precompiler                                         */         
 /*         C/370                                                    */         
 /*      Module size = See linkedit output                           */         
 /*      Attributes = Not reentrant or reusable                      */         
 /*                                                                  */         
 /*   Entry point = DSN8ED1                                          */         
 /*      Purpose  = See Function                                     */         
 /*      Linkage  = Standard MVS program invocation, one parameter.  */         
 /*                                                                  */         
 /*   Exit normal =                                                  */         
 /*                                                                  */         
 /*      Return code 0 on normal completion.                         */         
 /*                                                                  */         
 /*   Normal messages =                                              */         
 /*                                                                  */         
 /*      *** Input statement:  <DB2 command input statement text>    */         
 /*      *** IFI return area:  <Results of DB2 command execution>    */         
 /*                                                                  */         
 /*                                                                  */         
 /*   Exit-error =                                                   */         
 /*                                                                  */         
 /*      Return code =  4 - Warnings occurred.                       */         
 /*        -  The DB2 for MVS/ESA Instrumentation Facility Interface */         
 /*           (IFI) invocation of the DB2 command resulted in a      */         
 /*           return code 4. The accompanying reason code indicates  */         
 /*           the specific problem.                                  */         
 /*                                                                  */         
 /*      Return code =  8 - Errors occurred.                         */         
 /*        -  The DB2 for MVS/ESA Instrumentation Facility Interface */         
 /*           (IFI) invocation of the DB2 command resulted in a      */         
 /*           return code 8. The accompanying reason code indicates  */         
 /*           the specific problem.                                  */         
 /*                                                                  */         
 /*      Return code = 12 - Severe errors occurred.                  */         
 /*        -  Input parameter 1 did not contain the name of the      */         
 /*           DB2 server where the stored procedure resides.         */         
 /*        -  The input dataset (SYSIN) did not contain any data.    */         
 /*        -  Command input did not begin with a hyphen.             */         
 /*        -  Command input was not ended with a semicolon.          */         
 /*        -  An input statement contained more than STMTMAX         */         
 /*           bytes.                                                 */         
 /*        -  Connection to the stored procedure location failed.    */         
 /*        -  The SQL CALL statement to the stored procedure failed. */         
 /*        -  The DB2 for MVS/ESA Instrumentation Facility Interface */         
 /*           (IFI) invocation of the DB2 command resulted in a      */         
 /*           return code 12. The accompanying reason code indicates */         
 /*           the specific problem.                                  */         
 /*        -  The call to the stored procedure, DSN8ED2, succeeded   */         
 /*           but DSN8ED2 experienced SQL problems.  The formatted   */         
 /*           SQL error message appears in SYSPRINT.                 */         
 /*        -  The call to the stored procedure, DSN8ED2, succeeded   */         
 /*           but no result set was returned.  SYSPRINT messages     */         
 /*           should provide more information.                       */         
 /*        -  A result set was returned by DSN8ED2 but one of the    */         
 /*           following occurred (see SYSPRINT messages for details):*/         
 /*           - The locator variable could not be associated with    */         
 /*             the result set.                                      */         
 /*           - The result set cursor could not be allocated         */         
 /*           - No data could be fetched from the result set cursor. */         
 /*                                                                  */         
 /*      Abend codes = None                                          */         
 /*                                                                  */         
 /*   Error messages =                                               */         
 /*      -  *** ERROR: No server name provided - DSN8ED1 ended.      */         
 /*      -  *** ERROR: No input records found - DSN8ED1 ended.       */         
 /*      -  *** ERROR: Syntax for DB2 command is invalid.            */         
 /*         ***        A valid command ends with a semicolon.        */         
 /*      -  *** ERROR: Syntax for DB2 command is invalid.            */         
 /*         ***        A valid command begins with a hyphen.         */         
 /*      -  *** ERROR: Statement length is greater than the ____     */         
 /*                    character maximum.                            */         
 /*      -  *** ERROR: Connection to server <location> was unsuc-    */         
 /*                    cessful.                                      */         
 /*      -  *** ERROR: Call to stored procedure DSN8ED2 failed;      */         
 /*                    diagnostics follow.                           */         
 /*      -  *** ERROR: The following diagnostics were returned by    */         
 /*                    stored procedure DSN8ED2.                     */         
 /*      -  *** ERROR: DSNTIAR could not format the message.         */         
 /*                    SQLCODE is ____, SQLERRM is ___________ ...   */         
 /*      -  *** WARNING: Call to stored procedure DSN8ED2 succeeded  */         
 /*                      but no result set was returned.             */         
 /*      -  *** WARNING: IFI error codes returned by DSN8ED2.        */         
 /*                      Return code=___, reason code=____ from      */         
 /*                      IFI request.                                */         
 /*      -  *** WARNING: ____ records were lost because the IFI      */         
 /*                      return area in stored procedure DSN8ED2     */         
 /*                      is too small to accomodate this request.    */         
 /*                   ** Increase the IFI return area (RETURN_LEN)   */         
 /*                      in DSN8ED2 and then recompile/relink/rebind */         
 /*                      before resubmitting this request.           */         
 /*                                                                  */         
 /*      -  *** Syntax for DB2 command is invalid.                   */         
 /*         *** A valid command must begin with a hyphen.            */         
 /*                                                                  */         
 /*      -  *** Statement length is greater than the <STMTMAX>       */         
 /*             character maximum.                                   */         
 /*      -  *** Connection to <location> unsuccessful.               */         
 /*         *** SQLCODE is <sqlcode>.                                */         
 /*      -  *** Call to DSN8ED2 unsuccessful.                        */         
 /*         *** SQLCODE is <sqlcode>.                                */         
 /*      -  *** Insufficient space to receive all output from IFI    */         
 /*             return area.                                         */         
 /*      -  *** Return code=<return code>, reason code=<reason code> */         
 /*             from IFI request.                                    */         
 /*      -  *** Severe error occurred. Program is terminating.       */         
 /*                                                                  */         
 /*   External references =                                          */         
 /*      Routines/services =                                         */         
 /*         none                                                     */         
 /*      Data areas =                                                */         
 /*         none                                                     */         
 /*      Control blocks =                                            */         
 /*         SQLCA - SQL communication area                           */         
 /*                                                                  */         
 /*   Pseudocode =                                                   */         
 /*                                                                  */         
 /*   DSN8ED1:                                                       */         
 /*   - Extract the name of the DB2 server where stored procedure    */         
 /*     DSN8ED2 resides from input parameter number 1.               */         
 /*   - Call build_DB2_command to create a logical DB2 command record*/         
 /*     from one or more records from SYSIN.                         */         
 /*   - If a command was created successfully, do the following until*/         
 /*     all input has been processed or severe errors occur.         */         
 /*       - Call connect_to_sp_server to connect to the DB2 server   */         
 /*         specified in the first input parameter.                  */         
 /*       - Call send_DB2_command_to_sp to invoke stored procedure   */         
 /*         DSN8ED2 to process the command.                          */         
 /*       - Call output_results_from_sp to unload the result set     */         
 /*         from DSN8ED2 to SYSPRINT.                                */         
 /*       - Call build_DB2_command to create the next logical DB2    */         
 /*         command record from SYSIN records.                       */         
 /*   End DSN8ED1                                                    */         
 /*                                                                  */         
 /*   build_DB2_command:                                             */         
 /*   - Read a record from SYSIN                                     */         
 /*   - Do the following until either a full command is built, end   */         
 /*     of file is reached, or an error occurs:                      */         
 /*     - if the first byte of the record is '*' or the first two    */         
 /*       nonblank bytes of the record are '--' then the whole       */         
 /*       record is a comment.  Disregard it.                        */         
 /*     - if '--' is encountered after nonblanks are found then the  */         
 /*       rest of the record is a comment and can be disregarded.    */         
 /*     - else if a semicolon is found inside a delimited string     */         
 /*       call copy_byte_to_cmd_buf to add it to the command string. */         
 /*       - a delimited string is one that starts but has not yet    */         
 /*         terminated with a single quote or a double quote         */         
 /*     - else if a semicolon is found outside a delimited string    */         
 /*       then the command is complete.                              */         
 /*     - else if a nonblank is found then call copy_byte_to_cmd_buf */         
 /*       to add it to the command string.                           */         
 /*     - else if a blank is found inside a delimited string then    */         
 /*       call copy_byte_to_cmd_buf to add it to the command string. */         
 /*     - else if a blank is found outside a delimited string and    */         
 /*       the preceding byte was nonblank then call copy_byte_to_    */         
 /*       cmd_buf to add it to the command string.                   */         
 /*     - else if a blank is found outside a delimited string and    */         
 /*       the preceding byte was blank then disregard the blank.     */         
 /*     - if the input record is exhausted before a terminating      */         
 /*       semicolon is found, read the next input record.            */         
 /*   - When a command is created successfully, call echo_DB2_command*/         
 /*     to output the reformatted command.                           */         
 /*   - Check the command to ensure that it starts with a hypen.     */         
 /*   End build_DB2_command                                          */         
 /*                                                                  */         
 /*   copy_byte_to_cmd_buf                                           */         
 /*   - append the current byte of the input record to the end of    */         
 /*     the command string and update length of command string.      */         
 /*   - if command string exceeds buffer size, issue a message and   */         
 /*     end DSN8ED1.                                                 */         
 /*   End copy_byte_to_cmd_buf                                       */         
 /*                                                                  */         
 /*   echo_DB2_command                                               */         
 /*   - output the reformatted DB2 command to SYSPRINT               */         
 /*   End echo_DB2_command                                           */         
 /*                                                                  */         
 /*   connect_to_sp_server                                           */         
 /*   - invoke SQL to CONNECT to the DB2 server where stored proc-   */         
 /*     edure DSN8ED2 resides.                                       */         
 /*   - if the CONNECT fails, issue a message and end DSN8ED1.       */         
 /*   End connect_to_sp_server                                       */         
 /*                                                                  */         
 /*   send_DB2_command_to_sp                                         */         
 /*   - invoke SQL to call stored procedure DSN8ED2 to process the   */         
 /*     contents of the command buffer.                              */         
 /*   - analyze the resultant SQLCODE, IFI return and result codes,  */         
 /*     and buffer overload and error parameters returned by DSN8ED2.*/         
 /*   End send_DB2_command_to_sp                                     */         
 /*                                                                  */         
 /*   output_results_from_sp                                         */         
 /*   - associate a DB2 locator variable with the result set from    */         
 /*     stored procedure DSN8ED2                                     */         
 /*   - allocate a cursor to the result set                          */         
 /*   - fetch each row from the result set and output it to SYSPRINT */         
 /*   End output_results_from_sp                                     */         
 /*                                                                  */         
 /*   sql_error                                                      */         
 /*   - invoke DSNTIAR to format the current SQL code and print the  */         
 /*     messages to SYSPRINT                                         */         
 /*   - if DSNTIAR cannot detail the code, output the SQLCODE and    */         
 /*     SQLERRM to SYSPRINT                                                     
 /*   End sql_error                                                  */         
 /*                                                                  */         
 /*  Change activity =                                               */         
 /*    none                                                          */         
 /********************************************************************/         
                                                                                
 /********************** C library definitions ***********************/         
 #include    <stdio.h>                                                          
 #include    <stdlib.h>                                                         
 #include    <string.h>                                                         
                                                                                
 /**************************** Constants *****************************/         
 #define     INPUTL         81         /* Length of input line       */         
 #define     INPUSED        72         /* Bytes used in an input line*/         
 #define     LOCLEN         16         /* Length of input parm (loc) */         
 #define     OUTLEN         81         /* Length of output line      */         
 #define     RETWRN          4         /* Warning return code        */         
 #define     RETERR          8         /* Error return code          */         
 #define     RETSEV         12         /* Severe error return code   */         
 #define     STMTMAX      4096         /* Maximum statement length   */         
 #define     ASTERISK      '*'         /* Comment indicator          */         
 #define     BLANK         ' '         /* Blank                      */         
 #define     HYPHEN        '-'         /* Hyphen                     */         
 #define     NULLCHAR     '\0'         /* Null character             */         
 #define     QUOTE        '\''         /* Quotation mark             */         
 #define     DQUOTE        '"'         /* Double quote               */         
 #define     SEMICOLON     ';'         /* SQL stmt terminator        */         
                                                                                
 enum flag   {No, Yes};                /* Settings for flags         */         
                                                                                
 /********************** Program Argument List ***********************/         
 char *parms[];                        /* Contains input parameter   */         
                                                                                
 /********************** Standard Input/Output ***********************/         
 FILE        *sysin;                   /* Input statements           */         
 char        input[INPUTL];            /* Current input data         */         
 char        *inres;                   /* Result of gets invocation  */         
                                                                                
 FILE        *sysprint;                /* Command results/error msgs */         
                                                                                
 /************************ Working variables *************************/         
 short int   c;                        /* pointer to command buffer  */         
 enum flag   dquotflag;                /* '"' delimiter status       */         
 short int   i;                        /* pointer to input buffer    */         
 short int   j;                        /* miscellaneous counter, ptr */         
 enum flag   endstr;                   /* End of statement flag      */         
 enum flag   input_eof;                /* End of input data flag     */         
 enum flag   quoteflag;                /* "'" delimiter status       */         
                                                                                
 /************************ DB2 Host Variables ************************/         
 EXEC SQL BEGIN DECLARE SECTION;                                                
 char        db2loc2[17];              /* Remote DB2 location name   */         
 long int    ifca_ret_hex;             /* Return code from IFI call  */         
 long int    ifca_res_hex;             /* Reason code from IFI call  */         
 long int    xs_bytes_hex;             /* No. of bytes not returned  */         
 long int    rc;                       /* All-purpose return var     */         
 struct {                                                                       
   short int   sp_err_blen;            /* Error msg buffer length    */         
   char        sp_err_txt[880];        /* Error msg text             */         
        }    sp_err_buf;               /* Error message buffer from  */         
                                       /*  stored procedure          */         
 short int   sperind1;                 /* Indicator vars for parm 1  */         
 short int   sperind2;                 /* Indicator vars for parm 2  */         
 short int   sperind3;                 /* Indicator vars for parm 3  */         
 short int   sperind4;                 /* Indicator vars for parm 4  */         
 short int   sperind5;                 /* Indicator vars for parm 5  */         
                                                                                
 struct {                                                                       
   short int   cmdlen;                 /* Statement length           */         
   char        cmdtxt[4096];           /* Statement text             */         
        }    cmdbuf;                   /* Statement buffer passed to */         
                                       /*  stored procedure          */         
                                                                                
                                       /* Result set locator         */         
 static volatile SQL TYPE IS RESULT_SET_LOCATOR *DSN8ED2_rs_loc;                
                                                                                
 long int    rs_sequence;              /* Result set table data sequ */         
 char        rs_data[80];              /* Result set data buffer     */         
                                       /* - length is OUTLEN - 1     */         
 EXEC SQL END DECLARE SECTION;                                                  
                                                                                
 /******************** DB2 SQL Communication Area ********************/         
 EXEC SQL INCLUDE SQLCA;                                                        
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** main routine                                                     **         
 **********************************************************************         
 *********************************************************************/         
 int main( int argc, char *argv[] )                            /*proc*/         
 {                                                                              
   /*******************************************************************         
   * initialize working variables                                     *         
   *******************************************************************/         
   cmdbuf.cmdlen = 0;                  /* Nothing in command buf yet */         
   input_eof = No;                     /* Not at end of input        */         
   rc = 0;                             /* No errors yet              */         
                                                                                
   sperind1 = -1;                      /* Clear null indicator var 1 */         
   sperind2 = -1;                      /* Clear null indicator var 2 */         
   sperind3 = -1;                      /* Clear null indicator var 3 */         
   sperind4 = -1;                      /* Clear null indicator var 4 */         
   sperind5 = -1;                      /* Clear null indicator var 5 */         
                                                                                
   /*******************************************************************         
   * get input parameter (name of server where stored proc resides)   *         
   *******************************************************************/         
   for( j=1; j<argc; j++ )             /* break out the input parms  */         
     parms[j] = argv[j];                                                        
                                                                                
   for( j=0; j<LOCLEN; j++ )           /* Extract name of DB2 server */         
     db2loc2[j] = *(parms[1]+j);       /*  where sp resides          */         
                                                                                
   if( db2loc2[1] == BLANK )           /* If no server specified,    */         
   {                                   /*  issue error               */         
     printf( " *** ERROR: No server name provided - DSN8ED1 ended.\n" );        
     rc = RETSEV;                                                               
   }                                                                            
                                                                                
   db2loc2[j]=NULLCHAR;                /* Null-terminate the string  */         
                                                                                
   /*******************************************************************         
   * build the first DB2 command from one or more input records       *         
   *******************************************************************/         
   if( rc < RETSEV )                                                            
   {                                                                            
     build_DB2_command();                                                       
     if( input_eof == Yes  &&  rc < RETSEV )                                    
     {                                                                          
       printf( " *** ERROR: No input records found - DSN8ED1 ended.\n");        
       rc = RETSEV;                                                             
     }                                                                          
   }                                                                            
                                                                                
   /******************************************************************/         
   /* If a command was built successfully, connect to the DB2 server */         
   /* where the stored procedure resides, send the command to the    */         
   /* stored procedure, output the results, and build the next com-  */         
   /* mand, if any.                                                  */         
   /******************************************************************/         
   while( input_eof == No  &&  rc < RETSEV )                                    
   {                                                                            
     connect_to_sp_server();           /* connect to the server      */         
                                                                                
     if( rc < RETSEV )                 /* if successful              */         
       send_DB2_command_to_sp();       /*  invoke the stored proc    */         
                                                                                
     if( rc < RETSEV )                 /* if successful              */         
       output_results_from_sp();       /*  out the results           */         
                                                                                
     if( rc < RETSEV )                 /* if successful              */         
       build_DB2_command();            /*  process the next input    */         
   }                                                                            
                                                                                
   printf( " \n \n *** DSN8ED1 completed; highest return code was %d\n",        
           rc );                                                                
                                                                                
   return( rc );                       /* put return code in ctl blk */         
                                                                                
                                                                                
 } /* end of main program */                                                    
                                                                                
                                                                                
 /********************************************************************          
 *********************************************************************          
 ** Build a DB2 command from one or more physical input records     **          
 *********************************************************************          
 ********************************************************************/          
 build_DB2_command()                                           /*proc*/         
 {                                                                              
   /*******************************************************************         
   * initialize working variables                                     *         
   *******************************************************************/         
   for( i=0; i<INPUTL; i++ )           /* Blank the input array      */         
     input[i] = ' ';                                                            
                                                                                
   c = 0;                              /* marks pos'n in command buf */         
   cmdbuf.cmdlen = 0;                  /* no. of bytes in cmd buffer */         
   dquotflag = No;                     /* flags delimiter stat of '"'*/         
   endstr = No;                        /* flags end of log inp record*/         
   i = 0;                              /* marks pos'n in input buffer*/         
   quoteflag = No;                     /* flags delimiter stat of "'"*/         
                                                                                
   /*******************************************************************         
   * read the first physical record of the command from input         *         
   *******************************************************************/         
   inres = gets( input );                                                       
   if( inres == NULL )                 /* If end of file reached     */         
     input_eof = Yes;                  /*  then all finished         */         
                                                                                
   /*******************************************************************         
   * parse the current input record for DB2 command parts             *         
   *******************************************************************/         
   while( endstr == No  &&  input_eof == No  &&  rc < RETSEV )                  
   {                                                                            
     /*****************************************************************         
     * If 1st char in a line is '*' -OR- the 1st two non-blank chars  *         
     * in a line are '--', this is a comment line.  Don't copy it to  *         
     * the command buffer; request next line.                         *         
     *****************************************************************/         
     if( i == 0  &&  input[0] == ASTERISK )                                     
       i = INPUSED;                                                             
     else if( cmdbuf.cmdlen == 0                                                
           && input[0] == HYPHEN  &&  input[1] == HYPHEN )                      
       i = INPUSED;                                                             
                                                                                
     /*****************************************************************         
     * Otherwise, this must be a command line.  Parse it into the com-*         
     * mand buffer while looking for delimiters and the end of stmt.  *         
     *****************************************************************/         
     else                                                                       
       while( i < INPUSED  &&  endstr == No  &&  rc < RETSEV )                  
       {                                                                        
         if( input[i] == DQUOTE )      /* if double quote found      */         
           if( dquotflag == Yes )      /*  and is already a delimiter*/         
             dquotflag = No;           /*   note end of delimited str*/         
           else if( quoteflag == No )  /*  else if it's not delimited*/         
             dquotflag = Yes;          /*   then it's a delimiter    */         
                                                                                
         if( input[i] == QUOTE )       /* if single quote found      */         
           if( quoteflag == Yes )      /*  and is already a delimiter*/         
             quoteflag = No;           /*  -note end of delimited str*/         
           else if( dquotflag == No )  /*  else if it's not delimited*/         
             quoteflag = Yes;          /*  then it's a delimiter     */         
                                                                                
         if( input[i] == HYPHEN        /* if '--' found in current   */         
         &&  input[i+1] == HYPHEN      /*  and next byte             */         
          && i < INPUSED               /*  not at end of input line  */         
          && quoteflag == No           /*  and not in a delimited    */         
          && dquotflag == No )         /*  strng then rest is comment*/         
           i = INPUSED;                /*   ignore it; rqst next line*/         
                                                                                
         else if( input[i] == SEMICOLON/* else if semicolon found    */         
          && quoteflag == No           /*  and it's not delimited    */         
          && dquotflag == No )         /*  then command is complete  */         
           endstr = Yes;               /*   fall through             */         
                                                                                
         else if( input[i] != BLANK )  /* else if non-blank found    */         
           copy_byte_to_cmd_buf();     /*  copy it to command buffer */         
                                                                                
         else if( input[i] == BLANK    /* else if blank found        */         
          && ( quoteflag == Yes        /*  and it's in a delimited   */         
            || dquotflag == Yes ) )    /*  string                    */         
           copy_byte_to_cmd_buf();     /*   copy it to command buffer*/         
                                                                                
         else if( input[i] == BLANK    /* else if blank found        */         
          && c > 0                     /*  and something's in cmd buf*/         
          && cmdbuf.cmdtxt[c-1]!=BLANK)/* and prev cmd byte nonblank */         
           copy_byte_to_cmd_buf();     /*   copy it to command buffer*/         
                                                                                
         else;                         /* swallow all other blanks   */         
                                                                                
         i++;                          /* bump pos'n in input record */         
                                                                                
       } /* end while( i<INPUSED  &&  endstr == No  &&  rc<RETSEV )  */         
                                                                                
     /*****************************************************************         
     * if current physical record is exhausted but the current log-   *         
     * ical record is still incomplete, get the next physical record  *         
     *****************************************************************/         
     if( i >= INPUSED  &&  endstr == No  &&  rc < RETSEV )                      
     {                                                                          
       for( i=0; i<INPUTL; i++ )       /* Blank the input array      */         
         input[i] = ' ';                                                        
       i = 0;                          /* reset pointer to input buff*/         
       inres = gets( input );          /* Read the next physical rec */         
       if( inres == NULL )             /* If end of file reached     */         
       {                               /*  current logical rec inmplt*/         
         input_eof = Yes;              /*  don't ask for more        */         
         printf( " *** ERROR: Syntax for DB2 command is invalid.\n");           
         printf( " ***        A valid command ends with a" );                   
         printf( " semicolon.\n" );                                             
         rc = RETSEV;                  /*  stop the program          */         
       }                                                                        
     }                                                                          
   } /* end while( endstr == No && input_eof == No && rc < RETSEV )  */         
                                                                                
   /*******************************************************************         
   * display the reformatted command (if one exists)                  *         
   *******************************************************************/         
   if( cmdbuf.cmdlen > 0 )                                                      
     echo_DB2_command();                                                        
                                                                                
   /*******************************************************************         
   * verify that the command has a valid syntax                       *         
   *******************************************************************/         
   if( endstr == Yes  &&  input_eof == No  &&  rc < RETSEV )                    
     if( cmdbuf.cmdtxt[0] != HYPHEN )                                           
     {                                                                          
       printf( " *** ERROR: Syntax for DB2 command is invalid.\n");             
       printf( " ***        A valid command begins with a hyphen.\n" );         
       rc = RETSEV;                                                             
     }                                                                          
 } /* end of build_DB2_command() */                                             
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** Copy the current byte of current input line to command buffer    **         
 **********************************************************************         
 *********************************************************************/         
 copy_byte_to_cmd_buf()                                        /*proc*/         
 {                                                                              
   cmdbuf.cmdtxt[c++] = input[i];                                               
   cmdbuf.cmdlen = c;                                                           
                                                                                
   /*******************************************************************         
   * if entry is too long for command buffer, issue message and quit  *         
   *******************************************************************/         
   if( cmdbuf.cmdlen >= STMTMAX )                                               
   {                                                                            
     printf( " *** ERROR: Statement length is greater than the" );              
     printf( " %d character maximum.\n",STMTMAX );                              
     rc = RETSEV;                                                               
   }                                                                            
 } /* end of copy_byte_to_cmd_buf() */                                          
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** Connect to the server where the stored procedure resides         **         
 **********************************************************************         
 *********************************************************************/         
 connect_to_sp_server()                                        /*proc*/         
 {                                                                              
   EXEC SQL CONNECT TO :db2loc2;                                                
   if( SQLCODE != 0 )                                                           
   {                                                                            
     printf( " *** ERROR: Connection to server %s was unsuccessful.\n",         
             db2loc2 );                                                         
     sql_error( " *** Connection to server unsuccessful" );                     
     rc = RETSEV;                                                               
   }                                                                            
 } /* end of connect_to_sp_server() */                                          
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** Process the current DB2 command built from the input file        **         
 **********************************************************************         
 *********************************************************************/         
 send_DB2_command_to_sp()                                      /*proc*/         
 {                                                                              
   sperind1 = 0;                          /* tell DB2 to transmit    */         
                                          /*  contents of parm 1     */         
   EXEC SQL CALL DSN8.DSN8ED2(       :cmdbuf :sperind1,                         
                               :ifca_ret_hex :sperind2,                         
                               :ifca_res_hex :sperind3,                         
                               :xs_bytes_hex :sperind4,                         
                                 :sp_err_buf :sperind5 );                       
                                                                                
   /*******************************************************************         
   * verify the SQL return code returned by the stored procedure      *         
   *******************************************************************/         
   if( SQLCODE == 0 )                                                           
   {                                                                            
     printf( " *** WARNING: Call to stored procedure DSN8ED2" );                
     printf(     " succeeded\n" );                                              
     printf( "              but no result set was returned.\n" );               
     if( rc < RETERR )                                                          
       rc = RETERR;                                                             
   }                                                                            
   else if( SQLCODE == 466 )                                                    
   {                                                                            
     printf( " *** A result set was returned by stored procedure" );            
     printf(     " DSN8ED2.\n" );                                               
   }                                                                            
   else                                                                         
   {                                                                            
     printf( " *** ERROR: Call to stored procedure DSN8ED2 failed;" );          
     printf(     " diagnostics follow.\n" );                                    
     sql_error( "*** Stored procedure call unsuccessful." );                    
     rc = RETSEV;                                                               
   }                                                                            
                                                                                
   /*******************************************************************         
   * verify the IFI return code returned by the stored procedure      *         
   *******************************************************************/         
   if( sperind2 != -1  &&  ifca_ret_hex != 0 )                                  
   {                                                                            
     printf( " *** WARNING: IFI error codes returned by DSN8ED2.\n" );          
     printf( " ***          Return code=%0X ", ifca_ret_hex );                  
     printf( " *** reason code=%0X from IFI request.\n", ifca_res_hex );        
     if( ifca_ret_hex > rc )                                                    
       rc = ifca_ret_hex;                                                       
   }                                                                            
                                                                                
   /*******************************************************************         
   * if IFI return buffer was too small, output a message             *         
   *******************************************************************/         
   if( sperind4 != -1  &&  xs_bytes_hex != 0 )                                  
   {                                                                            
     printf( " *** WARNING: %d bytes were lost", xs_bytes_hex );                
     printf( " because the IFI return area in stored\n" );                      
     printf( " ***          procedure DSN8ED2 is too small" );                  
     printf( " to accomodate this request.\n" );                                
     printf( " ***       ** Increase the IFI return area" );                    
     printf( " (RETURN_LEN) in DSN8ED2 and then\n" );                           
     printf( " ***          recompile/relink/rebind before" );                  
     printf( " resubmitting the request.\n" );                                  
     if( rc < RETWRN )                                                          
       rc = RETWRN;                                                             
   }                                                                            
                                                                                
   /*******************************************************************         
   * output any data from the error message buffer                    *         
   *******************************************************************/         
   if( sperind5 != -1 )                                                         
   {                                                                            
     printf( " *** ERROR: The following diagnostics were returned by" );        
     printf(     " stored procedure DSN8ED2.\n \n" );                           
     for( j = 0; j < sp_err_buf.sp_err_blen; j++ )                              
       printf( "%c",sp_err_buf.sp_err_txt[j] );                                 
     printf( "\n" );                                                            
     if( rc < RETSEV )                                                          
       rc = RETSEV;                                                             
   }                                                                            
                                                                                
 } /* end of send_DB2_command_to_sp() */                                        
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** Write out the DB2 command that has been built from input records **         
 **********************************************************************         
 *********************************************************************/         
 echo_DB2_command()                                            /*proc*/         
 {                                                                              
   short int  c;                       /* local ptr to command buffer*/         
   short int  k,kk,l;                  /* counters and loop control  */         
                                                                                
   printf( " \n \n *** Input Statement:\n" );                                   
                                                                                
   c = 0;                                                                       
   /*******************************************************************         
   * calculate no. of full print lines the cmd uses and print them    *         
   *******************************************************************/         
   kk = cmdbuf.cmdlen / (OUTLEN - 1);                                           
   for( k=1; k<=kk; k++ )                                                       
   {                                                                            
     printf( " " );                                                             
     for( l=0; l<(OUTLEN-1); l++ )                                              
     {                                                                          
       printf( "%c",cmdbuf.cmdtxt[c++] );                                       
     }                                                                          
     printf( "\n" );                                                            
   }                                                                            
                                                                                
   /*******************************************************************         
   * calculate no. of partial print lines the cmd uses; print them    *         
   *******************************************************************/         
   kk = cmdbuf.cmdlen % (OUTLEN - 1);                                           
   if( kk > 0 )                                                                 
   {                                                                            
     printf( " " );                                                             
     for( k=1; k<=kk; k++ )                                                     
     {                                                                          
       printf( "%c",cmdbuf.cmdtxt[c++] );                                       
     }                                                                          
     printf( "\n" );                                                            
   }                                                                            
 } /* end of echo_DB2_command() */                                              
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** Output the contents of the result set returned by the stored     **         
 ** procedure.                                                       **         
 **********************************************************************         
 *********************************************************************/         
 output_results_from_sp()                                      /*proc*/         
 {                                                                              
                                                                                
   /*******************************************************************         
   * local initialization                                             *         
   *******************************************************************/         
   for(j=0; j<(OUTLEN-1); j++)         /* Blank the input array      */         
     rs_data[j] = BLANK;               /* Initialize result string   */         
   rs_sequence = 0;                    /* Initialize data sequence   */         
                                                                                
   printf( " \n \n *** IFI return area:\n" );                                   
                                                                                
   /*******************************************************************         
   * associate a locator variable with the result                     *         
   *******************************************************************/         
   EXEC SQL ASSOCIATE LOCATOR          /* Associate the result set   */         
     (:DSN8ED2_rs_loc)                 /* locator with a host var.   */         
     WITH PROCEDURE DSN8.DSN8ED2;      /*                            */         
   if (SQLCODE != 0 )                  /* If unsuccessful then       */         
   {                                   /* - Say so                   */         
     sql_error( "*** Associate result set locator call unsuccessful." );        
                                       /* - Print the sqlcode        */         
     rc = RETSEV;                      /* - Flush remainder of proc  */         
   }                                   /*                            */         
                                                                                
   /*******************************************************************         
   * allocate the result set cursor                                   *         
   *******************************************************************/         
   if( rc < RETSEV )                   /* Or if okay so far then     */         
   {                                   /*                            */         
     EXEC SQL ALLOCATE DSN8ED2_RS_CSR  /* - Allocate a cursor to read*/         
       CURSOR FOR                      /* - Allocate a cursor to read*/         
       RESULT SET :DSN8ED2_rs_loc;     /*   the result set locator   */         
     if (SQLCODE != 0 )                /* - If unsuccessful then     */         
     {                                 /*   - Say so                 */         
       sql_error( "*** Allocate result set cursor call unsuccessful." );        
                                       /*   - Print the sqlcode      */         
       rc = RETSEV;                    /*   - Flush remainder of proc*/         
     }                                 /*                            */         
   }                                   /*                            */         
                                                                                
   /*******************************************************************         
   * fetch first row from the result set                              *         
   *******************************************************************/         
   if( rc < RETSEV )                   /* Or if okay so far then     */         
   {                                                                            
     EXEC SQL FETCH DSN8ED2_RS_CSR     /* - Fetch first row (if any) */         
       INTO :rs_sequence, :rs_data;    /*   from the result set csr  */         
     if (SQLCODE != 0 )                /* - If unsuccessful then     */         
     {                                 /*   - Say so                 */         
       sql_error("*** Priming fetch of result set cursor unsuccessful");        
                                       /*   - Print the sqlcode      */         
       rc = RETSEV;                    /*   - Flush remainder of proc*/         
     }                                 /*                            */         
   }                                   /*                            */         
                                                                                
   /*******************************************************************         
   * output the contents of the result set                            *         
   *******************************************************************/         
   while(SQLCODE == 0 && rc < RETSEV)  /* Or if okay so far then     */         
   {                                   /* until all lines processed  */         
     printf( " %s\n", rs_data );       /* -- Output current line     */         
                                       /*                            */         
     EXEC SQL FETCH DSN8ED2_RS_CSR     /* -- Get the next one from   */         
       INTO :rs_sequence, :rs_data;    /*    the result set cursor   */         
   }                                   /*                            */         
                                                                                
   /*******************************************************************         
   * check for successful processing of result set                    *         
   *******************************************************************/         
   if (SQLCODE != 100 && rc < RETSEV)  /* If unsuccessful then       */         
   {                                   /* - Say so                   */         
     sql_error( "*** Fetch of result set cursor unsuccessful." );               
                                       /* - Print the sqlcode        */         
     rc = RETSEV;                      /* - Set return code          */         
   }                                   /*                            */         
                                                                                
 } /* end of output_results_from_sp() */                                        
                                                                                
                                                                                
 /*********************************************************************         
 **********************************************************************         
 ** SQL error handler                                                **         
 **********************************************************************         
 *********************************************************************/         
 #pragma linkage(dsntiar, OS)                                                   
                                                                                
 sql_error( char locmsg[] )                                    /*proc*/         
 {                                                                              
   #define     DATA_DIM       10       /* Number of message lines    */         
                                                                                
   struct      error_struct {          /* DSNTIAR message structure  */         
     short int   error_len;                                                     
     char        error_text[DATA_DIM][OUTLEN-1];                                
     }         error_message = {DATA_DIM * (OUTLEN-1)};                         
                                                                                
   extern short int dsntiar( struct      sqlca         *sqlca,                  
                             struct      error_struct  *msg,                    
                             int                       *len );                  
                                                                                
   short int   rc;                     /* DSNTIAR Return code        */         
   int         j;                      /* Loop control               */         
   static int  lrecl = OUTLEN - 1;     /* Width of message lines     */         
                                                                                
   /*******************************************************************         
   * print the locator message                                        *         
   *******************************************************************/         
   printf( " %.80s\n", locmsg );                                                
                                                                                
   /*******************************************************************         
   * format and print the SQL message                                 *         
   *******************************************************************/         
   rc = dsntiar( &sqlca, &error_message, &lrecl );                              
   if( rc == 0 )                                                                
     for( j=0; j<=DATA_DIM; j++ )                                               
       printf( " %.80s\n", error_message.error_text[j] );                       
   else                                                                         
     {                                                                          
       printf( " *** ERROR: DSNTIAR could not format the message\n" );          
       printf( " ***        SQLCODE is %d\n",SQLCODE );                         
       printf( " ***        SQLERRM is \n" );                                   
       for( j=0; j<sqlca.sqlerrml; j++ )                                        
         printf( "%c", sqlca.sqlerrmc[j] );                                     
       printf( "\n" );                                                          
     }                                                                          
                                                                                
 } /* end of sql_error */