DSN8DLTC

Compares the data in the EMP_PHOTO_RESUME sample Db2 table to the data in the source data sets to ensure that the LOB columns are being populated and retrieved correctly.

 /*********************************************************************         
 * Module name = DSN8DLTC (DB2 sample program)                        *         
 *                                                                    *         
 * DESCRIPTIVE NAME = Validate length and contents of sample LOB data *         
 *                                                                    *         
 *                                                                    *         
 *     Licensed Materials - Property of IBM                           *         
 *     5635-DB2                                                       *         
 *     (C) COPYRIGHT 1982, 2006 IBM Corp.  All Rights Reserved.       *         
 *                                                                    *         
 *     STATUS = Version 9                                             *         
 *                                                                    *         
 * Function: Compares the data in the EMP_PHOTO_RESUME sample DB2     *         
 *           table to the data in the source data sets to ensure that *         
 *           the LOB columns are being populated and retrieved        *         
 *           correctly.                                               *         
 *                                                                    *         
 * Notes:                                                             *         
 *   Dependencies: Requires IBM C/C++ for OS/390 V1R3 or higher       *         
 *                                                                    *         
 *   Restrictions:                                                    *         
 *                                                                    *         
 * Module type: C program                                             *         
 *   Processor: IBM C/C++ for OS/390 V1R3 or subsequent release       *         
 * Module size: See linkedit output                                   *         
 *  Attributes: Re-entrant and re-usable                              *         
 *                                                                    *         
 * Entry Point: CEESTART (Language Environment entry point)           *         
 *     Purpose: See Function                                          *         
 *     Linkage: Standard MVS program invocation, no parameters        *         
 *                                                                    *         
 *       Input: Symbolic label/name = PSEGINnn, where 00 <= nn <= 99  *         
 *              Description = PSEG photo image data                   *         
 *                                                                    *         
 *              Symbolic label/name = BMPINnn, where 00 <= nn <= 99   *         
 *              Description = BMP photo image data                    *         
 *                                                                    *         
 *              Symbolic label/name = RESUMEnn, where 00 <= nn <= 99  *         
 *              Description = Resume data                             *         
 *                                                                    *         
 *      Output: Symbolic label/name = SYSPRINT                        *         
 *              Description = Report and messages                     *         
 *                                                                    *         
 * Normal Exit: Return Code = 0000                                    *         
 *              - Message: DSN8DLTC DB2 Sample Program                *         
 *                                    Results of LOB data validation  *         
 *                                    for employee number xxxxxx      *         
 *                                    follow:                         *         
 *                                                                    *         
 *              - Message: *** VALID: The PSEG BLOB column length     *         
 *                                    matches the PSEG file length    *         
 *                                    length                          *         
 *              - Message: *** VALID: The PSEG BLOB column data       *         
 *                                    matches the PSEG file data      *         
 *                                                                    *         
 *              - Message: *** VALID: The BMP BLOB column length      *         
 *                                    matches the BMP file length     *         
 *                                    length                          *         
 *                                                                    *         
 *              - Message: *** VALID: The BMP BLOB column data        *         
 *                                    matches the BMP file data       *         
 *                                                                    *         
 *              - Message: *** VALID: The RESUME CLOB column length   *         
 *                                    matches the RESUME file length  *         
 *                                    length                          *         
 *                                                                    *         
 *              - Message: *** VALID: The RESUME CLOB column data     *         
 *                                    matches the RESUME file data    *         
 *                                                                    *         
 *  Error Exit: Return Code = 0008                                    *         
 *              - Message: *** ERROR: The PSEG BLOB column data does  *         
 *                                    does not match the PSEG file    *         
 *                                    data                            *         
 *                                    - first mismatch occurred at    *         
 *                                      byte offset nnn               *         
 *                                                                    *         
 *              - Message: *** ERROR: The PSEG BLOB column length     *         
 *                                    does not match the PSEG file    *         
 *                                    length                          *         
 *                                    - PSEG BLOB length is: nnnn     *         
 *                                    - PSEG file length is: nnnn     *         
 *                                                                    *         
 *              - Message: *** ERROR: The BMP BLOB column data does   *         
 *                                    does not match the BMP file     *         
 *                                    data                            *         
 *                                    - first mismatch occurred at    *         
 *                                      byte offset nnn               *         
 *                                                                    *         
 *              - Message: *** ERROR: The BMP BLOB column length      *         
 *                                    does not match the BMP file     *         
 *                                    length                          *         
 *                                    - BMP BLOB length is: nnnn      *         
 *                                    - BMP file length is: nnnn      *         
 *                                                                    *         
 *              - Message: *** ERROR: The RESUME CLOB column data does*         
 *                                    does not match the RESUME file  *         
 *                                    data                            *         
 *                                    - first mismatch occurred at    *         
 *                                      byte offset nnn               *         
 *                                                                    *         
 *              - Message: *** ERROR: The RESUME BLOB column length   *         
 *                                    does not match the RESUME file  *         
 *                                    length                          *         
 *                                    - RESUME BLOB length is: nnnn   *         
 *                                    - RESUME file length is: nnnn   *         
 *                                                                    *         
 *              - Message: *** ERROR: DSN8DLTC DB2 Sample Program     *         
 *                                    Unable to open BMPINnn DD data  *         
 *                                    set.  Processing terminated.    *         
 *                                                                    *         
 *              - Message: *** ERROR: DSN8DLTC DB2 Sample Program     *         
 *                                    Unable to open RESUMEnn DD data *         
 *                                    set.  Processing terminated.    *         
 *                                                                    *         
 *              - Message: *** ERROR: DSN8DLTC DB2 Sample Program     *         
 *                                    Unexpected SQLCODE encountered  *         
 *                                    at location xxx                 *         
 *                                    Error detailed below            *         
 *                                    Processing terminated           *         
 *                                    (DSNTIAR-formatted message      *         
 *                                    follows).                       *         
 *                                                                    *         
 *    External References:                                            *         
 *             - Routines/Services: DSNTIAR                           *         
 *             - Data areas       : DSNTIAR error_message             *         
 *             - Control blocks   : None                              *         
 *                                                                    *         
 *                                                                    *         
 *  Pseudocode:                                                       *         
 *   DSN8DLTC:                                                        *         
 *   - Set DD counter (nn) to 00                                      *         
 *   - Do while more PSEGINnn DD's to process                         *         
 *     - Call getPSEGdata to read in an employee's photo image in PSEG*         
 *       PSEG format from the data set associated with the PSEGINnn   *         
 *       DD.                                                          *         
 *     - Call getBMPdata to read in an employee's photo image in BMP  *         
 *       format from the data set associated with the BMPINnn DD.     *         
 *     - Call storeBLOBdata to apply the PSEG and BMP images to the   *         
 *       PSEG_PHOTO and BMP_PHOTO columns of the EMP_PHOTO_RESUME     *         
 *       sample table.                                                *         
 *     - Increment DD counter (nn) by 1.                              *         
 *   End DSN8DLTC                                                     *         
 *                                                                    *         
 *   getPSEGdata:                                                     *         
 *   - Open the PSEGINnn input file                                   *         
 *   - Read in bytes and concatenate them in a buffer until EOF       *         
 *   - Close the PSEGINnn input file                                  *         
 *                                                                    *         
 *   getBMPdata:                                                      *         
 *   - Open the BMPINnn input file                                    *         
 *   - Read in bytes and concatenate them in a buffer until EOF       *         
 *   - Close the BMPINnn input file                                   *         
 *                                                                    *         
 *   storeBLOBdata:                                                   *         
 *   - Extract the employee serial from bytes 10-15 of the PSEG       *         
 *     buffer.                                                        *         
 *   - SQL UPDATE the PSEG buffer into the PSEG_PHOTO column and the  *         
 *     BMP buffer into the BMP_PHOTO column of the EMP_PHOTO_RESUME   *         
 *     sample table for the employee number.                          *         
 *   - If an SQL error occurs, call sql_error                         *         
 *                                                                    *         
 *   sql_error:                                                       *         
 *   - call DSNTIAR to format the unexpected SQLCODE.                 *         
 *                                                                    *         
 *********************************************************************/         
 /********************** C library definitions ***********************/         
 #include <stdlib.h>                                                            
 #include <stdio.h>                                                             
 #include <string.h>                                                            
                                                                                
                                                                                
 /***************************** Equates ******************************/         
 #define       NO             0        /* False                      */         
 #define       YES            1        /* True                       */         
                                                                                
 #define       NOT_OK         0        /* Bad                        */         
 #define       OK             1        /* Good                       */         
                                                                                
 #define       TIAR_DIM      10        /* Max no. of DSNTIAR msgs    */         
 #define       TIAR_LEN      80        /* Length of DSNTIAR messages */         
                                                                                
                                                                                
 /****************************** Files *******************************/         
 FILE          *BMPin;                 /* pointer to BMP input file  */         
 FILE          *PSEGin;                /* pointer to PSEG input file */         
 FILE          *RESUMEin;              /* pntr to resume input file  */         
                                                                                
                                                                                
 /************************** Global Storage **************************/         
 int           status       = OK;      /* Run status indicator       */         
 int           mismatch     = NO;      /* Data check status          */         
                                                                                
 short int     DDcounter    = 0;       /* DD allocation counter      */         
 short int     validDD      = YES;     /* unprocessed DD indicator   */         
                                                                                
 short int     PSEGblkLen   = 0;       /* length of PSEG input block */         
 short int     PSEGblkPos   = 0;       /* offset in PSEG input block */         
 short int     PSEGrecLen   = 0;       /* length of PSEG input record*/         
 short int     PSEGrecPos   = 0;       /* offset in PSEG input record*/         
                                                                                
 short int     BMPblkLen    = 0;       /* length of BMP input block  */         
 short int     BMPblkPos    = 0;       /* offset in BMP input block  */         
 short int     BMPrecLen    = 0;       /* length of BMP input record */         
 short int     BMPrecPos    = 0;       /* offset in BMP input record */         
                                                                                
 short int     RSMblkLen = 0;          /* length of resume inp block */         
 short int     RSMblkPos = 0;          /* offset in resume inp block */         
 short int     RSMrecLen = 0;          /* length of resume inp record*/         
 short int     RSMrecPos = 0;          /* offset in resume inp record*/         
                                                                                
 int           byteIn;                 /* current incoming byte      */         
                                                                                
                                                                                
 /******************** DB2 SQL Communication Area ********************/         
 EXEC SQL INCLUDE SQLCA;                                                        
                                                                                
                                                                                
 /**************************** DB2 Tables ****************************/         
 EXEC SQL DECLARE  EMP_PHOTO_RESUME  TABLE                                      
   (        EMPNO  CHAR(06)     NOT NULL,                                       
        EMP_ROWID  ROWID,                                                       
       PSEG_PHOTO  BLOB( 500K ),                                                
        BMP_PHOTO  BLOB( 100K ),                                                
           RESUME  CLOB(   5K )         );                                      
                                                                                
                                                                                
 /************** DB2 Host and Null Indicator Variables ***************/         
 EXEC SQL BEGIN DECLARE SECTION;                                                
   char        hvEMPNO[7];             /* Hots var for emp no. col   */         
                                                                                
   SQL TYPE IS BLOB(500K) PSEGinRec;   /* Area for PSEG input record */         
   SQL TYPE IS BLOB(500K) hvPSEG_PHOTO;/* Host var for PSEG photo col*/         
   short int     niPSEG_PHOTO = 0;     /* Null ind for PSEG photo col*/         
                                                                                
   SQL TYPE IS BLOB(100K) BMPinRec;    /* Area for BMP input record  */         
   SQL TYPE IS BLOB(100K) hvBMP_PHOTO; /* Host var for BMP photo col */         
   short int     niBMP_PHOTO  = 0;     /* Null ind for BMP photo col */         
                                                                                
   SQL TYPE IS CLOB(5K) RESUMErec;     /* Area for RESUME input rec  */         
   SQL TYPE IS CLOB(5K) hvRESUME;      /* Host var for resume column */         
   short int     niRESUME     = 0;     /* Null ind for resume column */         
                                                                                
 EXEC SQL END DECLARE SECTION;                                                  
                                                                                
                                                                                
 /********************** DB2 Message Formatter ***********************/         
 struct      error_struct {            /* DSNTIAR message structure  */         
   short int   error_len;                                                       
   char        error_text[TIAR_DIM][TIAR_LEN];                                  
   }         error_message = {TIAR_DIM * (TIAR_LEN)};                           
                                                                                
 #pragma linkage( dsntiar, OS )                                                 
                                                                                
 extern  short int dsntiar( struct      sqlca         *sqlca,                   
                            struct      error_struct  *msg,                     
                            int                       *len );                   
                                                                                
                                                                                
 /************************* Global Functions *************************/         
 int  main( void );                    /* driver                     */         
 void readPSEGfile( void );            /* load data from PSEG file   */         
 void readBMPfile( void );             /* load data from BMP file    */         
 void readResumeFile( void );          /* load data from resume file */         
 void readEMP_PHOTO_RESUMEtable(void); /* get PSEG, BMP, and resume  */         
 void compareData( void );             /* compare DB2 data vs. file  */         
 void sql_error( char *locnMsg );      /* generate msg for SQL error */         
                                                                                
 /********************************************************************/         
 /*************************** main routine ***************************/         
 /********************************************************************/         
 int main( void )                                                               
 {                                                                              
   /*******************************************************************         
   * Write identification header                                      *         
   *******************************************************************/         
   printf( "****************************************"                           
           "****************************************\n" );                      
   printf( "* DSN8DLTC DB2 Sample Program\n"            );                      
   printf( "****************************************"                           
           "****************************************\n" );                      
                                                                                
   /*******************************************************************         
   * Cycle through PSEGINnn and BMPINnn DD pairs, incrementing the DD *         
   * counter, until all pairs have been processed.                    *         
   *******************************************************************/         
   for( DDcounter=0; validDD == YES  &&  status == OK; DDcounter++ )            
     {                                                                          
       /***************************************************************         
       * Fetch the PSEG data from the PSEGINnn data set.  This record *         
       * also contains the serial number of the employee associated   *         
       * with the photo.                                              *         
       ***************************************************************/         
       readPSEGfile();                                                          
                                                                                
       /***************************************************************         
       * Fetch the BMP data from the BMPINnn data set                 *         
       ***************************************************************/         
       if( validDD == YES  &&  status == OK )                                   
         readBMPfile();                                                         
                                                                                
       /***************************************************************         
       * Fetch the resume data from the RESUMEin data set             *         
       ***************************************************************/         
       if( validDD == YES  &&  status == OK )                                   
         readResumeFile();                                                      
                                                                                
       /***************************************************************         
       * Fetch the BMP and PSEG photo image and resume data from DB2  *         
       ***************************************************************/         
       if( validDD == YES  &&  status == OK )                                   
         readEMP_PHOTO_RESUMEtable();                                           
                                                                                
       /***************************************************************         
       * Compare the data on DB2 to the data from the flatfiles       *         
       ***************************************************************/         
       if( validDD == YES  &&  status == OK )                                   
         compareData();                                                         
     } /* end for */                                                            
                                                                                
   /*******************************************************************         
   * If an unexpected situation occurred, set return code 0012        *         
   *******************************************************************/         
   if( status != OK )                                                           
      return( 12 );                                                             
   /*******************************************************************         
   * Or, if a data mismatch was detected, set return code 0008        *         
   *******************************************************************/         
   else if( mismatch == YES )                                                   
      return( 8 );                                                              
   /*******************************************************************         
   * Otherwise, set return code 0000                                  *         
   *******************************************************************/         
   else                                                                         
      return( 0 );                                                              
                                                                                
 } /* end main */                                                               
                                                                                
                                                                                
 void readPSEGfile( void )                                                      
 /*********************************************************************         
 * Called by the main routine to read the contents of the PSEG input  *         
 * data set into a buffer, PSEGinRec.  Subsequently, this buffer will *         
 * be compared to the data in the PSEG_PHOTO column of the EMP_PHOTO_ *         
 * RESUME table to ensure a match.                                    *         
 **********************************************************************         
 * Because the C language is not record-oriented in the sense of MVS  *         
 * data sets, it's necessary to treat the PSEG data set, which has a  *         
 * variable-blocked format, as an unformatted dataset in order to     *         
 * access the block descriptor word (BDW) of each input block and the *         
 * record descriptor word (RDW) of each input record.                 *         
 *                                                                    *         
 * Each RDW provides the number of bytes of data in its record,       *         
 * including 4 bytes for itself.                                      *         
 *                                                                    *         
 * Each BDW provides the number of bytes of data in its block,        *         
 * including 4 bytes for each RDW in the block and 4 bytes for        *         
 * itself.                                                            *         
 *********************************************************************/         
 {                                                                              
   /*******************************************************************         
   * local variables                                                  *         
   *******************************************************************/         
   char PSEGinDD[12]  = "DD:PSEGIN\0"; /* PSEGin DD template         */         
   char DDnum[2];                      /* DD number string template  */         
                                                                                
   /*******************************************************************         
   * intialize work variables                                         *         
   *******************************************************************/         
   PSEGrecLen = 0;                                                              
   PSEGrecPos = 0;                                                              
   PSEGblkPos = 0;                                                              
   PSEGblkLen = 0;                                                              
   PSEGinRec.length = 0;                                                        
                                                                                
   /*******************************************************************         
   * form the DD name for the next PSEG data set                      *         
   *******************************************************************/         
   sprintf( DDnum,"%02d",DDcounter );  /* convert DD cntr to string  */         
   strcat( PSEGinDD,DDnum );           /* form PSEGINnn DD name      */         
                                                                                
   /*******************************************************************         
   * open the PSEG input file                                         *         
   *******************************************************************/         
   PSEGin = fopen( PSEGinDD,"rb,recfm=u" );                                     
                                                                                
   if( PSEGin == NULL )                /* if no pointer returned     */         
     validDD = NO;                     /* .. no more data sets left  */         
                                                                                
   /*******************************************************************         
   * read the 1st byte of the record                                  *         
   *******************************************************************/         
   while( status == OK                                                          
      &&  validDD == YES                                                        
      && (byteIn = getc(PSEGin)) != EOF )                                       
     {                                                                          
       /***************************************************************         
       * if at the end of a block, read and process the next BDW      *         
       ***************************************************************/         
       if( PSEGblkPos >= PSEGblkLen  &&  PSEGrecPos >= PSEGrecLen )             
         {                                                                      
           /***********************************************************         
           * length of block = (16**2) * BDW[0]                       *         
           * ............... + (16**0) * BDW[1]                       *         
           * ............... - 4 (length of BDW)                      *         
           ***********************************************************/         
           PSEGblkLen = 256 * byteIn;                                           
           byteIn = getc(PSEGin);                                               
           PSEGblkLen = PSEGblkLen + byteIn - 4;                                
                                                                                
           /***********************************************************         
           * skip remainder of BDW                                    *         
           ***********************************************************/         
           byteIn = getc(PSEGin);                                               
           byteIn = getc(PSEGin);                                               
           PSEGblkPos = 0;                                                      
                                                                                
           /***********************************************************         
           * read first byte of RDW                                   *         
           ***********************************************************/         
           byteIn = getc(PSEGin);                                               
         }                                                                      
       /***************************************************************         
       * if at the end of a record, read and process next RDW         *         
       ***************************************************************/         
       if( PSEGrecPos >= PSEGrecLen )                                           
         {                                                                      
           /***********************************************************         
           * length of record = (16**2) * RDW[0]                      *         
           * ................ + (16**0) * RDW[1]                      *         
           * ................ - 4 (length of RDW)                     *         
           ***********************************************************/         
           PSEGrecLen = 256 * byteIn;                                           
           byteIn = getc(PSEGin);                                               
           PSEGrecLen = PSEGrecLen + byteIn - 4;                                
           /***********************************************************         
           * skip remainder of RDW                                    *         
           ***********************************************************/         
           byteIn = getc(PSEGin);                                               
           byteIn = getc(PSEGin);                                               
           PSEGrecPos = 0;                                                      
                                                                                
           /***********************************************************         
           * update position in block                                 *         
           ***********************************************************/         
           PSEGblkPos = PSEGblkPos + PSEGrecLen + 4;                            
         }                                                                      
       /***************************************************************         
       * move PSEG data bytes to the PSEGin file buffer               *         
       ***************************************************************/         
       else                                                                     
         {                                                                      
           PSEGinRec.data[PSEGinRec.length++] = byteIn;                         
           PSEGrecPos++;                                                        
         }                                                                      
     }                                                                          
                                                                                
   /*******************************************************************         
   * close the PSEG input file                                        *         
   *******************************************************************/         
   fclose( PSEGin );                                                            
                                                                                
 } /* end readPSEGfile */                                                       
                                                                                
                                                                                
 void readBMPfile( void )                                                       
 /*********************************************************************         
 * Called by the main routine to read the contents of the BMP input   *         
 * data set into a buffer, BMPinRec.  Subsequently, this buffer will  *         
 * be compared to the data in the BMP_PHOTO column of the EMP_PHOTO_  *         
 * RESUME table to ensure a match.                                    *         
 **********************************************************************         
 * Because the C language is not record-oriented in the sense of MVS  *         
 * data sets, it's necessary to treat the BMP data set, which has a   *         
 * variable-blocked format, as an unformatted dataset in order to     *         
 * access the block descriptor word (BDW) of each input block and the *         
 * record descriptor word (RDW) of each input record.                 *         
 *                                                                    *         
 * Each RDW provides the number of bytes of data in its record,       *         
 * including 4 bytes for itself.                                      *         
 *                                                                    *         
 * Each BDW provides the number of bytes of data in its block,        *         
 * including 4 bytes for each RDW in the block and 4 bytes for        *         
 * itself.                                                            *         
 *********************************************************************/         
 {                                                                              
   /*******************************************************************         
   * local variables                                                  *         
   *******************************************************************/         
   char BMPinDD[12]  = "DD:BMPIN\0";   /* BMPin DD template          */         
   char DDnum[2];                      /* DD number string template  */         
                                                                                
   /*******************************************************************         
   * intialize work variables                                         *         
   *******************************************************************/         
   BMPrecLen = 0;                                                               
   BMPrecPos = 0;                                                               
   BMPblkPos = 0;                                                               
   BMPblkLen = 0;                                                               
   BMPinRec.length = 0;                                                         
                                                                                
   /*******************************************************************         
   * form the DD name for the next BMP data set                       *         
   *******************************************************************/         
   sprintf( DDnum,"%02d",DDcounter );  /* convert DD cntr to string  */         
   strcat( BMPinDD,DDnum );            /* form BMPINnn DD name       */         
                                                                                
   /*******************************************************************         
   * open the current BMPINnn DD data set                             *         
   *******************************************************************/         
   BMPin = fopen( BMPinDD,"rb,recfm=u" );                                       
                                                                                
   if( BMPin == NULL )                                                          
     {                                                                          
       printf( "*************************************************\n" );         
       printf( "*** ERROR: DSN8DLTC DB2 Sample Program\n"            );         
       printf( "***        Unable to open BMPIN%s DD data set\n",               
               DDnum );                                                         
       printf( "***        Processing terminated\n"                  );         
       printf( "*************************************************\n" );         
       status = NOT_OK;                                                         
     }                                                                          
                                                                                
   /*******************************************************************         
   * read the 1st byte of the record                                  *         
   *******************************************************************/         
   while( status == OK  &&  (byteIn = getc(BMPin)) != EOF )                     
     {                                                                          
       /***************************************************************         
       * if at the end of a block, read and process the next BDW      *         
       ***************************************************************/         
       if( BMPblkPos >= BMPblkLen  &&  BMPrecPos >= BMPrecLen )                 
         {                                                                      
           /***********************************************************         
           * length of block = (16**2) * BDW[0]                       *         
           * ............... + (16**0) * BDW[1]                       *         
           * ............... - 4 (length of BDW)                      *         
           ***********************************************************/         
           BMPblkLen = 256 * byteIn;                                            
           byteIn = getc(BMPin);                                                
           BMPblkLen = BMPblkLen + byteIn - 4;                                  
                                                                                
           /***********************************************************         
           * skip remainder of BDW                                    *         
           ***********************************************************/         
           byteIn = getc(BMPin);                                                
           byteIn = getc(BMPin);                                                
           BMPblkPos = 0;                                                       
                                                                                
           /***********************************************************         
           * read first byte of RDW                                   *         
           ***********************************************************/         
           byteIn = getc(BMPin);                                                
         }                                                                      
       /***************************************************************         
       * if at the end of a record, read and process next RDW         *         
       ***************************************************************/         
       if( BMPrecPos >= BMPrecLen )                                             
         {                                                                      
           /***********************************************************         
           * length of record = (16**2) * RDW[0]                      *         
           * ................ + (16**0) * RDW[1]                      *         
           * ................ - 4 (length of RDW)                     *         
           ***********************************************************/         
           BMPrecLen = 256 * byteIn;                                            
           byteIn = getc(BMPin);                                                
           BMPrecLen = BMPrecLen + byteIn - 4;                                  
           /***********************************************************         
           * skip remainder of RDW                                    *         
           ***********************************************************/         
           byteIn = getc(BMPin);                                                
           byteIn = getc(BMPin);                                                
           BMPrecPos = 0;                                                       
                                                                                
           /***********************************************************         
           * update position in block                                 *         
           ***********************************************************/         
           BMPblkPos = BMPblkPos + BMPrecLen + 4;                               
         }                                                                      
       /***************************************************************         
       * move BMP data bytes to the BMPin file buffer                 *         
       ***************************************************************/         
       else                                                                     
         {                                                                      
           BMPinRec.data[BMPinRec.length++] = byteIn;                           
           BMPrecPos++;                                                         
         }                                                                      
     }                                                                          
                                                                                
   /*******************************************************************         
   * close the BMP input file                                         *         
   *******************************************************************/         
   fclose( BMPin );                                                             
                                                                                
 } /* end readBMPfile */                                                        
                                                                                
                                                                                
 void readResumeFile( void )                                                    
 /*********************************************************************         
 * Called by the main routine to read the contents of the RESUME in-  *         
 * put data set into a buffer, RESUMErec.  Subsequently, this buffer  *         
 * will be compared to the data in the RESUME column of the EMP_      *         
 * PHOTO_RESUME table to ensure a match.                              *         
 **********************************************************************         
 * Because the C language is not record-oriented in the sense of MVS  *         
 * data sets, it's necessary to treat the RESUME data set, which has  *         
 * a variable-blocked format, as an unformatted dataset in order to   *         
 * access the block descriptor word (BDW) of each input block and the *         
 * record descriptor word (RDW) of each input record.                 *         
 *                                                                    *         
 * Each RDW provides the number of bytes of data in its record,       *         
 * including 4 bytes for itself.                                      *         
 *                                                                    *         
 * Each BDW provides the number of bytes of data in its block,        *         
 * including 4 bytes for each RDW in the block and 4 bytes for        *         
 * itself.                                                            *         
 *********************************************************************/         
 {                                                                              
   /*******************************************************************         
   * local variables                                                  *         
   *******************************************************************/         
   char RESUMEDD[12]  = "DD:RESUME\0"; /* BMPin DD template          */         
   char DDnum[2];                      /* DD number string template  */         
                                                                                
   /*******************************************************************         
   * intialize work variables                                         *         
   *******************************************************************/         
   RSMrecLen = 0;                                                               
   RSMrecPos = 0;                                                               
   RSMblkPos = 0;                                                               
   RSMblkLen = 0;                                                               
   RESUMErec.length = 0;                                                        
                                                                                
   /*******************************************************************         
   * form the DD name for the next RESUME data set                    *         
   *******************************************************************/         
   sprintf( DDnum,"%02d",DDcounter );  /* convert DD cntr to string  */         
   strcat( RESUMEDD,DDnum );           /* form RESUMEnn DD name      */         
                                                                                
   /*******************************************************************         
   * open the current RESUMEnn DD data set                            *         
   *******************************************************************/         
   RESUMEin = fopen( RESUMEDD,"rb,recfm=u" );                                   
                                                                                
   if( RESUMEin == NULL )                                                       
     {                                                                          
       printf( "*************************************************\n" );         
       printf( "*** ERROR: DSN8DLTC DB2 Sample Program\n"            );         
       printf( "***        Unable to open RESUME%s DD data set\n",              
               DDnum );                                                         
       printf( "***        Processing terminated\n"                  );         
       printf( "*************************************************\n" );         
       status = NOT_OK;                                                         
     }                                                                          
                                                                                
   /*******************************************************************         
   * read the 1st byte of the record                                  *         
   *******************************************************************/         
   while( status == OK  &&  (byteIn = getc(RESUMEin)) != EOF )                  
     {                                                                          
       /***************************************************************         
       * if at the end of a block, read and process the next BDW      *         
       ***************************************************************/         
       if(RSMblkPos >= RSMblkLen && RSMrecPos >= RSMrecLen)                     
         {                                                                      
           /***********************************************************         
           * length of block = (16**2) * BDW[0]                       *         
           * ............... + (16**0) * BDW[1]                       *         
           * ............... - 4 (length of BDW)                      *         
           ***********************************************************/         
           RSMblkLen = 256 * byteIn;                                            
           byteIn = getc(RESUMEin);                                             
           RSMblkLen = RSMblkLen + byteIn - 4;                                  
                                                                                
           /***********************************************************         
           * skip remainder of BDW                                    *         
           ***********************************************************/         
           byteIn = getc(RESUMEin);                                             
           byteIn = getc(RESUMEin);                                             
           RSMblkPos = 0;                                                       
                                                                                
           /***********************************************************         
           * read first byte of RDW                                   *         
           ***********************************************************/         
           byteIn = getc(RESUMEin);                                             
         }                                                                      
       /***************************************************************         
       * if at the end of a record, read and process next RDW         *         
       ***************************************************************/         
       if( RSMrecPos >= RSMrecLen )                                             
         {                                                                      
           /***********************************************************         
           * length of record = (16**2) * RDW[0]                      *         
           * ................ + (16**0) * RDW[1]                      *         
           * ................ - 4 (length of RDW)                     *         
           ***********************************************************/         
           RSMrecLen = 256 * byteIn;                                            
           byteIn = getc(RESUMEin);                                             
           RSMrecLen = RSMrecLen + byteIn - 4;                                  
           /***********************************************************         
           * skip remainder of RDW                                    *         
           ***********************************************************/         
           byteIn = getc(RESUMEin);                                             
           byteIn = getc(RESUMEin);                                             
           RSMrecPos = 0;                                                       
                                                                                
           /***********************************************************         
           * update position in block                                 *         
           ***********************************************************/         
           RSMblkPos = RSMblkPos + RSMrecLen + 4;                               
         }                                                                      
       /***************************************************************         
       * move RESUME data bytes to the RESUMEin file buffer           *         
       ***************************************************************/         
       else                                                                     
         {                                                                      
           RESUMErec.data[RESUMErec.length++] = byteIn;                         
           RSMrecPos++;                                                         
         }                                                                      
     }                                                                          
                                                                                
   /*******************************************************************         
   * close the RESUME input file                                      *         
   *******************************************************************/         
   fclose( RESUMEin );                                                          
                                                                                
 } /* end readResumeFile */                                                     
                                                                                
                                                                                
 void readEMP_PHOTO_RESUMEtable( void )                                         
 /*********************************************************************         
 * Called by the main routine to retrieve the PSEG and BMP photo      *         
 * images and the resume data for an employee from the EMP_PHOTO_     *         
 * RESUME table.                                                      *         
 *                                                                    *         
 * The employee number, which is the table key, is extracted from     *         
 * bytes 10-15 of the PSEG input record.                              *         
 *********************************************************************/         
 {                                                                              
   /*******************************************************************         
   * local variables                                                  *         
   *******************************************************************/         
   char *pEmpno;                       /* Pointer to employee no.    */         
                                                                                
   /*******************************************************************         
   * Extract the employee number from bytes 10-15 of the PSEG record  *         
   *******************************************************************/         
   pEmpno = &PSEGinRec.data[9];        /* point to start of emp. no. */         
   strncpy( hvEMPNO,pEmpno,6 );        /* and capture it             */         
                                                                                
   /*******************************************************************         
   * Fetch the PSEG, BMP, and resume data for the employee            *         
   *******************************************************************/         
   EXEC SQL SELECT  PSEG_PHOTO, BMP_PHOTO, RESUME                               
              INTO :hvPSEG_PHOTO,                                               
                   :hvBMP_PHOTO,                                                
                   :hvRESUME                                                    
              FROM  EMP_PHOTO_RESUME                                            
             WHERE  EMPNO = :hvEMPNO;                                           
                                                                                
   if( SQLCODE != 0 )                                                           
     {                                                                          
       status = NOT_OK;                                                         
       sql_error( "readEMP_PHOTO_RESUMEtable @1" );                             
     }                                                                          
                                                                                
 } /* end readEMP_PHOTO_RESUMEtable */                                          
                                                                                
                                                                                
 void compareData( void )                                                       
 /*********************************************************************         
 * Called by the main routine to compare the data from the photo      *         
 * images and the resume data for an employee from the EMP_PHOTO_     *         
 * RESUME table.                                                      *         
 *                                                                    *         
 * The employee number, which is the table key, is extracted from     *         
 * bytes 10-15 of the PSEG input record.                              *         
 *********************************************************************/         
 {                                                                              
                                                                                
   unsigned long h;                                                             
                                                                                
   /*******************************************************************         
   * Write heading for current employee                               *         
   *******************************************************************/         
   printf( "*   Results of LOB data validation for employee "                   
             "number %s follow:\n", hvEMPNO );                                  
   printf( "*   \n" );                                                          
                                                                                
   /*******************************************************************         
   * Compare employee's PSEG photo image on DB2 to flatfile version   *         
   *******************************************************************/         
   if( PSEGinRec.length == hvPSEG_PHOTO.length )                                
     {                                                                          
       printf( "*   VALID: The PSEG BLOB column length "                        
               "matches the PSEG file length\n" );                              
       for( h = 0;                                                              
            h < PSEGinRec.length                                                
             && PSEGinRec.data[h] == hvPSEG_PHOTO.data[h];                      
            h++ );                                                              
       if( h == PSEGinRec.length )                                              
         printf( "*   VALID: The PSEG BLOB column data "                        
                 "matches the PSEG file data\n" );                              
       else                                                                     
         {                                                                      
           printf( "* > ERROR: The PSEG BLOB column data "                      
                   "does not match the PSEG file data\n" );                     
           printf( "*   - first mismatch occurred "                             
                   "at byte offset %d\n",h );                                   
           mismatch = YES;                                                      
         }                                                                      
     }                                                                          
   else                                                                         
     {                                                                          
       printf( "* > ERROR: The PSEG BLOB column length "                        
               "does not match the PSEG file length\n" );                       
       printf( "*   - PSEG BLOB length is: %d\n",hvPSEG_PHOTO.length );         
       printf( "*   - PSEG file length is: %d\n",PSEGinRec.length );            
       mismatch = YES;                                                          
     }                                                                          
                                                                                
   /*******************************************************************         
   * Compare employee's BMP photo image on DB2 to flatfile version    *         
   *******************************************************************/         
   if( BMPinRec.length == hvBMP_PHOTO.length )                                  
     {                                                                          
       printf( "*   VALID: The BMP BLOB column length "                         
               "matches the BMP file length\n" );                               
       for( h = 0;                                                              
            h < BMPinRec.length                                                 
             && BMPinRec.data[h] == hvBMP_PHOTO.data[h];                        
            h++ );                                                              
       if( h == BMPinRec.length )                                               
         printf( "*   VALID: The BMP BLOB column data "                         
                 "matches the BMP file data\n" );                               
       else                                                                     
         {                                                                      
           printf( "* > ERROR: The BMP BLOB column data "                       
                   "does not match the BMP file data\n" );                      
           printf( "*   - first mismatch occurred "                             
                   "at byte offset %d\n",h );                                   
           mismatch = YES;                                                      
         }                                                                      
     }                                                                          
   else                                                                         
     {                                                                          
       printf( "* > ERROR: The BMP BLOB column length "                         
               "does not match the BMP file length\n" );                        
       printf( "*   - BMP BLOB length is: %d\n",hvBMP_PHOTO.length );           
       printf( "*   - BMP file length is: %d\n",BMPinRec.length );              
       mismatch = YES;                                                          
     }                                                                          
                                                                                
   /*******************************************************************         
   * Compare employee's resume image on DB2 to flatfile version       *         
   *******************************************************************/         
   if( RESUMErec.length == hvRESUME.length )                                    
     {                                                                          
       printf( "*   VALID: The RESUME CLOB column length "                      
               "matches the resume file length\n" );                            
       for( h = 0;                                                              
            h < RESUMErec.length                                                
             && RESUMErec.data[h] == hvRESUME.data[h];                          
            h++ );                                                              
       if( h == RESUMErec.length )                                              
         printf( "*   VALID: The RESUME CLOB column data "                      
                 "matches the resume file data\n" );                            
       else                                                                     
         {                                                                      
           printf( "* > ERROR: The RESUME CLOB column data "                    
                   "does not match the resume file data\n" );                   
           printf( "*   - first mismatch occurred "                             
                   "at byte offset %d\n",h );                                   
           mismatch = YES;                                                      
         }                                                                      
     }                                                                          
   else                                                                         
     {                                                                          
       printf( "* > ERROR: The RESUME CLOB column length "                      
               "does not match the resume file length\n" );                     
       printf( "*   - RESUME CLOB length is: %d\n",hvRESUME.length );           
       printf( "*   - Resume file length is: %d\n",RESUMErec.length );          
       mismatch = YES;                                                          
     }                                                                          
                                                                                
   printf( "****************************************"                           
           "****************************************\n" );                      
                                                                                
 } /* end compareData */                                                        
                                                                                
                                                                                
 void sql_error( char *locmsg )                                                 
 /*********************************************************************         
 * SQL error handler                                                  *         
 *********************************************************************/         
 {                                                                              
   short int   rc;                     /* DSNTIAR Return code        */         
   int         j,k;                    /* Loop control               */         
   static int  lrecl = TIAR_LEN;       /* Width of message lines     */         
                                                                                
   /*******************************************************************         
   * print the location message                                       *         
   *******************************************************************/         
   printf( "*****************************************************\n" );         
   printf( "*** ERROR: DSN8DLTC DB2 Sample Program\n"                );         
   printf( "***        Unexpected SQLCODE encountered at location\n" );         
   printf( "***         %.68s\n", locmsg                             );         
   printf( "***        Error detailed below\n"                       );         
   printf( "***        Processing terminated\n"                      );         
   printf( "*****************************************************\n" );         
                                                                                
   /*******************************************************************         
   * format and print the SQL message                                 *         
   *******************************************************************/         
   rc = dsntiar( &sqlca, &error_message, &lrecl );                              
   if( rc == 0 )                                                                
     for( j=0; j<TIAR_DIM; j++ )                                                
       {                                                                        
         for( k=0; k<TIAR_LEN; k++ )                                            
           putchar(error_message.error_text[j][k] );                            
         putchar('\n');                                                         
       }                                                                        
   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 sql_error */